Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/common/java2d/opengl/OGLRenderer.c
41159 views
1
/*
2
* Copyright (c) 2003, 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
#ifndef HEADLESS
27
28
#include <jlong.h>
29
#include <jni_util.h>
30
#include <math.h>
31
32
#include "sun_java2d_opengl_OGLRenderer.h"
33
34
#include "OGLRenderer.h"
35
#include "OGLRenderQueue.h"
36
#include "OGLSurfaceData.h"
37
38
/**
39
* Note: Some of the methods in this file apply a "magic number"
40
* translation to line segments. The OpenGL specification lays out the
41
* "diamond exit rule" for line rasterization, but it is loose enough to
42
* allow for a wide range of line rendering hardware. (It appears that
43
* some hardware, such as the Nvidia GeForce2 series, does not even meet
44
* the spec in all cases.) As such it is difficult to find a mapping
45
* between the Java2D and OpenGL line specs that works consistently across
46
* all hardware combinations.
47
*
48
* Therefore the "magic numbers" you see here have been empirically derived
49
* after testing on a variety of graphics hardware in order to find some
50
* reasonable middle ground between the two specifications. The general
51
* approach is to apply a fractional translation to vertices so that they
52
* hit pixel centers and therefore touch the same pixels as in our other
53
* pipelines. Emphasis was placed on finding values so that OGL lines with
54
* a slope of +/- 1 hit all the same pixels as our other (software) loops.
55
* The stepping in other diagonal lines rendered with OGL may deviate
56
* slightly from those rendered with our software loops, but the most
57
* important thing is that these magic numbers ensure that all OGL lines
58
* hit the same endpoints as our software loops.
59
*
60
* If you find it necessary to change any of these magic numbers in the
61
* future, just be sure that you test the changes across a variety of
62
* hardware to ensure consistent rendering everywhere.
63
*/
64
65
void
66
OGLRenderer_DrawLine(OGLContext *oglc, jint x1, jint y1, jint x2, jint y2)
67
{
68
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawLine");
69
70
RETURN_IF_NULL(oglc);
71
72
CHECK_PREVIOUS_OP(GL_LINES);
73
74
if (y1 == y2) {
75
// horizontal
76
GLfloat fx1 = (GLfloat)x1;
77
GLfloat fx2 = (GLfloat)x2;
78
GLfloat fy = ((GLfloat)y1) + 0.2f;
79
80
if (x1 > x2) {
81
GLfloat t = fx1; fx1 = fx2; fx2 = t;
82
}
83
84
j2d_glVertex2f(fx1+0.2f, fy);
85
j2d_glVertex2f(fx2+1.2f, fy);
86
} else if (x1 == x2) {
87
// vertical
88
GLfloat fx = ((GLfloat)x1) + 0.2f;
89
GLfloat fy1 = (GLfloat)y1;
90
GLfloat fy2 = (GLfloat)y2;
91
92
if (y1 > y2) {
93
GLfloat t = fy1; fy1 = fy2; fy2 = t;
94
}
95
96
j2d_glVertex2f(fx, fy1+0.2f);
97
j2d_glVertex2f(fx, fy2+1.2f);
98
} else {
99
// diagonal
100
GLfloat fx1 = (GLfloat)x1;
101
GLfloat fy1 = (GLfloat)y1;
102
GLfloat fx2 = (GLfloat)x2;
103
GLfloat fy2 = (GLfloat)y2;
104
105
if (x1 < x2) {
106
fx1 += 0.2f;
107
fx2 += 1.0f;
108
} else {
109
fx1 += 0.8f;
110
fx2 -= 0.2f;
111
}
112
113
if (y1 < y2) {
114
fy1 += 0.2f;
115
fy2 += 1.0f;
116
} else {
117
fy1 += 0.8f;
118
fy2 -= 0.2f;
119
}
120
121
j2d_glVertex2f(fx1, fy1);
122
j2d_glVertex2f(fx2, fy2);
123
}
124
}
125
126
void
127
OGLRenderer_DrawRect(OGLContext *oglc, jint x, jint y, jint w, jint h)
128
{
129
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawRect");
130
131
if (w < 0 || h < 0) {
132
return;
133
}
134
135
RETURN_IF_NULL(oglc);
136
137
if (w < 2 || h < 2) {
138
// If one dimension is less than 2 then there is no
139
// gap in the middle - draw a solid filled rectangle.
140
CHECK_PREVIOUS_OP(GL_QUADS);
141
GLRECT_BODY_XYWH(x, y, w+1, h+1);
142
} else {
143
GLfloat fx1 = ((GLfloat)x) + 0.2f;
144
GLfloat fy1 = ((GLfloat)y) + 0.2f;
145
GLfloat fx2 = fx1 + ((GLfloat)w);
146
GLfloat fy2 = fy1 + ((GLfloat)h);
147
148
// Avoid drawing the endpoints twice.
149
// Also prefer including the endpoints in the
150
// horizontal sections which draw pixels faster.
151
152
CHECK_PREVIOUS_OP(GL_LINES);
153
// top
154
j2d_glVertex2f(fx1, fy1);
155
j2d_glVertex2f(fx2+1.0f, fy1);
156
// right
157
j2d_glVertex2f(fx2, fy1+1.0f);
158
j2d_glVertex2f(fx2, fy2);
159
// bottom
160
j2d_glVertex2f(fx1, fy2);
161
j2d_glVertex2f(fx2+1.0f, fy2);
162
// left
163
j2d_glVertex2f(fx1, fy1+1.0f);
164
j2d_glVertex2f(fx1, fy2);
165
}
166
}
167
168
void
169
OGLRenderer_DrawPoly(OGLContext *oglc,
170
jint nPoints, jint isClosed,
171
jint transX, jint transY,
172
jint *xPoints, jint *yPoints)
173
{
174
jboolean isEmpty = JNI_TRUE;
175
jint mx, my;
176
jint i;
177
178
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawPoly");
179
180
if (xPoints == NULL || yPoints == NULL) {
181
J2dRlsTraceLn(J2D_TRACE_ERROR,
182
"OGLRenderer_DrawPoly: points array is null");
183
return;
184
}
185
186
RETURN_IF_NULL(oglc);
187
188
// Note that BufferedRenderPipe.drawPoly() has already rejected polys
189
// with nPoints<2, so we can be certain here that we have nPoints>=2.
190
191
mx = xPoints[0];
192
my = yPoints[0];
193
194
CHECK_PREVIOUS_OP(GL_LINE_STRIP);
195
for (i = 0; i < nPoints; i++) {
196
jint x = xPoints[i];
197
jint y = yPoints[i];
198
199
isEmpty = isEmpty && (x == mx && y == my);
200
201
// Translate each vertex by a fraction so that we hit pixel centers.
202
j2d_glVertex2f((GLfloat)(x + transX) + 0.5f,
203
(GLfloat)(y + transY) + 0.5f);
204
}
205
206
if (isClosed && !isEmpty &&
207
(xPoints[nPoints-1] != mx ||
208
yPoints[nPoints-1] != my))
209
{
210
// In this case, the polyline's start and end positions are
211
// different and need to be closed manually; we do this by adding
212
// one more segment back to the starting position. Note that we
213
// do not need to fill in the last pixel (as we do in the following
214
// block) because we are returning to the starting pixel, which
215
// has already been filled in.
216
j2d_glVertex2f((GLfloat)(mx + transX) + 0.5f,
217
(GLfloat)(my + transY) + 0.5f);
218
RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
219
} else if (!isClosed || isEmpty) {
220
// OpenGL omits the last pixel in a polyline, so we fix this by
221
// adding a one-pixel segment at the end. Also, if the polyline
222
// never went anywhere (isEmpty is true), we need to use this
223
// workaround to ensure that a single pixel is touched.
224
CHECK_PREVIOUS_OP(GL_LINES); // this closes the line strip first
225
mx = xPoints[nPoints-1] + transX;
226
my = yPoints[nPoints-1] + transY;
227
j2d_glVertex2i(mx, my);
228
j2d_glVertex2i(mx+1, my+1);
229
// no need for RESET_PREVIOUS_OP, as the line strip is no longer open
230
} else {
231
RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
232
}
233
}
234
235
JNIEXPORT void JNICALL
236
Java_sun_java2d_opengl_OGLRenderer_drawPoly
237
(JNIEnv *env, jobject oglr,
238
jintArray xpointsArray, jintArray ypointsArray,
239
jint nPoints, jboolean isClosed,
240
jint transX, jint transY)
241
{
242
jint *xPoints, *yPoints;
243
244
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_drawPoly");
245
246
xPoints = (jint *)
247
(*env)->GetPrimitiveArrayCritical(env, xpointsArray, NULL);
248
if (xPoints != NULL) {
249
yPoints = (jint *)
250
(*env)->GetPrimitiveArrayCritical(env, ypointsArray, NULL);
251
if (yPoints != NULL) {
252
OGLContext *oglc = OGLRenderQueue_GetCurrentContext();
253
254
OGLRenderer_DrawPoly(oglc,
255
nPoints, isClosed,
256
transX, transY,
257
xPoints, yPoints);
258
259
// 6358147: reset current state, and ensure rendering is
260
// flushed to dest
261
if (oglc != NULL) {
262
RESET_PREVIOUS_OP();
263
j2d_glFlush();
264
}
265
266
(*env)->ReleasePrimitiveArrayCritical(env, ypointsArray, yPoints,
267
JNI_ABORT);
268
}
269
(*env)->ReleasePrimitiveArrayCritical(env, xpointsArray, xPoints,
270
JNI_ABORT);
271
}
272
}
273
274
void
275
OGLRenderer_DrawScanlines(OGLContext *oglc,
276
jint scanlineCount, jint *scanlines)
277
{
278
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DrawScanlines");
279
280
RETURN_IF_NULL(oglc);
281
RETURN_IF_NULL(scanlines);
282
283
CHECK_PREVIOUS_OP(GL_LINES);
284
while (scanlineCount > 0) {
285
// Translate each vertex by a fraction so
286
// that we hit pixel centers.
287
GLfloat x1 = ((GLfloat)*(scanlines++)) + 0.2f;
288
GLfloat x2 = ((GLfloat)*(scanlines++)) + 1.2f;
289
GLfloat y = ((GLfloat)*(scanlines++)) + 0.5f;
290
j2d_glVertex2f(x1, y);
291
j2d_glVertex2f(x2, y);
292
scanlineCount--;
293
}
294
}
295
296
void
297
OGLRenderer_FillRect(OGLContext *oglc, jint x, jint y, jint w, jint h)
298
{
299
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillRect");
300
301
if (w <= 0 || h <= 0) {
302
return;
303
}
304
305
RETURN_IF_NULL(oglc);
306
307
CHECK_PREVIOUS_OP(GL_QUADS);
308
GLRECT_BODY_XYWH(x, y, w, h);
309
}
310
311
void
312
OGLRenderer_FillSpans(OGLContext *oglc, jint spanCount, jint *spans)
313
{
314
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_FillSpans");
315
316
RETURN_IF_NULL(oglc);
317
RETURN_IF_NULL(spans);
318
319
CHECK_PREVIOUS_OP(GL_QUADS);
320
while (spanCount > 0) {
321
jint x1 = *(spans++);
322
jint y1 = *(spans++);
323
jint x2 = *(spans++);
324
jint y2 = *(spans++);
325
GLRECT_BODY_XYXY(x1, y1, x2, y2);
326
spanCount--;
327
}
328
}
329
330
#define FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12) \
331
do { \
332
j2d_glVertex2f(fx11, fy11); \
333
j2d_glVertex2f(fx11 + dx21, fy11 + dy21); \
334
j2d_glVertex2f(fx11 + dx21 + dx12, fy11 + dy21 + dy12); \
335
j2d_glVertex2f(fx11 + dx12, fy11 + dy12); \
336
} while (0)
337
338
void
339
OGLRenderer_FillParallelogram(OGLContext *oglc,
340
jfloat fx11, jfloat fy11,
341
jfloat dx21, jfloat dy21,
342
jfloat dx12, jfloat dy12)
343
{
344
J2dTraceLn6(J2D_TRACE_INFO,
345
"OGLRenderer_FillParallelogram "
346
"(x=%6.2f y=%6.2f "
347
"dx1=%6.2f dy1=%6.2f "
348
"dx2=%6.2f dy2=%6.2f)",
349
fx11, fy11,
350
dx21, dy21,
351
dx12, dy12);
352
353
RETURN_IF_NULL(oglc);
354
355
CHECK_PREVIOUS_OP(GL_QUADS);
356
357
FILL_PGRAM(fx11, fy11, dx21, dy21, dx12, dy12);
358
}
359
360
void
361
OGLRenderer_DrawParallelogram(OGLContext *oglc,
362
jfloat fx11, jfloat fy11,
363
jfloat dx21, jfloat dy21,
364
jfloat dx12, jfloat dy12,
365
jfloat lwr21, jfloat lwr12)
366
{
367
// dx,dy for line width in the "21" and "12" directions.
368
jfloat ldx21 = dx21 * lwr21;
369
jfloat ldy21 = dy21 * lwr21;
370
jfloat ldx12 = dx12 * lwr12;
371
jfloat ldy12 = dy12 * lwr12;
372
373
// calculate origin of the outer parallelogram
374
jfloat ox11 = fx11 - (ldx21 + ldx12) / 2.0f;
375
jfloat oy11 = fy11 - (ldy21 + ldy12) / 2.0f;
376
377
J2dTraceLn8(J2D_TRACE_INFO,
378
"OGLRenderer_DrawParallelogram "
379
"(x=%6.2f y=%6.2f "
380
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
381
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
382
fx11, fy11,
383
dx21, dy21, lwr21,
384
dx12, dy12, lwr12);
385
386
RETURN_IF_NULL(oglc);
387
388
CHECK_PREVIOUS_OP(GL_QUADS);
389
390
// Only need to generate 4 quads if the interior still
391
// has a hole in it (i.e. if the line width ratio was
392
// less than 1.0)
393
if (lwr21 < 1.0f && lwr12 < 1.0f) {
394
// Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are
395
// relative to whether the dxNN variables are positive
396
// and negative. The math works fine regardless of
397
// their signs, but for conceptual simplicity the
398
// comments will refer to the sides as if the dxNN
399
// were all positive. "TOP" and "BOTTOM" segments
400
// are defined by the dxy21 deltas. "LEFT" and "RIGHT"
401
// segments are defined by the dxy12 deltas.
402
403
// Each segment includes its starting corner and comes
404
// to just short of the following corner. Thus, each
405
// corner is included just once and the only lengths
406
// needed are the original parallelogram delta lengths
407
// and the "line width deltas". The sides will cover
408
// the following relative territories:
409
//
410
// T T T T T R
411
// L R
412
// L R
413
// L R
414
// L R
415
// L B B B B B
416
417
// TOP segment, to left side of RIGHT edge
418
// "width" of original pgram, "height" of hor. line size
419
fx11 = ox11;
420
fy11 = oy11;
421
FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);
422
423
// RIGHT segment, to top of BOTTOM edge
424
// "width" of vert. line size , "height" of original pgram
425
fx11 = ox11 + dx21;
426
fy11 = oy11 + dy21;
427
FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);
428
429
// BOTTOM segment, from right side of LEFT edge
430
// "width" of original pgram, "height" of hor. line size
431
fx11 = ox11 + dx12 + ldx21;
432
fy11 = oy11 + dy12 + ldy21;
433
FILL_PGRAM(fx11, fy11, dx21, dy21, ldx12, ldy12);
434
435
// LEFT segment, from bottom of TOP edge
436
// "width" of vert. line size , "height" of inner pgram
437
fx11 = ox11 + ldx12;
438
fy11 = oy11 + ldy12;
439
FILL_PGRAM(fx11, fy11, ldx21, ldy21, dx12, dy12);
440
} else {
441
// The line width ratios were large enough to consume
442
// the entire hole in the middle of the parallelogram
443
// so we can just issue one large quad for the outer
444
// parallelogram.
445
dx21 += ldx21;
446
dy21 += ldy21;
447
dx12 += ldx12;
448
dy12 += ldy12;
449
FILL_PGRAM(ox11, oy11, dx21, dy21, dx12, dy12);
450
}
451
}
452
453
static GLhandleARB aaPgramProgram = 0;
454
455
/*
456
* This shader fills the space between an outer and inner parallelogram.
457
* It can be used to draw an outline by specifying both inner and outer
458
* values. It fills pixels by estimating what portion falls inside the
459
* outer shape, and subtracting an estimate of what portion falls inside
460
* the inner shape. Specifying both inner and outer values produces a
461
* standard "wide outline". Specifying an inner shape that falls far
462
* outside the outer shape allows the same shader to fill the outer
463
* shape entirely since pixels that fall within the outer shape are never
464
* inside the inner shape and so they are filled based solely on their
465
* coverage of the outer shape.
466
*
467
* The setup code renders this shader over the bounds of the outer
468
* shape (or the only shape in the case of a fill operation) and
469
* sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those
470
* texture coordinates map to the four corners of the parallelogram.
471
* Similarly the texture 1 coordinates map the inner shape to the
472
* unit square as well, but in a different coordinate system.
473
*
474
* When viewed in the texture coordinate systems the parallelograms
475
* we are filling are unit squares, but the pixels have then become
476
* tiny parallelograms themselves. Both of the texture coordinate
477
* systems are affine transforms so the rate of change in X and Y
478
* of the texture coordinates are essentially constants and happen
479
* to correspond to the size and direction of the slanted sides of
480
* the distorted pixels relative to the "square mapped" boundary
481
* of the parallelograms.
482
*
483
* The shader uses the dFdx() and dFdy() functions to measure the "rate
484
* of change" of these texture coordinates and thus gets an accurate
485
* measure of the size and shape of a pixel relative to the two
486
* parallelograms. It then uses the bounds of the size and shape
487
* of a pixel to intersect with the unit square to estimate the
488
* coverage of the pixel. Unfortunately, without a lot more work
489
* to calculate the exact area of intersection between a unit
490
* square (the original parallelogram) and a parallelogram (the
491
* distorted pixel), this shader only approximates the pixel
492
* coverage, but emperically the estimate is very useful and
493
* produces visually pleasing results, if not theoretically accurate.
494
*/
495
static const char *aaPgramShaderSource =
496
"void main() {"
497
// Calculate the vectors for the "legs" of the pixel parallelogram
498
// for the outer parallelogram.
499
" vec2 oleg1 = dFdx(gl_TexCoord[0].st);"
500
" vec2 oleg2 = dFdy(gl_TexCoord[0].st);"
501
// Calculate the bounds of the distorted pixel parallelogram.
502
" vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"
503
" vec2 omin = min(corner, corner+oleg1);"
504
" omin = min(omin, corner+oleg2);"
505
" omin = min(omin, corner+oleg1+oleg2);"
506
" vec2 omax = max(corner, corner+oleg1);"
507
" omax = max(omax, corner+oleg2);"
508
" omax = max(omax, corner+oleg1+oleg2);"
509
// Calculate the vectors for the "legs" of the pixel parallelogram
510
// for the inner parallelogram.
511
" vec2 ileg1 = dFdx(gl_TexCoord[1].st);"
512
" vec2 ileg2 = dFdy(gl_TexCoord[1].st);"
513
// Calculate the bounds of the distorted pixel parallelogram.
514
" corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"
515
" vec2 imin = min(corner, corner+ileg1);"
516
" imin = min(imin, corner+ileg2);"
517
" imin = min(imin, corner+ileg1+ileg2);"
518
" vec2 imax = max(corner, corner+ileg1);"
519
" imax = max(imax, corner+ileg2);"
520
" imax = max(imax, corner+ileg1+ileg2);"
521
// Clamp the bounds of the parallelograms to the unit square to
522
// estimate the intersection of the pixel parallelogram with
523
// the unit square. The ratio of the 2 rectangle areas is a
524
// reasonable estimate of the proportion of coverage.
525
" vec2 o1 = clamp(omin, 0.0, 1.0);"
526
" vec2 o2 = clamp(omax, 0.0, 1.0);"
527
" float oint = (o2.y-o1.y)*(o2.x-o1.x);"
528
" float oarea = (omax.y-omin.y)*(omax.x-omin.x);"
529
" vec2 i1 = clamp(imin, 0.0, 1.0);"
530
" vec2 i2 = clamp(imax, 0.0, 1.0);"
531
" float iint = (i2.y-i1.y)*(i2.x-i1.x);"
532
" float iarea = (imax.y-imin.y)*(imax.x-imin.x);"
533
// Proportion of pixel in outer shape minus the proportion
534
// of pixel in the inner shape == the coverage of the pixel
535
// in the area between the two.
536
" float coverage = oint/oarea - iint / iarea;"
537
" gl_FragColor = gl_Color * coverage;"
538
"}";
539
540
#define ADJUST_PGRAM(V1, DV, V2) \
541
do { \
542
if ((DV) >= 0) { \
543
(V2) += (DV); \
544
} else { \
545
(V1) += (DV); \
546
} \
547
} while (0)
548
549
// Invert the following transform:
550
// DeltaT(0, 0) == (0, 0)
551
// DeltaT(1, 0) == (DX1, DY1)
552
// DeltaT(0, 1) == (DX2, DY2)
553
// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
554
// TM00 = DX1, TM01 = DX2, (TM02 = X11)
555
// TM10 = DY1, TM11 = DY2, (TM12 = Y11)
556
// Determinant = TM00*TM11 - TM01*TM10
557
// = DX1*DY2 - DX2*DY1
558
// Inverse is:
559
// IM00 = TM11/det, IM01 = -TM01/det
560
// IM10 = -TM10/det, IM11 = TM00/det
561
// IM02 = (TM01 * TM12 - TM11 * TM02) / det,
562
// IM12 = (TM10 * TM02 - TM00 * TM12) / det,
563
564
#define DECLARE_MATRIX(MAT) \
565
jfloat MAT ## 00, MAT ## 01, MAT ## 02, MAT ## 10, MAT ## 11, MAT ## 12
566
567
#define GET_INVERTED_MATRIX(MAT, X11, Y11, DX1, DY1, DX2, DY2, RET_CODE) \
568
do { \
569
jfloat det = DX1*DY2 - DX2*DY1; \
570
if (det == 0) { \
571
RET_CODE; \
572
} \
573
MAT ## 00 = DY2/det; \
574
MAT ## 01 = -DX2/det; \
575
MAT ## 10 = -DY1/det; \
576
MAT ## 11 = DX1/det; \
577
MAT ## 02 = (DX2 * Y11 - DY2 * X11) / det; \
578
MAT ## 12 = (DY1 * X11 - DX1 * Y11) / det; \
579
} while (0)
580
581
#define TRANSFORM(MAT, TX, TY, X, Y) \
582
do { \
583
TX = (X) * MAT ## 00 + (Y) * MAT ## 01 + MAT ## 02; \
584
TY = (X) * MAT ## 10 + (Y) * MAT ## 11 + MAT ## 12; \
585
} while (0)
586
587
void
588
OGLRenderer_FillAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,
589
jfloat fx11, jfloat fy11,
590
jfloat dx21, jfloat dy21,
591
jfloat dx12, jfloat dy12)
592
{
593
DECLARE_MATRIX(om);
594
// parameters for parallelogram bounding box
595
jfloat bx11, by11, bx22, by22;
596
// parameters for uv texture coordinates of parallelogram corners
597
jfloat u11, v11, u12, v12, u21, v21, u22, v22;
598
599
J2dTraceLn6(J2D_TRACE_INFO,
600
"OGLRenderer_FillAAParallelogram "
601
"(x=%6.2f y=%6.2f "
602
"dx1=%6.2f dy1=%6.2f "
603
"dx2=%6.2f dy2=%6.2f)",
604
fx11, fy11,
605
dx21, dy21,
606
dx12, dy12);
607
608
RETURN_IF_NULL(oglc);
609
RETURN_IF_NULL(dstOps);
610
611
GET_INVERTED_MATRIX(om, fx11, fy11, dx21, dy21, dx12, dy12,
612
return);
613
614
CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);
615
616
bx11 = bx22 = fx11;
617
by11 = by22 = fy11;
618
ADJUST_PGRAM(bx11, dx21, bx22);
619
ADJUST_PGRAM(by11, dy21, by22);
620
ADJUST_PGRAM(bx11, dx12, bx22);
621
ADJUST_PGRAM(by11, dy12, by22);
622
bx11 = (jfloat) floor(bx11);
623
by11 = (jfloat) floor(by11);
624
bx22 = (jfloat) ceil(bx22);
625
by22 = (jfloat) ceil(by22);
626
627
TRANSFORM(om, u11, v11, bx11, by11);
628
TRANSFORM(om, u21, v21, bx22, by11);
629
TRANSFORM(om, u12, v12, bx11, by22);
630
TRANSFORM(om, u22, v22, bx22, by22);
631
632
j2d_glBegin(GL_QUADS);
633
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u11, v11);
634
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 5.f);
635
j2d_glVertex2f(bx11, by11);
636
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u21, v21);
637
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 5.f);
638
j2d_glVertex2f(bx22, by11);
639
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u22, v22);
640
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 6.f, 6.f);
641
j2d_glVertex2f(bx22, by22);
642
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u12, v12);
643
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 5.f, 6.f);
644
j2d_glVertex2f(bx11, by22);
645
j2d_glEnd();
646
}
647
648
void
649
OGLRenderer_FillAAParallelogramInnerOuter(OGLContext *oglc, OGLSDOps *dstOps,
650
jfloat ox11, jfloat oy11,
651
jfloat ox21, jfloat oy21,
652
jfloat ox12, jfloat oy12,
653
jfloat ix11, jfloat iy11,
654
jfloat ix21, jfloat iy21,
655
jfloat ix12, jfloat iy12)
656
{
657
DECLARE_MATRIX(om);
658
DECLARE_MATRIX(im);
659
// parameters for parallelogram bounding box
660
jfloat bx11, by11, bx22, by22;
661
// parameters for uv texture coordinates of outer parallelogram corners
662
jfloat ou11, ov11, ou12, ov12, ou21, ov21, ou22, ov22;
663
// parameters for uv texture coordinates of inner parallelogram corners
664
jfloat iu11, iv11, iu12, iv12, iu21, iv21, iu22, iv22;
665
666
RETURN_IF_NULL(oglc);
667
RETURN_IF_NULL(dstOps);
668
669
GET_INVERTED_MATRIX(im, ix11, iy11, ix21, iy21, ix12, iy12,
670
// inner parallelogram is degenerate
671
// therefore it encloses no area
672
// fill outer
673
OGLRenderer_FillAAParallelogram(oglc, dstOps,
674
ox11, oy11,
675
ox21, oy21,
676
ox12, oy12);
677
return);
678
GET_INVERTED_MATRIX(om, ox11, oy11, ox21, oy21, ox12, oy12,
679
return);
680
681
CHECK_PREVIOUS_OP(OGL_STATE_PGRAM_OP);
682
683
bx11 = bx22 = ox11;
684
by11 = by22 = oy11;
685
ADJUST_PGRAM(bx11, ox21, bx22);
686
ADJUST_PGRAM(by11, oy21, by22);
687
ADJUST_PGRAM(bx11, ox12, bx22);
688
ADJUST_PGRAM(by11, oy12, by22);
689
bx11 = (jfloat) floor(bx11);
690
by11 = (jfloat) floor(by11);
691
bx22 = (jfloat) ceil(bx22);
692
by22 = (jfloat) ceil(by22);
693
694
TRANSFORM(om, ou11, ov11, bx11, by11);
695
TRANSFORM(om, ou21, ov21, bx22, by11);
696
TRANSFORM(om, ou12, ov12, bx11, by22);
697
TRANSFORM(om, ou22, ov22, bx22, by22);
698
699
TRANSFORM(im, iu11, iv11, bx11, by11);
700
TRANSFORM(im, iu21, iv21, bx22, by11);
701
TRANSFORM(im, iu12, iv12, bx11, by22);
702
TRANSFORM(im, iu22, iv22, bx22, by22);
703
704
j2d_glBegin(GL_QUADS);
705
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou11, ov11);
706
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu11, iv11);
707
j2d_glVertex2f(bx11, by11);
708
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou21, ov21);
709
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu21, iv21);
710
j2d_glVertex2f(bx22, by11);
711
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou22, ov22);
712
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu22, iv22);
713
j2d_glVertex2f(bx22, by22);
714
j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, ou12, ov12);
715
j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, iu12, iv12);
716
j2d_glVertex2f(bx11, by22);
717
j2d_glEnd();
718
}
719
720
void
721
OGLRenderer_DrawAAParallelogram(OGLContext *oglc, OGLSDOps *dstOps,
722
jfloat fx11, jfloat fy11,
723
jfloat dx21, jfloat dy21,
724
jfloat dx12, jfloat dy12,
725
jfloat lwr21, jfloat lwr12)
726
{
727
// dx,dy for line width in the "21" and "12" directions.
728
jfloat ldx21, ldy21, ldx12, ldy12;
729
// parameters for "outer" parallelogram
730
jfloat ofx11, ofy11, odx21, ody21, odx12, ody12;
731
// parameters for "inner" parallelogram
732
jfloat ifx11, ify11, idx21, idy21, idx12, idy12;
733
734
J2dTraceLn8(J2D_TRACE_INFO,
735
"OGLRenderer_DrawAAParallelogram "
736
"(x=%6.2f y=%6.2f "
737
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
738
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
739
fx11, fy11,
740
dx21, dy21, lwr21,
741
dx12, dy12, lwr12);
742
743
RETURN_IF_NULL(oglc);
744
RETURN_IF_NULL(dstOps);
745
746
// calculate true dx,dy for line widths from the "line width ratios"
747
ldx21 = dx21 * lwr21;
748
ldy21 = dy21 * lwr21;
749
ldx12 = dx12 * lwr12;
750
ldy12 = dy12 * lwr12;
751
752
// calculate coordinates of the outer parallelogram
753
ofx11 = fx11 - (ldx21 + ldx12) / 2.0f;
754
ofy11 = fy11 - (ldy21 + ldy12) / 2.0f;
755
odx21 = dx21 + ldx21;
756
ody21 = dy21 + ldy21;
757
odx12 = dx12 + ldx12;
758
ody12 = dy12 + ldy12;
759
760
// Only process the inner parallelogram if the line width ratio
761
// did not consume the entire interior of the parallelogram
762
// (i.e. if the width ratio was less than 1.0)
763
if (lwr21 < 1.0f && lwr12 < 1.0f) {
764
// calculate coordinates of the inner parallelogram
765
ifx11 = fx11 + (ldx21 + ldx12) / 2.0f;
766
ify11 = fy11 + (ldy21 + ldy12) / 2.0f;
767
idx21 = dx21 - ldx21;
768
idy21 = dy21 - ldy21;
769
idx12 = dx12 - ldx12;
770
idy12 = dy12 - ldy12;
771
772
OGLRenderer_FillAAParallelogramInnerOuter(oglc, dstOps,
773
ofx11, ofy11,
774
odx21, ody21,
775
odx12, ody12,
776
ifx11, ify11,
777
idx21, idy21,
778
idx12, idy12);
779
} else {
780
OGLRenderer_FillAAParallelogram(oglc, dstOps,
781
ofx11, ofy11,
782
odx21, ody21,
783
odx12, ody12);
784
}
785
}
786
787
void
788
OGLRenderer_EnableAAParallelogramProgram()
789
{
790
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_EnableAAParallelogramProgram");
791
792
if (aaPgramProgram == 0) {
793
aaPgramProgram = OGLContext_CreateFragmentProgram(aaPgramShaderSource);
794
if (aaPgramProgram == 0) {
795
J2dRlsTraceLn(J2D_TRACE_ERROR,
796
"OGLRenderer_EnableAAParallelogramProgram: "
797
"error creating program");
798
return;
799
}
800
}
801
j2d_glUseProgramObjectARB(aaPgramProgram);
802
}
803
804
void
805
OGLRenderer_DisableAAParallelogramProgram()
806
{
807
J2dTraceLn(J2D_TRACE_INFO, "OGLRenderer_DisableAAParallelogramProgram");
808
809
j2d_glUseProgramObjectARB(0);
810
}
811
812
#endif /* !HEADLESS */
813
814