/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef HEADLESS
#include <jlong.h>
#include <jni_util.h>
#include <math.h>
#include "sun_java2d_opengl_OGLRenderer.h"
#include "OGLRenderer.h"
#include "OGLRenderQueue.h"
#include "OGLSurfaceData.h"
/**
* Note: Some of the methods in this file apply a "magic number"
* translation to line segments. The OpenGL specification lays out the
* "diamond exit rule" for line rasterization, but it is loose enough to
* allow for a wide range of line rendering hardware. (It appears that
* some hardware, such as the Nvidia GeForce2 series, does not even meet
* the spec in all cases.) As such it is difficult to find a mapping
* between the Java2D and OpenGL line specs that works consistently across
* all hardware combinations.
*
* Therefore the "magic numbers" you see here have been empirically derived
* after testing on a variety of graphics hardware in order to find some
* reasonable middle ground between the two specifications. The general
* approach is to apply a fractional translation to vertices so that they
* hit pixel centers and therefore touch the same pixels as in our other
* pipelines. Emphasis was placed on finding values so that OGL lines with
* a slope of +/- 1 hit all the same pixels as our other (software) loops.
* The stepping in other diagonal lines rendered with OGL may deviate
* slightly from those rendered with our software loops, but the most
* important thing is that these magic numbers ensure that all OGL lines
* hit the same endpoints as our software loops.
*
* If you find it necessary to change any of these magic numbers in the
* future, just be sure that you test the changes across a variety of
* hardware to ensure consistent rendering everywhere.
*/
void
{
// horizontal
}
// vertical
}
} else {
// diagonal
fx1 += 0.2f;
fx2 += 1.0f;
} else {
fx1 += 0.8f;
fx2 -= 0.2f;
}
fy1 += 0.2f;
fy2 += 1.0f;
} else {
fy1 += 0.8f;
fy2 -= 0.2f;
}
}
}
void
{
if (w < 0 || h < 0) {
return;
}
if (w < 2 || h < 2) {
// If one dimension is less than 2 then there is no
// gap in the middle - draw a solid filled rectangle.
} else {
// Avoid drawing the endpoints twice.
// Also prefer including the endpoints in the
// horizontal sections which draw pixels faster.
// top
// right
// bottom
// left
}
}
void
{
jint i;
"OGLRenderer_DrawPoly: points array is null");
return;
}
// Note that BufferedRenderPipe.drawPoly() has already rejected polys
// with nPoints<2, so we can be certain here that we have nPoints>=2.
for (i = 0; i < nPoints; i++) {
// Translate each vertex by a fraction so that we hit pixel centers.
}
{
// In this case, the polyline's start and end positions are
// different and need to be closed manually; we do this by adding
// one more segment back to the starting position. Note that we
// do not need to fill in the last pixel (as we do in the following
// block) because we are returning to the starting pixel, which
// has already been filled in.
RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
// OpenGL omits the last pixel in a polyline, so we fix this by
// adding a one-pixel segment at the end. Also, if the polyline
// never went anywhere (isEmpty is true), we need to use this
// workaround to ensure that a single pixel is touched.
// no need for RESET_PREVIOUS_OP, as the line strip is no longer open
} else {
RESET_PREVIOUS_OP(); // so that we don't leave the line strip open
}
}
{
// 6358147: reset current state, and ensure rendering is
// flushed to dest
j2d_glFlush();
}
}
}
}
void
{
while (scanlineCount > 0) {
// Translate each vertex by a fraction so
// that we hit pixel centers.
j2d_glVertex2f(x1, y);
j2d_glVertex2f(x2, y);
}
}
void
{
if (w <= 0 || h <= 0) {
return;
}
GLRECT_BODY_XYWH(x, y, w, h);
}
void
{
while (spanCount > 0) {
spanCount--;
}
}
do { \
} while (0)
void
{
"OGLRenderer_FillParallelogram "
"(x=%6.2f y=%6.2f "
"dx1=%6.2f dy1=%6.2f "
"dx2=%6.2f dy2=%6.2f)",
}
void
{
// dx,dy for line width in the "21" and "12" directions.
// calculate origin of the outer parallelogram
"OGLRenderer_DrawParallelogram "
"(x=%6.2f y=%6.2f "
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
// Only need to generate 4 quads if the interior still
// has a hole in it (i.e. if the line width ratio was
// less than 1.0)
// Note: "TOP", "BOTTOM", "LEFT" and "RIGHT" here are
// relative to whether the dxNN variables are positive
// and negative. The math works fine regardless of
// their signs, but for conceptual simplicity the
// comments will refer to the sides as if the dxNN
// were all positive. "TOP" and "BOTTOM" segments
// are defined by the dxy21 deltas. "LEFT" and "RIGHT"
// segments are defined by the dxy12 deltas.
// Each segment includes its starting corner and comes
// to just short of the following corner. Thus, each
// corner is included just once and the only lengths
// needed are the original parallelogram delta lengths
// and the "line width deltas". The sides will cover
// the following relative territories:
//
// T T T T T R
// L R
// L R
// L R
// L R
// L B B B B B
// TOP segment, to left side of RIGHT edge
// "width" of original pgram, "height" of hor. line size
// RIGHT segment, to top of BOTTOM edge
// "width" of vert. line size , "height" of original pgram
// BOTTOM segment, from right side of LEFT edge
// "width" of original pgram, "height" of hor. line size
// LEFT segment, from bottom of TOP edge
// "width" of vert. line size , "height" of inner pgram
} else {
// The line width ratios were large enough to consume
// the entire hole in the middle of the parallelogram
// so we can just issue one large quad for the outer
// parallelogram.
}
}
/*
* This shader fills the space between an outer and inner parallelogram.
* It can be used to draw an outline by specifying both inner and outer
* values. It fills pixels by estimating what portion falls inside the
* outer shape, and subtracting an estimate of what portion falls inside
* the inner shape. Specifying both inner and outer values produces a
* standard "wide outline". Specifying an inner shape that falls far
* outside the outer shape allows the same shader to fill the outer
* shape entirely since pixels that fall within the outer shape are never
* inside the inner shape and so they are filled based solely on their
* coverage of the outer shape.
*
* The setup code renders this shader over the bounds of the outer
* shape (or the only shape in the case of a fill operation) and
* sets the texture 0 coordinates so that 0,0=>0,1=>1,1=>1,0 in those
* texture coordinates map to the four corners of the parallelogram.
* Similarly the texture 1 coordinates map the inner shape to the
* unit square as well, but in a different coordinate system.
*
* When viewed in the texture coordinate systems the parallelograms
* we are filling are unit squares, but the pixels have then become
* tiny parallelograms themselves. Both of the texture coordinate
* systems are affine transforms so the rate of change in X and Y
* of the texture coordinates are essentially constants and happen
* to correspond to the size and direction of the slanted sides of
* the distorted pixels relative to the "square mapped" boundary
* of the parallelograms.
*
* The shader uses the dFdx() and dFdy() functions to measure the "rate
* of change" of these texture coordinates and thus gets an accurate
* measure of the size and shape of a pixel relative to the two
* parallelograms. It then uses the bounds of the size and shape
* of a pixel to intersect with the unit square to estimate the
* coverage of the pixel. Unfortunately, without a lot more work
* to calculate the exact area of intersection between a unit
* square (the original parallelogram) and a parallelogram (the
* distorted pixel), this shader only approximates the pixel
* coverage, but emperically the estimate is very useful and
* produces visually pleasing results, if not theoretically accurate.
*/
static const char *aaPgramShaderSource =
"void main() {"
// Calculate the vectors for the "legs" of the pixel parallelogram
// for the outer parallelogram.
" vec2 oleg1 = dFdx(gl_TexCoord[0].st);"
" vec2 oleg2 = dFdy(gl_TexCoord[0].st);"
// Calculate the bounds of the distorted pixel parallelogram.
" vec2 corner = gl_TexCoord[0].st - (oleg1+oleg2)/2.0;"
" vec2 omin = min(corner, corner+oleg1);"
" omin = min(omin, corner+oleg2);"
" omin = min(omin, corner+oleg1+oleg2);"
" vec2 omax = max(corner, corner+oleg1);"
" omax = max(omax, corner+oleg2);"
" omax = max(omax, corner+oleg1+oleg2);"
// Calculate the vectors for the "legs" of the pixel parallelogram
// for the inner parallelogram.
" vec2 ileg1 = dFdx(gl_TexCoord[1].st);"
" vec2 ileg2 = dFdy(gl_TexCoord[1].st);"
// Calculate the bounds of the distorted pixel parallelogram.
" corner = gl_TexCoord[1].st - (ileg1+ileg2)/2.0;"
" vec2 imin = min(corner, corner+ileg1);"
" imin = min(imin, corner+ileg2);"
" imin = min(imin, corner+ileg1+ileg2);"
" vec2 imax = max(corner, corner+ileg1);"
" imax = max(imax, corner+ileg2);"
" imax = max(imax, corner+ileg1+ileg2);"
// Clamp the bounds of the parallelograms to the unit square to
// estimate the intersection of the pixel parallelogram with
// the unit square. The ratio of the 2 rectangle areas is a
// reasonable estimate of the proportion of coverage.
" vec2 o1 = clamp(omin, 0.0, 1.0);"
" vec2 o2 = clamp(omax, 0.0, 1.0);"
" float oint = (o2.y-o1.y)*(o2.x-o1.x);"
" float oarea = (omax.y-omin.y)*(omax.x-omin.x);"
" vec2 i1 = clamp(imin, 0.0, 1.0);"
" vec2 i2 = clamp(imax, 0.0, 1.0);"
" float iint = (i2.y-i1.y)*(i2.x-i1.x);"
" float iarea = (imax.y-imin.y)*(imax.x-imin.x);"
// Proportion of pixel in outer shape minus the proportion
// of pixel in the inner shape == the coverage of the pixel
// in the area between the two.
" gl_FragColor = gl_Color * coverage;"
"}";
do { \
if ((DV) >= 0) { \
} else { \
} \
} while (0)
// Invert the following transform:
// DeltaT(0, 0) == (0, 0)
// DeltaT(1, 0) == (DX1, DY1)
// DeltaT(0, 1) == (DX2, DY2)
// DeltaT(1, 1) == (DX1+DX2, DY1+DY2)
// TM00 = DX1, TM01 = DX2, (TM02 = X11)
// TM10 = DY1, TM11 = DY2, (TM12 = Y11)
// Determinant = TM00*TM11 - TM01*TM10
// = DX1*DY2 - DX2*DY1
// Inverse is:
// IM02 = (TM01 * TM12 - TM11 * TM02) / det,
// IM12 = (TM10 * TM02 - TM00 * TM12) / det,
do { \
if (det == 0) { \
RET_CODE; \
} \
} while (0)
do { \
} while (0)
void
{
// parameters for parallelogram bounding box
// parameters for uv texture coordinates of parallelogram corners
"OGLRenderer_FillAAParallelogram "
"(x=%6.2f y=%6.2f "
"dx1=%6.2f dy1=%6.2f "
"dx2=%6.2f dy2=%6.2f)",
return);
j2d_glEnd();
}
void
{
// parameters for parallelogram bounding box
// parameters for uv texture coordinates of outer parallelogram corners
// parameters for uv texture coordinates of inner parallelogram corners
// inner parallelogram is degenerate
// therefore it encloses no area
// fill outer
return);
return);
j2d_glEnd();
}
void
{
// dx,dy for line width in the "21" and "12" directions.
// parameters for "outer" parallelogram
// parameters for "inner" parallelogram
"OGLRenderer_DrawAAParallelogram "
"(x=%6.2f y=%6.2f "
"dx1=%6.2f dy1=%6.2f lwr1=%6.2f "
"dx2=%6.2f dy2=%6.2f lwr2=%6.2f)",
// calculate true dx,dy for line widths from the "line width ratios"
// calculate coordinates of the outer parallelogram
// Only process the inner parallelogram if the line width ratio
// did not consume the entire interior of the parallelogram
// (i.e. if the width ratio was less than 1.0)
// calculate coordinates of the inner parallelogram
} else {
}
}
void
{
if (aaPgramProgram == 0) {
if (aaPgramProgram == 0) {
"OGLRenderer_EnableAAParallelogramProgram: "
"error creating program");
return;
}
}
}
void
{
}
#endif /* !HEADLESS */