17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * 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.
237117f1b4Smrg */
247117f1b4Smrg
2501e04c3fSmrg#include "main/errors.h"
26c1f859d4Smrg#include "main/glheader.h"
27c1f859d4Smrg#include "main/macros.h"
287ec681f3Smrg
29af69d88dSmrg#include "main/format_pack.h"
307117f1b4Smrg
317117f1b4Smrg#include "s_context.h"
327117f1b4Smrg#include "s_span.h"
337117f1b4Smrg#include "s_stencil.h"
347117f1b4Smrg#include "s_zoom.h"
357117f1b4Smrg
367117f1b4Smrg
377117f1b4Smrg/**
387117f1b4Smrg * Compute the bounds of the region resulting from zooming a pixel span.
397117f1b4Smrg * The resulting region will be entirely inside the window/scissor bounds
407117f1b4Smrg * so no additional clipping is needed.
417117f1b4Smrg * \param imageX, imageY  position of the mage being drawn (gl WindowPos)
427117f1b4Smrg * \param spanX, spanY  position of span being drawing
437117f1b4Smrg * \param width  number of pixels in span
447117f1b4Smrg * \param x0, x1  returned X bounds of zoomed region [x0, x1)
457117f1b4Smrg * \param y0, y1  returned Y bounds of zoomed region [y0, y1)
467117f1b4Smrg * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
477117f1b4Smrg */
487117f1b4Smrgstatic GLboolean
493464ebd5Sriastradhcompute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
507117f1b4Smrg                      GLint spanX, GLint spanY, GLint width,
517117f1b4Smrg                      GLint *x0, GLint *x1, GLint *y0, GLint *y1)
527117f1b4Smrg{
537117f1b4Smrg   const struct gl_framebuffer *fb = ctx->DrawBuffer;
547117f1b4Smrg   GLint c0, c1, r0, r1;
557117f1b4Smrg
5601e04c3fSmrg   assert(spanX >= imageX);
5701e04c3fSmrg   assert(spanY >= imageY);
587117f1b4Smrg
597117f1b4Smrg   /*
607117f1b4Smrg    * Compute destination columns: [c0, c1)
617117f1b4Smrg    */
627117f1b4Smrg   c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
637117f1b4Smrg   c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
647117f1b4Smrg   if (c1 < c0) {
657117f1b4Smrg      /* swap */
667117f1b4Smrg      GLint tmp = c1;
677117f1b4Smrg      c1 = c0;
687117f1b4Smrg      c0 = tmp;
697117f1b4Smrg   }
707117f1b4Smrg   c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
717117f1b4Smrg   c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
727117f1b4Smrg   if (c0 == c1) {
737117f1b4Smrg      return GL_FALSE; /* no width */
747117f1b4Smrg   }
757117f1b4Smrg
767117f1b4Smrg   /*
777117f1b4Smrg    * Compute destination rows: [r0, r1)
787117f1b4Smrg    */
797117f1b4Smrg   r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
807117f1b4Smrg   r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
817117f1b4Smrg   if (r1 < r0) {
827117f1b4Smrg      /* swap */
837117f1b4Smrg      GLint tmp = r1;
847117f1b4Smrg      r1 = r0;
857117f1b4Smrg      r0 = tmp;
867117f1b4Smrg   }
877117f1b4Smrg   r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
887117f1b4Smrg   r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
897117f1b4Smrg   if (r0 == r1) {
907117f1b4Smrg      return GL_FALSE; /* no height */
917117f1b4Smrg   }
927117f1b4Smrg
937117f1b4Smrg   *x0 = c0;
947117f1b4Smrg   *x1 = c1;
957117f1b4Smrg   *y0 = r0;
967117f1b4Smrg   *y1 = r1;
977117f1b4Smrg
987117f1b4Smrg   return GL_TRUE;
997117f1b4Smrg}
1007117f1b4Smrg
1017117f1b4Smrg
1027117f1b4Smrg/**
1037117f1b4Smrg * Convert a zoomed x image coordinate back to an unzoomed x coord.
1047117f1b4Smrg * 'zx' is screen position of a pixel in the zoomed image, who's left edge
1057117f1b4Smrg * is at 'imageX'.
1067117f1b4Smrg * return corresponding x coord in the original, unzoomed image.
1077117f1b4Smrg * This can use this for unzooming X or Y values.
1087117f1b4Smrg */
109af69d88dSmrgstatic inline GLint
1107117f1b4Smrgunzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
1117117f1b4Smrg{
1127117f1b4Smrg   /*
1137117f1b4Smrg   zx = imageX + (x - imageX) * zoomX;
1147117f1b4Smrg   zx - imageX = (x - imageX) * zoomX;
1157117f1b4Smrg   (zx - imageX) / zoomX = x - imageX;
1167117f1b4Smrg   */
1177117f1b4Smrg   GLint x;
11801e04c3fSmrg   if (zoomX < 0.0F)
1197117f1b4Smrg      zx++;
1207117f1b4Smrg   x = imageX + (GLint) ((zx - imageX) / zoomX);
1217117f1b4Smrg   return x;
1227117f1b4Smrg}
1237117f1b4Smrg
1247117f1b4Smrg
1257117f1b4Smrg
1267117f1b4Smrg/**
1277117f1b4Smrg * Helper function called from _swrast_write_zoomed_rgba/rgb/
1287117f1b4Smrg * index/depth_span().
1297117f1b4Smrg */
1307117f1b4Smrgstatic void
1313464ebd5Sriastradhzoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
1327117f1b4Smrg           const GLvoid *src, GLenum format )
1337117f1b4Smrg{
134c1f859d4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1357117f1b4Smrg   SWspan zoomed;
1367117f1b4Smrg   GLint x0, x1, y0, y1;
1377117f1b4Smrg   GLint zoomedWidth;
1387117f1b4Smrg
1397117f1b4Smrg   if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
1407117f1b4Smrg                              &x0, &x1, &y0, &y1)) {
1417117f1b4Smrg      return;  /* totally clipped */
1427117f1b4Smrg   }
1437117f1b4Smrg
144c1f859d4Smrg   if (!swrast->ZoomedArrays) {
145c1f859d4Smrg      /* allocate on demand */
146af69d88dSmrg      swrast->ZoomedArrays = (SWspanarrays *) calloc(1, sizeof(SWspanarrays));
147c1f859d4Smrg      if (!swrast->ZoomedArrays)
148c1f859d4Smrg         return;
149c1f859d4Smrg   }
150c1f859d4Smrg
1517117f1b4Smrg   zoomedWidth = x1 - x0;
15201e04c3fSmrg   assert(zoomedWidth > 0);
15301e04c3fSmrg   assert(zoomedWidth <= SWRAST_MAX_WIDTH);
1547117f1b4Smrg
1557117f1b4Smrg   /* no pixel arrays! must be horizontal spans. */
15601e04c3fSmrg   assert((span->arrayMask & SPAN_XY) == 0);
15701e04c3fSmrg   assert(span->primitive == GL_BITMAP);
1587117f1b4Smrg
159c1f859d4Smrg   INIT_SPAN(zoomed, GL_BITMAP);
1607117f1b4Smrg   zoomed.x = x0;
1617117f1b4Smrg   zoomed.end = zoomedWidth;
162c1f859d4Smrg   zoomed.array = swrast->ZoomedArrays;
163c1f859d4Smrg   zoomed.array->ChanType = span->array->ChanType;
164c1f859d4Smrg   if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
165c1f859d4Smrg      zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
166c1f859d4Smrg   else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
167c1f859d4Smrg      zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
168c1f859d4Smrg   else
169af69d88dSmrg      zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[VARYING_SLOT_COL0];
1707117f1b4Smrg
171af69d88dSmrg   COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
172af69d88dSmrg   COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
173af69d88dSmrg   COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
1747117f1b4Smrg
175af69d88dSmrg   zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
176af69d88dSmrg   zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
177af69d88dSmrg   zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_FOGC][0];
1787117f1b4Smrg
1797117f1b4Smrg   if (format == GL_RGBA || format == GL_RGB) {
1807117f1b4Smrg      /* copy Z info */
1817117f1b4Smrg      zoomed.z = span->z;
1827117f1b4Smrg      zoomed.zStep = span->zStep;
1837117f1b4Smrg      /* we'll generate an array of colorss */
1847117f1b4Smrg      zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
1857117f1b4Smrg      zoomed.arrayMask |= SPAN_RGBA;
186af69d88dSmrg      zoomed.arrayAttribs |= VARYING_BIT_COL0;  /* we'll produce these values */
18701e04c3fSmrg      assert(span->arrayMask & SPAN_RGBA);
1887117f1b4Smrg   }
1897117f1b4Smrg   else if (format == GL_DEPTH_COMPONENT) {
1907117f1b4Smrg      /* Copy color info */
1917117f1b4Smrg      zoomed.red = span->red;
1927117f1b4Smrg      zoomed.green = span->green;
1937117f1b4Smrg      zoomed.blue = span->blue;
1947117f1b4Smrg      zoomed.alpha = span->alpha;
1957117f1b4Smrg      zoomed.redStep = span->redStep;
1967117f1b4Smrg      zoomed.greenStep = span->greenStep;
1977117f1b4Smrg      zoomed.blueStep = span->blueStep;
1987117f1b4Smrg      zoomed.alphaStep = span->alphaStep;
1997117f1b4Smrg      /* we'll generate an array of depth values */
2007117f1b4Smrg      zoomed.interpMask = span->interpMask & ~SPAN_Z;
2017117f1b4Smrg      zoomed.arrayMask |= SPAN_Z;
20201e04c3fSmrg      assert(span->arrayMask & SPAN_Z);
2037117f1b4Smrg   }
2047117f1b4Smrg   else {
2057117f1b4Smrg      _mesa_problem(ctx, "Bad format in zoom_span");
2067117f1b4Smrg      return;
2077117f1b4Smrg   }
2087117f1b4Smrg
2097117f1b4Smrg   /* zoom the span horizontally */
2107117f1b4Smrg   if (format == GL_RGBA) {
2117117f1b4Smrg      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
2127117f1b4Smrg         const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
2137117f1b4Smrg         GLint i;
2147117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2157117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
21601e04c3fSmrg            assert(j >= 0);
21701e04c3fSmrg            assert(j < (GLint) span->end);
218c1f859d4Smrg            COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
2197117f1b4Smrg         }
2207117f1b4Smrg      }
2217117f1b4Smrg      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
2227117f1b4Smrg         const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
2237117f1b4Smrg         GLint i;
2247117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2257117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
22601e04c3fSmrg            assert(j >= 0);
22701e04c3fSmrg            assert(j < (GLint) span->end);
228c1f859d4Smrg            COPY_4V(zoomed.array->rgba16[i], rgba[j]);
2297117f1b4Smrg         }
2307117f1b4Smrg      }
2317117f1b4Smrg      else {
2327117f1b4Smrg         const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
2337117f1b4Smrg         GLint i;
2347117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2357117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
23601e04c3fSmrg            assert(j >= 0);
23701e04c3fSmrg            assert(j < (GLint) span->end);
238af69d88dSmrg            COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]);
2397117f1b4Smrg         }
2407117f1b4Smrg      }
2417117f1b4Smrg   }
2427117f1b4Smrg   else if (format == GL_RGB) {
2437117f1b4Smrg      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
2447117f1b4Smrg         const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
2457117f1b4Smrg         GLint i;
2467117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2477117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
24801e04c3fSmrg            assert(j >= 0);
24901e04c3fSmrg            assert(j < (GLint) span->end);
250c1f859d4Smrg            zoomed.array->rgba8[i][0] = rgb[j][0];
251c1f859d4Smrg            zoomed.array->rgba8[i][1] = rgb[j][1];
252c1f859d4Smrg            zoomed.array->rgba8[i][2] = rgb[j][2];
253c1f859d4Smrg            zoomed.array->rgba8[i][3] = 0xff;
2547117f1b4Smrg         }
2557117f1b4Smrg      }
2567117f1b4Smrg      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
2577117f1b4Smrg         const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
2587117f1b4Smrg         GLint i;
2597117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2607117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
26101e04c3fSmrg            assert(j >= 0);
26201e04c3fSmrg            assert(j < (GLint) span->end);
263c1f859d4Smrg            zoomed.array->rgba16[i][0] = rgb[j][0];
264c1f859d4Smrg            zoomed.array->rgba16[i][1] = rgb[j][1];
265c1f859d4Smrg            zoomed.array->rgba16[i][2] = rgb[j][2];
266c1f859d4Smrg            zoomed.array->rgba16[i][3] = 0xffff;
2677117f1b4Smrg         }
2687117f1b4Smrg      }
2697117f1b4Smrg      else {
2707117f1b4Smrg         const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
2717117f1b4Smrg         GLint i;
2727117f1b4Smrg         for (i = 0; i < zoomedWidth; i++) {
2737117f1b4Smrg            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
27401e04c3fSmrg            assert(j >= 0);
27501e04c3fSmrg            assert(j < (GLint) span->end);
276af69d88dSmrg            zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
277af69d88dSmrg            zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
278af69d88dSmrg            zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
279af69d88dSmrg            zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F;
2807117f1b4Smrg         }
2817117f1b4Smrg      }
2827117f1b4Smrg   }
2837117f1b4Smrg   else if (format == GL_DEPTH_COMPONENT) {
2847117f1b4Smrg      const GLuint *zValues = (const GLuint *) src;
2857117f1b4Smrg      GLint i;
2867117f1b4Smrg      for (i = 0; i < zoomedWidth; i++) {
2877117f1b4Smrg         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
28801e04c3fSmrg         assert(j >= 0);
28901e04c3fSmrg         assert(j < (GLint) span->end);
2907117f1b4Smrg         zoomed.array->z[i] = zValues[j];
2917117f1b4Smrg      }
292cdc920a0Smrg      /* Now, fall into the RGB path below */
293cdc920a0Smrg      format = GL_RGBA;
2947117f1b4Smrg   }
2957117f1b4Smrg
2967117f1b4Smrg   /* write the span in rows [r0, r1) */
2977117f1b4Smrg   if (format == GL_RGBA || format == GL_RGB) {
2987117f1b4Smrg      /* Writing the span may modify the colors, so make a backup now if we're
2997117f1b4Smrg       * going to call _swrast_write_zoomed_span() more than once.
3007117f1b4Smrg       * Also, clipping may change the span end value, so store it as well.
3017117f1b4Smrg       */
3027117f1b4Smrg      const GLint end = zoomed.end; /* save */
303af69d88dSmrg      void *rgbaSave;
3047117f1b4Smrg      const GLint pixelSize =
3057117f1b4Smrg         (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
3067117f1b4Smrg         ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
3077117f1b4Smrg          : 4 * sizeof(GLfloat));
308af69d88dSmrg
309af69d88dSmrg      rgbaSave = malloc(zoomed.end * pixelSize);
310af69d88dSmrg      if (!rgbaSave) {
311af69d88dSmrg         return;
312af69d88dSmrg      }
313af69d88dSmrg
3147117f1b4Smrg      if (y1 - y0 > 1) {
315cdc920a0Smrg         memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
3167117f1b4Smrg      }
3177117f1b4Smrg      for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
3187117f1b4Smrg         _swrast_write_rgba_span(ctx, &zoomed);
3197117f1b4Smrg         zoomed.end = end;  /* restore */
3207117f1b4Smrg         if (y1 - y0 > 1) {
3217117f1b4Smrg            /* restore the colors */
322cdc920a0Smrg            memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
3237117f1b4Smrg         }
3247117f1b4Smrg      }
325af69d88dSmrg
326af69d88dSmrg      free(rgbaSave);
3277117f1b4Smrg   }
3287117f1b4Smrg}
3297117f1b4Smrg
3307117f1b4Smrg
3317117f1b4Smrgvoid
3323464ebd5Sriastradh_swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
3337117f1b4Smrg                               const SWspan *span, const GLvoid *rgba)
3347117f1b4Smrg{
3357117f1b4Smrg   zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
3367117f1b4Smrg}
3377117f1b4Smrg
3387117f1b4Smrg
3397117f1b4Smrgvoid
3403464ebd5Sriastradh_swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
3417117f1b4Smrg                              const SWspan *span, const GLvoid *rgb)
3427117f1b4Smrg{
3437117f1b4Smrg   zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
3447117f1b4Smrg}
3457117f1b4Smrg
3467117f1b4Smrg
3477117f1b4Smrgvoid
3483464ebd5Sriastradh_swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
3497117f1b4Smrg                                const SWspan *span)
3507117f1b4Smrg{
3517117f1b4Smrg   zoom_span(ctx, imgX, imgY, span,
3527117f1b4Smrg             (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
3537117f1b4Smrg}
3547117f1b4Smrg
3557117f1b4Smrg
3567117f1b4Smrg/**
3577117f1b4Smrg * Zoom/write stencil values.
3587117f1b4Smrg * No per-fragment operations are applied.
3597117f1b4Smrg */
3607117f1b4Smrgvoid
3613464ebd5Sriastradh_swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
3627117f1b4Smrg                                  GLint width, GLint spanX, GLint spanY,
363af69d88dSmrg                                  const GLubyte stencil[])
3647117f1b4Smrg{
365af69d88dSmrg   GLubyte *zoomedVals;
3667117f1b4Smrg   GLint x0, x1, y0, y1, y;
3677117f1b4Smrg   GLint i, zoomedWidth;
3687117f1b4Smrg
3697117f1b4Smrg   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
3707117f1b4Smrg                              &x0, &x1, &y0, &y1)) {
3717117f1b4Smrg      return;  /* totally clipped */
3727117f1b4Smrg   }
3737117f1b4Smrg
3747117f1b4Smrg   zoomedWidth = x1 - x0;
37501e04c3fSmrg   assert(zoomedWidth > 0);
37601e04c3fSmrg   assert(zoomedWidth <= SWRAST_MAX_WIDTH);
377af69d88dSmrg
378af69d88dSmrg   zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
379af69d88dSmrg   if (!zoomedVals)
380af69d88dSmrg      return;
3817117f1b4Smrg
3827117f1b4Smrg   /* zoom the span horizontally */
3837117f1b4Smrg   for (i = 0; i < zoomedWidth; i++) {
3847117f1b4Smrg      GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
38501e04c3fSmrg      assert(j >= 0);
38601e04c3fSmrg      assert(j < width);
3877117f1b4Smrg      zoomedVals[i] = stencil[j];
3887117f1b4Smrg   }
3897117f1b4Smrg
3907117f1b4Smrg   /* write the zoomed spans */
3917117f1b4Smrg   for (y = y0; y < y1; y++) {
3927117f1b4Smrg      _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
3937117f1b4Smrg   }
394af69d88dSmrg
395af69d88dSmrg   free(zoomedVals);
3967117f1b4Smrg}
3977117f1b4Smrg
3987117f1b4Smrg
3997117f1b4Smrg/**
400af69d88dSmrg * Zoom/write 32-bit Z values.
4017117f1b4Smrg * No per-fragment operations are applied.
4027117f1b4Smrg */
4037117f1b4Smrgvoid
4043464ebd5Sriastradh_swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
4057117f1b4Smrg                            GLint width, GLint spanX, GLint spanY,
406af69d88dSmrg                            const GLuint *zVals)
4077117f1b4Smrg{
408af69d88dSmrg   struct gl_renderbuffer *rb =
409af69d88dSmrg      ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
410af69d88dSmrg   GLuint *zoomedVals;
4117117f1b4Smrg   GLint x0, x1, y0, y1, y;
4127117f1b4Smrg   GLint i, zoomedWidth;
4137117f1b4Smrg
4147117f1b4Smrg   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
4157117f1b4Smrg                              &x0, &x1, &y0, &y1)) {
4167117f1b4Smrg      return;  /* totally clipped */
4177117f1b4Smrg   }
4187117f1b4Smrg
4197117f1b4Smrg   zoomedWidth = x1 - x0;
42001e04c3fSmrg   assert(zoomedWidth > 0);
42101e04c3fSmrg   assert(zoomedWidth <= SWRAST_MAX_WIDTH);
422af69d88dSmrg
423af69d88dSmrg   zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
424af69d88dSmrg   if (!zoomedVals)
425af69d88dSmrg      return;
4267117f1b4Smrg
4277117f1b4Smrg   /* zoom the span horizontally */
428af69d88dSmrg   for (i = 0; i < zoomedWidth; i++) {
429af69d88dSmrg      GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
43001e04c3fSmrg      assert(j >= 0);
43101e04c3fSmrg      assert(j < width);
432af69d88dSmrg      zoomedVals[i] = zVals[j];
4337117f1b4Smrg   }
4347117f1b4Smrg
4357117f1b4Smrg   /* write the zoomed spans */
4367117f1b4Smrg   for (y = y0; y < y1; y++) {
437af69d88dSmrg      GLubyte *dst = _swrast_pixel_address(rb, x0, y);
438af69d88dSmrg      _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
4397117f1b4Smrg   }
440af69d88dSmrg
441af69d88dSmrg   free(zoomedVals);
4427117f1b4Smrg}
443