Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2009  VMware, Inc.  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 /**
     27  * \file viewport.c
     28  * glViewport and glDepthRange functions.
     29  */
     30 
     31 
     32 #include "context.h"
     33 #include "enums.h"
     34 #include "macros.h"
     35 #include "mtypes.h"
     36 #include "viewport.h"
     37 
     38 static void
     39 clamp_viewport(struct gl_context *ctx, GLfloat *x, GLfloat *y,
     40                GLfloat *width, GLfloat *height)
     41 {
     42    /* clamp width and height to the implementation dependent range */
     43    *width  = MIN2(*width, (GLfloat) ctx->Const.MaxViewportWidth);
     44    *height = MIN2(*height, (GLfloat) ctx->Const.MaxViewportHeight);
     45 
     46    /* The GL_ARB_viewport_array spec says:
     47     *
     48     *     "The location of the viewport's bottom-left corner, given by (x,y),
     49     *     are clamped to be within the implementation-dependent viewport
     50     *     bounds range.  The viewport bounds range [min, max] tuple may be
     51     *     determined by calling GetFloatv with the symbolic constant
     52     *     VIEWPORT_BOUNDS_RANGE (see section 6.1)."
     53     */
     54    if (_mesa_has_ARB_viewport_array(ctx) ||
     55        _mesa_has_OES_viewport_array(ctx)) {
     56       *x = CLAMP(*x,
     57                  ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
     58       *y = CLAMP(*y,
     59                  ctx->Const.ViewportBounds.Min, ctx->Const.ViewportBounds.Max);
     60    }
     61 }
     62 
     63 static void
     64 set_viewport_no_notify(struct gl_context *ctx, unsigned idx,
     65                        GLfloat x, GLfloat y,
     66                        GLfloat width, GLfloat height)
     67 {
     68    if (ctx->ViewportArray[idx].X == x &&
     69        ctx->ViewportArray[idx].Width == width &&
     70        ctx->ViewportArray[idx].Y == y &&
     71        ctx->ViewportArray[idx].Height == height)
     72       return;
     73 
     74    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewViewport ? 0 : _NEW_VIEWPORT);
     75    ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
     76 
     77    ctx->ViewportArray[idx].X = x;
     78    ctx->ViewportArray[idx].Width = width;
     79    ctx->ViewportArray[idx].Y = y;
     80    ctx->ViewportArray[idx].Height = height;
     81 }
     82 
     83 struct gl_viewport_inputs {
     84    GLfloat X, Y;                /**< position */
     85    GLfloat Width, Height;       /**< size */
     86 };
     87 
     88 struct gl_depthrange_inputs {
     89    GLdouble Near, Far;          /**< Depth buffer range */
     90 };
     91 
     92 static void
     93 viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei width,
     94          GLsizei height)
     95 {
     96    struct gl_viewport_inputs input = { x, y, width, height };
     97 
     98    /* Clamp the viewport to the implementation dependent values. */
     99    clamp_viewport(ctx, &input.X, &input.Y, &input.Width, &input.Height);
    100 
    101    /* The GL_ARB_viewport_array spec says:
    102     *
    103     *     "Viewport sets the parameters for all viewports to the same values
    104     *     and is equivalent (assuming no errors are generated) to:
    105     *
    106     *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
    107     *         ViewportIndexedf(i, 1, (float)x, (float)y, (float)w, (float)h);"
    108     *
    109     * Set all of the viewports supported by the implementation, but only
    110     * signal the driver once at the end.
    111     */
    112    for (unsigned i = 0; i < ctx->Const.MaxViewports; i++)
    113       set_viewport_no_notify(ctx, i, input.X, input.Y, input.Width, input.Height);
    114 
    115    if (ctx->Driver.Viewport)
    116       ctx->Driver.Viewport(ctx);
    117 }
    118 
    119 /**
    120  * Set the viewport.
    121  * \sa Called via glViewport() or display list execution.
    122  *
    123  * Flushes the vertices and calls _mesa_set_viewport() with the given
    124  * parameters.
    125  */
    126 void GLAPIENTRY
    127 _mesa_Viewport_no_error(GLint x, GLint y, GLsizei width, GLsizei height)
    128 {
    129    GET_CURRENT_CONTEXT(ctx);
    130    viewport(ctx, x, y, width, height);
    131 }
    132 
    133 void GLAPIENTRY
    134 _mesa_Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
    135 {
    136    GET_CURRENT_CONTEXT(ctx);
    137 
    138    if (MESA_VERBOSE & VERBOSE_API)
    139       _mesa_debug(ctx, "glViewport %d %d %d %d\n", x, y, width, height);
    140 
    141    if (width < 0 || height < 0) {
    142       _mesa_error(ctx,  GL_INVALID_VALUE,
    143                    "glViewport(%d, %d, %d, %d)", x, y, width, height);
    144       return;
    145    }
    146 
    147    viewport(ctx, x, y, width, height);
    148 }
    149 
    150 
    151 /**
    152  * Set new viewport parameters and update derived state.
    153  * Usually called from _mesa_Viewport().
    154  *
    155  * \param ctx GL context.
    156  * \param idx    Index of the viewport to be updated.
    157  * \param x, y coordinates of the lower left corner of the viewport rectangle.
    158  * \param width width of the viewport rectangle.
    159  * \param height height of the viewport rectangle.
    160  */
    161 void
    162 _mesa_set_viewport(struct gl_context *ctx, unsigned idx, GLfloat x, GLfloat y,
    163                     GLfloat width, GLfloat height)
    164 {
    165    clamp_viewport(ctx, &x, &y, &width, &height);
    166    set_viewport_no_notify(ctx, idx, x, y, width, height);
    167 
    168    if (ctx->Driver.Viewport)
    169       ctx->Driver.Viewport(ctx);
    170 }
    171 
    172 static void
    173 viewport_array(struct gl_context *ctx, GLuint first, GLsizei count,
    174                struct gl_viewport_inputs *inputs)
    175 {
    176    for (GLsizei i = 0; i < count; i++) {
    177       clamp_viewport(ctx, &inputs[i].X, &inputs[i].Y,
    178                      &inputs[i].Width, &inputs[i].Height);
    179 
    180       set_viewport_no_notify(ctx, i + first, inputs[i].X, inputs[i].Y,
    181                              inputs[i].Width, inputs[i].Height);
    182    }
    183 
    184    if (ctx->Driver.Viewport)
    185       ctx->Driver.Viewport(ctx);
    186 }
    187 
    188 void GLAPIENTRY
    189 _mesa_ViewportArrayv_no_error(GLuint first, GLsizei count, const GLfloat *v)
    190 {
    191    GET_CURRENT_CONTEXT(ctx);
    192 
    193    struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
    194    viewport_array(ctx, first, count, p);
    195 }
    196 
    197 void GLAPIENTRY
    198 _mesa_ViewportArrayv(GLuint first, GLsizei count, const GLfloat *v)
    199 {
    200    int i;
    201    struct gl_viewport_inputs *p = (struct gl_viewport_inputs *)v;
    202    GET_CURRENT_CONTEXT(ctx);
    203 
    204    if (MESA_VERBOSE & VERBOSE_API)
    205       _mesa_debug(ctx, "glViewportArrayv %d %d\n", first, count);
    206 
    207    if ((first + count) > ctx->Const.MaxViewports) {
    208       _mesa_error(ctx, GL_INVALID_VALUE,
    209                   "glViewportArrayv: first (%d) + count (%d) > MaxViewports "
    210                   "(%d)",
    211                   first, count, ctx->Const.MaxViewports);
    212       return;
    213    }
    214 
    215    /* Verify width & height */
    216    for (i = 0; i < count; i++) {
    217       if (p[i].Width < 0 || p[i].Height < 0) {
    218          _mesa_error(ctx, GL_INVALID_VALUE,
    219                      "glViewportArrayv: index (%d) width or height < 0 "
    220                      "(%f, %f)",
    221                      i + first, p[i].Width, p[i].Height);
    222          return;
    223       }
    224    }
    225 
    226    viewport_array(ctx, first, count, p);
    227 }
    228 
    229 static void
    230 viewport_indexed_err(struct gl_context *ctx, GLuint index, GLfloat x, GLfloat y,
    231                      GLfloat w, GLfloat h, const char *function)
    232 {
    233    if (MESA_VERBOSE & VERBOSE_API)
    234       _mesa_debug(ctx, "%s(%d, %f, %f, %f, %f)\n",
    235                   function, index, x, y, w, h);
    236 
    237    if (index >= ctx->Const.MaxViewports) {
    238       _mesa_error(ctx, GL_INVALID_VALUE,
    239                   "%s: index (%d) >= MaxViewports (%d)",
    240                   function, index, ctx->Const.MaxViewports);
    241       return;
    242    }
    243 
    244    /* Verify width & height */
    245    if (w < 0 || h < 0) {
    246       _mesa_error(ctx, GL_INVALID_VALUE,
    247                   "%s: index (%d) width or height < 0 (%f, %f)",
    248                   function, index, w, h);
    249       return;
    250    }
    251 
    252    _mesa_set_viewport(ctx, index, x, y, w, h);
    253 }
    254 
    255 void GLAPIENTRY
    256 _mesa_ViewportIndexedf_no_error(GLuint index, GLfloat x, GLfloat y,
    257                                 GLfloat w, GLfloat h)
    258 {
    259    GET_CURRENT_CONTEXT(ctx);
    260    _mesa_set_viewport(ctx, index, x, y, w, h);
    261 }
    262 
    263 void GLAPIENTRY
    264 _mesa_ViewportIndexedf(GLuint index, GLfloat x, GLfloat y,
    265                        GLfloat w, GLfloat h)
    266 {
    267    GET_CURRENT_CONTEXT(ctx);
    268    viewport_indexed_err(ctx, index, x, y, w, h, "glViewportIndexedf");
    269 }
    270 
    271 void GLAPIENTRY
    272 _mesa_ViewportIndexedfv_no_error(GLuint index, const GLfloat *v)
    273 {
    274    GET_CURRENT_CONTEXT(ctx);
    275    _mesa_set_viewport(ctx, index, v[0], v[1], v[2], v[3]);
    276 }
    277 
    278 void GLAPIENTRY
    279 _mesa_ViewportIndexedfv(GLuint index, const GLfloat *v)
    280 {
    281    GET_CURRENT_CONTEXT(ctx);
    282    viewport_indexed_err(ctx, index, v[0], v[1], v[2], v[3],
    283                         "glViewportIndexedfv");
    284 }
    285 
    286 static void
    287 set_depth_range_no_notify(struct gl_context *ctx, unsigned idx,
    288                           GLclampd nearval, GLclampd farval)
    289 {
    290    if (ctx->ViewportArray[idx].Near == nearval &&
    291        ctx->ViewportArray[idx].Far == farval)
    292       return;
    293 
    294    /* The depth range is needed by program state constants. */
    295    FLUSH_VERTICES(ctx, _NEW_VIEWPORT);
    296    ctx->NewDriverState |= ctx->DriverFlags.NewViewport;
    297 
    298    ctx->ViewportArray[idx].Near = CLAMP(nearval, 0.0, 1.0);
    299    ctx->ViewportArray[idx].Far = CLAMP(farval, 0.0, 1.0);
    300 }
    301 
    302 void
    303 _mesa_set_depth_range(struct gl_context *ctx, unsigned idx,
    304                       GLclampd nearval, GLclampd farval)
    305 {
    306    set_depth_range_no_notify(ctx, idx, nearval, farval);
    307 
    308    if (ctx->Driver.DepthRange)
    309       ctx->Driver.DepthRange(ctx);
    310 }
    311 
    312 /**
    313  * Called by glDepthRange
    314  *
    315  * \param nearval  specifies the Z buffer value which should correspond to
    316  *                 the near clip plane
    317  * \param farval  specifies the Z buffer value which should correspond to
    318  *                the far clip plane
    319  */
    320 void GLAPIENTRY
    321 _mesa_DepthRange(GLclampd nearval, GLclampd farval)
    322 {
    323    unsigned i;
    324    GET_CURRENT_CONTEXT(ctx);
    325 
    326    if (MESA_VERBOSE&VERBOSE_API)
    327       _mesa_debug(ctx, "glDepthRange %f %f\n", nearval, farval);
    328 
    329    /* The GL_ARB_viewport_array spec says:
    330     *
    331     *     "DepthRange sets the depth range for all viewports to the same
    332     *     values and is equivalent (assuming no errors are generated) to:
    333     *
    334     *     for (uint i = 0; i < MAX_VIEWPORTS; i++)
    335     *         DepthRangeIndexed(i, n, f);"
    336     *
    337     * Set the depth range for all of the viewports supported by the
    338     * implementation, but only signal the driver once at the end.
    339     */
    340    for (i = 0; i < ctx->Const.MaxViewports; i++)
    341       set_depth_range_no_notify(ctx, i, nearval, farval);
    342 
    343    if (ctx->Driver.DepthRange) {
    344       ctx->Driver.DepthRange(ctx);
    345    }
    346 }
    347 
    348 void GLAPIENTRY
    349 _mesa_DepthRangef(GLclampf nearval, GLclampf farval)
    350 {
    351    _mesa_DepthRange(nearval, farval);
    352 }
    353 
    354 /**
    355  * Update a range DepthRange values
    356  *
    357  * \param first   starting array index
    358  * \param count   count of DepthRange items to update
    359  * \param v       pointer to memory containing
    360  *                GLclampd near and far clip-plane values
    361  */
    362 static ALWAYS_INLINE void
    363 depth_range_arrayv(struct gl_context *ctx, GLuint first, GLsizei count,
    364                    const struct gl_depthrange_inputs *const inputs)
    365 {
    366    for (GLsizei i = 0; i < count; i++)
    367       set_depth_range_no_notify(ctx, i + first, inputs[i].Near, inputs[i].Far);
    368 
    369    if (ctx->Driver.DepthRange)
    370       ctx->Driver.DepthRange(ctx);
    371 }
    372 
    373 void GLAPIENTRY
    374 _mesa_DepthRangeArrayv_no_error(GLuint first, GLsizei count, const GLclampd *v)
    375 {
    376    GET_CURRENT_CONTEXT(ctx);
    377 
    378    const struct gl_depthrange_inputs *const p =
    379       (struct gl_depthrange_inputs *)v;
    380    depth_range_arrayv(ctx, first, count, p);
    381 }
    382 
    383 void GLAPIENTRY
    384 _mesa_DepthRangeArrayv(GLuint first, GLsizei count, const GLclampd *v)
    385 {
    386    const struct gl_depthrange_inputs *const p =
    387       (struct gl_depthrange_inputs *) v;
    388    GET_CURRENT_CONTEXT(ctx);
    389 
    390    if (MESA_VERBOSE & VERBOSE_API)
    391       _mesa_debug(ctx, "glDepthRangeArrayv %d %d\n", first, count);
    392 
    393    if ((first + count) > ctx->Const.MaxViewports) {
    394       _mesa_error(ctx, GL_INVALID_VALUE,
    395                   "glDepthRangev: first (%d) + count (%d) >= MaxViewports (%d)",
    396                   first, count, ctx->Const.MaxViewports);
    397       return;
    398    }
    399 
    400    depth_range_arrayv(ctx, first, count, p);
    401 }
    402 
    403 void GLAPIENTRY
    404 _mesa_DepthRangeArrayfvOES(GLuint first, GLsizei count, const GLfloat *v)
    405 {
    406    int i;
    407    GET_CURRENT_CONTEXT(ctx);
    408 
    409    if (MESA_VERBOSE & VERBOSE_API)
    410       _mesa_debug(ctx, "glDepthRangeArrayfv %d %d\n", first, count);
    411 
    412    if ((first + count) > ctx->Const.MaxViewports) {
    413       _mesa_error(ctx, GL_INVALID_VALUE,
    414                   "glDepthRangeArrayfv: first (%d) + count (%d) >= MaxViewports (%d)",
    415                   first, count, ctx->Const.MaxViewports);
    416       return;
    417    }
    418 
    419    for (i = 0; i < count; i++)
    420       set_depth_range_no_notify(ctx, i + first, v[i * 2], v[i * 2 + 1]);
    421 
    422    if (ctx->Driver.DepthRange)
    423       ctx->Driver.DepthRange(ctx);
    424 }
    425 
    426 /**
    427  * Update a single DepthRange
    428  *
    429  * \param index    array index to update
    430  * \param nearval  specifies the Z buffer value which should correspond to
    431  *                 the near clip plane
    432  * \param farval   specifies the Z buffer value which should correspond to
    433  *                 the far clip plane
    434  */
    435 void GLAPIENTRY
    436 _mesa_DepthRangeIndexed_no_error(GLuint index, GLclampd nearval,
    437                                  GLclampd farval)
    438 {
    439    GET_CURRENT_CONTEXT(ctx);
    440    _mesa_set_depth_range(ctx, index, nearval, farval);
    441 }
    442 
    443 
    444 void GLAPIENTRY
    445 _mesa_DepthRangeIndexed(GLuint index, GLclampd nearval, GLclampd farval)
    446 {
    447    GET_CURRENT_CONTEXT(ctx);
    448 
    449    if (MESA_VERBOSE & VERBOSE_API)
    450       _mesa_debug(ctx, "glDepthRangeIndexed(%d, %f, %f)\n",
    451                   index, nearval, farval);
    452 
    453    if (index >= ctx->Const.MaxViewports) {
    454       _mesa_error(ctx, GL_INVALID_VALUE,
    455                   "glDepthRangeIndexed: index (%d) >= MaxViewports (%d)",
    456                   index, ctx->Const.MaxViewports);
    457       return;
    458    }
    459 
    460    _mesa_set_depth_range(ctx, index, nearval, farval);
    461 }
    462 
    463 void GLAPIENTRY
    464 _mesa_DepthRangeIndexedfOES(GLuint index, GLfloat nearval, GLfloat farval)
    465 {
    466    _mesa_DepthRangeIndexed(index, nearval, farval);
    467 }
    468 
    469 /**
    470  * Initialize the context viewport attribute group.
    471  * \param ctx  the GL context.
    472  */
    473 void _mesa_init_viewport(struct gl_context *ctx)
    474 {
    475    unsigned i;
    476 
    477    ctx->Transform.ClipOrigin = GL_LOWER_LEFT;
    478    ctx->Transform.ClipDepthMode = GL_NEGATIVE_ONE_TO_ONE;
    479 
    480    /* Note: ctx->Const.MaxViewports may not have been set by the driver yet,
    481     * so just initialize all of them.
    482     */
    483    for (i = 0; i < MAX_VIEWPORTS; i++) {
    484       /* Viewport group */
    485       ctx->ViewportArray[i].X = 0;
    486       ctx->ViewportArray[i].Y = 0;
    487       ctx->ViewportArray[i].Width = 0;
    488       ctx->ViewportArray[i].Height = 0;
    489       ctx->ViewportArray[i].Near = 0.0;
    490       ctx->ViewportArray[i].Far = 1.0;
    491    }
    492 }
    493 
    494 
    495 static ALWAYS_INLINE void
    496 clip_control(struct gl_context *ctx, GLenum origin, GLenum depth, bool no_error)
    497 {
    498    if (ctx->Transform.ClipOrigin == origin &&
    499        ctx->Transform.ClipDepthMode == depth)
    500       return;
    501 
    502    if (!no_error &&
    503        origin != GL_LOWER_LEFT && origin != GL_UPPER_LEFT) {
    504       _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
    505       return;
    506    }
    507 
    508    if (!no_error &&
    509        depth != GL_NEGATIVE_ONE_TO_ONE && depth != GL_ZERO_TO_ONE) {
    510       _mesa_error(ctx, GL_INVALID_ENUM, "glClipControl");
    511       return;
    512    }
    513 
    514    /* Affects transform state and the viewport transform */
    515    FLUSH_VERTICES(ctx, ctx->DriverFlags.NewClipControl ? 0 :
    516                   _NEW_TRANSFORM | _NEW_VIEWPORT);
    517    ctx->NewDriverState |= ctx->DriverFlags.NewClipControl;
    518 
    519    if (ctx->Transform.ClipOrigin != origin) {
    520       ctx->Transform.ClipOrigin = origin;
    521 
    522       /* Affects the winding order of the front face. */
    523       if (ctx->DriverFlags.NewPolygonState)
    524          ctx->NewDriverState |= ctx->DriverFlags.NewPolygonState;
    525       else
    526          ctx->NewState |= _NEW_POLYGON;
    527 
    528       if (ctx->Driver.FrontFace)
    529          ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace);
    530    }
    531 
    532    if (ctx->Transform.ClipDepthMode != depth) {
    533       ctx->Transform.ClipDepthMode = depth;
    534 
    535       if (ctx->Driver.DepthRange)
    536          ctx->Driver.DepthRange(ctx);
    537    }
    538 }
    539 
    540 
    541 void GLAPIENTRY
    542 _mesa_ClipControl_no_error(GLenum origin, GLenum depth)
    543 {
    544    GET_CURRENT_CONTEXT(ctx);
    545    clip_control(ctx, origin, depth, true);
    546 }
    547 
    548 
    549 void GLAPIENTRY
    550 _mesa_ClipControl(GLenum origin, GLenum depth)
    551 {
    552    GET_CURRENT_CONTEXT(ctx);
    553 
    554    if (MESA_VERBOSE & VERBOSE_API)
    555       _mesa_debug(ctx, "glClipControl(%s, %s)\n",
    556 	          _mesa_enum_to_string(origin),
    557                   _mesa_enum_to_string(depth));
    558 
    559    ASSERT_OUTSIDE_BEGIN_END(ctx);
    560 
    561    if (!ctx->Extensions.ARB_clip_control) {
    562       _mesa_error(ctx, GL_INVALID_OPERATION, "glClipControl");
    563       return;
    564    }
    565 
    566    clip_control(ctx, origin, depth, false);
    567 }
    568 
    569 /**
    570  * Computes the scaling and the translation part of the
    571  * viewport transform matrix of the \param i-th viewport
    572  * and writes that into \param scale and \param translate.
    573  */
    574 void
    575 _mesa_get_viewport_xform(struct gl_context *ctx, unsigned i,
    576                          float scale[3], float translate[3])
    577 {
    578    float x = ctx->ViewportArray[i].X;
    579    float y = ctx->ViewportArray[i].Y;
    580    float half_width = 0.5f * ctx->ViewportArray[i].Width;
    581    float half_height = 0.5f * ctx->ViewportArray[i].Height;
    582    double n = ctx->ViewportArray[i].Near;
    583    double f = ctx->ViewportArray[i].Far;
    584 
    585    scale[0] = half_width;
    586    translate[0] = half_width + x;
    587    if (ctx->Transform.ClipOrigin == GL_UPPER_LEFT) {
    588       scale[1] = -half_height;
    589    } else {
    590       scale[1] = half_height;
    591    }
    592    translate[1] = half_height + y;
    593 
    594    if (ctx->Transform.ClipDepthMode == GL_NEGATIVE_ONE_TO_ONE) {
    595       scale[2] = 0.5 * (f - n);
    596       translate[2] = 0.5 * (n + f);
    597    } else {
    598       scale[2] = f - n;
    599       translate[2] = n;
    600    }
    601 }
    602