1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <PiscesUtil.h>
  27 #include <PiscesRenderer.h>
  28 
  29 #include <PiscesSysutils.h>
  30 #include <PiscesMath.h>
  31 
  32 #define NO_REPEAT_NO_INTERPOLATE        0
  33 #define REPEAT_NO_INTERPOLATE           1
  34 #define NO_REPEAT_INTERPOLATE_NO_ALPHA  2
  35 #define NO_REPEAT_INTERPOLATE_ALPHA     3
  36 #define REPEAT_INTERPOLATE_NO_ALPHA     4
  37 #define REPEAT_INTERPOLATE_ALPHA        5
  38 
  39 static jlong lmod(jlong x, jlong y) {
  40     x = x % y;
  41     if (x < 0) {
  42         x += y;
  43     }
  44     return x;
  45 }
  46 
  47 
  48 #if defined(__arm__) && (defined(__GNUC__) && __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
  49 #define GCC_BUG_57967_WORKAROUND
  50 #endif
  51 
  52 #ifdef GCC_BUG_57967_WORKAROUND
  53 #pragma GCC push_options
  54 #pragma GCC optimize ("O1")
  55 #endif
  56 
  57 static INLINE jint interp(jint x0, jint x1, jint frac) {
  58     return ((x0 << 16) + (x1 - x0) * frac + 0x8000) >> 16;
  59 }
  60 
  61 #ifdef GCC_BUG_57967_WORKAROUND
  62 #pragma GCC pop_options
  63 #endif
  64 
  65 static INLINE jint
  66 pad(jint ifrac, jint cycleMethod) {
  67     switch (cycleMethod) {
  68     case CYCLE_NONE:
  69         if (ifrac < 0) {
  70             ifrac = 0;
  71         } else if (ifrac > 0xffff) {
  72             ifrac = 0xffff;
  73         }
  74         break;
  75     case CYCLE_REPEAT:
  76         ifrac &= 0xffff;
  77         break;
  78     case CYCLE_REFLECT:
  79         if (ifrac < 0) {
  80             ifrac = -ifrac;
  81         }
  82         ifrac &= 0x1ffff;
  83         if (ifrac > 0xffff) {
  84             ifrac = 0x1ffff - ifrac;
  85         }
  86         break;
  87     }
  88 
  89     return ifrac;
  90 }
  91 
  92 void
  93 genLinearGradientPaint(Renderer *rdr, jint height) {
  94     jint paintOffset = 0;
  95     jint width = rdr->_alphaWidth;
  96 
  97     jint minX, maxX;
  98     jfloat frac;
  99     jint pidx;
 100 
 101     jint x, y;
 102     jint i, j;
 103 
 104     jint cycleMethod = rdr->_gradient_cycleMethod;
 105     jfloat mx = rdr->_lg_mx;
 106     jfloat my = rdr->_lg_my;
 107     jfloat b = rdr->_lg_b;
 108 
 109     jint* paint = rdr->_paint;
 110     jint* colors = rdr->_gradient_colors;
 111 
 112     minX = rdr->_minTouched;
 113     maxX = rdr->_maxTouched;
 114 
 115     y = rdr->_currY;
 116     for (j = 0; j < height; j++, y++) {
 117         x = rdr->_currX;
 118         pidx = paintOffset;
 119 
 120         frac = x * mx + y * my + b;
 121         for (i = 0; i < width; i++, pidx++) {
 122             jint ifrac = pad((jint)frac, cycleMethod);
 123             ifrac >>= 16 - LG_GRADIENT_MAP_SIZE;
 124             paint[pidx] = colors[ifrac];
 125 
 126             frac += mx;
 127         }
 128 
 129         paintOffset += width;
 130     }
 131 }
 132 
 133 void
 134 genRadialGradientPaint(Renderer *rdr, jint height) {
 135     jint cycleMethod = rdr->_gradient_cycleMethod;
 136     jint width = rdr->_alphaWidth;
 137     jint minX, maxX;
 138     jint paintOffset = 0;
 139     jint pidx;
 140     jint i, j;
 141     jint x, y;
 142 
 143     jfloat a00, a01, a02, a10, a11, a12;
 144     jfloat cx, cy, fx, fy, r, rsq;
 145     jfloat cfxcfx, cfycfy, cfxcfy;
 146     jfloat a00a00, a10a10, a00a10, sube;
 147 
 148     float txx, tyy, fxx, fyy, cfx, cfy;
 149     float A, B, B2, C, C2, U, dU, V, dV, ddV, tmp;
 150     float _Csq, _C;
 151     jint ifrac;
 152 
 153     jint* paint = rdr->_paint;
 154     jint* colors = rdr->_gradient_colors;
 155 
 156     minX = rdr->_minTouched;
 157     maxX = rdr->_maxTouched;
 158 
 159     a00 = rdr->_rg_a00;
 160     a01 = rdr->_rg_a01;
 161     a02 = rdr->_rg_a02;
 162     a10 = rdr->_rg_a10;
 163     a11 = rdr->_rg_a11;
 164     a12 = rdr->_rg_a12;
 165 
 166     a00a00 = rdr->_rg_a00a00;
 167     a10a10 = rdr->_rg_a10a10;
 168     a00a10 = rdr->_rg_a00a10;
 169 
 170     cx = rdr->_rg_cx;
 171     cy = rdr->_rg_cy;
 172     fx = rdr->_rg_fx;
 173     fy = rdr->_rg_fy;
 174     r = rdr->_rg_r;
 175     rsq = rdr->_rg_rsq;
 176 
 177     y = rdr->_currY;
 178     for (j = 0; j < height; j++, y++) {
 179         pidx = paintOffset;
 180         x = rdr->_currX;
 181 
 182         txx = x * a00 + y * a01 + a02;
 183         tyy = x * a10 + y * a11 + a12;
 184 
 185         fxx = fx - txx;
 186         fyy = fy - tyy;
 187         A = fxx * fxx + fyy * fyy;
 188         cfx = cx - fx;
 189         cfy = cy - fy;
 190         cfxcfx = (jfloat)(cfx * cfx);
 191         cfycfy = (jfloat)(cfy * cfy);
 192         cfxcfy = (jfloat)(cfx * cfy);
 193         B = (cfx * fxx + cfy * fyy);
 194         B2 = -B * 2.0f;
 195         C = cfxcfx + cfycfy - rsq;
 196         C2 = 2.0f * C;
 197         _C = 1.0f / C;
 198         _Csq = _C * _C;
 199         U = (-B * _C);
 200         dU = (a00 * cfx + a10 * cfy) * _C;
 201         V =  ((B * B - A * C) * _Csq);
 202         sube = 2.0f * a00a10 *cfxcfy;
 203         dV =  (sube +
 204               (a00a00 * (cfxcfx - C) + a00 * (B2 * cfx + C2 * fxx)) +
 205               (a10a10 * (cfycfy - C) + a10 * (B2 * cfy + C2 * fyy))) * _Csq;
 206         tmp = a00a00*cfycfy - sube + a10a10*cfxcfx;
 207         ddV = 2.0f * ((a00a00 + a10a10) * rsq - tmp) * _Csq;
 208 
 209         U   = (65536.0f * U); // 65536.0f to be in fixed-point level needed by "frac"
 210         V   = (65536.0f * 65536.0f * V); // 65536.0f * 65536.0f to stay in fixed point level after sqrt
 211         dU  = (65536.0f * dU);
 212         dV  = (65536.0f * 65536.0f * dV);
 213         ddV = (65536.0f * 65536.0f * ddV);
 214         for (i = 0; i < width; i++, pidx++) {
 215             if (V < 0) {
 216                 V = 0;
 217             }
 218 
 219             ifrac = (jint)(U + PISCESsqrt(V));
 220 
 221             U += dU;
 222             V += dV ;
 223             dV += ddV;
 224 
 225             ifrac = pad(ifrac, cycleMethod);
 226             ifrac >>= (16 - LG_GRADIENT_MAP_SIZE);
 227             paint[pidx] = colors[ifrac];
 228         }
 229 
 230         paintOffset += width;
 231     }
 232 }
 233 
 234 static INLINE jint interpolate2points(jint p0, jint p1, jint frac) {
 235     jint a0 = (p0 >> 24) & 0xff;
 236     jint r0 = (p0 >> 16) & 0xff;
 237     jint g0 = (p0 >> 8)  & 0xff;
 238     jint b0 =  p0        & 0xff;
 239 
 240     jint a1 = (p1 >> 24) & 0xff;
 241     jint r1 = (p1 >> 16) & 0xff;
 242     jint g1 = (p1 >> 8)  & 0xff;
 243     jint b1 =  p1        & 0xff;
 244 
 245     jint aa = interp(a0, a1, frac);
 246     jint rr = interp(r0, r1, frac);
 247     jint gg = interp(g0, g1, frac);
 248     jint bb = interp(b0, b1, frac);
 249 
 250     return (aa << 24) | (rr << 16) | (gg << 8) | bb;
 251 }
 252 
 253 /**
 254  * Function interpolate4points() takes color ARGB-value of pixel p00 and
 255  * recalculates (using linear interpolation) it's color with ARGB values of
 256  * neighbouring pixels.
 257  * p01 - right neighbour of p00
 258  * p10 - below p00
 259  * p11 - below right
 260  */
 261 
 262 static INLINE jint interpolate4points(jint p00, jint p01, jint p10, jint p11,
 263                                jint hfrac, jint vfrac) {
 264     jint a00 = (p00 >> 24) & 0xff;
 265     jint r00 = (p00 >> 16) & 0xff;
 266     jint g00 = (p00 >> 8)  & 0xff;
 267     jint b00 =  p00        & 0xff;
 268 
 269     jint a01 = (p01 >> 24) & 0xff;
 270     jint r01 = (p01 >> 16) & 0xff;
 271     jint g01 = (p01 >> 8)  & 0xff;
 272     jint b01 =  p01        & 0xff;
 273 
 274     jint a0 = interp(a00, a01, hfrac);
 275     jint r0 = interp(r00, r01, hfrac);
 276     jint g0 = interp(g00, g01, hfrac);
 277     jint b0 = interp(b00, b01, hfrac);
 278 
 279     jint a10 = (p10 >> 24) & 0xff;
 280     jint r10 = (p10 >> 16) & 0xff;
 281     jint g10 = (p10 >> 8)  & 0xff;
 282     jint b10 =  p10        & 0xff;
 283 
 284     jint a11 = (p11 >> 24) & 0xff;
 285     jint r11 = (p11 >> 16) & 0xff;
 286     jint g11 = (p11 >> 8)  & 0xff;
 287     jint b11 =  p11        & 0xff;
 288 
 289     jint a1 = interp(a10, a11, hfrac);
 290     jint r1 = interp(r10, r11, hfrac);
 291     jint g1 = interp(g10, g11, hfrac);
 292     jint b1 = interp(b10, b11, hfrac);
 293 
 294     jint aa = interp(a0, a1, vfrac);
 295     jint rr = interp(r0, r1, vfrac);
 296     jint gg = interp(g0, g1, vfrac);
 297     jint bb = interp(b0, b1, vfrac);
 298 
 299     return (aa << 24) | (rr << 16) | (gg << 8) | bb;
 300 }
 301 
 302 static INLINE jint interpolate2pointsNoAlpha(jint p0, jint p1, jint frac) {
 303     jint r0 = (p0 >> 16) & 0xff;
 304     jint g0 = (p0 >> 8)  & 0xff;
 305     jint b0 =  p0        & 0xff;
 306 
 307     jint r1 = (p1 >> 16) & 0xff;
 308     jint g1 = (p1 >> 8)  & 0xff;
 309     jint b1 =  p1        & 0xff;
 310 
 311     jint rr = interp(r0, r1, frac);
 312     jint gg = interp(g0, g1, frac);
 313     jint bb = interp(b0, b1, frac);
 314 
 315     return (0xff000000) | (rr << 16) | (gg << 8) | bb;
 316 }
 317 
 318 static INLINE jint interpolate4pointsNoAlpha(jint p00, jint p01, jint p10, jint p11,
 319                                       jint hfrac, jint vfrac) {
 320     jint r00 = (p00 >> 16) & 0xff;
 321     jint g00 = (p00 >> 8)  & 0xff;
 322     jint b00 =  p00        & 0xff;
 323 
 324     jint r01 = (p01 >> 16) & 0xff;
 325     jint g01 = (p01 >> 8)  & 0xff;
 326     jint b01 =  p01        & 0xff;
 327 
 328     jint r0 = interp(r00, r01, hfrac);
 329     jint g0 = interp(g00, g01, hfrac);
 330     jint b0 = interp(b00, b01, hfrac);
 331 
 332     jint r10 = (p10 >> 16) & 0xff;
 333     jint g10 = (p10 >> 8)  & 0xff;
 334     jint b10 =  p10        & 0xff;
 335 
 336     jint r11 = (p11 >> 16) & 0xff;
 337     jint g11 = (p11 >> 8)  & 0xff;
 338     jint b11 =  p11        & 0xff;
 339 
 340     jint r1 = interp(r10, r11, hfrac);
 341     jint g1 = interp(g10, g11, hfrac);
 342     jint b1 = interp(b10, b11, hfrac);
 343 
 344     jint rr = interp(r0, r1, vfrac);
 345     jint gg = interp(g0, g1, vfrac);
 346     jint bb = interp(b0, b1, vfrac);
 347 
 348     return (0xff000000) | (rr << 16) | (gg << 8) | bb;
 349 }
 350 
 351 static INLINE jboolean isInBoundsNoRepeat(jint *a, jlong *la, jint min, jint max) {
 352     jboolean inBounds = XNI_TRUE;
 353     jint aval = *a;
 354     if (aval < min || aval > max) {
 355         inBounds = XNI_FALSE;
 356     }
 357     return inBounds;
 358 }
 359 
 360 //
 361 // this function is called when transform is translate or scale
 362 // because the bounding box will be always fully filled
 363 //
 364 static INLINE void checkBoundsRepeat(jint *a, jlong *la, jint min, jint max) {
 365     jint aval = *a;
 366     if (aval < min || aval > max) {
 367         if (max >= 0) {
 368             *la = lmod(*la, (max+1) << 16);
 369             *a = (jint)(*la >> 16);
 370         } else {
 371             *la = 0;
 372             *a = 0;
 373         }
 374     }
 375 }
 376 
 377 static INLINE void checkBoundsNoRepeat(jint *a, jlong *la, jint min, jint max) {
 378     jint aval = *a;
 379     if (aval < min) {
 380         *a = min;
 381     } else if (aval > max) {
 382         *a = max;
 383     }
 384 }
 385 
 386 static INLINE void getPointsToInterpolate(jint *pts, jint *data, jint sidx, jint stride, jint p00,
 387     jint tx, jint txMax, jint ty, jint tyMax)
 388 {
 389     jint sidx2 = (ty >= tyMax) ? sidx : sidx + stride;
 390     jboolean isXin = (tx < txMax);
 391     pts[0] = (isXin) ? data[sidx + 1] : p00;
 392     pts[1] = data[sidx2];
 393     pts[2] = (isXin) ? data[sidx2 + 1] : data[sidx2];
 394 }
 395 
 396 static INLINE void getPointsToInterpolateRepeat(jint *pts, jint *data, jint sidx, jint stride, jint p00,
 397     jint tx, jint txMax, jint ty, jint tyMax)
 398 {
 399     jint sidx2 = (ty >= tyMax) ? MAX(tx,0) : sidx + stride;
 400     jboolean isXin = (tx < txMax);
 401     pts[0] = (isXin) ? data[sidx + 1] : data[sidx - MAX(tx,0)];
 402     pts[1] = data[sidx2];
 403     pts[2] = (isXin) ? data[sidx2 + 1] : data[sidx2 - MAX(tx,0)];
 404 }
 405 
 406 void
 407 genTexturePaintTarget(Renderer *rdr, jint *paint, jint height) {
 408     jint j;
 409     jint paintStride = rdr->_alphaWidth;
 410 
 411     jint x, y;
 412     jint* txtData = rdr->_texture_intData;
 413     jint txtWidth = rdr->_texture_imageWidth;
 414     jint txtHeight = rdr->_texture_imageHeight;
 415     jint txtStride = rdr->_texture_stride;
 416     jint txMin = rdr->_texture_txMin;
 417     jint tyMin = rdr->_texture_tyMin;
 418     jint txMax = rdr->_texture_txMax;
 419     jint tyMax = rdr->_texture_tyMax;
 420     jint repeatInterpolateMode;
 421 
 422     if (rdr->_texture_interpolate) {
 423         if (rdr->_texture_hasAlpha) {
 424             repeatInterpolateMode = (rdr->_texture_repeat) ?
 425                 REPEAT_INTERPOLATE_ALPHA : NO_REPEAT_INTERPOLATE_ALPHA;
 426         } else {
 427             repeatInterpolateMode = (rdr->_texture_repeat) ?
 428                 REPEAT_INTERPOLATE_NO_ALPHA : NO_REPEAT_INTERPOLATE_NO_ALPHA;
 429         }
 430     } else {
 431         repeatInterpolateMode = (rdr->_texture_repeat) ?
 432             REPEAT_NO_INTERPOLATE : NO_REPEAT_NO_INTERPOLATE;
 433     }
 434 
 435     switch (rdr->_texture_transformType) {
 436     case TEXTURE_TRANSFORM_IDENTITY:
 437         // There used to be special case code for IDENTITY, but it had a number
 438         // of bugs where it punted on some calculations which turned out to be
 439         // necessary.  It was also rarely used because it relied on no
 440         // translations to be set and/or no sub-textures to be used, which
 441         // almost never happens in a scene graph, so this code was largely
 442         // untested (witness the bugs mentioned above).  The decision was made
 443         // to just have this case fall through to the translate case which is
 444         // reasonably optimal and the code that was being used 99% of the
 445         // time when there was no scale anyway.
 446     /* NO BREAK */
 447 
 448     // just TRANSLATION
 449     case TEXTURE_TRANSFORM_TRANSLATE:
 450         {
 451         jint cval, pidx;
 452         jint *a, *am;
 453         jlong ltx, lty;
 454         jint tx, ty, vfrac, hfrac;
 455         jint paintOffset = 0;
 456         jint pts[3];
 457         jint sidx, p00;
 458 
 459         y = rdr->_currY;
 460 
 461         for (j = 0; j < height; j++, y++) {
 462             pidx = paintOffset;
 463 
 464             x = rdr->_currX;
 465 
 466             ltx = (x << 16) + rdr->_texture_m02;
 467             lty = (y << 16) + rdr->_texture_m12;
 468 
 469             // we can compute here since (m00 == 65536) && (m10 == 0)
 470             tx = (jint)(ltx >> 16);
 471             ty = (jint)(lty >> 16);
 472             hfrac = (jint)(ltx & 0xffff);
 473             vfrac = (jint)(lty & 0xffff);
 474 
 475             if (rdr->_texture_repeat) {
 476                 checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 477             } else {
 478                 checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 479             }
 480 
 481             a = paint + pidx;
 482             am = a + paintStride;
 483 
 484             PISCES_DEBUG("TRANSLATE, txMin: %d, txMax: %d, tyMin: %d, tyMax: %d\n", txMin, txMax, tyMin, tyMax);
 485 
 486             switch (repeatInterpolateMode) {
 487             case NO_REPEAT_NO_INTERPOLATE:
 488             {
 489                 jint *txtRow = txtData + (MAX(0, ty) * txtStride);
 490                 jint len;
 491                 tx = (jint)(ltx >> 16);
 492                 while (tx < txMin && a < am) {
 493                     *a++ = txtRow[txMin];
 494                     ++tx;
 495                 }
 496                 len = MIN(am-a, txMax-tx+1);
 497                 if (len > 0) {
 498                     memcpy(a, txtRow + tx, sizeof(jint) * len);
 499                     a += len;
 500                 }
 501                 while (a < am) {
 502                     *a++ = txtRow[txMax];
 503                 }
 504                 break;
 505             }
 506             case REPEAT_NO_INTERPOLATE:
 507                 while (a < am) {
 508                     tx = (jint)(ltx >> 16);
 509                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 510                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 511                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 512                     assert(pidx >= 0);
 513                     assert(pidx < rdr->_paint_length);
 514                     paint[pidx] = txtData[sidx];
 515                     ++a;
 516                     ++pidx;
 517                     ltx += 0x10000;
 518                 } // while (a < am)
 519                 break;
 520             case NO_REPEAT_INTERPOLATE_ALPHA:
 521                 while (a < am) {
 522                     tx = (jint)(ltx >> 16);
 523                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 524                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 525                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 526                     p00 = txtData[sidx];
 527                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 528                         tx, txtWidth-1, ty, txtHeight-1);
 529                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 530                     if (hfrac && vfrac) {
 531                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 532                     } else if (hfrac) {
 533                         cval = interpolate2points(p00, pts[0], hfrac);
 534                     } else if (vfrac) {
 535                         cval = interpolate2points(p00, pts[1], vfrac);
 536                     } else {
 537                         cval = p00;
 538                     }
 539                     assert(pidx >= 0);
 540                     assert(pidx < rdr->_paint_length);
 541                     paint[pidx] = cval;
 542                     ++a;
 543                     ++pidx;
 544                     ltx += 0x10000;
 545                 } // while (a < am)
 546                 break;
 547             case REPEAT_INTERPOLATE_ALPHA:
 548                 while (a < am) {
 549                     tx = (jint)(ltx >> 16);
 550                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 551                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 552                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 553                     p00 = txtData[sidx];
 554                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 555                         tx, txtWidth-1, ty, txtHeight-1);
 556                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 557                     if (hfrac && vfrac) {
 558                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 559                     } else if (hfrac) {
 560                         cval = interpolate2points(p00, pts[0], hfrac);
 561                     } else if (vfrac) {
 562                         cval = interpolate2points(p00, pts[1], vfrac);
 563                     } else {
 564                         cval = p00;
 565                     }
 566                     assert(pidx >= 0);
 567                     assert(pidx < rdr->_paint_length);
 568                     paint[pidx] = cval;
 569                     ++a;
 570                     ++pidx;
 571                     ltx += 0x10000;
 572                 } // while (a < am)
 573                 break;
 574             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 575                 while (a < am) {
 576                     tx = (jint)(ltx >> 16);
 577                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 578                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 579                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 580                     p00 = txtData[sidx];
 581                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 582                         tx, txtWidth-1, ty, txtHeight-1);
 583                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 584                     if (hfrac && vfrac) {
 585                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 586                     } else if (hfrac) {
 587                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 588                     } else if (vfrac) {
 589                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 590                     } else {
 591                         cval = p00;
 592                     }
 593                     assert(pidx >= 0);
 594                     assert(pidx < rdr->_paint_length);
 595                     paint[pidx] = cval;
 596                     ++a;
 597                     ++pidx;
 598                     ltx += 0x10000;
 599                 } // while (a < am)
 600                 break;
 601             case REPEAT_INTERPOLATE_NO_ALPHA:
 602                 while (a < am) {
 603                     tx = (jint)(ltx >> 16);
 604                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 605                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 606                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 607                     p00 = txtData[sidx];
 608                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 609                         tx, txtWidth-1, ty, txtHeight-1);
 610                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 611                     if (hfrac && vfrac) {
 612                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 613                     } else if (hfrac) {
 614                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 615                     } else if (vfrac) {
 616                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 617                     } else {
 618                         cval = p00;
 619                     }
 620                     assert(pidx >= 0);
 621                     assert(pidx < rdr->_paint_length);
 622                     paint[pidx] = cval;
 623                     ++a;
 624                     ++pidx;
 625                     ltx += 0x10000;
 626                 } // while (a < am)
 627                 break;
 628             }
 629             PISCES_DEBUG("\n");
 630             paintOffset += paintStride;
 631         } // for
 632         }
 633         break;
 634 
 635     // scale transform
 636     case TEXTURE_TRANSFORM_SCALE_TRANSLATE:
 637         {
 638         jint cval, pidx;
 639         jint *a, *am;
 640         jlong ltx, lty;
 641         jint tx, ty, vfrac, hfrac;
 642         jint paintOffset = 0;
 643         jint pts[3];
 644         jint sidx, p00;
 645 
 646         y = rdr->_currY;
 647 
 648         for (j = 0; j < height; j++, y++) {
 649             pidx = paintOffset;
 650 
 651             x = rdr->_currX;
 652 
 653             ltx = x * rdr->_texture_m00 + y * rdr->_texture_m01 + rdr->_texture_m02;
 654             lty = x * rdr->_texture_m10 + y * rdr->_texture_m11 + rdr->_texture_m12;
 655 
 656             a = paint + pidx;
 657             am = a + paintStride;
 658 
 659             PISCES_DEBUG("SCALE, txMin: %d, txMax: %d, tyMin: %d, tyMax: %d\n", txMin, txMax, tyMin, tyMax);
 660 
 661             switch (repeatInterpolateMode) {
 662             case NO_REPEAT_NO_INTERPOLATE:
 663                 while (a < am) {
 664                     tx = (jint)(ltx >> 16);
 665                     ty = (jint)(lty >> 16);
 666                     hfrac = (jint)(ltx & 0xffff);
 667                     vfrac = (jint)(lty & 0xffff);
 668                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 669                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 670                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 671                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 672                     assert(pidx >= 0);
 673                     assert(pidx < rdr->_paint_length);
 674                     paint[pidx] = txtData[sidx];
 675                     ++a;
 676                     ++pidx;
 677                     ltx += rdr->_texture_m00;
 678                     lty += rdr->_texture_m10;
 679                 } // while (a < am)b
 680                 break;
 681             case REPEAT_NO_INTERPOLATE:
 682                 while (a < am) {
 683                     tx = (jint)(ltx >> 16);
 684                     ty = (jint)(lty >> 16);
 685                     hfrac = (jint)(ltx & 0xffff);
 686                     vfrac = (jint)(lty & 0xffff);
 687                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 688                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 689                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 690                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 691                     assert(pidx >= 0);
 692                     assert(pidx < rdr->_paint_length);
 693                     paint[pidx] = txtData[sidx];
 694                     ++a;
 695                     ++pidx;
 696                     ltx += rdr->_texture_m00;
 697                     lty += rdr->_texture_m10;
 698                 } // while (a < am)b
 699                 break;
 700             case NO_REPEAT_INTERPOLATE_ALPHA:
 701                 while (a < am) {
 702                     tx = (jint)(ltx >> 16);
 703                     ty = (jint)(lty >> 16);
 704                     hfrac = (jint)(ltx & 0xffff);
 705                     vfrac = (jint)(lty & 0xffff);
 706                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 707                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 708                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 709                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 710                     p00 = txtData[sidx];
 711                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 712                         tx, txtWidth-1, ty, txtHeight-1);
 713                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 714                     if (hfrac && vfrac) {
 715                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 716                     } else if (hfrac) {
 717                         cval = interpolate2points(p00, pts[0], hfrac);
 718                     } else if (vfrac) {
 719                         cval = interpolate2points(p00, pts[1], vfrac);
 720                     } else {
 721                         cval = p00;
 722                     }
 723                     assert(pidx >= 0);
 724                     assert(pidx < rdr->_paint_length);
 725                     paint[pidx] = cval;
 726 
 727                     ++a;
 728                     ++pidx;
 729                     ltx += rdr->_texture_m00;
 730                     lty += rdr->_texture_m10;
 731                 } // while (a < am)b
 732                 break;
 733             case REPEAT_INTERPOLATE_ALPHA:
 734                 while (a < am) {
 735                     tx = (jint)(ltx >> 16);
 736                     ty = (jint)(lty >> 16);
 737                     hfrac = (jint)(ltx & 0xffff);
 738                     vfrac = (jint)(lty & 0xffff);
 739                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 740                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 741                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 742                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 743                     p00 = txtData[sidx];
 744                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 745                         tx, txtWidth-1, ty, txtHeight-1);
 746                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 747                     if (hfrac && vfrac) {
 748                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 749                     } else if (hfrac) {
 750                         cval = interpolate2points(p00, pts[0], hfrac);
 751                     } else if (vfrac) {
 752                         cval = interpolate2points(p00, pts[1], vfrac);
 753                     } else {
 754                         cval = p00;
 755                     }
 756                     assert(pidx >= 0);
 757                     assert(pidx < rdr->_paint_length);
 758                     paint[pidx] = cval;
 759 
 760                     ++a;
 761                     ++pidx;
 762                     ltx += rdr->_texture_m00;
 763                     lty += rdr->_texture_m10;
 764                 } // while (a < am)b
 765                 break;
 766             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 767                 while (a < am) {
 768                     tx = (jint)(ltx >> 16);
 769                     ty = (jint)(lty >> 16);
 770                     hfrac = (jint)(ltx & 0xffff);
 771                     vfrac = (jint)(lty & 0xffff);
 772                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 773                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 774                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 775                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 776                     p00 = txtData[sidx];
 777                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 778                         tx, txtWidth-1, ty, txtHeight-1);
 779                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 780                     if (hfrac && vfrac) {
 781                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 782                     } else if (hfrac) {
 783                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 784                     } else if (vfrac) {
 785                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 786                     } else {
 787                         cval = p00;
 788                     }
 789                     assert(pidx >= 0);
 790                     assert(pidx < rdr->_paint_length);
 791                     paint[pidx] = cval;
 792 
 793                     ++a;
 794                     ++pidx;
 795                     ltx += rdr->_texture_m00;
 796                     lty += rdr->_texture_m10;
 797                 } // while (a < am)b
 798                 break;
 799             case REPEAT_INTERPOLATE_NO_ALPHA:
 800                 while (a < am) {
 801                     tx = (jint)(ltx >> 16);
 802                     ty = (jint)(lty >> 16);
 803                     hfrac = (jint)(ltx & 0xffff);
 804                     vfrac = (jint)(lty & 0xffff);
 805                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 806                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 807                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 808                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 809                     p00 = txtData[sidx];
 810                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 811                         tx, txtWidth-1, ty, txtHeight-1);
 812                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 813                     if (hfrac && vfrac) {
 814                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 815                     } else if (hfrac) {
 816                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 817                     } else if (vfrac) {
 818                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 819                     } else {
 820                         cval = p00;
 821                     }
 822                     assert(pidx >= 0);
 823                     assert(pidx < rdr->_paint_length);
 824                     paint[pidx] = cval;
 825 
 826                     ++a;
 827                     ++pidx;
 828                     ltx += rdr->_texture_m00;
 829                     lty += rdr->_texture_m10;
 830                 } // while (a < am)b
 831                 break;
 832             }
 833             PISCES_DEBUG("\n");
 834             paintOffset += paintStride;
 835         }//for
 836         }
 837         break;
 838 
 839     // generic transform
 840     case TEXTURE_TRANSFORM_GENERIC:
 841         {
 842         jint cval, pidx;
 843         jint *a, *am;
 844         jlong ltx, lty;
 845         jint tx, ty, vfrac, hfrac;
 846         jint paintOffset = 0;
 847         jint pts[3];
 848         jint sidx, p00;
 849         jboolean inBounds;
 850 
 851         y = rdr->_currY;
 852 
 853         for (j = 0; j < height; j++, y++) {
 854             pidx = paintOffset;
 855 
 856             x = rdr->_currX;
 857 
 858             ltx = x * rdr->_texture_m00 + y * rdr->_texture_m01 + rdr->_texture_m02;
 859             lty = x * rdr->_texture_m10 + y * rdr->_texture_m11 + rdr->_texture_m12;
 860 
 861             a = paint + pidx;
 862             am = a + paintStride;
 863 
 864             PISCES_DEBUG("GENERIC, txMin: %d, txMax: %d, tyMin: %d, tyMax: %d\n", txMin, txMax, tyMin, tyMax);
 865 
 866             switch (repeatInterpolateMode) {
 867             case NO_REPEAT_NO_INTERPOLATE:
 868                 while (a < am) {
 869                     tx = (jint)(ltx >> 16);
 870                     ty = (jint)(lty >> 16);
 871                     hfrac = (jint)(ltx & 0xffff);
 872                     vfrac = (jint)(lty & 0xffff);
 873 
 874                     inBounds =
 875                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 876                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 877                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 878                     if (inBounds) {
 879                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 880                         p00 = txtData[sidx];
 881                         assert(pidx >= 0);
 882                         assert(pidx < rdr->_paint_length);
 883                         paint[pidx] = p00;
 884                     } else {
 885                         assert(pidx >= 0);
 886                         assert(pidx < rdr->_paint_length);
 887                         paint[pidx] = 0x00000000;
 888                     }
 889                     ++a;
 890                     ++pidx;
 891                     ltx += rdr->_texture_m00;
 892                     lty += rdr->_texture_m10;
 893                 } // while (a < am)b
 894                 break;
 895             case REPEAT_NO_INTERPOLATE:
 896                 while (a < am) {
 897                     tx = (jint)(ltx >> 16);
 898                     ty = (jint)(lty >> 16);
 899                     hfrac = (jint)(ltx & 0xffff);
 900                     vfrac = (jint)(lty & 0xffff);
 901                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 902                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 903                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 904                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 905                     p00 = txtData[sidx];
 906                     assert(pidx >= 0);
 907                     assert(pidx < rdr->_paint_length);
 908                     paint[pidx] = p00;
 909                     ++a;
 910                     ++pidx;
 911                     ltx += rdr->_texture_m00;
 912                     lty += rdr->_texture_m10;
 913                 } // while (a < am)b
 914                 break;
 915             case NO_REPEAT_INTERPOLATE_ALPHA:
 916                 while (a < am) {
 917                     tx = (jint)(ltx >> 16);
 918                     ty = (jint)(lty >> 16);
 919                     hfrac = (jint)(ltx & 0xffff);
 920                     vfrac = (jint)(lty & 0xffff);
 921 
 922                     inBounds =
 923                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 924                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 925                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 926                     if (inBounds) {
 927                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 928                         p00 = txtData[sidx];
 929 
 930                         getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 931                             tx, txtWidth-1, ty, txtHeight-1);
 932                         PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 933                         if (hfrac && vfrac) {
 934                             cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 935                         } else if (hfrac) {
 936                             cval = interpolate2points(p00, pts[0], hfrac);
 937                         } else if (vfrac) {
 938                             cval = interpolate2points(p00, pts[1], vfrac);
 939                         } else {
 940                             cval = p00;
 941                         }
 942                         assert(pidx >= 0);
 943                         assert(pidx < rdr->_paint_length);
 944                         paint[pidx] = cval;
 945                     } else {
 946                         assert(pidx >= 0);
 947                         assert(pidx < rdr->_paint_length);
 948                         paint[pidx] = 0x00000000;
 949                     }
 950                     ++a;
 951                     ++pidx;
 952                     ltx += rdr->_texture_m00;
 953                     lty += rdr->_texture_m10;
 954                 } // while (a < am)b
 955                 break;
 956             case REPEAT_INTERPOLATE_ALPHA:
 957                 while (a < am) {
 958                     tx = (jint)(ltx >> 16);
 959                     ty = (jint)(lty >> 16);
 960                     hfrac = (jint)(ltx & 0xffff);
 961                     vfrac = (jint)(lty & 0xffff);
 962                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 963                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 964                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 965                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 966                     p00 = txtData[sidx];
 967                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 968                         tx, txtWidth-1, ty, txtHeight-1);
 969                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 970                     if (hfrac && vfrac) {
 971                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 972                     } else if (hfrac) {
 973                         cval = interpolate2points(p00, pts[0], hfrac);
 974                     } else if (vfrac) {
 975                         cval = interpolate2points(p00, pts[1], vfrac);
 976                     } else {
 977                         cval = p00;
 978                     }
 979                     assert(pidx >= 0);
 980                     assert(pidx < rdr->_paint_length);
 981                     paint[pidx] = cval;
 982                     ++a;
 983                     ++pidx;
 984                     ltx += rdr->_texture_m00;
 985                     lty += rdr->_texture_m10;
 986                 } // while (a < am)b
 987                 break;
 988             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 989                 while (a < am) {
 990                     tx = (jint)(ltx >> 16);
 991                     ty = (jint)(lty >> 16);
 992                     hfrac = (jint)(ltx & 0xffff);
 993                     vfrac = (jint)(lty & 0xffff);
 994 
 995                     inBounds =
 996                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 997                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 998                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 999                     if (inBounds) {
1000                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
1001                         p00 = txtData[sidx];
1002 
1003                         getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
1004                             tx, txtWidth-1, ty, txtHeight-1);
1005                         PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
1006                         if (hfrac && vfrac) {
1007                             cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
1008                         } else if (hfrac) {
1009                             cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
1010                         } else if (vfrac) {
1011                             cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
1012                         } else {
1013                             cval = p00;
1014                         }
1015                         assert(pidx >= 0);
1016                         assert(pidx < rdr->_paint_length);
1017                         paint[pidx] = cval;
1018                     } else {
1019                         assert(pidx >= 0);
1020                         assert(pidx < rdr->_paint_length);
1021                         paint[pidx] = 0x00000000;
1022                     }
1023                     ++a;
1024                     ++pidx;
1025                     ltx += rdr->_texture_m00;
1026                     lty += rdr->_texture_m10;
1027                 } // while (a < am)b
1028                 break;
1029             case REPEAT_INTERPOLATE_NO_ALPHA:
1030                 while (a < am) {
1031                     tx = (jint)(ltx >> 16);
1032                     ty = (jint)(lty >> 16);
1033                     hfrac = (jint)(ltx & 0xffff);
1034                     vfrac = (jint)(lty & 0xffff);
1035                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
1036                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
1037                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
1038                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
1039                     p00 = txtData[sidx];
1040                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
1041                         tx, txtWidth-1, ty, txtHeight-1);
1042                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
1043                     if (hfrac && vfrac) {
1044                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
1045                     } else if (hfrac) {
1046                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
1047                     } else if (vfrac) {
1048                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
1049                     } else {
1050                         cval = p00;
1051                     }
1052                     assert(pidx >= 0);
1053                     assert(pidx < rdr->_paint_length);
1054                     paint[pidx] = cval;
1055                     ++a;
1056                     ++pidx;
1057                     ltx += rdr->_texture_m00;
1058                     lty += rdr->_texture_m10;
1059                 } // while (a < am)b
1060                 break;
1061             }
1062             PISCES_DEBUG("\n");
1063             paintOffset += paintStride;
1064         }//for
1065         }
1066         break;
1067     }
1068 }
1069 
1070 void
1071 genTexturePaint(Renderer *rdr, jint height) {
1072     genTexturePaintTarget(rdr, rdr->_paint, height);
1073 }
1074 
1075 void
1076 genTexturePaintMultiply(Renderer *rdr, jint height) {
1077     jint i, j, idx;
1078     jint x_from = rdr->_minTouched;
1079     jint x_to = rdr->_maxTouched;
1080     jint w = (x_to - x_from + 1);
1081     jint *paint = rdr->_paint;
1082     jint paintStride = rdr->_alphaWidth;
1083     jint pval, tval, palpha_1;
1084     jint calpha = rdr->_calpha;
1085     jint cred = rdr->_cred;
1086     jint cgreen = rdr->_cgreen;
1087     jint cblue = rdr->_cblue;
1088     jint oalpha, ored, ogreen, oblue;
1089 
1090     switch (rdr->_prevPaintMode) {
1091     case PAINT_FLAT_COLOR:
1092         genTexturePaintTarget(rdr, paint, height);
1093         palpha_1 = calpha + 1;
1094         if (cred == 0xFF && cgreen == 0xFF && cblue == 0xFF) {
1095             if (calpha < 0xFF) {
1096                 for (i = 0; i < height; i++) {
1097                     idx = i * paintStride;
1098                     for (j = 0; j < w; j++) {
1099                         tval = paint[idx + j];
1100                         oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1101                         ored = (palpha_1 * ((tval >> 16) & 0xFF)) >> 8;
1102                         ogreen = (palpha_1 * ((tval >> 8) & 0xFF)) >> 8;
1103                         oblue = (palpha_1 * (tval & 0xFF)) >> 8;
1104                         paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1105                     }
1106                 }
1107             }
1108         } else {
1109             for (i = 0; i < height; i++) {
1110                 idx = i * paintStride;
1111                 for (j = 0; j < w; j++) {
1112                     tval = paint[idx + j];
1113                     oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1114                     ored = ((((cred + 1) * ((tval >> 16) & 0xFF)) >> 8) * palpha_1) >> 8;
1115                     ogreen = ((((cgreen + 1) * ((tval >> 8) & 0xFF)) >> 8) * palpha_1) >> 8;
1116                     oblue = ((((cblue + 1) * (tval & 0xFF)) >> 8) * palpha_1) >> 8;
1117                     paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1118                 }
1119             }
1120         }
1121         break;
1122     case PAINT_LINEAR_GRADIENT:
1123     case PAINT_RADIAL_GRADIENT:
1124         {
1125         jint *imagePaint = my_malloc(jint, w * height);
1126         if (imagePaint != NULL) {
1127             if (rdr->_prevPaintMode == PAINT_LINEAR_GRADIENT) {
1128                 genLinearGradientPaint(rdr, height);
1129             } else {
1130                 genRadialGradientPaint(rdr, height);
1131             }
1132             genTexturePaintTarget(rdr, imagePaint, height);
1133             for (i = 0; i < height; i++) {
1134                 idx = i * paintStride;
1135                 for (j = 0; j < w; j++) {
1136                     pval = paint[idx + j];
1137                     tval = imagePaint[idx + j];
1138                     palpha_1 = ((pval >> 24) & 0xFF) + 1;
1139                     oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1140                     ored = ((((((pval >> 16) & 0xFF) + 1) * ((tval >> 16) & 0xFF)) >> 8) * palpha_1) >> 8;
1141                     ogreen = ((((((pval >> 8) & 0xFF) + 1) * ((tval >> 8) & 0xFF)) >> 8) * palpha_1) >> 8;
1142                     oblue = (((((pval & 0xFF) + 1) * (tval & 0xFF)) >> 8) * palpha_1) >> 8;
1143                     paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1144                 }
1145             }
1146             my_free(imagePaint);
1147         }
1148         }
1149         break;
1150     }
1151 }
1152