1 /*
   2  * Copyright (c) 2009, 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 package com.sun.prism.impl;
  27 
  28 import com.sun.javafx.geom.transform.AffineBase;
  29 import com.sun.prism.paint.Color;
  30 import java.util.Arrays;
  31 
  32 public class VertexBuffer {
  33 
  34     protected static final int VERTS_PER_QUAD  = 4;
  35 
  36     protected static final int FLOATS_PER_TC   = 2;
  37     protected static final int FLOATS_PER_VC   = 3;
  38     protected static final int FLOATS_PER_VERT = FLOATS_PER_VC + (2 * FLOATS_PER_TC);
  39 
  40     protected static final int BYTES_PER_VERT = 4;
  41 
  42     protected static final int VCOFF = 0;
  43     protected static final int TC1OFF = VCOFF  + FLOATS_PER_VC;
  44     protected static final int TC2OFF = TC1OFF + FLOATS_PER_TC;
  45 
  46     protected int capacity, index;
  47 
  48     protected byte r, g, b, a;
  49 
  50     protected byte  colorArray[];
  51     protected float coordArray[];
  52 
  53     public VertexBuffer(int maxQuads) {
  54         capacity = maxQuads * VERTS_PER_QUAD;
  55         index = 0;
  56 
  57         colorArray = new byte [capacity * BYTES_PER_VERT];
  58         coordArray = new float[capacity * FLOATS_PER_VERT];
  59     }
  60 
  61     protected void drawQuads(int numVertices) {
  62         throw new Error ("flush not implemented for lightweight");
  63     }
  64 
  65     // it had better be the case if this method be moved to Graphics
  66     // so that we can delete D3DVertexBuffer and ES2(N)VertexBuffer
  67     protected void drawTriangles(int numTriangles, float fData[], byte cData[]) {
  68         throw new Error ("flush not implemented for lightweight");
  69     }
  70 
  71     public final void setPerVertexColor(Color c, float extraAlpha) {
  72         float ca = c.getAlpha() * extraAlpha;
  73         r = (byte)(c.getRed()   * ca * 0xff);
  74         g = (byte)(c.getGreen() * ca * 0xff);
  75         b = (byte)(c.getBlue()  * ca * 0xff);
  76         a = (byte)(               ca * 0xff);
  77     }
  78 
  79     public final void setPerVertexColor(float extraAlpha) {
  80         r = g = b = a = (byte)(extraAlpha * 0xff);
  81     }
  82 
  83     public final void updateVertexColors(int numVerts) {
  84         for (int i=0; i!=numVerts; ++i) {
  85             putColor(i);
  86         }
  87     }
  88 
  89     private void putColor(int idx) {
  90         int i = idx * BYTES_PER_VERT;
  91         colorArray[i+0] = r;
  92         colorArray[i+1] = g;
  93         colorArray[i+2] = b;
  94         colorArray[i+3] = a;
  95     }
  96 
  97     /**
  98      * Flushes (renders) all pending vertices (triangles) in the buffer to the
  99      * destination render target.  This operation only applies to heavyweight
 100      * buffers; calling flush() on a lightweight buffer will result in an
 101      * exception.
 102      */
 103     public final void flush() {
 104         if (index > 0) {
 105             drawQuads(index);
 106             index = 0;
 107         }
 108     }
 109 
 110     public final void rewind() {
 111         index = 0;
 112     }
 113 
 114     private void grow() {
 115         capacity *= 2;
 116         colorArray = Arrays.copyOf(colorArray, capacity * BYTES_PER_VERT);
 117         coordArray = Arrays.copyOf(coordArray, capacity * FLOATS_PER_VERT);
 118     }
 119 
 120     public final void addVert(float x, float y) {
 121         // unlike the other (private) addVert() variants, this checks capacity
 122         if (index == capacity) {
 123             grow();
 124         }
 125 
 126         int i = FLOATS_PER_VERT * index;
 127         coordArray[i+0] = x;
 128         coordArray[i+1] = y;
 129         coordArray[i+2] = 0f;
 130         putColor(index);
 131         index++;
 132     }
 133 
 134     public final void addVert(float x, float y, float tx, float ty) {
 135         // unlike the (private) addVert() variants, this checks capacity
 136         if (index == capacity) {
 137             grow();
 138         }
 139 
 140         int i = FLOATS_PER_VERT * index;
 141         coordArray[i+0] = x;
 142         coordArray[i+1] = y;
 143         coordArray[i+2] = 0f;
 144         coordArray[i+3] = tx;
 145         coordArray[i+4] = ty;
 146         putColor(index);
 147         index++;
 148     }
 149 
 150     public final void addVert(float x, float y, float t0x, float t0y, float t1x, float t1y) {
 151         // unlike the (private) addVert() variants, this checks capacity
 152         if (index == capacity) {
 153             grow();
 154         }
 155 
 156         int i = FLOATS_PER_VERT * index;
 157         coordArray[i+0] = x;
 158         coordArray[i+1] = y;
 159         coordArray[i+2] = 0f;
 160         coordArray[i+3] = t0x;
 161         coordArray[i+4] = t0y;
 162         coordArray[i+5] = t1x;
 163         coordArray[i+6] = t1y;
 164         putColor(index);
 165         index++;
 166     }
 167 
 168     private void addVertNoCheck(float x, float y) {
 169         // note: assumes caller has already checked capacity
 170         int i = FLOATS_PER_VERT * index;
 171         coordArray[i+0] = x;
 172         coordArray[i+1] = y;
 173         coordArray[i+2] = 0f;
 174         putColor(index);
 175         index++;
 176     }
 177 
 178     private void addVertNoCheck(float x, float y, float tx, float ty) {
 179         // note: assumes caller has already checked capacity
 180         int i = FLOATS_PER_VERT * index;
 181         coordArray[i+0] = x;
 182         coordArray[i+1] = y;
 183         coordArray[i+2] = 0f;
 184         coordArray[i+3] = tx;
 185         coordArray[i+4] = ty;
 186         putColor(index);
 187         index++;
 188     }
 189 
 190     private void addVertNoCheck(float x, float y, float t0x, float t0y, float t1x, float t1y) {
 191         // note: assumes caller has already checked capacity
 192         int i = FLOATS_PER_VERT * index;
 193         coordArray[i+0] = x;
 194         coordArray[i+1] = y;
 195         coordArray[i+2] = 0f;
 196         coordArray[i+3] = t0x;
 197         coordArray[i+4] = t0y;
 198         coordArray[i+5] = t1x;
 199         coordArray[i+6] = t1y;
 200         putColor(index);
 201         index++;
 202     }
 203 
 204     // render a trianglelist
 205     public final void addVerts(VertexBuffer vb, int numVerts) {
 206         flush();
 207         drawTriangles(numVerts/3, vb.coordArray, vb.colorArray);
 208     }
 209 
 210     private void ensureCapacityForQuad() {
 211         if (index + VERTS_PER_QUAD > capacity) {
 212             drawQuads(index);
 213             index = 0;
 214         }
 215     }
 216 
 217     public final void addQuad(float dx1, float dy1, float dx2, float dy2) {
 218         ensureCapacityForQuad();
 219 
 220         addVertNoCheck(dx1, dy1);
 221         addVertNoCheck(dx1, dy2);
 222         addVertNoCheck(dx2, dy1);
 223         addVertNoCheck(dx2, dy2);
 224     }
 225 
 226     public final void addQuad(
 227             float dx1, float dy1, float dx2, float dy2,
 228             float t1x1, float t1y1, float t1x2, float t1y2,
 229             float t2x1, float t2y1, float t2x2, float t2y2)
 230     {
 231         ensureCapacityForQuad();
 232 
 233         addVertNoCheck(dx1, dy1, t1x1, t1y1, t2x1, t2y1);
 234         addVertNoCheck(dx1, dy2, t1x1, t1y2, t2x1, t2y2);
 235         addVertNoCheck(dx2, dy1, t1x2, t1y1, t2x2, t2y1);
 236         addVertNoCheck(dx2, dy2, t1x2, t1y2, t2x2, t2y2);
 237     }
 238 
 239     public final void addMappedQuad(
 240             float dx1, float dy1, float dx2, float dy2,
 241             float tx11, float ty11, float tx21, float ty21,
 242             float tx12, float ty12, float tx22, float ty22)
 243     {
 244         ensureCapacityForQuad();
 245 
 246         addVertNoCheck(dx1, dy1, tx11, ty11);
 247         addVertNoCheck(dx1, dy2, tx12, ty12);
 248         addVertNoCheck(dx2, dy1, tx21, ty21);
 249         addVertNoCheck(dx2, dy2, tx22, ty22);
 250     }
 251 
 252     public final void addMappedQuad(
 253             float dx1, float dy1, float dx2, float dy2,
 254             float ux11, float uy11, float ux21, float uy21,
 255             float ux12, float uy12, float ux22, float uy22,
 256             float vx11, float vy11, float vx21, float vy21,
 257             float vx12, float vy12, float vx22, float vy22)
 258     {
 259         ensureCapacityForQuad();
 260 
 261         addVertNoCheck(dx1, dy1, ux11, uy11, vx11, vy11);
 262         addVertNoCheck(dx1, dy2, ux12, uy12, vx12, vy12);
 263         addVertNoCheck(dx2, dy1, ux21, uy21, vx21, vy21);
 264         addVertNoCheck(dx2, dy2, ux22, uy22, vx22, vy22);
 265     }
 266 
 267     public final void addQuad(
 268             float dx1, float dy1, float dx2, float dy2,
 269             float tx1, float ty1, float tx2, float ty2,
 270             AffineBase tx)
 271     {
 272         addQuad(dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2);
 273 
 274         if (tx != null) {
 275             int i = FLOATS_PER_VERT * index - FLOATS_PER_VERT;
 276             tx.transform(coordArray, i+VCOFF, coordArray, i+TC2OFF, 1);
 277             i -= FLOATS_PER_VERT;
 278             tx.transform(coordArray, i+VCOFF, coordArray, i+TC2OFF, 1);
 279             i -= FLOATS_PER_VERT;
 280             tx.transform(coordArray, i+VCOFF, coordArray, i+TC2OFF, 1);
 281             i -= FLOATS_PER_VERT;
 282             tx.transform(coordArray, i+VCOFF, coordArray, i+TC2OFF, 1);
 283         }
 284     }
 285 
 286     public final void addSuperQuad(
 287             float dx1, float dy1, float dx2, float dy2,
 288             float tx1, float ty1, float tx2, float ty2,
 289             boolean isText)
 290     {
 291 //        ensureCapacityForQuad();
 292         int idx = index;
 293         if (idx + VERTS_PER_QUAD > capacity) {
 294 //            grow();
 295             drawQuads(idx);
 296             idx = index = 0;
 297         }
 298 
 299         int i = FLOATS_PER_VERT * idx;
 300         float farr[] = coordArray;
 301 
 302         float text = isText ? 1 : 0;
 303         float image = isText ? 0 : 1;
 304 
 305 //        addVertNoCheck(dx1, dy1, tx1, ty1);
 306         farr[  i] = dx1; farr[++i] = dy1; farr[++i] = 0;
 307         farr[++i] = tx1; farr[++i] = ty1;
 308         farr[++i] = image; farr[++i] = text; i++;
 309 //        addVertNoCheck(dx1, dy2, tx1, ty2);
 310         farr[  i] = dx1; farr[++i] = dy2; farr[++i] = 0;
 311         farr[++i] = tx1; farr[++i] = ty2;
 312         farr[++i] = image; farr[++i] = text; i++;
 313 //        addVertNoCheck(dx2, dy1, tx2, ty1);
 314         farr[  i] = dx2; farr[++i] = dy1; farr[++i] = 0;
 315         farr[++i] = tx2; farr[++i] = ty1;
 316         farr[++i] = image; farr[++i] = text; i++;
 317 //        addVertNoCheck(dx2, dy2, tx2, ty2);
 318         farr[  i] = dx2; farr[++i] = dy2; farr[++i] = 0;
 319         farr[++i] = tx2; farr[++i] = ty2;
 320         farr[++i] = image; farr[++i] = text; i++;
 321 
 322         byte barr[] = colorArray;
 323         byte r = this.r, g = this.g, b = this.b, a = this.a;
 324         int j = BYTES_PER_VERT * idx;
 325         barr[  j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 326         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 327         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 328         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 329 
 330         index = idx + VERTS_PER_QUAD;
 331     }
 332 
 333     public final void addQuad(
 334             float dx1, float dy1, float dx2, float dy2,
 335             float tx1, float ty1, float tx2, float ty2)
 336     {
 337 //        ensureCapacityForQuad();
 338         int idx = index;
 339         if (idx + VERTS_PER_QUAD > capacity) {
 340             drawQuads(idx);
 341             idx = index = 0;
 342         }
 343 
 344         int i = FLOATS_PER_VERT * idx;
 345         float farr[] = coordArray;
 346 
 347 //        addVertNoCheck(dx1, dy1, tx1, ty1);
 348         farr[  i] = dx1; farr[++i] = dy1; farr[++i] = 0;
 349         farr[++i] = tx1; farr[++i] = ty1;
 350         i += 3;
 351 //        addVertNoCheck(dx1, dy2, tx1, ty2);
 352         farr[  i] = dx1; farr[++i] = dy2; farr[++i] = 0;
 353         farr[++i] = tx1; farr[++i] = ty2;
 354         i += 3;
 355 //        addVertNoCheck(dx2, dy1, tx2, ty1);
 356         farr[  i] = dx2; farr[++i] = dy1; farr[++i] = 0;
 357         farr[++i] = tx2; farr[++i] = ty1;
 358         i += 3;
 359 //        addVertNoCheck(dx2, dy2, tx2, ty2);
 360         farr[  i] = dx2; farr[++i] = dy2; farr[++i] = 0;
 361         farr[++i] = tx2; farr[++i] = ty2;
 362 
 363         byte barr[] = colorArray;
 364         byte r = this.r, g = this.g, b = this.b, a = this.a;
 365         int j = BYTES_PER_VERT * idx;
 366         barr[  j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 367         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 368         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 369         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 370 
 371         index = idx + VERTS_PER_QUAD;
 372     }
 373 
 374     public final void addQuadVO(float topopacity, float botopacity,
 375             float dx1, float dy1, float dx2, float dy2,
 376             float tx1, float ty1, float tx2, float ty2)
 377     {
 378         int idx = index;
 379         if (idx + VERTS_PER_QUAD > capacity) {
 380             drawQuads(idx);
 381             idx = index = 0;
 382         }
 383 
 384         int i = FLOATS_PER_VERT * idx;
 385         float farr[] = coordArray;
 386 
 387         // addVertNoCheck(dx1, dy1, tx1, ty1, topopacity);
 388         farr[  i] = dx1; farr[++i] = dy1; farr[++i] = 0;
 389         farr[++i] = tx1; farr[++i] = ty1;
 390         i += 3;
 391 
 392         // addVertNoCheck(dx1, dy2, tx1, ty2, botopacity);
 393         farr[  i] = dx1; farr[++i] = dy2; farr[++i] = 0;
 394         farr[++i] = tx1; farr[++i] = ty2;
 395         i += 3;
 396 
 397         // addVertNoCheck(dx2, dy1, tx2, ty1, topopacity);
 398         farr[  i] = dx2; farr[++i] = dy1; farr[++i] = 0;
 399         farr[++i] = tx2; farr[++i] = ty1;
 400         i += 3;
 401 
 402         // addVertNoCheck(dx2, dy2, tx2, ty2, botopacity);
 403         farr[  i] = dx2; farr[++i] = dy2; farr[++i] = 0;
 404         farr[++i] = tx2; farr[++i] = ty2;
 405 
 406         byte barr[] = colorArray;
 407         int j = BYTES_PER_VERT * idx;
 408 
 409         byte to = (byte)(topopacity * 0xff);
 410         byte bo = (byte)(botopacity * 0xff);
 411 
 412         barr[  j] = to; barr[++j] = to; barr[++j] = to; barr[++j] = to;
 413         barr[++j] = bo; barr[++j] = bo; barr[++j] = bo; barr[++j] = bo;
 414         barr[++j] = to; barr[++j] = to; barr[++j] = to; barr[++j] = to;
 415         barr[++j] = bo; barr[++j] = bo; barr[++j] = bo; barr[++j] = bo;
 416 
 417         index = idx + VERTS_PER_QUAD;
 418     }
 419 
 420     public final void addMappedPgram(
 421             float dx11, float dy11, float dx21, float dy21,
 422             float dx12, float dy12, float dx22, float dy22,
 423             float ux11, float uy11, float ux21, float uy21,
 424             float ux12, float uy12, float ux22, float uy22,
 425             float vx11, float vy11, float vx22, float vy22,
 426             AffineBase tx)
 427     {
 428         addMappedPgram(dx11, dy11, dx21, dy21, dx12, dy12, dx22, dy22,
 429                        ux11, uy11, ux21, uy21, ux12, uy12, ux22, uy22,
 430                        vx11, vy11, vx22, vy11, vx11, vy22, vx22, vy22);
 431 
 432         int i = FLOATS_PER_VERT * index - FLOATS_PER_VERT;
 433         tx.transform(coordArray, i+TC2OFF, coordArray, i+TC2OFF, 1);
 434         i -= FLOATS_PER_VERT;
 435         tx.transform(coordArray, i+TC2OFF, coordArray, i+TC2OFF, 1);
 436         i -= FLOATS_PER_VERT;
 437         tx.transform(coordArray, i+TC2OFF, coordArray, i+TC2OFF, 1);
 438         i -= FLOATS_PER_VERT;
 439         tx.transform(coordArray, i+TC2OFF, coordArray, i+TC2OFF, 1);
 440     }
 441 
 442     public final void addMappedPgram(
 443             float dx11, float dy11, float dx21, float dy21,
 444             float dx12, float dy12, float dx22, float dy22,
 445             float ux11, float uy11, float ux21, float uy21,
 446             float ux12, float uy12, float ux22, float uy22,
 447             float vx, float vy)
 448     {
 449         int idx = index;
 450         if (idx + VERTS_PER_QUAD > capacity) {
 451             drawQuads(idx);
 452             idx = index = 0;
 453         }
 454 
 455         int i = FLOATS_PER_VERT * idx;
 456         float farr[] = coordArray;
 457 
 458         //addVertNoCheck(dx11, dy11, ux11, uy11, vx, vy);
 459         farr[i]   = dx11; farr[++i] = dy11; farr[++i] = 0;
 460         farr[++i] = ux11; farr[++i] = uy11;
 461         farr[++i] = vx; farr[++i] = vy;
 462 
 463         //addVertNoCheck(dx12, dy12, ux12, uy12, vx, vy);
 464         farr[++i] = dx12; farr[++i] = dy12; farr[++i] = 0;
 465         farr[++i] = ux12; farr[++i] = uy12;
 466         farr[++i] = vx; farr[++i] = vy;
 467 
 468         //addVertNoCheck(dx21, dy21, ux21, uy21, vx, vy);
 469         farr[++i] = dx21; farr[++i] = dy21; farr[++i] = 0;
 470         farr[++i] = ux21; farr[++i] = uy21;
 471         farr[++i] = vx; farr[++i] = vy;
 472 
 473             //addVertNoCheck(dx22, dy22, ux22, uy22, vx, vy);
 474         farr[++i] = dx22; farr[++i] = dy22; farr[++i] = 0;
 475         farr[++i] = ux22; farr[++i] = uy22;
 476         farr[++i] = vx; farr[++i] = vy;
 477 
 478         byte barr[] = colorArray;
 479         byte r = this.r, g = this.g, b = this.b, a = this.a;
 480         int j = BYTES_PER_VERT * idx;
 481         barr[  j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 482         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 483         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 484         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 485 
 486         index = idx + VERTS_PER_QUAD;
 487     }
 488 
 489     public final void addMappedPgram(
 490             float dx11, float dy11, float dx21, float dy21,
 491             float dx12, float dy12, float dx22, float dy22,
 492             float ux11, float uy11, float ux21, float uy21,
 493             float ux12, float uy12, float ux22, float uy22,
 494             float vx11, float vy11, float vx21, float vy21,
 495             float vx12, float vy12, float vx22, float vy22)
 496     {
 497         int idx = index;
 498         if (idx + VERTS_PER_QUAD > capacity) {
 499             drawQuads(idx);
 500             idx = index = 0;
 501         }
 502 
 503         int i = FLOATS_PER_VERT * idx;
 504         float farr[] = coordArray;
 505 
 506         //addVertNoCheck(dx11, dy11, ux11, uy11, vx, vy);
 507         farr[i]   = dx11; farr[++i] = dy11; farr[++i] = 0;
 508         farr[++i] = ux11; farr[++i] = uy11;
 509         farr[++i] = vx11; farr[++i] = vy11;
 510 
 511         //addVertNoCheck(dx12, dy12, ux12, uy12, vx, vy);
 512         farr[++i] = dx12; farr[++i] = dy12; farr[++i] = 0;
 513         farr[++i] = ux12; farr[++i] = uy12;
 514         farr[++i] = vx12; farr[++i] = vy12;
 515 
 516         //addVertNoCheck(dx21, dy21, ux21, uy21, vx, vy);
 517         farr[++i] = dx21; farr[++i] = dy21; farr[++i] = 0;
 518         farr[++i] = ux21; farr[++i] = uy21;
 519         farr[++i] = vx21; farr[++i] = vy21;
 520 
 521         //addVertNoCheck(dx22, dy22, ux22, uy22, vx, vy);
 522         farr[++i] = dx22; farr[++i] = dy22; farr[++i] = 0;
 523         farr[++i] = ux22; farr[++i] = uy22;
 524         farr[++i] = vx22; farr[++i] = vy22;
 525 
 526         byte barr[] = colorArray;
 527         byte r = this.r, g = this.g, b = this.b, a = this.a;
 528         int j = BYTES_PER_VERT * idx;
 529         barr[  j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 530         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 531         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 532         barr[++j] = r; barr[++j] = g; barr[++j] = b; barr[++j] = a;
 533 
 534         index = idx + VERTS_PER_QUAD;
 535     }
 536 }