1 /* 2 * Copyright (c) 2007, 2008, 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 "D3DPipeline.h" 27 #include "D3DVertexCacher.h" 28 #include "D3DPaints.h" 29 30 #include "math.h" 31 32 // non-texturized macros 33 34 #define ADD_VERTEX_XYC(X, Y, VCOLOR) \ 35 do { \ 36 vertices[firstUnusedVertex].x = (X); \ 37 vertices[firstUnusedVertex].y = (Y); \ 38 vertices[firstUnusedVertex].color = (DWORD)(VCOLOR); \ 39 firstUnusedVertex++; \ 40 } while (0) 41 42 #define ADD_LINE_XYC(X1, Y1, X2, Y2, VCOLOR) \ 43 do { \ 44 ADD_VERTEX_XYC(X1, Y1, VCOLOR); \ 45 ADD_VERTEX_XYC(X2, Y2, VCOLOR); \ 46 batches[currentBatch].pNum++; \ 47 } while (0) 48 49 #define ADD_LINE_SEG_XYC(X, Y, VCOLOR) \ 50 do { \ 51 ADD_VERTEX_XYC(X, Y, VCOLOR); \ 52 batches[currentBatch].pNum++; \ 53 } while (0) 54 55 #define ADD_TRIANGLE_XYC(X1, Y1, X2, Y2, X3, Y3, VCOLOR) \ 56 do { \ 57 ADD_VERTEX_XYC(X1, Y1, VCOLOR); \ 58 ADD_VERTEX_XYC(X2, Y2, VCOLOR); \ 59 ADD_VERTEX_XYC(X3, Y3, VCOLOR); \ 60 batches[currentBatch].pNum++; \ 61 } while (0) 62 63 // texturized macros 64 65 #define ADD_VERTEX_XYUVC(X, Y, U1, V1, VCOLOR) \ 66 do { \ 67 vertices[firstUnusedVertex].x = (X); \ 68 vertices[firstUnusedVertex].y = (Y); \ 69 vertices[firstUnusedVertex].tu1 = (U1); \ 70 vertices[firstUnusedVertex].tv1 = (V1); \ 71 vertices[firstUnusedVertex].color = (DWORD)(VCOLOR); \ 72 firstUnusedVertex++; \ 73 } while (0) 74 75 #define ADD_VERTEX_XYUVUVC(X, Y, U1, V1, U2, V2, VCOLOR) \ 76 do { \ 77 vertices[firstUnusedVertex].tu2 = (U2); \ 78 vertices[firstUnusedVertex].tv2 = (V2); \ 79 ADD_VERTEX_XYUVC(X, Y, U1, V1, VCOLOR); \ 80 } while (0) 81 82 #define ADD_TRIANGLE_XYUVC(X1, Y1, X2, Y2, X3, Y3, \ 83 U1, V1, U2, V2, U3, V3, VCOLOR) \ 84 do { \ 85 ADD_VERTEX_XYUVC(X1, Y1, U1, V1, VCOLOR); \ 86 ADD_VERTEX_XYUVC(X2, Y2, U2, V2, VCOLOR); \ 87 ADD_VERTEX_XYUVC(X3, Y3, U3, V3, VCOLOR); \ 88 batches[currentBatch].pNum++; \ 89 } while (0) 90 91 #define ADD_TRIANGLE_XYUVUVC(X1, Y1, X2, Y2, X3, Y3, \ 92 U11, V11, U12, V12, U13, V13, \ 93 U21, V21, U22, V22, U23, V23, \ 94 VCOLOR) \ 95 do { \ 96 ADD_VERTEX_XYUVUVC(X1, Y1, U11, V11, U21, V21, VCOLOR); \ 97 ADD_VERTEX_XYUVUVC(X2, Y2, U12, V12, U22, V22, VCOLOR); \ 98 ADD_VERTEX_XYUVUVC(X3, Y3, U13, V13, U23, V23, VCOLOR); \ 99 batches[currentBatch].pNum++; \ 100 } while (0) 101 102 // These are fudge factors for rendering lines found by experimenting. 103 // They are used to tweak the geometry such that the rendering (mostly) matches 104 // our software rendering on most hardware. The main goal was to pick the 105 // numbers such that the beginning and ending pixels of lines match. 106 #define LINE_FUDGE 107 // fudge factors 108 #ifdef LINE_FUDGE 109 110 // Horiz/vertical 111 #define HV_FF1 ( 0.0f) 112 #define HV_FF2 ( 0.51f) 113 // For the record: value below (or larger) is required for Intel 855, but 114 // breaks Nvidia, ATI and Intel 965, and since the pipeline is disabled on 115 // 855 anyway we'll use 0.51f. 116 //#define HV_FF2 ( 0.5315f) 117 #define HV_FF3 (-0.2f) 118 // single pixel 119 #define SP_FF4 ( 0.3f) 120 121 // diagonal, down 122 #define DD_FX1 (-0.1f) 123 #define DD_FY1 (-0.25f) 124 #define DD_FX2 ( 0.2f) 125 #define DD_FY2 ( 0.304f) 126 // For the record: with this value diagonal-down lines with Texture paint 127 // are a bit off on all chipsets but Intel 965. So instead we'll use 128 // .304f which makes it better for the rest, but at a price of a bit 129 // of pixel/texel shifting on 965G 130 //#define DD_FY2 ( 0.4f) 131 // diagonal, up 132 #define DU_FX1 (-0.1f) 133 #define DU_FY1 ( 0.4f) 134 #define DU_FX2 ( 0.3f) 135 #define DU_FY2 (-0.3f) 136 137 #else 138 139 #define HV_FF1 (0.0f) 140 #define HV_FF2 (0.0f) 141 #define HV_FF3 (0.0f) 142 #define SP_FF4 (0.0f) 143 144 #define DD_FX1 (0.0f) 145 #define DD_FY1 (0.0f) 146 #define DD_FX2 (0.0f) 147 #define DD_FY2 (0.0f) 148 #define DU_FX1 (0.0f) 149 #define DU_FY1 (0.0f) 150 #define DU_FX2 (0.0f) 151 #define DU_FY2 (0.0f) 152 153 #endif 154 155 HRESULT 156 D3DVertexCacher::CreateInstance(D3DContext *pCtx, D3DVertexCacher **ppVC) 157 { 158 HRESULT res; 159 160 J2dTraceLn(J2D_TRACE_INFO, "D3DVertexCacher::CreateInstance"); 161 162 *ppVC = new D3DVertexCacher(); 163 if (FAILED(res = (*ppVC)->Init(pCtx))) { 164 delete *ppVC; 165 *ppVC = NULL; 166 } 167 return res; 168 } 169 170 D3DVertexCacher::D3DVertexCacher() 171 { 172 lpD3DDevice = NULL; 173 lpD3DVertexBuffer = NULL; 174 } 175 176 HRESULT 177 D3DVertexCacher::Init(D3DContext *pCtx) 178 { 179 D3DCAPS9 caps; 180 181 RETURN_STATUS_IF_NULL(pCtx, E_FAIL); 182 183 ReleaseDefPoolResources(); 184 185 this->pCtx = pCtx; 186 187 firstPendingBatch = 0; 188 firstPendingVertex = 0; 189 firstUnusedVertex = 0; 190 currentBatch = 0; 191 ZeroMemory(vertices, sizeof(vertices)); 192 ZeroMemory(batches, sizeof(batches)); 193 194 lpD3DDevice = pCtx->Get3DDevice(); 195 RETURN_STATUS_IF_NULL(lpD3DDevice, E_FAIL); 196 197 ZeroMemory(&caps, sizeof(caps)); 198 lpD3DDevice->GetDeviceCaps(&caps); 199 200 D3DPOOL pool = (caps.DeviceType == D3DDEVTYPE_HAL) ? 201 D3DPOOL_DEFAULT : D3DPOOL_SYSTEMMEM; 202 // usage depends on whether we use hw or sw vertex processing 203 HRESULT res = 204 lpD3DDevice->CreateVertexBuffer(MAX_BATCH_SIZE*sizeof(J2DLVERTEX), 205 D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, D3DFVF_J2DLVERTEX, 206 pool, &lpD3DVertexBuffer, NULL); 207 RETURN_STATUS_IF_FAILED(res); 208 209 res = lpD3DDevice->SetStreamSource(0, lpD3DVertexBuffer, 0, 210 sizeof(J2DLVERTEX)); 211 RETURN_STATUS_IF_FAILED(res); 212 213 lpD3DDevice->SetFVF(D3DFVF_J2DLVERTEX); 214 215 fudge2 = HV_FF2; 216 if (fudge2 > 0) { 217 D3DADAPTER_IDENTIFIER9 aid; 218 if (SUCCEEDED(pCtx->Get3DObject()->GetAdapterIdentifier(pCtx-> 219 getAdapterOrdinal(), 0, &aid)) && aid.VendorId == 0x8086) { 220 // Intel 221 fudge2 -= 0.09f; 222 } 223 } 224 return res; 225 } 226 227 void 228 D3DVertexCacher::ReleaseDefPoolResources() 229 { 230 SAFE_RELEASE(lpD3DVertexBuffer); 231 pCtx = NULL; 232 } 233 234 HRESULT D3DVertexCacher::DrawLine(int x1, int y1, int x2, int y2) 235 { 236 HRESULT res; 237 if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, 1*2))) { 238 float fx1, fy1, fx2, fy2; 239 if (y1 == y2) { 240 // horizontal 241 fy1 = (float)y1+HV_FF1; 242 fy2 = fy1; 243 244 if (x1 > x2) { 245 fx1 = (float)x2+HV_FF3; 246 fx2 = (float)x1+fudge2; 247 } else if (x1 < x2) { 248 fx1 = (float)x1+HV_FF3; 249 fx2 = (float)x2+fudge2; 250 } else { 251 // single point, offset a little so that a single 252 // pixel is rendered 253 fx1 = (float)x1-SP_FF4; 254 fy1 = (float)y1-SP_FF4; 255 fx2 = (float)x2+SP_FF4; 256 fy2 = (float)y2+SP_FF4; 257 } 258 } else if (x1 == x2) { 259 // vertical 260 fx1 = (float)x1+HV_FF1; 261 fx2 = fx1; 262 if (y1 > y2) { 263 fy1 = (float)y2+HV_FF3; 264 fy2 = (float)y1+fudge2; 265 } else { 266 fy1 = (float)y1+HV_FF3; 267 fy2 = (float)y2+fudge2; 268 } 269 } else { 270 // diagonal 271 if (x1 > x2 && y1 > y2) { 272 // ^ 273 // \ case -> inverse 274 fx1 = (float)x2; 275 fy1 = (float)y2; 276 fx2 = (float)x1; 277 fy2 = (float)y1; 278 } else if (x1 > x2 && y2 > y1) { 279 // / 280 // v case - inverse 281 fx1 = (float)x2; 282 fy1 = (float)y2; 283 fx2 = (float)x1; 284 fy2 = (float)y1; 285 } else { 286 // \ ^ 287 // v or / - leave as is 288 fx1 = (float)x1; 289 fy1 = (float)y1; 290 fx2 = (float)x2; 291 fy2 = (float)y2; 292 } 293 294 if (fx2 > fx1 && fy2 > fy1) { 295 // \ 296 // v 297 fx1 += DD_FX1; 298 fy1 += DD_FY1; 299 fx2 += DD_FX2; 300 fy2 += DD_FY2; 301 } else { 302 // ^ 303 // / 304 fx1 += DU_FX1; 305 fy1 += DU_FY1; 306 fx2 += DU_FX2; 307 fy2 += DU_FY2; 308 } 309 } 310 ADD_LINE_XYC(fx1, fy1, fx2, fy2, color); 311 } 312 return res; 313 } 314 315 HRESULT 316 D3DVertexCacher::DrawPoly(jint nPoints, jboolean isClosed, 317 jint transX, jint transY, 318 jint *xPoints, jint *yPoints) 319 { 320 HRESULT res; 321 jfloat mx = (jfloat)xPoints[0]; 322 jfloat my = (jfloat)yPoints[0]; 323 jboolean isEmpty = TRUE; 324 325 if (nPoints == 0) { 326 return S_OK; 327 } 328 329 if (isClosed && 330 xPoints[nPoints - 1] == xPoints[0] && 331 yPoints[nPoints - 1] == yPoints[0]) 332 { 333 isClosed = FALSE; 334 } 335 336 // npoints is exactly the number of vertices we need, 337 // possibly plus one (if the path is closed) 338 UINT reqVerts = nPoints * 1; 339 int i = 0; 340 do { 341 // leave room for one possible additional closing point 342 UINT vertsInBatch = min(MAX_BATCH_SIZE-1, max(2, reqVerts)); 343 if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINESTRIP, vertsInBatch+1))) { 344 reqVerts -= vertsInBatch; 345 do { 346 jfloat x = (jfloat)xPoints[i]; 347 jfloat y = (jfloat)yPoints[i]; 348 349 isEmpty = isEmpty && (x == mx && y == my); 350 351 ADD_LINE_SEG_XYC(x + transX, y + transY, color); 352 i++; 353 vertsInBatch--; 354 } while (vertsInBatch > 0); 355 // include the last point from the current batch into the next 356 if (reqVerts > 0) { 357 i--; 358 reqVerts++; 359 // loop continues 360 } else if (isClosed && !isEmpty) { 361 // if this was the last batch, see if the closing point is needed; 362 // note that we have left the room for it 363 ADD_LINE_SEG_XYC(mx + transX, my + transY, color); 364 // for clarity, the loop is ended anyway 365 break; 366 } else if (isEmpty || !isClosed) { 367 // - either we went nowhere, then change the last point 368 // so that a single pixel is rendered 369 // - or it's not empty and not closed - add another 370 // point because on some boards the last point is not rendered 371 mx = xPoints[nPoints-1] + transX +SP_FF4; 372 my = yPoints[nPoints-1] + transY +SP_FF4; 373 ADD_LINE_SEG_XYC(mx, my, color); 374 // for clarity 375 break; 376 } 377 } 378 } while (reqVerts > 0 && SUCCEEDED(res)); 379 380 return res; 381 } 382 383 HRESULT 384 D3DVertexCacher::DrawScanlines(jint scanlineCount, jint *scanlines) 385 { 386 HRESULT res; 387 float x1, x2, y; 388 UINT reqVerts = scanlineCount*2/*vertices per line*/; 389 390 if (scanlineCount == 0) { 391 return S_OK; 392 } 393 394 do { 395 UINT vertsInBatch = min(2*(MAX_BATCH_SIZE/2), reqVerts); 396 if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, vertsInBatch))) { 397 reqVerts -= vertsInBatch; 398 do { 399 x1 = ((float)*(scanlines++)) +HV_FF3; 400 x2 = ((float)*(scanlines++)) +fudge2; 401 y = ((float)*(scanlines++)) +HV_FF1; 402 ADD_LINE_XYC(x1, y, x2, y, color); 403 vertsInBatch -= 2; 404 } while (vertsInBatch > 0); 405 } 406 } while (reqVerts > 0 && SUCCEEDED(res)); 407 return res; 408 } 409 410 HRESULT 411 D3DVertexCacher::FillSpans(jint spanCount, jint *spans) 412 { 413 HRESULT res; 414 float x1, y1, x2, y2; 415 UINT reqVerts = spanCount*2*3/*vertices per span: two triangles*/; 416 417 if (spanCount == 0) { 418 return S_OK; 419 } 420 421 do { 422 UINT vertsInBatch = min(6*(MAX_BATCH_SIZE/6), reqVerts); 423 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, vertsInBatch))) { 424 reqVerts -= vertsInBatch; 425 do { 426 x1 = ((float)*(spans++)); 427 y1 = ((float)*(spans++)); 428 x2 = ((float)*(spans++)); 429 y2 = ((float)*(spans++)); 430 431 ADD_TRIANGLE_XYC(x1, y1, x2, y1, x1, y2, color); 432 ADD_TRIANGLE_XYC(x1, y2, x2, y1, x2, y2, color); 433 vertsInBatch -= 6; 434 } while (vertsInBatch > 0); 435 } 436 } while (reqVerts > 0 && SUCCEEDED(res)); 437 438 return res; 439 } 440 441 HRESULT D3DVertexCacher::DrawRect(int x1, int y1, int x2, int y2) 442 { 443 HRESULT res; 444 445 if ((x2 - x1) < 2 || (y2 - y1) < 2) { 446 return FillRect(x1, y1, x2+1, y2+1); 447 } 448 if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, 4*2))) { 449 450 float fx1 = (float)x1; 451 float fy1 = (float)y1; 452 float fx2 = (float)x2; 453 float fy2 = (float)y2; 454 455 // horiz: top left - top right 456 ADD_LINE_XYC(fx1+HV_FF3, fy1+HV_FF1, fx2-1.0f+fudge2, fy1+HV_FF1,color); 457 // horiz: bottom left - bottom right 458 ADD_LINE_XYC(fx1+1.0f+HV_FF3, fy2+HV_FF1, fx2+fudge2, fy2+HV_FF1,color); 459 // vert : top right - bottom right 460 ADD_LINE_XYC(fx2+HV_FF1, fy1+HV_FF3, fx2+HV_FF1, fy2-1.0f+fudge2,color); 461 // vert : top left - bottom left 462 ADD_LINE_XYC(fx1+HV_FF1, fy1+1.0f+HV_FF3, fx1+HV_FF1, fy2+fudge2,color); 463 } 464 return res; 465 } 466 467 HRESULT D3DVertexCacher::FillRect(int x1, int y1, int x2, int y2) 468 { 469 HRESULT res; 470 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 471 float fx1 = (float)x1; 472 float fy1 = (float)y1; 473 float fx2 = (float)x2; 474 float fy2 = (float)y2; 475 ADD_TRIANGLE_XYUVC(fx1, fy1, fx2, fy1, fx1, fy2, 476 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 477 color); 478 ADD_TRIANGLE_XYUVC(fx1, fy2, fx2, fy1, fx2, fy2, 479 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 480 color); 481 } 482 return res; 483 } 484 485 HRESULT D3DVertexCacher::FillParallelogram(float fx11, float fy11, 486 float dx21, float dy21, 487 float dx12, float dy12) 488 { 489 HRESULT res; 490 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 491 // correct texel to pixel mapping; see D3DContext::SetTransform() 492 // for non-id tx case 493 if (pCtx->IsIdentityTx()) { 494 fx11 -= 0.5f; 495 fy11 -= 0.5f; 496 } 497 dx21 += fx11; 498 dy21 += fy11; 499 float fx22 = dx21 + dx12; 500 float fy22 = dy21 + dy12; 501 dx12 += fx11; 502 dy12 += fy11; 503 504 ADD_TRIANGLE_XYUVC(fx11, fy11, dx21, dy21, dx12, dy12, 505 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 506 color); 507 ADD_TRIANGLE_XYUVC(dx12, dy12, dx21, dy21, fx22, fy22, 508 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 509 color); 510 } 511 return res; 512 } 513 514 #define ADJUST_PGRAM(V, DV, DIM) \ 515 do { \ 516 if ((DV) >= 0) { \ 517 (DIM) += (DV); \ 518 } else { \ 519 (DIM) -= (DV); \ 520 (V) += (DV); \ 521 } \ 522 } while (0) 523 524 // Invert the following transform: 525 // DeltaT(0, 0) == (0, 0) 526 // DeltaT(1, 0) == (DX1, DY1) 527 // DeltaT(0, 1) == (DX2, DY2) 528 // DeltaT(1, 1) == (DX1+DX2, DY1+DY2) 529 // TM00 = DX1, TM01 = DX2, (TM02 = X11) 530 // TM10 = DY1, TM11 = DY2, (TM12 = Y11) 531 // Determinant = TM00*TM11 - TM01*TM10 532 // = DX1*DY2 - DX2*DY1 533 // Inverse is: 534 // IM00 = TM11/det, IM01 = -TM01/det 535 // IM10 = -TM10/det, IM11 = TM00/det 536 // IM02 = (TM01 * TM12 - TM11 * TM02) / det, 537 // IM12 = (TM10 * TM02 - TM00 * TM12) / det, 538 539 #define DECLARE_MATRIX(MAT) \ 540 float MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12 541 542 #define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \ 543 do { \ 544 float det = DX1*DY2 - DX2*DY1; \ 545 if (det == 0) { \ 546 RET_CODE; \ 547 } \ 548 MAT ## 00 = DY2/det; \ 549 MAT ## 01 = -DX2/det; \ 550 MAT ## 10 = -DY1/det; \ 551 MAT ## 11 = DX1/det; \ 552 MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \ 553 MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \ 554 } while (0) 555 556 #define TRANSFORM(MAT, TX, TY, X, Y) \ 557 do { \ 558 TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \ 559 TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \ 560 } while (0) 561 562 HRESULT D3DVertexCacher::FillParallelogramAA(float fx11, float fy11, 563 float dx21, float dy21, 564 float dx12, float dy12) 565 { 566 HRESULT res; 567 DECLARE_MATRIX(om); 568 569 GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12, 570 return D3D_OK); 571 572 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 573 float px = fx11, py = fy11; 574 float pw = 0.0f, ph = 0.0f; 575 ADJUST_PGRAM(px, dx21, pw); 576 ADJUST_PGRAM(py, dy21, ph); 577 ADJUST_PGRAM(px, dx12, pw); 578 ADJUST_PGRAM(py, dy12, ph); 579 float px1 = floor(px); 580 float py1 = floor(py); 581 float px2 = ceil(px + pw); 582 float py2 = ceil(py + ph); 583 float u11, v11, u12, v12, u21, v21, u22, v22; 584 TRANSFORM(om, u11, v11, px1, py1); 585 TRANSFORM(om, u21, v21, px2, py1); 586 TRANSFORM(om, u12, v12, px1, py2); 587 TRANSFORM(om, u22, v22, px2, py2); 588 ADD_TRIANGLE_XYUVUVC(px1, py1, px2, py1, px1, py2, 589 u11, v11, u21, v21, u12, v12, 590 5.0, 5.0, 6.0, 5.0, 5.0, 6.0, 591 color); 592 ADD_TRIANGLE_XYUVUVC(px1, py2, px2, py1, px2, py2, 593 u12, v12, u21, v21, u22, v22, 594 5.0, 6.0, 6.0, 5.0, 6.0, 6.0, 595 color); 596 } 597 return res; 598 } 599 600 HRESULT D3DVertexCacher::DrawParallelogramAA(float ox11, float oy11, 601 float ox21, float oy21, 602 float ox12, float oy12, 603 float ix11, float iy11, 604 float ix21, float iy21, 605 float ix12, float iy12) 606 { 607 HRESULT res; 608 DECLARE_MATRIX(om); 609 DECLARE_MATRIX(im); 610 611 GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12, 612 // inner parallelogram is degenerate 613 // therefore it encloses no area 614 // fill outer 615 return FillParallelogramAA(ox11, oy11, 616 ox21, oy21, 617 ox12, oy12)); 618 GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12, 619 return D3D_OK); 620 621 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 622 float ox = ox11, oy = oy11; 623 float ow = 0.0f, oh = 0.0f; 624 ADJUST_PGRAM(ox, ox21, ow); 625 ADJUST_PGRAM(oy, oy21, oh); 626 ADJUST_PGRAM(ox, ox12, ow); 627 ADJUST_PGRAM(oy, oy12, oh); 628 float ox11 = floor(ox); 629 float oy11 = floor(oy); 630 float ox22 = ceil(ox + ow); 631 float oy22 = ceil(oy + oh); 632 float ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22; 633 TRANSFORM(om, ou11, ov11, ox11, oy11); 634 TRANSFORM(om, ou21, ov21, ox22, oy11); 635 TRANSFORM(om, ou12, ov12, ox11, oy22); 636 TRANSFORM(om, ou22, ov22, ox22, oy22); 637 float iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22; 638 TRANSFORM(im, iu11, iv11, ox11, oy11); 639 TRANSFORM(im, iu21, iv21, ox22, oy11); 640 TRANSFORM(im, iu12, iv12, ox11, oy22); 641 TRANSFORM(im, iu22, iv22, ox22, oy22); 642 ADD_TRIANGLE_XYUVUVC(ox11, oy11, ox22, oy11, ox11, oy22, 643 ou11, ov11, ou21, ov21, ou12, ov12, 644 iu11, iv11, iu21, iv21, iu12, iv12, 645 color); 646 ADD_TRIANGLE_XYUVUVC(ox11, oy22, ox22, oy11, ox22, oy22, 647 ou12, ov12, ou21, ov21, ou22, ov22, 648 iu12, iv12, iu21, iv21, iu22, iv22, 649 color); 650 } 651 return res; 652 } 653 654 HRESULT 655 D3DVertexCacher::DrawTexture(float x1, float y1, float x2, float y2, 656 float u1, float v1, float u2, float v2) 657 { 658 HRESULT res; 659 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 660 // correct texel to pixel mapping; see D3DContext::SetTransform() 661 // for non-id tx case 662 if (pCtx->IsIdentityTx()) { 663 x1 -= 0.5f; 664 y1 -= 0.5f; 665 x2 -= 0.5f; 666 y2 -= 0.5f; 667 } 668 669 ADD_TRIANGLE_XYUVC(x1, y1, x2, y1, x1, y2, 670 u1, v1, u2, v1, u1, v2, 671 color); 672 ADD_TRIANGLE_XYUVC(x1, y2, x2, y1, x2, y2, 673 u1, v2, u2, v1, u2, v2, 674 color); 675 } 676 return res; 677 } 678 679 HRESULT 680 D3DVertexCacher::DrawTexture(float x1, float y1, float x2, float y2, 681 float u11, float v11, float u12, float v12, 682 float u21, float v21, float u22, float v22) 683 { 684 HRESULT res; 685 if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) { 686 // correct texel to pixel mapping; see D3DContext::SetTransform() 687 // for non-id tx case 688 if (pCtx->IsIdentityTx()) { 689 x1 -= 0.5f; 690 y1 -= 0.5f; 691 x2 -= 0.5f; 692 y2 -= 0.5f; 693 } 694 695 ADD_TRIANGLE_XYUVUVC(x1, y1, x2, y1, x1, y2, 696 u11, v11, u12, v11, u11, v12, 697 u21, v21, u22, v21, u21, v22, 698 color); 699 ADD_TRIANGLE_XYUVUVC(x1, y2, x2, y1, x2, y2, 700 u11, v12, u12, v11, u12, v12, 701 u21, v22, u22, v21, u22, v22, 702 color); 703 } 704 return res; 705 } 706 707 HRESULT D3DVertexCacher::Render(int actionType) 708 { 709 J2DLVERTEX *lpVert; 710 HRESULT res; 711 DWORD dwLockFlags; 712 UINT pendingVertices = firstUnusedVertex - firstPendingVertex; 713 714 // nothing to render 715 if (pendingVertices == 0) { 716 if (actionType == RESET_ACTION) { 717 firstPendingBatch = 0; 718 firstPendingVertex = 0; 719 firstUnusedVertex = 0; 720 currentBatch = 0; 721 } 722 return D3D_OK; 723 } 724 725 if (firstPendingVertex == 0) { 726 // no data in the buffer yet, we don't care about 727 // vertex buffer's contents 728 dwLockFlags = D3DLOCK_DISCARD; 729 } else { 730 // append to the existing data in the vertex buffer 731 dwLockFlags = D3DLOCK_NOOVERWRITE; 732 } 733 734 if (SUCCEEDED(res = 735 lpD3DVertexBuffer->Lock((UINT)firstPendingVertex*sizeof(J2DLVERTEX), 736 (UINT)pendingVertices*sizeof(J2DLVERTEX), 737 (void**)&lpVert, dwLockFlags))) 738 { 739 // copy only new vertices 740 memcpy((void *)lpVert, 741 (void *)(vertices + firstPendingVertex), 742 pendingVertices * sizeof(J2DLVERTEX)); 743 res = lpD3DVertexBuffer->Unlock(); 744 UINT currentVertex = firstPendingVertex; 745 UINT batchSize; 746 J2dTraceLn2(J2D_TRACE_VERBOSE, 747 "D3DVC::Render Starting flushing of %d vertices "\ 748 "in %d batches", 749 pendingVertices, 750 (currentBatch - firstPendingBatch + 1)); 751 752 753 for (UINT b = firstPendingBatch; b <= currentBatch; b++) { 754 D3DPRIMITIVETYPE pType = batches[b].pType; 755 UINT primCount = batches[b].pNum; 756 switch (pType) { 757 // the macro for adding a line segment adds one too many prims 758 case D3DPT_LINESTRIP: batchSize = primCount; primCount--; break; 759 case D3DPT_LINELIST: batchSize = primCount*2; break; 760 default: batchSize = primCount*3; break; 761 } 762 res = lpD3DDevice->DrawPrimitive(pType, currentVertex, primCount); 763 currentVertex += batchSize; 764 // init to something it can never be 765 batches[b].pType = (D3DPRIMITIVETYPE)0; 766 batches[b].pNum = 0; 767 } 768 } else { 769 DebugPrintD3DError(res, "Can't lock vertex buffer"); 770 } 771 772 // REMIND: may need to rethink what to do in case of an error, 773 // should we try to render them later? 774 if (actionType == RESET_ACTION) { 775 firstPendingBatch = 0; 776 firstPendingVertex = 0; 777 firstUnusedVertex = 0; 778 currentBatch = 0; 779 } else { 780 firstPendingBatch = currentBatch; 781 firstPendingVertex = firstUnusedVertex; 782 } 783 784 return res; 785 } 786 787 HRESULT D3DVertexCacher::EnsureCapacity(D3DPRIMITIVETYPE newPType, UINT vNum) 788 { 789 HRESULT res = D3D_OK; 790 if (vNum > MAX_BATCH_SIZE) { 791 // REMIND: need to define our own errors 792 return D3DERR_NOTAVAILABLE; 793 } 794 if ((firstUnusedVertex + vNum) > MAX_BATCH_SIZE) { 795 // if we can't fit new vertices in the vertex buffer, 796 // render whatever we have in the buffer and start 797 // from the beginning of the vertex buffer 798 J2dTraceLn2(J2D_TRACE_VERBOSE, 799 "D3DVC::EnsureCapacity exceeded capacity. "\ 800 "current v: %d, requested vertices: %d\n", 801 firstUnusedVertex, vNum); 802 if (FAILED(res = Render(RESET_ACTION))) { 803 return res; 804 } 805 } 806 807 J2dTraceLn5(J2D_TRACE_VERBOSE, 808 "D3DVC::EnsureCapacity current batch: %d "\ 809 " batch.type=%d newType=%d vNum=%d firstUnusedV=%d", 810 currentBatch, batches[currentBatch].pType, newPType, vNum, 811 firstUnusedVertex); 812 // there should not be multiple linestrips in a batch, 813 // or they will be counted as a single line strip 814 if (batches[currentBatch].pType != newPType || 815 batches[currentBatch].pType == D3DPT_LINESTRIP) 816 { 817 // if this is a first unused batch, use it 818 if (firstUnusedVertex == firstPendingVertex) { 819 // record the first batch and vertex scheduled for rendering 820 firstPendingBatch = currentBatch; 821 firstPendingVertex = firstUnusedVertex; 822 } else { 823 // otherwise go to the next batch 824 currentBatch++; 825 } 826 batches[currentBatch].pType = newPType; 827 batches[currentBatch].pNum = 0; 828 } 829 // firstUnusedVertex is updated when new vertices are added 830 // to the vertices array 831 832 return res; 833 }