1 | /* |
2 | * Copyright (c) 2008, 2010, 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 "math.h" |
27 | #include "GraphicsPrimitiveMgr.h" |
28 | #include "LineUtils.h" |
29 | #include "Trace.h" |
30 | #include "ParallelogramUtils.h" |
31 | |
32 | #include "sun_java2d_loops_DrawParallelogram.h" |
33 | |
34 | #define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \ |
35 | pRasInfo, pixel, pPrim, pFunc, pCompInfo) \ |
36 | do { \ |
37 | jint ix1 = (jint) floor(X1); \ |
38 | jint ix2 = (jint) floor(X2); \ |
39 | jint iy1 = (jint) floor(Y1); \ |
40 | jint iy2 = (jint) floor(Y2); \ |
41 | LineUtils_ProcessLine(pRasInfo, pixel, \ |
42 | pFunc, pPrim, pCompInfo, \ |
43 | ix1, iy1, ix2, iy2, JNI_TRUE); \ |
44 | } while (0) |
45 | |
46 | typedef struct { |
47 | jdouble x0; |
48 | jdouble y0; |
49 | jdouble y1; |
50 | jdouble slope; |
51 | jlong dx; |
52 | jint ystart; |
53 | jint yend; |
54 | } EdgeInfo; |
55 | |
56 | #define STORE_EDGE(pEDGE, X0, Y0, Y1, SLOPE, DELTAX) \ |
57 | do { \ |
58 | (pEDGE)->x0 = (X0); \ |
59 | (pEDGE)->y0 = (Y0); \ |
60 | (pEDGE)->y1 = (Y1); \ |
61 | (pEDGE)->slope = (SLOPE); \ |
62 | (pEDGE)->dx = (DELTAX); \ |
63 | (pEDGE)->ystart = (jint) floor((Y0) + 0.5); \ |
64 | (pEDGE)->yend = (jint) floor((Y1) + 0.5); \ |
65 | } while (0) |
66 | |
67 | #define STORE_PGRAM(pLTEDGE, pRTEDGE, \ |
68 | X0, Y0, dX1, dY1, dX2, dY2, \ |
69 | SLOPE1, SLOPE2, DELTAX1, DELTAX2) \ |
70 | do { \ |
71 | STORE_EDGE((pLTEDGE)+0, \ |
72 | (X0), (Y0), (Y0) + (dY1), \ |
73 | (SLOPE1), (DELTAX1)); \ |
74 | STORE_EDGE((pRTEDGE)+0, \ |
75 | (X0), (Y0), (Y0) + (dY2), \ |
76 | (SLOPE2), (DELTAX2)); \ |
77 | STORE_EDGE((pLTEDGE)+1, \ |
78 | (X0) + (dX1), (Y0) + (dY1), (Y0) + (dY1) + (dY2), \ |
79 | (SLOPE2), (DELTAX2)); \ |
80 | STORE_EDGE((pRTEDGE)+1, \ |
81 | (X0) + (dX2), (Y0) + (dY2), (Y0) + (dY1) + (dY2), \ |
82 | (SLOPE1), (DELTAX1)); \ |
83 | } while (0) |
84 | |
85 | /* |
86 | * Class: sun_java2d_loops_DrawParallelogram |
87 | * Method: DrawParallelogram |
88 | * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDDDD)V |
89 | */ |
90 | JNIEXPORT void JNICALL |
91 | Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram |
92 | (JNIEnv *env, jobject self, |
93 | jobject sg2d, jobject sData, |
94 | jdouble x0, jdouble y0, |
95 | jdouble dx1, jdouble dy1, |
96 | jdouble dx2, jdouble dy2, |
97 | jdouble lw1, jdouble lw2) |
98 | { |
99 | SurfaceDataOps *sdOps; |
100 | SurfaceDataRasInfo rasInfo; |
101 | NativePrimitive *pPrim; |
102 | CompositeInfo compInfo; |
103 | jint pixel; |
104 | EdgeInfo edges[8]; |
105 | EdgeInfo *active[4]; |
106 | jint ix1, iy1, ix2, iy2; |
107 | jdouble ldx1, ldy1, ldx2, ldy2; |
108 | jdouble ox0, oy0; |
109 | |
110 | /* |
111 | * Sort parallelogram by y values, ensure that each delta vector |
112 | * has a non-negative y delta. |
113 | */ |
114 | SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, |
115 | v = lw1; lw1 = lw2; lw2 = v;); |
116 | |
117 | // dx,dy for line width in the "1" and "2" directions. |
118 | ldx1 = dx1 * lw1; |
119 | ldy1 = dy1 * lw1; |
120 | ldx2 = dx2 * lw2; |
121 | ldy2 = dy2 * lw2; |
122 | |
123 | // calculate origin of the outer parallelogram |
124 | ox0 = x0 - (ldx1 + ldx2) / 2.0; |
125 | oy0 = y0 - (ldy1 + ldy2) / 2.0; |
126 | |
127 | PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE); |
128 | iy1 = (jint) floor(oy0 + 0.5); |
129 | iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5); |
130 | |
131 | pPrim = GetNativePrim(env, self); |
132 | if (pPrim == NULL) { |
133 | return; |
134 | } |
135 | pixel = GrPrim_Sg2dGetPixel(env, sg2d); |
136 | if (pPrim->pCompType->getCompInfo != NULL) { |
137 | GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); |
138 | } |
139 | |
140 | sdOps = SurfaceData_GetOps(env, sData); |
141 | if (sdOps == NULL) { |
142 | return; |
143 | } |
144 | |
145 | GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); |
146 | SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); |
147 | if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || |
148 | rasInfo.bounds.x2 <= rasInfo.bounds.x1) |
149 | { |
150 | return; |
151 | } |
152 | |
153 | if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { |
154 | return; |
155 | } |
156 | |
157 | ix1 = rasInfo.bounds.x1; |
158 | iy1 = rasInfo.bounds.y1; |
159 | ix2 = rasInfo.bounds.x2; |
160 | iy2 = rasInfo.bounds.y2; |
161 | if (ix2 > ix1 && iy2 > iy1) { |
162 | sdOps->GetRasInfo(env, sdOps, &rasInfo); |
163 | if (rasInfo.rasBase) { |
164 | jdouble lslope, rslope; |
165 | jlong ldx, rdx; |
166 | jint loy, hiy, numedges; |
167 | FillParallelogramFunc *pFill = |
168 | pPrim->funcs.drawparallelogram->fillpgram; |
169 | |
170 | lslope = (dy1 == 0) ? 0 : dx1 / dy1; |
171 | rslope = (dy2 == 0) ? 0 : dx2 / dy2; |
172 | ldx = DblToLong(lslope); |
173 | rdx = DblToLong(rslope); |
174 | |
175 | // Only need to generate 4 quads if the interior still |
176 | // has a hole in it (i.e. if the line width ratios were |
177 | // both less than 1.0) |
178 | if (lw1 < 1.0 && lw2 < 1.0) { |
179 | // If the line widths are both less than a pixel wide |
180 | // then we can use a drawline function instead for even |
181 | // more performance. |
182 | lw1 = sqrt(ldx1*ldx1 + ldy1*ldy1); |
183 | lw2 = sqrt(ldx2*ldx2 + ldy2*ldy2); |
184 | if (lw1 <= 1.0001 && lw2 <= 1.0001) { |
185 | jdouble x3, y3; |
186 | DrawLineFunc *pLine = |
187 | pPrim->funcs.drawparallelogram->drawline; |
188 | |
189 | x3 = (dx1 += x0); |
190 | y3 = (dy1 += y0); |
191 | x3 += dx2; |
192 | y3 += dy2; |
193 | dx2 += x0; |
194 | dy2 += y0; |
195 | |
196 | HANDLE_PGRAM_EDGE( x0, y0, dx1, dy1, |
197 | &rasInfo, pixel, pPrim, pLine, &compInfo); |
198 | HANDLE_PGRAM_EDGE(dx1, dy1, x3, y3, |
199 | &rasInfo, pixel, pPrim, pLine, &compInfo); |
200 | HANDLE_PGRAM_EDGE( x3, y3, dx2, dy2, |
201 | &rasInfo, pixel, pPrim, pLine, &compInfo); |
202 | HANDLE_PGRAM_EDGE(dx2, dy2, x0, y0, |
203 | &rasInfo, pixel, pPrim, pLine, &compInfo); |
204 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
205 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
206 | return; |
207 | } |
208 | |
209 | // To simplify the edge management below we presort the |
210 | // inner and outer edges so that they are globally sorted |
211 | // from left to right. If you scan across the array of |
212 | // edges for a given Y range then the edges you encounter |
213 | // will be sorted in X as well. |
214 | // If AB are left top and bottom edges of outer parallelogram, |
215 | // and CD are the right pair of edges, and abcd are the |
216 | // corresponding inner parallelogram edges then we want them |
217 | // sorted as ABabcdCD to ensure this horizontal ordering. |
218 | // Conceptually it is like 2 pairs of nested parentheses. |
219 | STORE_PGRAM(edges + 2, edges + 4, |
220 | ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2, |
221 | dx1 - ldx1, dy1 - ldy1, |
222 | dx2 - ldx2, dy2 - ldy2, |
223 | lslope, rslope, ldx, rdx); |
224 | numedges = 8; |
225 | } else { |
226 | // The line width ratios were large enough to consume |
227 | // the entire hole in the middle of the parallelogram |
228 | // so we can just issue one large quad for the outer |
229 | // parallelogram. |
230 | numedges = 4; |
231 | } |
232 | |
233 | // The outer parallelogram always goes in the first two |
234 | // and last two entries in the array so we either have |
235 | // ABabcdCD ordering for 8 edges or ABCD ordering for 4 |
236 | // edges. See comment above where we store the inner |
237 | // parallelogram for a more complete description. |
238 | STORE_PGRAM(edges + 0, edges + numedges-2, |
239 | ox0, oy0, |
240 | dx1 + ldx1, dy1 + ldy1, |
241 | dx2 + ldx2, dy2 + ldy2, |
242 | lslope, rslope, ldx, rdx); |
243 | |
244 | loy = edges[0].ystart; |
245 | if (loy < iy1) loy = iy1; |
246 | while (loy < iy2) { |
247 | jint numactive = 0; |
248 | jint cur; |
249 | |
250 | hiy = iy2; |
251 | // Maintaining a sorted edge list is probably overkill for |
252 | // 4 or 8 edges. The indices chosen above for storing the |
253 | // inner and outer left and right edges already guarantee |
254 | // left to right ordering so we just need to scan for edges |
255 | // that overlap the current Y range (and also determine the |
256 | // maximum Y value for which the range is valid). |
257 | for (cur = 0; cur < numedges; cur++) { |
258 | EdgeInfo *pEdge = &edges[cur]; |
259 | jint yend = pEdge->yend; |
260 | if (loy < yend) { |
261 | // This edge is still in play, have we reached it yet? |
262 | jint ystart = pEdge->ystart; |
263 | if (loy < ystart) { |
264 | // This edge is not active (yet) |
265 | // Stop before we get to the top of it |
266 | if (hiy > ystart) hiy = ystart; |
267 | } else { |
268 | // This edge is active, store it |
269 | active[numactive++] = pEdge; |
270 | // And stop when we get to the bottom of it |
271 | if (hiy > yend) hiy = yend; |
272 | } |
273 | } |
274 | } |
275 | #ifdef DEBUG |
276 | if ((numactive & 1) != 0) { |
277 | J2dTraceLn1(J2D_TRACE_ERROR, |
278 | "DrawParallelogram: " |
279 | "ODD NUMBER OF PGRAM EDGES (%d)!!" , |
280 | numactive); |
281 | } |
282 | #endif |
283 | for (cur = 0; cur < numactive; cur += 2) { |
284 | EdgeInfo *pLeft = active[cur+0]; |
285 | EdgeInfo *pRight = active[cur+1]; |
286 | jlong lx = PGRAM_INIT_X(loy, |
287 | pLeft->x0, pLeft->y0, |
288 | pLeft->slope); |
289 | jlong rx = PGRAM_INIT_X(loy, |
290 | pRight->x0, pRight->y0, |
291 | pRight->slope); |
292 | (*pFill)(&rasInfo, |
293 | ix1, loy, ix2, hiy, |
294 | lx, pLeft->dx, |
295 | rx, pRight->dx, |
296 | pixel, pPrim, &compInfo); |
297 | } |
298 | loy = hiy; |
299 | } |
300 | } |
301 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
302 | } |
303 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
304 | } |
305 | |