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                 while (a < am) {
 489                     tx = (jint)(ltx >> 16);
 490                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 491                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 492                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 493                     assert(pidx >= 0);
 494                     assert(pidx < rdr->_paint_length);
 495                     paint[pidx] = txtData[sidx];
 496                     ++a;
 497                     ++pidx;
 498                     ltx += 0x10000;
 499                 } // while (a < am)
 500                 break;
 501             case REPEAT_NO_INTERPOLATE:
 502                 while (a < am) {
 503                     tx = (jint)(ltx >> 16);
 504                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 505                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 506                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 507                     assert(pidx >= 0);
 508                     assert(pidx < rdr->_paint_length);
 509                     paint[pidx] = txtData[sidx];
 510                     ++a;
 511                     ++pidx;
 512                     ltx += 0x10000;
 513                 } // while (a < am)
 514                 break;
 515             case NO_REPEAT_INTERPOLATE_ALPHA:
 516                 while (a < am) {
 517                     tx = (jint)(ltx >> 16);
 518                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 519                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 520                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 521                     p00 = txtData[sidx];
 522                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 523                         tx, txtWidth-1, ty, txtHeight-1);
 524                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 525                     if (hfrac && vfrac) {
 526                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 527                     } else if (hfrac) {
 528                         cval = interpolate2points(p00, pts[0], hfrac);
 529                     } else if (vfrac) {
 530                         cval = interpolate2points(p00, pts[1], vfrac);
 531                     } else {
 532                         cval = p00;
 533                     }
 534                     assert(pidx >= 0);
 535                     assert(pidx < rdr->_paint_length);
 536                     paint[pidx] = cval;
 537                     ++a;
 538                     ++pidx;
 539                     ltx += 0x10000;
 540                 } // while (a < am)
 541                 break;
 542             case REPEAT_INTERPOLATE_ALPHA:
 543                 while (a < am) {
 544                     tx = (jint)(ltx >> 16);
 545                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 546                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 547                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 548                     p00 = txtData[sidx];
 549                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 550                         tx, txtWidth-1, ty, txtHeight-1);
 551                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 552                     if (hfrac && vfrac) {
 553                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 554                     } else if (hfrac) {
 555                         cval = interpolate2points(p00, pts[0], hfrac);
 556                     } else if (vfrac) {
 557                         cval = interpolate2points(p00, pts[1], vfrac);
 558                     } else {
 559                         cval = p00;
 560                     }
 561                     assert(pidx >= 0);
 562                     assert(pidx < rdr->_paint_length);
 563                     paint[pidx] = cval;
 564                     ++a;
 565                     ++pidx;
 566                     ltx += 0x10000;
 567                 } // while (a < am)
 568                 break;
 569             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 570                 while (a < am) {
 571                     tx = (jint)(ltx >> 16);
 572                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 573                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 574                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 575                     p00 = txtData[sidx];
 576                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 577                         tx, txtWidth-1, ty, txtHeight-1);
 578                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 579                     if (hfrac && vfrac) {
 580                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 581                     } else if (hfrac) {
 582                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 583                     } else if (vfrac) {
 584                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 585                     } else {
 586                         cval = p00;
 587                     }
 588                     assert(pidx >= 0);
 589                     assert(pidx < rdr->_paint_length);
 590                     paint[pidx] = cval;
 591                     ++a;
 592                     ++pidx;
 593                     ltx += 0x10000;
 594                 } // while (a < am)
 595                 break;
 596             case REPEAT_INTERPOLATE_NO_ALPHA:
 597                 while (a < am) {
 598                     tx = (jint)(ltx >> 16);
 599                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 600                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 601                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 602                     p00 = txtData[sidx];
 603                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 604                         tx, txtWidth-1, ty, txtHeight-1);
 605                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 606                     if (hfrac && vfrac) {
 607                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 608                     } else if (hfrac) {
 609                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 610                     } else if (vfrac) {
 611                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 612                     } else {
 613                         cval = p00;
 614                     }
 615                     assert(pidx >= 0);
 616                     assert(pidx < rdr->_paint_length);
 617                     paint[pidx] = cval;
 618                     ++a;
 619                     ++pidx;
 620                     ltx += 0x10000;
 621                 } // while (a < am)
 622                 break;
 623             }
 624             PISCES_DEBUG("\n");
 625             paintOffset += paintStride;
 626         } // for
 627         }
 628         break;
 629 
 630     // scale transform
 631     case TEXTURE_TRANSFORM_SCALE_TRANSLATE:
 632         {
 633         jint cval, pidx;
 634         jint *a, *am;
 635         jlong ltx, lty;
 636         jint tx, ty, vfrac, hfrac;
 637         jint paintOffset = 0;
 638         jint pts[3];
 639         jint sidx, p00;
 640 
 641         y = rdr->_currY;
 642 
 643         for (j = 0; j < height; j++, y++) {
 644             pidx = paintOffset;
 645 
 646             x = rdr->_currX;
 647 
 648             ltx = x * rdr->_texture_m00 + y * rdr->_texture_m01 + rdr->_texture_m02;
 649             lty = x * rdr->_texture_m10 + y * rdr->_texture_m11 + rdr->_texture_m12;
 650 
 651             a = paint + pidx;
 652             am = a + paintStride;
 653 
 654             PISCES_DEBUG("SCALE, txMin: %d, txMax: %d, tyMin: %d, tyMax: %d\n", txMin, txMax, tyMin, tyMax);
 655 
 656             switch (repeatInterpolateMode) {
 657             case NO_REPEAT_NO_INTERPOLATE:
 658                 while (a < am) {
 659                     tx = (jint)(ltx >> 16);
 660                     ty = (jint)(lty >> 16);
 661                     hfrac = (jint)(ltx & 0xffff);
 662                     vfrac = (jint)(lty & 0xffff);
 663                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 664                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 665                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 666                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 667                     assert(pidx >= 0);
 668                     assert(pidx < rdr->_paint_length);
 669                     paint[pidx] = txtData[sidx];
 670                     ++a;
 671                     ++pidx;
 672                     ltx += rdr->_texture_m00;
 673                     lty += rdr->_texture_m10;
 674                 } // while (a < am)b
 675                 break;
 676             case REPEAT_NO_INTERPOLATE:
 677                 while (a < am) {
 678                     tx = (jint)(ltx >> 16);
 679                     ty = (jint)(lty >> 16);
 680                     hfrac = (jint)(ltx & 0xffff);
 681                     vfrac = (jint)(lty & 0xffff);
 682                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 683                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 684                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 685                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 686                     assert(pidx >= 0);
 687                     assert(pidx < rdr->_paint_length);
 688                     paint[pidx] = txtData[sidx];
 689                     ++a;
 690                     ++pidx;
 691                     ltx += rdr->_texture_m00;
 692                     lty += rdr->_texture_m10;
 693                 } // while (a < am)b
 694                 break;
 695             case NO_REPEAT_INTERPOLATE_ALPHA:
 696                 while (a < am) {
 697                     tx = (jint)(ltx >> 16);
 698                     ty = (jint)(lty >> 16);
 699                     hfrac = (jint)(ltx & 0xffff);
 700                     vfrac = (jint)(lty & 0xffff);
 701                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 702                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 703                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 704                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 705                     p00 = txtData[sidx];
 706                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 707                         tx, txtWidth-1, ty, txtHeight-1);
 708                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 709                     if (hfrac && vfrac) {
 710                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 711                     } else if (hfrac) {
 712                         cval = interpolate2points(p00, pts[0], hfrac);
 713                     } else if (vfrac) {
 714                         cval = interpolate2points(p00, pts[1], vfrac);
 715                     } else {
 716                         cval = p00;
 717                     }
 718                     assert(pidx >= 0);
 719                     assert(pidx < rdr->_paint_length);
 720                     paint[pidx] = cval;
 721 
 722                     ++a;
 723                     ++pidx;
 724                     ltx += rdr->_texture_m00;
 725                     lty += rdr->_texture_m10;
 726                 } // while (a < am)b
 727                 break;
 728             case REPEAT_INTERPOLATE_ALPHA:
 729                 while (a < am) {
 730                     tx = (jint)(ltx >> 16);
 731                     ty = (jint)(lty >> 16);
 732                     hfrac = (jint)(ltx & 0xffff);
 733                     vfrac = (jint)(lty & 0xffff);
 734                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 735                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 736                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 737                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 738                     p00 = txtData[sidx];
 739                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 740                         tx, txtWidth-1, ty, txtHeight-1);
 741                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 742                     if (hfrac && vfrac) {
 743                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 744                     } else if (hfrac) {
 745                         cval = interpolate2points(p00, pts[0], hfrac);
 746                     } else if (vfrac) {
 747                         cval = interpolate2points(p00, pts[1], vfrac);
 748                     } else {
 749                         cval = p00;
 750                     }
 751                     assert(pidx >= 0);
 752                     assert(pidx < rdr->_paint_length);
 753                     paint[pidx] = cval;
 754 
 755                     ++a;
 756                     ++pidx;
 757                     ltx += rdr->_texture_m00;
 758                     lty += rdr->_texture_m10;
 759                 } // while (a < am)b
 760                 break;
 761             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 762                 while (a < am) {
 763                     tx = (jint)(ltx >> 16);
 764                     ty = (jint)(lty >> 16);
 765                     hfrac = (jint)(ltx & 0xffff);
 766                     vfrac = (jint)(lty & 0xffff);
 767                     checkBoundsNoRepeat(&tx, &ltx, txMin-1, txMax);
 768                     checkBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 769                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 770                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 771                     p00 = txtData[sidx];
 772                     getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 773                         tx, txtWidth-1, ty, txtHeight-1);
 774                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 775                     if (hfrac && vfrac) {
 776                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 777                     } else if (hfrac) {
 778                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 779                     } else if (vfrac) {
 780                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 781                     } else {
 782                         cval = p00;
 783                     }
 784                     assert(pidx >= 0);
 785                     assert(pidx < rdr->_paint_length);
 786                     paint[pidx] = cval;
 787 
 788                     ++a;
 789                     ++pidx;
 790                     ltx += rdr->_texture_m00;
 791                     lty += rdr->_texture_m10;
 792                 } // while (a < am)b
 793                 break;
 794             case REPEAT_INTERPOLATE_NO_ALPHA:
 795                 while (a < am) {
 796                     tx = (jint)(ltx >> 16);
 797                     ty = (jint)(lty >> 16);
 798                     hfrac = (jint)(ltx & 0xffff);
 799                     vfrac = (jint)(lty & 0xffff);
 800                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 801                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 802                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 803                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 804                     p00 = txtData[sidx];
 805                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 806                         tx, txtWidth-1, ty, txtHeight-1);
 807                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 808                     if (hfrac && vfrac) {
 809                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 810                     } else if (hfrac) {
 811                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
 812                     } else if (vfrac) {
 813                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
 814                     } else {
 815                         cval = p00;
 816                     }
 817                     assert(pidx >= 0);
 818                     assert(pidx < rdr->_paint_length);
 819                     paint[pidx] = cval;
 820 
 821                     ++a;
 822                     ++pidx;
 823                     ltx += rdr->_texture_m00;
 824                     lty += rdr->_texture_m10;
 825                 } // while (a < am)b
 826                 break;
 827             }
 828             PISCES_DEBUG("\n");
 829             paintOffset += paintStride;
 830         }//for
 831         }
 832         break;
 833 
 834     // generic transform
 835     case TEXTURE_TRANSFORM_GENERIC:
 836         {
 837         jint cval, pidx;
 838         jint *a, *am;
 839         jlong ltx, lty;
 840         jint tx, ty, vfrac, hfrac;
 841         jint paintOffset = 0;
 842         jint pts[3];
 843         jint sidx, p00;
 844         jboolean inBounds;
 845 
 846         y = rdr->_currY;
 847 
 848         for (j = 0; j < height; j++, y++) {
 849             pidx = paintOffset;
 850 
 851             x = rdr->_currX;
 852 
 853             ltx = x * rdr->_texture_m00 + y * rdr->_texture_m01 + rdr->_texture_m02;
 854             lty = x * rdr->_texture_m10 + y * rdr->_texture_m11 + rdr->_texture_m12;
 855 
 856             a = paint + pidx;
 857             am = a + paintStride;
 858 
 859             PISCES_DEBUG("GENERIC, txMin: %d, txMax: %d, tyMin: %d, tyMax: %d\n", txMin, txMax, tyMin, tyMax);
 860 
 861             switch (repeatInterpolateMode) {
 862             case NO_REPEAT_NO_INTERPOLATE:
 863                 while (a < am) {
 864                     tx = (jint)(ltx >> 16);
 865                     ty = (jint)(lty >> 16);
 866                     hfrac = (jint)(ltx & 0xffff);
 867                     vfrac = (jint)(lty & 0xffff);
 868 
 869                     inBounds =
 870                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 871                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 872                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 873                     if (inBounds) {
 874                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 875                         p00 = txtData[sidx];
 876                         assert(pidx >= 0);
 877                         assert(pidx < rdr->_paint_length);
 878                         paint[pidx] = p00;
 879                     } else {
 880                         assert(pidx >= 0);
 881                         assert(pidx < rdr->_paint_length);
 882                         paint[pidx] = 0x00000000;
 883                     }
 884                     ++a;
 885                     ++pidx;
 886                     ltx += rdr->_texture_m00;
 887                     lty += rdr->_texture_m10;
 888                 } // while (a < am)b
 889                 break;
 890             case REPEAT_NO_INTERPOLATE:
 891                 while (a < am) {
 892                     tx = (jint)(ltx >> 16);
 893                     ty = (jint)(lty >> 16);
 894                     hfrac = (jint)(ltx & 0xffff);
 895                     vfrac = (jint)(lty & 0xffff);
 896                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 897                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 898                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 899                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 900                     p00 = txtData[sidx];
 901                     assert(pidx >= 0);
 902                     assert(pidx < rdr->_paint_length);
 903                     paint[pidx] = p00;
 904                     ++a;
 905                     ++pidx;
 906                     ltx += rdr->_texture_m00;
 907                     lty += rdr->_texture_m10;
 908                 } // while (a < am)b
 909                 break;
 910             case NO_REPEAT_INTERPOLATE_ALPHA:
 911                 while (a < am) {
 912                     tx = (jint)(ltx >> 16);
 913                     ty = (jint)(lty >> 16);
 914                     hfrac = (jint)(ltx & 0xffff);
 915                     vfrac = (jint)(lty & 0xffff);
 916 
 917                     inBounds =
 918                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 919                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 920                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 921                     if (inBounds) {
 922                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 923                         p00 = txtData[sidx];
 924 
 925                         getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 926                             tx, txtWidth-1, ty, txtHeight-1);
 927                         PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 928                         if (hfrac && vfrac) {
 929                             cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 930                         } else if (hfrac) {
 931                             cval = interpolate2points(p00, pts[0], hfrac);
 932                         } else if (vfrac) {
 933                             cval = interpolate2points(p00, pts[1], vfrac);
 934                         } else {
 935                             cval = p00;
 936                         }
 937                         assert(pidx >= 0);
 938                         assert(pidx < rdr->_paint_length);
 939                         paint[pidx] = cval;
 940                     } else {
 941                         assert(pidx >= 0);
 942                         assert(pidx < rdr->_paint_length);
 943                         paint[pidx] = 0x00000000;
 944                     }
 945                     ++a;
 946                     ++pidx;
 947                     ltx += rdr->_texture_m00;
 948                     lty += rdr->_texture_m10;
 949                 } // while (a < am)b
 950                 break;
 951             case REPEAT_INTERPOLATE_ALPHA:
 952                 while (a < am) {
 953                     tx = (jint)(ltx >> 16);
 954                     ty = (jint)(lty >> 16);
 955                     hfrac = (jint)(ltx & 0xffff);
 956                     vfrac = (jint)(lty & 0xffff);
 957                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
 958                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
 959                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 960                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 961                     p00 = txtData[sidx];
 962                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
 963                         tx, txtWidth-1, ty, txtHeight-1);
 964                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
 965                     if (hfrac && vfrac) {
 966                         cval = interpolate4points(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
 967                     } else if (hfrac) {
 968                         cval = interpolate2points(p00, pts[0], hfrac);
 969                     } else if (vfrac) {
 970                         cval = interpolate2points(p00, pts[1], vfrac);
 971                     } else {
 972                         cval = p00;
 973                     }
 974                     assert(pidx >= 0);
 975                     assert(pidx < rdr->_paint_length);
 976                     paint[pidx] = cval;
 977                     ++a;
 978                     ++pidx;
 979                     ltx += rdr->_texture_m00;
 980                     lty += rdr->_texture_m10;
 981                 } // while (a < am)b
 982                 break;
 983             case NO_REPEAT_INTERPOLATE_NO_ALPHA:
 984                 while (a < am) {
 985                     tx = (jint)(ltx >> 16);
 986                     ty = (jint)(lty >> 16);
 987                     hfrac = (jint)(ltx & 0xffff);
 988                     vfrac = (jint)(lty & 0xffff);
 989 
 990                     inBounds =
 991                         isInBoundsNoRepeat(&tx, &ltx, txMin-1, txMax) &&
 992                         isInBoundsNoRepeat(&ty, &lty, tyMin-1, tyMax);
 993                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
 994                     if (inBounds) {
 995                         sidx = MAX(0, ty) * txtStride + MAX(0, tx);
 996                         p00 = txtData[sidx];
 997 
 998                         getPointsToInterpolate(pts, txtData, sidx, txtStride, p00,
 999                             tx, txtWidth-1, ty, txtHeight-1);
1000                         PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
1001                         if (hfrac && vfrac) {
1002                             cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
1003                         } else if (hfrac) {
1004                             cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
1005                         } else if (vfrac) {
1006                             cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
1007                         } else {
1008                             cval = p00;
1009                         }
1010                         assert(pidx >= 0);
1011                         assert(pidx < rdr->_paint_length);
1012                         paint[pidx] = cval;
1013                     } else {
1014                         assert(pidx >= 0);
1015                         assert(pidx < rdr->_paint_length);
1016                         paint[pidx] = 0x00000000;
1017                     }
1018                     ++a;
1019                     ++pidx;
1020                     ltx += rdr->_texture_m00;
1021                     lty += rdr->_texture_m10;
1022                 } // while (a < am)b
1023                 break;
1024             case REPEAT_INTERPOLATE_NO_ALPHA:
1025                 while (a < am) {
1026                     tx = (jint)(ltx >> 16);
1027                     ty = (jint)(lty >> 16);
1028                     hfrac = (jint)(ltx & 0xffff);
1029                     vfrac = (jint)(lty & 0xffff);
1030                     checkBoundsRepeat(&tx, &ltx, txMin-1, txMax);
1031                     checkBoundsRepeat(&ty, &lty, tyMin-1, tyMax);
1032                     PISCES_DEBUG("[%d, %d, h:%d, v:%d] ", tx, ty, hfrac, vfrac);
1033                     sidx = MAX(0, ty) * txtStride + MAX(0, tx);
1034                     p00 = txtData[sidx];
1035                     getPointsToInterpolateRepeat(pts, txtData, sidx, txtStride, p00,
1036                         tx, txtWidth-1, ty, txtHeight-1);
1037                     PISCES_DEBUG("cols[%x, %x, %x, %x] ", p00, pts[0], pts[1], pts[2]);
1038                     if (hfrac && vfrac) {
1039                         cval = interpolate4pointsNoAlpha(p00, pts[0], pts[1], pts[2], hfrac, vfrac);
1040                     } else if (hfrac) {
1041                         cval = interpolate2pointsNoAlpha(p00, pts[0], hfrac);
1042                     } else if (vfrac) {
1043                         cval = interpolate2pointsNoAlpha(p00, pts[1], vfrac);
1044                     } else {
1045                         cval = p00;
1046                     }
1047                     assert(pidx >= 0);
1048                     assert(pidx < rdr->_paint_length);
1049                     paint[pidx] = cval;
1050                     ++a;
1051                     ++pidx;
1052                     ltx += rdr->_texture_m00;
1053                     lty += rdr->_texture_m10;
1054                 } // while (a < am)b
1055                 break;
1056             }
1057             PISCES_DEBUG("\n");
1058             paintOffset += paintStride;
1059         }//for
1060         }
1061         break;
1062     }
1063 }
1064 
1065 void
1066 genTexturePaint(Renderer *rdr, jint height) {
1067     genTexturePaintTarget(rdr, rdr->_paint, height);
1068 }
1069 
1070 void
1071 genTexturePaintMultiply(Renderer *rdr, jint height) {
1072     jint i, j, idx;
1073     jint x_from = rdr->_minTouched;
1074     jint x_to = rdr->_maxTouched;
1075     jint w = (x_to - x_from + 1);
1076     jint *paint = rdr->_paint;
1077     jint paintStride = rdr->_alphaWidth;
1078     jint pval, tval, palpha_1;
1079     jint calpha = rdr->_calpha;
1080     jint cred = rdr->_cred;
1081     jint cgreen = rdr->_cgreen;
1082     jint cblue = rdr->_cblue;
1083     jint oalpha, ored, ogreen, oblue;
1084 
1085     switch (rdr->_prevPaintMode) {
1086     case PAINT_FLAT_COLOR:
1087         genTexturePaintTarget(rdr, paint, height);
1088         palpha_1 = calpha + 1;
1089         if (cred == 0xFF && cgreen == 0xFF && cblue == 0xFF) {
1090             if (calpha < 0xFF) {
1091                 for (i = 0; i < height; i++) {
1092                     idx = i * paintStride;
1093                     for (j = 0; j < w; j++) {
1094                         tval = paint[idx + j];
1095                         oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1096                         ored = (palpha_1 * ((tval >> 16) & 0xFF)) >> 8;
1097                         ogreen = (palpha_1 * ((tval >> 8) & 0xFF)) >> 8;
1098                         oblue = (palpha_1 * (tval & 0xFF)) >> 8;
1099                         paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1100                     }
1101                 }
1102             }
1103         } else {
1104             for (i = 0; i < height; i++) {
1105                 idx = i * paintStride;
1106                 for (j = 0; j < w; j++) {
1107                     tval = paint[idx + j];
1108                     oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1109                     ored = ((((cred + 1) * ((tval >> 16) & 0xFF)) >> 8) * palpha_1) >> 8;
1110                     ogreen = ((((cgreen + 1) * ((tval >> 8) & 0xFF)) >> 8) * palpha_1) >> 8;
1111                     oblue = ((((cblue + 1) * (tval & 0xFF)) >> 8) * palpha_1) >> 8;
1112                     paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1113                 }
1114             }
1115         }
1116         break;
1117     case PAINT_LINEAR_GRADIENT:
1118     case PAINT_RADIAL_GRADIENT:
1119         {
1120         jint *imagePaint = my_malloc(jint, w * height);
1121         if (imagePaint != NULL) {
1122             if (rdr->_prevPaintMode == PAINT_LINEAR_GRADIENT) {
1123                 genLinearGradientPaint(rdr, height);
1124             } else {
1125                 genRadialGradientPaint(rdr, height);
1126             }
1127             genTexturePaintTarget(rdr, imagePaint, height);
1128             for (i = 0; i < height; i++) {
1129                 idx = i * paintStride;
1130                 for (j = 0; j < w; j++) {
1131                     pval = paint[idx + j];
1132                     tval = imagePaint[idx + j];
1133                     palpha_1 = ((pval >> 24) & 0xFF) + 1;
1134                     oalpha = (palpha_1 * ((tval >> 24) & 0xFF)) >> 8;
1135                     ored = ((((((pval >> 16) & 0xFF) + 1) * ((tval >> 16) & 0xFF)) >> 8) * palpha_1) >> 8;
1136                     ogreen = ((((((pval >> 8) & 0xFF) + 1) * ((tval >> 8) & 0xFF)) >> 8) * palpha_1) >> 8;
1137                     oblue = (((((pval & 0xFF) + 1) * (tval & 0xFF)) >> 8) * palpha_1) >> 8;
1138                     paint[idx + j] = (oalpha << 24) | (ored << 16) | (ogreen << 8) | oblue;
1139                 }
1140             }
1141             my_free(imagePaint);
1142         }
1143         }
1144         break;
1145     }
1146 }
1147