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
CreateInstance(D3DContext * pCtx,D3DVertexCacher ** ppVC)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 
D3DVertexCacher()170 D3DVertexCacher::D3DVertexCacher()
171 {
172     lpD3DDevice = NULL;
173     lpD3DVertexBuffer = NULL;
174 }
175 
176 HRESULT
Init(D3DContext * pCtx)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     return res;
215 }
216 
217 void
ReleaseDefPoolResources()218 D3DVertexCacher::ReleaseDefPoolResources()
219 {
220     SAFE_RELEASE(lpD3DVertexBuffer);
221     pCtx = NULL;
222 }
223 
DrawLine(int x1,int y1,int x2,int y2)224 HRESULT D3DVertexCacher::DrawLine(int x1, int y1, int x2, int y2)
225 {
226     HRESULT res;
227     if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, 1*2))) {
228         float fx1, fy1, fx2, fy2;
229         if (y1 == y2) {
230             // horizontal
231             fy1  = (float)y1+HV_FF1;
232             fy2  = fy1;
233 
234             if (x1 > x2) {
235                 fx1 = (float)x2+HV_FF3;
236                 fx2 = (float)x1+HV_FF2;
237             } else if (x1 < x2) {
238                 fx1 = (float)x1+HV_FF3;
239                 fx2 = (float)x2+HV_FF2;
240             } else {
241                 // single point, offset a little so that a single
242                 // pixel is rendered
243                 fx1 = (float)x1-SP_FF4;
244                 fy1 = (float)y1-SP_FF4;
245                 fx2 = (float)x2+SP_FF4;
246                 fy2 = (float)y2+SP_FF4;
247             }
248         } else if (x1 == x2) {
249             // vertical
250             fx1  = (float)x1+HV_FF1;
251             fx2  = fx1;
252             if (y1 > y2) {
253                 fy1 = (float)y2+HV_FF3;
254                 fy2 = (float)y1+HV_FF2;
255             } else {
256                 fy1 = (float)y1+HV_FF3;
257                 fy2 = (float)y2+HV_FF2;
258             }
259         } else {
260             // diagonal
261             if (x1 > x2 && y1 > y2) {
262                 // ^
263                 //  \ case -> inverse
264                 fx1 = (float)x2;
265                 fy1 = (float)y2;
266                 fx2 = (float)x1;
267                 fy2 = (float)y1;
268             } else if (x1 > x2 && y2 > y1) {
269                 //  /
270                 // v  case - inverse
271                 fx1 = (float)x2;
272                 fy1 = (float)y2;
273                 fx2 = (float)x1;
274                 fy2 = (float)y1;
275             } else {
276                 // \      ^
277                 //  v or /  - leave as is
278                 fx1 = (float)x1;
279                 fy1 = (float)y1;
280                 fx2 = (float)x2;
281                 fy2 = (float)y2;
282             }
283 
284             if (fx2 > fx1 && fy2 > fy1) {
285                 // \
286                 //  v
287                 fx1 += DD_FX1;
288                 fy1 += DD_FY1;
289                 fx2 += DD_FX2;
290                 fy2 += DD_FY2;
291             } else {
292                 //   ^
293                 //  /
294                 fx1 += DU_FX1;
295                 fy1 += DU_FY1;
296                 fx2 += DU_FX2;
297                 fy2 += DU_FY2;
298             }
299         }
300         ADD_LINE_XYC(fx1, fy1, fx2, fy2, color);
301     }
302     return res;
303 }
304 
305 HRESULT
DrawPoly(jint nPoints,jboolean isClosed,jint transX,jint transY,jint * xPoints,jint * yPoints)306 D3DVertexCacher::DrawPoly(jint nPoints, jboolean isClosed,
307                           jint transX, jint transY,
308                           jint *xPoints, jint *yPoints)
309 {
310     HRESULT res;
311     jfloat mx = (jfloat)xPoints[0];
312     jfloat my = (jfloat)yPoints[0];
313     jboolean isEmpty = TRUE;
314 
315     if (nPoints == 0) {
316         return S_OK;
317     }
318 
319     if (isClosed &&
320         xPoints[nPoints - 1] == xPoints[0] &&
321         yPoints[nPoints - 1] == yPoints[0])
322     {
323         isClosed = FALSE;
324     }
325 
326     // npoints is exactly the number of vertices we need,
327     // possibly plus one (if the path is closed)
328     UINT reqVerts = nPoints * 1;
329     int i = 0;
330     do {
331         // leave room for one possible additional closing point
332         UINT vertsInBatch = min(MAX_BATCH_SIZE-1, max(2, reqVerts));
333         if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINESTRIP, vertsInBatch+1))) {
334             reqVerts -= vertsInBatch;
335             do {
336                 jfloat x = (jfloat)xPoints[i];
337                 jfloat y = (jfloat)yPoints[i];
338 
339                 isEmpty = isEmpty && (x == mx && y == my);
340 
341                 ADD_LINE_SEG_XYC(x + transX, y + transY, color);
342                 i++;
343                 vertsInBatch--;
344             } while (vertsInBatch > 0);
345             // include the last point from the current batch into the next
346             if (reqVerts > 0) {
347                 i--;
348                 reqVerts++;
349                 // loop continues
350             } else if (isClosed && !isEmpty) {
351                 // if this was the last batch, see if the closing point is needed;
352                 // note that we have left the room for it
353                 ADD_LINE_SEG_XYC(mx + transX, my + transY, color);
354                 // for clarity, the loop is ended anyway
355                 break;
356             } else if (isEmpty || !isClosed) {
357                 // - either we went nowhere, then change the last point
358                 // so that a single pixel is rendered
359                 // - or it's not empty and not closed - add another
360                 // point because on some boards the last point is not rendered
361                 mx = xPoints[nPoints-1] + transX +SP_FF4;
362                 my = yPoints[nPoints-1] + transY +SP_FF4;
363                 ADD_LINE_SEG_XYC(mx, my, color);
364                 // for clarity
365                 break;
366             }
367         }
368     } while (reqVerts > 0 && SUCCEEDED(res));
369 
370     return res;
371 }
372 
373 HRESULT
DrawScanlines(jint scanlineCount,jint * scanlines)374 D3DVertexCacher::DrawScanlines(jint scanlineCount, jint *scanlines)
375 {
376     HRESULT res;
377     float x1, x2, y;
378     UINT reqVerts = scanlineCount*2/*vertices per line*/;
379 
380     if (scanlineCount == 0) {
381         return S_OK;
382     }
383 
384     do {
385         UINT vertsInBatch = min(2*(MAX_BATCH_SIZE/2), reqVerts);
386         if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, vertsInBatch))) {
387             reqVerts -= vertsInBatch;
388             do {
389                 x1 = ((float)*(scanlines++)) +HV_FF3;
390                 x2 = ((float)*(scanlines++)) +HV_FF2;
391                 y  = ((float)*(scanlines++)) +HV_FF1;
392                 ADD_LINE_XYC(x1, y, x2, y, color);
393                 vertsInBatch -= 2;
394             } while (vertsInBatch > 0);
395         }
396     } while (reqVerts > 0 && SUCCEEDED(res));
397     return res;
398 }
399 
400 HRESULT
FillSpans(jint spanCount,jint * spans)401 D3DVertexCacher::FillSpans(jint spanCount, jint *spans)
402 {
403     HRESULT res;
404     float x1, y1, x2, y2;
405     UINT reqVerts = spanCount*2*3/*vertices per span: two triangles*/;
406 
407     if (spanCount == 0) {
408         return S_OK;
409     }
410 
411     do {
412         UINT vertsInBatch = min(6*(MAX_BATCH_SIZE/6), reqVerts);
413         if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, vertsInBatch))) {
414             reqVerts -= vertsInBatch;
415             do {
416                 x1 = ((float)*(spans++));
417                 y1 = ((float)*(spans++));
418                 x2 = ((float)*(spans++));
419                 y2 = ((float)*(spans++));
420 
421                 ADD_TRIANGLE_XYC(x1, y1, x2, y1, x1, y2, color);
422                 ADD_TRIANGLE_XYC(x1, y2, x2, y1, x2, y2, color);
423                 vertsInBatch -= 6;
424             } while (vertsInBatch > 0);
425         }
426     } while (reqVerts > 0 && SUCCEEDED(res));
427 
428     return res;
429 }
430 
DrawRect(int x1,int y1,int x2,int y2)431 HRESULT D3DVertexCacher::DrawRect(int x1, int y1, int x2, int y2)
432 {
433     HRESULT res;
434 
435     if ((x2 - x1) < 2 || (y2 - y1) < 2) {
436         return FillRect(x1, y1, x2+1, y2+1);
437     }
438     if (SUCCEEDED(res = EnsureCapacity(D3DPT_LINELIST, 4*2))) {
439 
440         float fx1 = (float)x1;
441         float fy1 = (float)y1;
442         float fx2 = (float)x2;
443         float fy2 = (float)y2;
444 
445         // horiz: top left - top right
446         ADD_LINE_XYC(fx1+HV_FF3, fy1+HV_FF1, fx2-1.0f+HV_FF2, fy1+HV_FF1,color);
447         // horiz: bottom left - bottom right
448         ADD_LINE_XYC(fx1+1.0f+HV_FF3, fy2+HV_FF1, fx2+HV_FF2, fy2+HV_FF1,color);
449         // vert : top right - bottom right
450         ADD_LINE_XYC(fx2+HV_FF1, fy1+HV_FF3, fx2+HV_FF1, fy2-1.0f+HV_FF2,color);
451         // vert : top left - bottom left
452         ADD_LINE_XYC(fx1+HV_FF1, fy1+1.0f+HV_FF3, fx1+HV_FF1, fy2+HV_FF2,color);
453     }
454     return res;
455 }
456 
FillRect(int x1,int y1,int x2,int y2)457 HRESULT D3DVertexCacher::FillRect(int x1, int y1, int x2, int y2)
458 {
459     HRESULT res;
460     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
461         float fx1 = (float)x1;
462         float fy1 = (float)y1;
463         float fx2 = (float)x2;
464         float fy2 = (float)y2;
465         ADD_TRIANGLE_XYUVC(fx1, fy1, fx2, fy1, fx1, fy2,
466                            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
467                            color);
468         ADD_TRIANGLE_XYUVC(fx1, fy2, fx2, fy1, fx2, fy2,
469                            0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
470                            color);
471     }
472     return res;
473 }
474 
FillParallelogram(float fx11,float fy11,float dx21,float dy21,float dx12,float dy12)475 HRESULT D3DVertexCacher::FillParallelogram(float fx11, float fy11,
476                                            float dx21, float dy21,
477                                            float dx12, float dy12)
478 {
479     HRESULT res;
480     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
481         // correct texel to pixel mapping; see D3DContext::SetTransform()
482         // for non-id tx case
483         if (pCtx->IsIdentityTx()) {
484             fx11 -= 0.5f;
485             fy11 -= 0.5f;
486         }
487         dx21 += fx11;
488         dy21 += fy11;
489         float fx22 = dx21 + dx12;
490         float fy22 = dy21 + dy12;
491         dx12 += fx11;
492         dy12 += fy11;
493 
494         ADD_TRIANGLE_XYUVC(fx11, fy11, dx21, dy21, dx12, dy12,
495                            0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
496                            color);
497         ADD_TRIANGLE_XYUVC(dx12, dy12, dx21, dy21, fx22, fy22,
498                            0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
499                            color);
500     }
501     return res;
502 }
503 
504 #define ADJUST_PGRAM(V, DV, DIM) \
505     do { \
506         if ((DV) >= 0) { \
507             (DIM) += (DV); \
508         } else { \
509             (DIM) -= (DV); \
510             (V) += (DV); \
511         } \
512     } while (0)
513 
514 // Invert the following transform:
515 // DeltaT(0, 0) == (0,       0)
516 // DeltaT(1, 0) == (DX1,     DY1)
517 // DeltaT(0, 1) == (DX2,     DY2)
518 // DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
519 // TM00 = DX1,   TM01 = DX2,   (TM02 = X11)
520 // TM10 = DY1,   TM11 = DY2,   (TM12 = Y11)
521 // Determinant = TM00*TM11 - TM01*TM10
522 //             =  DX1*DY2  -  DX2*DY1
523 // Inverse is:
524 // IM00 =  TM11/det,   IM01 = -TM01/det
525 // IM10 = -TM10/det,   IM11 =  TM00/det
526 // IM02 = (TM01 * TM12 - TM11 * TM02) / det,
527 // IM12 = (TM10 * TM02 - TM00 * TM12) / det,
528 
529 #define DECLARE_MATRIX(MAT) \
530     float MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
531 
532 #define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
533     do { \
534         float det = DX1*DY2 - DX2*DY1; \
535         if (det == 0) { \
536             RET_CODE; \
537         } \
538         MAT ## 00 = DY2/det; \
539         MAT ## 01 = -DX2/det; \
540         MAT ## 10 = -DY1/det; \
541         MAT ## 11 = DX1/det; \
542         MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
543         MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
544     } while (0)
545 
546 #define TRANSFORM(MAT, TX, TY, X, Y) \
547     do { \
548         TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
549         TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
550     } while (0)
551 
FillParallelogramAA(float fx11,float fy11,float dx21,float dy21,float dx12,float dy12)552 HRESULT D3DVertexCacher::FillParallelogramAA(float fx11, float fy11,
553                                              float dx21, float dy21,
554                                              float dx12, float dy12)
555 {
556     HRESULT res;
557     DECLARE_MATRIX(om);
558 
559     GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12,
560                         return D3D_OK);
561 
562     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
563         float px = fx11, py = fy11;
564         float pw = 0.0f, ph = 0.0f;
565         ADJUST_PGRAM(px, dx21, pw);
566         ADJUST_PGRAM(py, dy21, ph);
567         ADJUST_PGRAM(px, dx12, pw);
568         ADJUST_PGRAM(py, dy12, ph);
569         float px1 = floor(px);
570         float py1 = floor(py);
571         float px2 = ceil(px + pw);
572         float py2 = ceil(py + ph);
573         float u11, v11, u12, v12, u21, v21, u22, v22;
574         TRANSFORM(om, u11, v11, px1, py1);
575         TRANSFORM(om, u21, v21, px2, py1);
576         TRANSFORM(om, u12, v12, px1, py2);
577         TRANSFORM(om, u22, v22, px2, py2);
578         ADD_TRIANGLE_XYUVUVC(px1, py1, px2, py1, px1, py2,
579                              u11, v11, u21, v21, u12, v12,
580                              5.0, 5.0, 6.0, 5.0, 5.0, 6.0,
581                              color);
582         ADD_TRIANGLE_XYUVUVC(px1, py2, px2, py1, px2, py2,
583                              u12, v12, u21, v21, u22, v22,
584                              5.0, 6.0, 6.0, 5.0, 6.0, 6.0,
585                              color);
586     }
587     return res;
588 }
589 
DrawParallelogramAA(float ox11,float oy11,float ox21,float oy21,float ox12,float oy12,float ix11,float iy11,float ix21,float iy21,float ix12,float iy12)590 HRESULT D3DVertexCacher::DrawParallelogramAA(float ox11, float oy11,
591                                              float ox21, float oy21,
592                                              float ox12, float oy12,
593                                              float ix11, float iy11,
594                                              float ix21, float iy21,
595                                              float ix12, float iy12)
596 {
597     HRESULT res;
598     DECLARE_MATRIX(om);
599     DECLARE_MATRIX(im);
600 
601     GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12,
602                         // inner parallelogram is degenerate
603                         // therefore it encloses no area
604                         // fill outer
605                         return FillParallelogramAA(ox11, oy11,
606                                                    ox21, oy21,
607                                                    ox12, oy12));
608     GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12,
609                         return D3D_OK);
610 
611     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
612         float ox = ox11, oy = oy11;
613         float ow = 0.0f, oh = 0.0f;
614         ADJUST_PGRAM(ox, ox21, ow);
615         ADJUST_PGRAM(oy, oy21, oh);
616         ADJUST_PGRAM(ox, ox12, ow);
617         ADJUST_PGRAM(oy, oy12, oh);
618         float ox11 = floor(ox);
619         float oy11 = floor(oy);
620         float ox22 = ceil(ox + ow);
621         float oy22 = ceil(oy + oh);
622         float ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;
623         TRANSFORM(om, ou11, ov11, ox11, oy11);
624         TRANSFORM(om, ou21, ov21, ox22, oy11);
625         TRANSFORM(om, ou12, ov12, ox11, oy22);
626         TRANSFORM(om, ou22, ov22, ox22, oy22);
627         float iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22;
628         TRANSFORM(im, iu11, iv11, ox11, oy11);
629         TRANSFORM(im, iu21, iv21, ox22, oy11);
630         TRANSFORM(im, iu12, iv12, ox11, oy22);
631         TRANSFORM(im, iu22, iv22, ox22, oy22);
632         ADD_TRIANGLE_XYUVUVC(ox11, oy11, ox22, oy11, ox11, oy22,
633                              ou11, ov11, ou21, ov21, ou12, ov12,
634                              iu11, iv11, iu21, iv21, iu12, iv12,
635                              color);
636         ADD_TRIANGLE_XYUVUVC(ox11, oy22, ox22, oy11, ox22, oy22,
637                              ou12, ov12, ou21, ov21, ou22, ov22,
638                              iu12, iv12, iu21, iv21, iu22, iv22,
639                              color);
640     }
641     return res;
642 }
643 
644 HRESULT
DrawTexture(float x1,float y1,float x2,float y2,float u1,float v1,float u2,float v2)645 D3DVertexCacher::DrawTexture(float x1, float y1, float x2, float y2,
646                              float u1, float v1, float u2, float v2)
647 {
648     HRESULT res;
649     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
650         // correct texel to pixel mapping; see D3DContext::SetTransform()
651         // for non-id tx case
652         if (pCtx->IsIdentityTx()) {
653             x1 -= 0.5f;
654             y1 -= 0.5f;
655             x2 -= 0.5f;
656             y2 -= 0.5f;
657         }
658 
659         ADD_TRIANGLE_XYUVC(x1, y1, x2, y1, x1, y2,
660                            u1, v1, u2, v1, u1, v2,
661                            color);
662         ADD_TRIANGLE_XYUVC(x1, y2, x2, y1, x2, y2,
663                            u1, v2, u2, v1, u2, v2,
664                            color);
665     }
666     return res;
667 }
668 
669 HRESULT
DrawTexture(float x1,float y1,float x2,float y2,float u11,float v11,float u12,float v12,float u21,float v21,float u22,float v22)670 D3DVertexCacher::DrawTexture(float  x1, float  y1, float  x2, float  y2,
671                              float u11, float v11, float u12, float v12,
672                              float u21, float v21, float u22, float v22)
673 {
674     HRESULT res;
675     if (SUCCEEDED(res = EnsureCapacity(D3DPT_TRIANGLELIST, 2*3))) {
676         // correct texel to pixel mapping; see D3DContext::SetTransform()
677         // for non-id tx case
678         if (pCtx->IsIdentityTx()) {
679             x1 -= 0.5f;
680             y1 -= 0.5f;
681             x2 -= 0.5f;
682             y2 -= 0.5f;
683         }
684 
685         ADD_TRIANGLE_XYUVUVC(x1, y1, x2, y1, x1, y2,
686                              u11, v11, u12, v11, u11, v12,
687                              u21, v21, u22, v21, u21, v22,
688                              color);
689         ADD_TRIANGLE_XYUVUVC(x1, y2, x2, y1, x2, y2,
690                              u11, v12, u12, v11, u12, v12,
691                              u21, v22, u22, v21, u22, v22,
692                              color);
693     }
694     return res;
695 }
696 
Render(int actionType)697 HRESULT D3DVertexCacher::Render(int actionType)
698 {
699     J2DLVERTEX *lpVert;
700     HRESULT res;
701     DWORD dwLockFlags;
702     UINT pendingVertices = firstUnusedVertex - firstPendingVertex;
703 
704     // nothing to render
705     if (pendingVertices == 0) {
706         if (actionType == RESET_ACTION) {
707             firstPendingBatch = 0;
708             firstPendingVertex = 0;
709             firstUnusedVertex = 0;
710             currentBatch = 0;
711         }
712         return D3D_OK;
713     }
714 
715     if (firstPendingVertex == 0) {
716         // no data in the buffer yet, we don't care about
717         // vertex buffer's contents
718         dwLockFlags = D3DLOCK_DISCARD;
719     } else {
720         // append to the existing data in the vertex buffer
721         dwLockFlags = D3DLOCK_NOOVERWRITE;
722     }
723 
724     if (SUCCEEDED(res =
725         lpD3DVertexBuffer->Lock((UINT)firstPendingVertex*sizeof(J2DLVERTEX),
726                                 (UINT)pendingVertices*sizeof(J2DLVERTEX),
727                                 (void**)&lpVert, dwLockFlags)))
728     {
729         // copy only new vertices
730         memcpy((void *)lpVert,
731                (void *)(vertices + firstPendingVertex),
732                pendingVertices * sizeof(J2DLVERTEX));
733         res = lpD3DVertexBuffer->Unlock();
734         UINT currentVertex = firstPendingVertex;
735         UINT batchSize;
736         J2dTraceLn2(J2D_TRACE_VERBOSE,
737                     "D3DVC::Render Starting flushing of %d vertices "\
738                     "in %d batches",
739                     pendingVertices,
740                     (currentBatch - firstPendingBatch + 1));
741 
742 
743         for (UINT b = firstPendingBatch; b <= currentBatch; b++) {
744             D3DPRIMITIVETYPE pType = batches[b].pType;
745             UINT primCount = batches[b].pNum;
746             switch (pType) {
747                 // the macro for adding a line segment adds one too many prims
748                 case D3DPT_LINESTRIP: batchSize = primCount; primCount--; break;
749                 case D3DPT_LINELIST: batchSize = primCount*2; break;
750                 default: batchSize = primCount*3; break;
751             }
752             res = lpD3DDevice->DrawPrimitive(pType, currentVertex, primCount);
753             currentVertex += batchSize;
754             // init to something it can never be
755             batches[b].pType = (D3DPRIMITIVETYPE)0;
756             batches[b].pNum = 0;
757         }
758     } else {
759         DebugPrintD3DError(res, "Can't lock vertex buffer");
760     }
761 
762     // REMIND: may need to rethink what to do in case of an error,
763     // should we try to render them later?
764     if (actionType == RESET_ACTION) {
765         firstPendingBatch = 0;
766         firstPendingVertex = 0;
767         firstUnusedVertex = 0;
768         currentBatch = 0;
769     } else {
770         firstPendingBatch = currentBatch;
771         firstPendingVertex = firstUnusedVertex;
772     }
773 
774     return res;
775 }
776 
EnsureCapacity(D3DPRIMITIVETYPE newPType,UINT vNum)777 HRESULT D3DVertexCacher::EnsureCapacity(D3DPRIMITIVETYPE newPType, UINT vNum)
778 {
779     HRESULT res = D3D_OK;
780     if (vNum > MAX_BATCH_SIZE) {
781         // REMIND: need to define our own errors
782         return D3DERR_NOTAVAILABLE;
783     }
784     if ((firstUnusedVertex + vNum) > MAX_BATCH_SIZE) {
785         // if we can't fit new vertices in the vertex buffer,
786         // render whatever we have in the buffer and start
787         // from the beginning of the vertex buffer
788         J2dTraceLn2(J2D_TRACE_VERBOSE,
789                     "D3DVC::EnsureCapacity exceeded capacity. "\
790                     "current v: %d, requested vertices: %d\n",
791                     firstUnusedVertex, vNum);
792         if (FAILED(res = Render(RESET_ACTION))) {
793             return res;
794         }
795     }
796 
797     J2dTraceLn5(J2D_TRACE_VERBOSE,
798                 "D3DVC::EnsureCapacity current batch: %d "\
799                 " batch.type=%d newType=%d vNum=%d firstUnusedV=%d",
800                 currentBatch, batches[currentBatch].pType, newPType, vNum,
801                 firstUnusedVertex);
802     // there should not be multiple linestrips in a batch,
803     // or they will be counted as a single line strip
804     if (batches[currentBatch].pType != newPType ||
805         batches[currentBatch].pType == D3DPT_LINESTRIP)
806     {
807         // if this is a first unused batch, use it
808         if (firstUnusedVertex == firstPendingVertex) {
809             // record the first batch and vertex scheduled for rendering
810             firstPendingBatch = currentBatch;
811             firstPendingVertex = firstUnusedVertex;
812         } else {
813             // otherwise go to the next batch
814             currentBatch++;
815         }
816         batches[currentBatch].pType = newPType;
817         batches[currentBatch].pNum = 0;
818     }
819     // firstUnusedVertex is updated when new vertices are added
820     // to the vertices array
821 
822     return res;
823 }
824