1
0
mirror of https://github.com/arduino/Arduino.git synced 2024-11-30 11:24:12 +01:00
Arduino/core/PTriangle.java

3828 lines
119 KiB
Java
Raw Normal View History

/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
/**
* Handles rendering of single (tesselated) triangles in 3D.
* <P>
* Written by sami www.sumea.com
*/
public class PTriangle implements PConstants
{
static final int R_GOURAUD = 0x1;
static final int R_TEXTURE8 = 0x2;
static final int R_TEXTURE24 = 0x4;
static final int R_TEXTURE32 = 0x8;
static final int R_ALPHA = 0x10;
private int[] m_pixels;
private int[] m_texture;
private int[] m_stencil;
private float[] m_zbuffer;
private int SCREEN_WIDTH;
private int SCREEN_HEIGHT;
//private int SCREEN_WIDTH1;
//private int SCREEN_HEIGHT1;
private int TEX_WIDTH;
private int TEX_HEIGHT;
private float F_TEX_WIDTH;
private float F_TEX_HEIGHT;
public boolean INTERPOLATE_UV;
public boolean INTERPOLATE_RGB;
public boolean INTERPOLATE_ALPHA;
// the power of 2 that tells how many pixels to interpolate
// for between exactly computed texture coordinates
private static final int DEFAULT_INTERP_POWER = 3;
private static int TEX_INTERP_POWER = DEFAULT_INTERP_POWER;
// Vertex coordinates
private float[] x_array;
private float[] y_array;
private float[] z_array;
private float[] camX;
private float[] camY;
private float[] camZ;
// U,V coordinates
private float[] u_array;
private float[] v_array;
// Vertex Intensity
private float[] r_array;
private float[] g_array;
private float[] b_array;
private float[] a_array;
// vertex offsets
private int o0;
private int o1;
private int o2;
/* rgb & a */
private float r0;
private float r1;
private float r2;
private float g0;
private float g1;
private float g2;
private float b0;
private float b1;
private float b2;
private float a0;
private float a1;
private float a2;
/* accurate texture uv coordinates */
private float u0;
private float u1;
private float u2;
private float v0;
private float v1;
private float v2;
/* deltas */
//private float dx0;
//private float dx1;
private float dx2;
private float dy0;
private float dy1;
private float dy2;
private float dz0;
//private float dz1;
private float dz2;
/* texture deltas */
private float du0;
//private float du1;
private float du2;
private float dv0;
//private float dv1;
private float dv2;
/* rgba deltas */
private float dr0;
//private float dr1;
private float dr2;
private float dg0;
//private float dg1;
private float dg2;
private float db0;
//private float db1;
private float db2;
private float da0;
//private float da1;
private float da2;
/* */
private float uleft;
private float vleft;
private float uleftadd;
private float vleftadd;
/* polyedge positions & adds */
private float xleft;
private float xrght;
private float xadd1;
private float xadd2;
private float zleft;
private float zleftadd;
/* rgba positions & adds */
private float rleft;
private float gleft;
private float bleft;
private float aleft;
private float rleftadd;
private float gleftadd;
private float bleftadd;
private float aleftadd;
/* other somewhat useful variables :) */
private float dta;
//private float dta2;
private float temp;
private float width;
/* integer poly UV adds */
private int iuadd;
private int ivadd;
private int iradd;
private int igadd;
private int ibadd;
private int iaadd;
private float izadd;
/* fill color */
private int m_fill;
/* draw flags */
public int m_drawFlags;
/* current poly number */
private int m_index;
/** */
private PGraphics3D parent;
private boolean noDepthTest;
/** */
private boolean m_culling;
/** */
private boolean m_singleRight;
/** */
private boolean m_bilinear;
//Vectors needed in accurate texture code
//We store them as class members to avoid too much code duplication
private float ax,ay,az;
private float bx,by,bz;
private float cx,cy,cz;
private float nearPlaneWidth;
private float nearPlaneHeight;
private float nearPlaneDepth;
private float xmult;
private float ymult;
private float newax,newbx,newcx; //optimization vars...not pretty, but save a couple mults per pixel
private boolean firstSegment; //are we currently drawing the first piece of the triangle, or have we already done so?
public PTriangle(PGraphics3D g) {
//SCREEN_WIDTH = g.width;
//SCREEN_HEIGHT = g.height;
//SCREEN_WIDTH1 = SCREEN_WIDTH-1;
//SCREEN_HEIGHT1 = SCREEN_HEIGHT-1;
//m_pixels = g.pixels;
//m_stencil = g.stencil;
//m_zbuffer = g.zbuffer;
x_array = new float[3];
y_array = new float[3];
z_array = new float[3];
u_array = new float[3];
v_array = new float[3];
r_array = new float[3];
g_array = new float[3];
b_array = new float[3];
a_array = new float[3];
camX = new float[3];
camY = new float[3];
camZ = new float[3];
this.parent = g;
reset();
}
/**
* Resets polygon attributes
*/
public void reset() {
// reset these in case PGraphics was resized
SCREEN_WIDTH = parent.width;
SCREEN_HEIGHT = parent.height;
//SCREEN_WIDTH1 = SCREEN_WIDTH-1;
//SCREEN_HEIGHT1 = SCREEN_HEIGHT-1;
m_pixels = parent.pixels;
m_stencil = parent.stencil;
m_zbuffer = parent.zbuffer;
noDepthTest = parent.hints[DISABLE_DEPTH_TEST];
// other things to reset
INTERPOLATE_UV = false;
INTERPOLATE_RGB = false;
INTERPOLATE_ALPHA = false;
//m_tImage = null;
m_texture = null;
m_drawFlags = 0;
}
/**
* Sets backface culling on/off
*/
public void setCulling(boolean tf) {
m_culling = tf;
}
/**
* Sets vertex coordinates for the triangle
*/
public void setVertices(float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2) {
x_array[0] = x0;
x_array[1] = x1;
x_array[2] = x2;
y_array[0] = y0;
y_array[1] = y1;
y_array[2] = y2;
z_array[0] = z0;
z_array[1] = z1;
z_array[2] = z2;
}
/**
* Pass camera-space coordinates for the triangle (needed to render if ENABLE_ACCURATE_TEXTURES is hinted).
*/
public void setCamVertices(float x0, float y0, float z0,
float x1, float y1, float z1,
float x2, float y2, float z2) {
//Generally this will not need to be called manually, currently called if hints[ENABLE_ACCURATE_TEXTURES]
//from PGraphics3D.render_triangles()
camX[0] = x0;
camX[1] = x1;
camX[2] = x2;
camY[0] = y0;
camY[1] = y1;
camY[2] = y2;
camZ[0] = z0;
camZ[1] = z1;
camZ[2] = z2;
}
/**
* Sets the UV coordinates of the texture
*/
public void setUV(float u0, float v0,
float u1, float v1,
float u2, float v2) {
// sets & scales uv texture coordinates to center of the pixel
u_array[0] = (u0 * F_TEX_WIDTH + 0.5f) * 65536f;
u_array[1] = (u1 * F_TEX_WIDTH + 0.5f) * 65536f;
u_array[2] = (u2 * F_TEX_WIDTH + 0.5f) * 65536f;
v_array[0] = (v0 * F_TEX_HEIGHT + 0.5f) * 65536f;
v_array[1] = (v1 * F_TEX_HEIGHT + 0.5f) * 65536f;
v_array[2] = (v2 * F_TEX_HEIGHT + 0.5f) * 65536f;
}
/**
* Sets vertex intensities in 0xRRGGBBAA format
*/
public void setIntensities( float r0, float g0, float b0, float a0,
float r1, float g1, float b1, float a1,
float r2, float g2, float b2, float a2) {
// Check if we need alpha or not?
if ((a0 != 1.0f) || (a1 != 1.0f) || (a2 != 1.0f)) {
INTERPOLATE_ALPHA = true;
a_array[0] = (a0 * 253f + 1.0f) * 65536f;
a_array[1] = (a1 * 253f + 1.0f) * 65536f;
a_array[2] = (a2 * 253f + 1.0f) * 65536f;
m_drawFlags|=R_ALPHA;
} else {
INTERPOLATE_ALPHA = false;
m_drawFlags&=~R_ALPHA;
}
// Check if we need to interpolate the intensity values
if ((r0 != r1) || (r1 != r2)) {
INTERPOLATE_RGB = true;
m_drawFlags|=R_GOURAUD;
} else if ((g0 != g1) || (g1 != g2)) {
INTERPOLATE_RGB = true;
m_drawFlags|=R_GOURAUD;
} else if ((b0 != b1) || (b1 != b2)) {
INTERPOLATE_RGB = true;
m_drawFlags|=R_GOURAUD;
} else {
//m_fill = parent.filli;
m_drawFlags&=~R_GOURAUD;
}
// push values to arrays.. some extra scaling is added
// to prevent possible color "overflood" due to rounding errors
r_array[0] = (r0 * 253f + 1.0f) * 65536f;
r_array[1] = (r1 * 253f + 1.0f) * 65536f;
r_array[2] = (r2 * 253f + 1.0f) * 65536f;
g_array[0] = (g0 * 253f + 1.0f) * 65536f;
g_array[1] = (g1 * 253f + 1.0f) * 65536f;
g_array[2] = (g2 * 253f + 1.0f) * 65536f;
b_array[0] = (b0 * 253f + 1.0f) * 65536f;
b_array[1] = (b1 * 253f + 1.0f) * 65536f;
b_array[2] = (b2 * 253f + 1.0f) * 65536f;
// for plain triangles
m_fill = ((int)(255*r0) << 16) | ((int)(255*g0) << 8) | (int)(255*b0);
}
/**
* Sets texture image used for the polygon
*/
public void setTexture(PImage image) {
//m_tImage = image;
m_texture = image.pixels;
TEX_WIDTH = image.width;
TEX_HEIGHT = image.height;
F_TEX_WIDTH = TEX_WIDTH-1;
F_TEX_HEIGHT = TEX_HEIGHT-1;
INTERPOLATE_UV = true;
if (image.format == ARGB) {
m_drawFlags|=R_TEXTURE32;
} else if (image.format == RGB) {
m_drawFlags|=R_TEXTURE24;
} else if (image.format == ALPHA) {
m_drawFlags|=R_TEXTURE8;
}
//if (parent.hints[SMOOTH_IMAGES]) {
/*
if (parent.smooth) {
m_bilinear = true;
} else {
m_bilinear = false;
}
*/
m_bilinear = true;
}
/**
*
*/
public void setUV(float[] u, float[] v) {
if (m_bilinear) {
// sets & scales uv texture coordinates to edges of pixels
u_array[0] = (u[0] * F_TEX_WIDTH) * 65500f;
u_array[1] = (u[1] * F_TEX_WIDTH) * 65500f;
u_array[2] = (u[2] * F_TEX_WIDTH) * 65500f;
v_array[0] = (v[0] * F_TEX_HEIGHT) * 65500f;
v_array[1] = (v[1] * F_TEX_HEIGHT) * 65500f;
v_array[2] = (v[2] * F_TEX_HEIGHT) * 65500f;
} else {
// sets & scales uv texture coordinates to center of the pixel
u_array[0] = (u[0] * TEX_WIDTH) * 65500f;
u_array[1] = (u[1] * TEX_WIDTH) * 65500f;
u_array[2] = (u[2] * TEX_WIDTH) * 65500f;
v_array[0] = (v[0] * TEX_HEIGHT) * 65500f;
v_array[1] = (v[1] * TEX_HEIGHT) * 65500f;
v_array[2] = (v[2] * TEX_HEIGHT) * 65500f;
}
}
public void setIndex(int index) {
m_index = index;
}
/**
* Renders the polygon
*/
public void render() {
// removed. done in PGraphics [rocha]
// increase polygon offset
//m_index = (m_index + 1) & 0xFFFFFFF;
// draw the polygon
draw();
// removed. replaced by external antialiasing [rocha]
// smooth edges?
//if (parent.smooth )
//{
// drawline_blender(x_array[0], y_array[0], x_array[1], y_array[1]);
// drawline_blender(x_array[1], y_array[1], x_array[2], y_array[2]);
// drawline_blender(x_array[2], y_array[2], x_array[0], y_array[0]);
//}
}
private void draw() {
// y-coordinates
float x0;
float x1;
float x2;
//
float z0;
float z1;
float z2;
//
float y0 = y_array[0];
float y1 = y_array[1];
float y2 = y_array[2];
// For accurate texture interpolation, need to mark whether
// we've already pre-calculated for the triangle
firstSegment = true;
// do backface culling?
if (m_culling) {
x0 = x_array[0];
if ((x_array[2]-x0)*(y1-y0) < (x_array[1]-x0)*(y2-y0))
return;
}
/* get vertex order from top -> down */
if (y0<y1) {
if (y2<y1) {
if (y2<y0) // 2,0,1
{
o0=2;
o1=0;
o2=1;
}
else // 0,2,1
{
o0=0;
o1=2;
o2=1;
}
}
else // 0,1,2
{
o0=0;
o1=1;
o2=2;
}
} else {
if (y2>y1) {
if (y2<y0) // 1,2,0
{
o0=1;
o1=2;
o2=0;
}
else // 1,0,2
{
o0=1;
o1=0;
o2=2;
}
}
else // 2,1,0
{
o0=2;
o1=1;
o2=0;
}
}
/**
* o0 = "top" vertex offset
* o1 = "mid" vertex offset
* o2 = "bot" vertex offset
*/
y0 = y_array[o0];
int yi0 = (int) (y0 + PIXEL_CENTER);
if (yi0 > SCREEN_HEIGHT) {
return;
} else if (yi0 < 0) {
yi0 = 0;
}
y2 = y_array[o2];
int yi2 = (int) (y2 + PIXEL_CENTER);
if (yi2 < 0) {
return;
} else if (yi2 > SCREEN_HEIGHT) {
yi2 = SCREEN_HEIGHT;
}
// Does the poly actually cross a scanline?
if (yi2 > yi0) {
x0 = x_array[o0];
x1 = x_array[o1];
x2 = x_array[o2];
// get mid Y and clip it
y1 = y_array[o1];
int yi1 = (int) (y1 + PIXEL_CENTER);
if (yi1 < 0)
yi1 = 0;
if (yi1 > SCREEN_HEIGHT)
yi1 = SCREEN_HEIGHT;
// calculate deltas etc.
dx2 = x2 - x0;
dy0 = y1 - y0;
dy2 = y2 - y0;
xadd2 = dx2 / dy2; // xadd for "single" edge
temp = dy0 / dy2;
width = temp * dx2 + x0 - x1;
// calculate alpha blend interpolation
if (INTERPOLATE_ALPHA) {
a0 = a_array[o0];
a1 = a_array[o1];
a2 = a_array[o2];
da0 = a1-a0;
da2 = a2-a0;
iaadd = (int) ((temp * da2 - da0) / width); // alpha add
}
// calculate intensity interpolation
if (INTERPOLATE_RGB) {
r0 = r_array[o0];
r1 = r_array[o1];
r2 = r_array[o2];
g0 = g_array[o0];
g1 = g_array[o1];
g2 = g_array[o2];
b0 = b_array[o0];
b1 = b_array[o1];
b2 = b_array[o2];
dr0 = r1-r0;
dg0 = g1-g0;
db0 = b1-b0;
dr2 = r2-r0;
dg2 = g2-g0;
db2 = b2-b0;
iradd = (int) ((temp * dr2 - dr0) / width); // r add
igadd = (int) ((temp * dg2 - dg0) / width); // g add
ibadd = (int) ((temp * db2 - db0) / width); // b add
}
// calculate UV interpolation
if (INTERPOLATE_UV) {
u0 = u_array[o0];
u1 = u_array[o1];
u2 = u_array[o2];
v0 = v_array[o0];
v1 = v_array[o1];
v2 = v_array[o2];
du0 = u1-u0;
dv0 = v1-v0;
du2 = u2-u0;
dv2 = v2-v0;
iuadd = (int) ((temp * du2 - du0) / width); // u add
ivadd = (int) ((temp * dv2 - dv0) / width); // v add
}
z0 = z_array[o0];
z1 = z_array[o1];
z2 = z_array[o2];
dz0 = z1-z0;
dz2 = z2-z0;
izadd = (temp * dz2 - dz0) / width;
// draw the upper poly segment if it's visible
if (yi1 > yi0) {
dta = (yi0 + PIXEL_CENTER) - y0;
xadd1 = (x1 - x0) / dy0;
// we can determine which side is "single" side by comparing left/right edge adds
if (xadd2 > xadd1) {
xleft = x0 + dta * xadd1;
xrght = x0 + dta * xadd2;
zleftadd = dz0 / dy0;
zleft = dta*zleftadd+z0;
//
if (INTERPOLATE_UV) {
uleftadd = du0 / dy0;
vleftadd = dv0 / dy0;
uleft = dta*uleftadd+u0;
vleft = dta*vleftadd+v0;
}
//
if (INTERPOLATE_RGB) {
rleftadd = dr0 / dy0;
gleftadd = dg0 / dy0;
bleftadd = db0 / dy0;
rleft = dta*rleftadd+r0;
gleft = dta*gleftadd+g0;
bleft = dta*bleftadd+b0;
}
//
if (INTERPOLATE_ALPHA) {
aleftadd = da0 / dy0;
aleft = dta*aleftadd+a0;
if (m_drawFlags == R_ALPHA) {
drawsegment_plain_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_ALPHA)) {
drawsegment_gouraud_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE8 + R_ALPHA)) {
drawsegment_texture8_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE24 + R_ALPHA)) {
drawsegment_texture24_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE32 + R_ALPHA)) {
drawsegment_texture32_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8 + R_ALPHA)) {
drawsegment_gouraud_texture8_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24 + R_ALPHA)) {
drawsegment_gouraud_texture24_alpha(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32 + R_ALPHA)) {
drawsegment_gouraud_texture32_alpha(xadd1,xadd2, yi0,yi1);
}
} else {
if (m_drawFlags == 0) {
drawsegment_plain(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == R_GOURAUD) {
drawsegment_gouraud(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE8) {
drawsegment_texture8(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE24) {
drawsegment_texture24(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE32) {
drawsegment_texture32(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8)) {
drawsegment_gouraud_texture8(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24)) {
drawsegment_gouraud_texture24(xadd1,xadd2, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32)) {
drawsegment_gouraud_texture32(xadd1,xadd2, yi0,yi1);
}
}
m_singleRight = true;
} else {
xleft = x0 + dta * xadd2;
xrght = x0 + dta * xadd1;
zleftadd = dz2 / dy2;
zleft = dta*zleftadd+z0;
//
if (INTERPOLATE_UV) {
uleftadd = du2 / dy2;
vleftadd = dv2 / dy2;
uleft = dta*uleftadd+u0;
vleft = dta*vleftadd+v0;
}
//
if (INTERPOLATE_RGB) {
rleftadd = dr2 / dy2;
gleftadd = dg2 / dy2;
bleftadd = db2 / dy2;
rleft = dta*rleftadd+r0;
gleft = dta*gleftadd+g0;
bleft = dta*bleftadd+b0;
}
if (INTERPOLATE_ALPHA) {
aleftadd = da2 / dy2;
aleft = dta*aleftadd+a0;
if (m_drawFlags == R_ALPHA) {
drawsegment_plain_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_ALPHA)) {
drawsegment_gouraud_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE8 + R_ALPHA)) {
drawsegment_texture8_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE24 + R_ALPHA)) {
drawsegment_texture24_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_TEXTURE32 + R_ALPHA)) {
drawsegment_texture32_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8 + R_ALPHA)) {
drawsegment_gouraud_texture8_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24 + R_ALPHA)) {
drawsegment_gouraud_texture24_alpha(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32 + R_ALPHA)) {
drawsegment_gouraud_texture32_alpha(xadd2, xadd1, yi0,yi1);
}
} else {
if (m_drawFlags == 0) {
drawsegment_plain(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == R_GOURAUD) {
drawsegment_gouraud(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE8) {
drawsegment_texture8(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE24) {
drawsegment_texture24(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == R_TEXTURE32) {
drawsegment_texture32(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8)) {
drawsegment_gouraud_texture8(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24)) {
drawsegment_gouraud_texture24(xadd2, xadd1, yi0,yi1);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32)) {
drawsegment_gouraud_texture32(xadd2, xadd1, yi0,yi1);
}
}
m_singleRight = false;
}
// if bottom segment height is zero, return
if (yi2 == yi1)
return;
// calculate xadd 1
dy1 = y2 - y1;
xadd1 = (x2 - x1) / dy1;
} else {
// top seg height was zero, calculate & clip single edge X
dy1 = y2 - y1;
xadd1 = (x2 - x1) / dy1;
// which edge is left?
if (xadd2 < xadd1) {
xrght = ((yi1 + PIXEL_CENTER) - y0) * xadd2 + x0;
m_singleRight = true;
} else {
dta = (yi1 + PIXEL_CENTER) - y0;
xleft = dta * xadd2 + x0;
zleftadd = dz2 / dy2;
zleft = dta * zleftadd + z0;
if (INTERPOLATE_UV) {
uleftadd = du2 / dy2;
vleftadd = dv2 / dy2;
uleft = dta * uleftadd + u0;
vleft = dta * vleftadd + v0;
}
if (INTERPOLATE_RGB) {
rleftadd = dr2 / dy2;
gleftadd = dg2 / dy2;
bleftadd = db2 / dy2;
rleft = dta * rleftadd + r0;
gleft = dta * gleftadd + g0;
bleft = dta * bleftadd + b0;
}
//
if (INTERPOLATE_ALPHA) {
aleftadd = da2 / dy2;
aleft = dta * aleftadd + a0;
}
m_singleRight = false;
}
}
// draw the lower segment
if (m_singleRight) {
dta = (yi1 + PIXEL_CENTER) - y1;
xleft = dta * xadd1 + x1;
zleftadd = (z2 - z1) / dy1;
zleft = dta * zleftadd + z1;
if (INTERPOLATE_UV) {
uleftadd = (u2 - u1) / dy1;
vleftadd = (v2 - v1) / dy1;
uleft = dta * uleftadd + u1;
vleft = dta * vleftadd + v1;
}
if (INTERPOLATE_RGB) {
rleftadd = (r2 - r1) / dy1;
gleftadd = (g2 - g1) / dy1;
bleftadd = (b2 - b1) / dy1;
rleft = dta * rleftadd + r1;
gleft = dta * gleftadd + g1;
bleft = dta * bleftadd + b1;
}
if (INTERPOLATE_ALPHA) {
aleftadd = (a2 - a1) / dy1;
aleft = dta * aleftadd + a1;
if (m_drawFlags == R_ALPHA) {
drawsegment_plain_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_ALPHA)) {
drawsegment_gouraud_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE8 + R_ALPHA)) {
drawsegment_texture8_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE24 + R_ALPHA)) {
drawsegment_texture24_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE32 + R_ALPHA)) {
drawsegment_texture32_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8 + R_ALPHA)) {
drawsegment_gouraud_texture8_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24 + R_ALPHA)) {
drawsegment_gouraud_texture24_alpha(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32 + R_ALPHA)) {
drawsegment_gouraud_texture32_alpha(xadd1, xadd2, yi1,yi2);
}
} else {
if (m_drawFlags == 0) {
drawsegment_plain(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == R_GOURAUD) {
drawsegment_gouraud(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE8) {
drawsegment_texture8(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE24) {
drawsegment_texture24(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE32) {
drawsegment_texture32(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8)) {
drawsegment_gouraud_texture8(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24)) {
drawsegment_gouraud_texture24(xadd1, xadd2, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32)) {
drawsegment_gouraud_texture32(xadd1, xadd2, yi1,yi2);
}
}
} else {
xrght = ((yi1 + PIXEL_CENTER)- y1) * xadd1 + x1;
if (INTERPOLATE_ALPHA) {
if (m_drawFlags == R_ALPHA) {
drawsegment_plain_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_ALPHA)) {
drawsegment_gouraud_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE8 + R_ALPHA)) {
drawsegment_texture8_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE24 + R_ALPHA)) {
drawsegment_texture24_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_TEXTURE32 + R_ALPHA)) {
drawsegment_texture32_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8 + R_ALPHA)) {
drawsegment_gouraud_texture8_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24 + R_ALPHA)) {
drawsegment_gouraud_texture24_alpha(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32 + R_ALPHA)) {
drawsegment_gouraud_texture32_alpha(xadd2, xadd1, yi1,yi2);
}
} else {
if (m_drawFlags == 0) {
drawsegment_plain(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == R_GOURAUD) {
drawsegment_gouraud(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE8) {
drawsegment_texture8(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE24) {
drawsegment_texture24(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == R_TEXTURE32) {
drawsegment_texture32(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE8)) {
drawsegment_gouraud_texture8(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE24)) {
drawsegment_gouraud_texture24(xadd2, xadd1, yi1,yi2);
} else if (m_drawFlags == (R_GOURAUD + R_TEXTURE32)) {
drawsegment_gouraud_texture32(xadd2, xadd1, yi1,yi2);
}
}
}
}
}
/*
Accurate texturing code by ewjordan@gmail.com, April 14, 2007
The getColorFromTexture() function should be inlined and optimized so that most of the heavy lifting
happens outside the per-pixel loop. The unoptimized generic algorithm looks like this (unless noted,
all of these variables are vectors, so the actual code will look messier):
p = camera space vector where u == 0, v == 0;
m = vector from p to location where u == TEX_WIDTH;
n = vector from p to location where v == TEX_HEIGHT;
A = p cross n;
B = m cross p;
C = n cross m;
A *= texture.width;
B *= texture.height;
for (scanlines in triangle){
float a = S * A;
float b = S * B;
float c = S * C;
for (pixels in scanline){
int u = a/c;
int v = b/c;
color = texture[v * texture.width + u];
a += A.x;
b += B.x;
c += C.x;
}
}
We don't use this exact algorithm here, however, because of the extra overhead from the divides.
Instead we compute the exact u and v (labelled iu and iv in the code) at the start of each scanline
and we perform a linear interpolation for every linearInterpLength = 1 << TEX_INTERP_POWER pixels.
This means that we only perform the true calculation once in a while, and the rest of the time
the algorithm functions exactly as in the fast inaccurate case, at least in theory. In practice,
even if we set linearInterpLength very high we still incur some speed penalty due to the preprocessing
that must take place per-scanline. A similar method could be applied per scanline to avoid this, but
it would only be worthwhile in the case that we never compute more than one exact calculation per
scanline. If we want something like this, however, it would be best to create another mode of calculation
called "constant-z" interpolation, which could be used for things like floors and ceilings where the
distance from the camera plane never changes over the course of a scanline. We could also add the
vertical analogue for drawing vertical walls. In any case, these are not critical as the current
algorithm runs fairly well, perhaps ~10% slower than the default perspective-less one.
*/
/**
* Solve for camera space coordinates of critical texture points and set up per-triangle variables for accurate texturing
*/
private boolean precomputeAccurateTexturing(){
//Sets all class variables relevant to accurate texture computation
//Should be called once per triangle - checks firstSegment to see if we've already called
float myFact = 65500.0f; //rescale u/v_array values when inverting matrix and performing other calcs
float myFact2 = 65500.0f;
//Matrix inversion to find affine transform between (u,v,(1)) -> (x,y,z)
//OPTIMIZE: There should be a way to avoid the inversion here, which is
//quite expensive (~150 mults). Also it might crap out due to loss of precision depending
//on the scaling of the u/v_arrays. Nothing clever currently happens if the inversion
//fails, since this means the transformation is degenerate - we just pass false back to
//the caller and let it handle the situation. [There is no good solution to this
//case from within this function, since the way the calculation proceeds presumes a non-
//degenerate transformation matrix between camera space and uv space]
//Obvious optimization: if the vertices are actually at the appropriate texture coordinates
//(e.g. (0,0), (TEX_WIDTH,0), and (0,TEX_HEIGHT)) then we can immediately return the
//right solution without the inversion. This is fairly common, so could speed up
//many cases of drawing. [not implemented]
//Furthermore, we could cache the p,resultT0,result0T vectors in the triangle's
//basis, since we could then do a look-up and generate the resulting coordinates very simply.
//This would include the above optimization as a special case - we could pre-populate the
//cache with special cases like that and dynamically add more. The idea here is
//that most people simply paste textures onto triangles and move the triangles from
//frame to frame, so any per-triangle-per-frame code is likely wasted effort.
//[not implemented]
//Note: o0, o1, and o2 vary depending on view angle to triangle, but p, n, and m should not depend on ordering differences
if(firstSegment){
PMatrix myMatrix = new PMatrix( u_array[o0]/myFact, v_array[o0]/myFact2, 1, 0,
u_array[o1]/myFact, v_array[o1]/myFact2, 1, 0,
u_array[o2]/myFact, v_array[o2]/myFact2, 1, 0,
0, 0, 0, 1);
myMatrix = myMatrix.invert(); //A 3x3 inversion would be more efficient here, given that the fourth r/c are unity
if (myMatrix == null) {return false;} //if the matrix inversion had trouble, let the caller know
float m00, m01, m02, m10, m11, m12, m20, m21, m22;
m00 = myMatrix.m00*camX[o0]+myMatrix.m01*camX[o1]+myMatrix.m02*camX[o2];
m01 = myMatrix.m10*camX[o0]+myMatrix.m11*camX[o1]+myMatrix.m12*camX[o2];
m02 = myMatrix.m20*camX[o0]+myMatrix.m21*camX[o1]+myMatrix.m22*camX[o2];
m10 = myMatrix.m00*camY[o0]+myMatrix.m01*camY[o1]+myMatrix.m02*camY[o2];
m11 = myMatrix.m10*camY[o0]+myMatrix.m11*camY[o1]+myMatrix.m12*camY[o2];
m12 = myMatrix.m20*camY[o0]+myMatrix.m21*camY[o1]+myMatrix.m22*camY[o2];
m20 = -(myMatrix.m00*camZ[o0]+myMatrix.m01*camZ[o1]+myMatrix.m02*camZ[o2]);
m21 = -(myMatrix.m10*camZ[o0]+myMatrix.m11*camZ[o1]+myMatrix.m12*camZ[o2]);
m22 = -(myMatrix.m20*camZ[o0]+myMatrix.m21*camZ[o1]+myMatrix.m22*camZ[o2]);
float px = m02;
float py = m12;
float pz = m22;
float resultT0x = m00*TEX_WIDTH+m02; //Bugfix: possibly we should use F_TEX_WIDTH/HEIGHT instead? Seems to read off end of array in that case, though...
float resultT0y = m10*TEX_WIDTH+m12;
float resultT0z = m20*TEX_WIDTH+m22;
float result0Tx = m01*TEX_HEIGHT+m02;
float result0Ty = m11*TEX_HEIGHT+m12;
float result0Tz = m21*TEX_HEIGHT+m22;
float mx = resultT0x-m02;
float my = resultT0y-m12;
float mz = resultT0z-m22;
float nx = result0Tx-m02;
float ny = result0Ty-m12;
float nz = result0Tz-m22;
//avec = p x n
ax = (py*nz-pz*ny)*TEX_WIDTH; //F_TEX_WIDTH/HEIGHT?
ay = (pz*nx-px*nz)*TEX_WIDTH;
az = (px*ny-py*nx)*TEX_WIDTH;
//bvec = m x p
bx = (my*pz-mz*py)*TEX_HEIGHT;
by = (mz*px-mx*pz)*TEX_HEIGHT;
bz = (mx*py-my*px)*TEX_HEIGHT;
//cvec = n x m
cx = ny*mz-nz*my;
cy = nz*mx-nx*mz;
cz = nx*my-ny*mx;
}
nearPlaneWidth = parent.rightScreen-parent.leftScreen;
nearPlaneHeight = parent.topScreen-parent.bottomScreen;
nearPlaneDepth = parent.nearPlane;
xmult = nearPlaneWidth / SCREEN_WIDTH; //one pixel width in nearPlane coordinates
ymult = nearPlaneHeight / SCREEN_HEIGHT;
newax = ax*xmult;//Extra scalings to map screen plane units to pixel units
newbx = bx*xmult;
newcx = cx*xmult;
return true;
}
/**
* Set the power of two used for linear interpolation of texture coordinates.
* A true texture coordinate is computed every 2^pwr pixels along a scanline.
*/
static public void setInterpPower(int pwr){
//Currently must be invoked from P5 as PTriangle.setInterpPower(...)
TEX_INTERP_POWER = pwr;
}
/**
* Plain color
*/
private void drawsegment_plain
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int f = m_fill;
int p = m_index;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
for ( ; xstart < xend; xstart++ ) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
m_zbuffer[xstart] = iz;
m_pixels[xstart] = f;
m_stencil[xstart] = p;
}
iz+=izadd;
}
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
zleft+=zleftadd;
}
}
/**
* Plain color, interpolated alpha
*/
private void drawsegment_plain_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int pr = m_fill & 0xFF0000;
int pg = m_fill & 0xFF00;
int pb = m_fill & 0xFF;
int p = m_index;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
float iz = izadd * xdiff + zleft;
int ia = (int) (iaf * xdiff + aleft);
xstart+=ytop;
xend+=ytop;
for ( ; xstart < xend; xstart++ ) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int alpha = ia >> 16;
int mr0 = m_pixels[xstart];
int mg0 = mr0 & 0xFF00;
int mb0 = mr0 & 0xFF;
mr0 &= 0xFF0000;
mr0 = mr0 + (((pr - mr0) * alpha) >> 8);
mg0 = mg0 + (((pg - mg0) * alpha) >> 8);
mb0 = mb0 + (((pb - mb0) * alpha) >> 8);
m_pixels[xstart] = (mr0 & 0xFF0000) | (mg0 & 0xFF00) | (mb0 & 0xFF);
m_stencil[xstart] = p;
}
iz += izadd;
ia += iaadd;
}
ytop += SCREEN_WIDTH;
xleft += leftadd;
xrght += rghtadd;
zleft += zleftadd;
}
}
/**
* RGB gouraud
*/
private void drawsegment_gouraud
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
for ( ; xstart < xend; xstart++ ) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
m_zbuffer[xstart] = iz;
m_pixels[xstart]=((ir & 0xFF0000) | ((ig >> 8) & 0xFF00) | (ib >> 16));
m_stencil[xstart] = p;
}
//
ir+=iradd;
ig+=igadd;
ib+=ibadd;
iz+=izadd;
}
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
zleft+=zleftadd;
}
}
/**
* RGB gouraud + interpolated alpha
*/
private void drawsegment_gouraud_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
for ( ; xstart < xend; xstart++ ) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
//
int red = (ir & 0xFF0000);
int grn = (ig >> 8) & 0xFF00;
int blu = (ib >> 16);
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
// blend alpha
int al = ia >> 16;
//
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) | ((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
m_stencil[xstart] = p;
}
//
ir+=iradd;
ig+=igadd;
ib+=ibadd;
ia+=iaadd;
iz+=izadd;
}
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
aleft+=aleftadd;
zleft+=zleftadd;
}
}
/**
* 8-bit plain texture
*/
//THIS IS MESSED UP, NEED TO GRAB ORIGINAL VERSION!!!
private void drawsegment_texture8
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
int red = m_fill & 0xFF0000;
int grn = m_fill & 0xFF00;
int blu = m_fill & 0xFF;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// try-catch just in case pixel offset it out of range
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int al0;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = iu & 0xFFFF;
al0 = m_texture[ofs] & 0xFF;
int al1 = m_texture[ofs + 1] & 0xFF;
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int al2 = m_texture[ofs] & 0xFF;
int al3 = m_texture[ofs + 1] & 0xFF;
al0 = al0 + (((al1-al0) * iui) >> 16);
al2 = al2 + (((al3-al2) * iui) >> 16);
al0 = al0 + (((al2-al0) * (iv & 0xFFFF)) >> 16);
} else {
al0 = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)] & 0xFF;
}
int br = m_pixels[xstart];
int bg = (br & 0xFF00);
int bb = (br & 0xFF);
br = (br & 0xFF0000);
m_pixels[xstart] = ((br + (((red - br) * al0) >> 8)) & 0xFF0000) | ((bg + (((grn - bg) * al0) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al0) >> 8)) & 0xFF);
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
zleft+=zleftadd;
}
}
/**
* 8-bit texutre + alpha
*/
private void drawsegment_texture8_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float iaf = iaadd;
int red = m_fill & 0xFF0000;
int grn = m_fill & 0xFF00;
int blu = m_fill & 0xFF;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// try-catch just in case pixel offset it out of range
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int al0;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = iu & 0xFFFF;
al0 = m_texture[ofs] & 0xFF;
int al1 = m_texture[ofs + 1] & 0xFF;
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int al2 = m_texture[ofs] & 0xFF;
int al3 = m_texture[ofs + 1] & 0xFF;
al0 = al0 + (((al1-al0) * iui) >> 16);
al2 = al2 + (((al3-al2) * iui) >> 16);
al0 = al0 + (((al2-al0) * (iv & 0xFFFF)) >> 16);
} else {
al0 = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)] & 0xFF;
}
al0 = (al0 * (ia >> 16)) >> 8;
int br = m_pixels[xstart];
int bg = (br & 0xFF00);
int bb = (br & 0xFF);
br = (br & 0xFF0000);
m_pixels[xstart] = ((br + (((red - br) * al0) >> 8)) & 0xFF0000) | ((bg + (((grn - bg) * al0) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al0) >> 8)) & 0xFF);
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
iz+=izadd;
ia+=iaadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
zleft+=zleftadd;
aleft+=aleftadd;
}
}
/**
* Plain 24-bit texture
*/
private void drawsegment_texture24
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
int ypixel = ytop/SCREEN_WIDTH;//ACCTEX
int lastRowStart = m_texture.length - TEX_WIDTH - 2;//If we're past this index, we can't shift down a row w/o throwing an exception
// int exCount = 0;//counter for exceptions caught
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES]; //bring this local since it will be accessed often
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
//Interpolation length of 16 tends to look good except at a small angle; 8 looks okay then, except for the
//above issue. When viewing close to flat, as high as 32 is often acceptable. Could add dynamic interpolation
//settings based on triangle angle - currently we just pick a value and leave it (by default I have the
//power set at 3, so every 8 pixels a true coordinate is calculated, which seems a decent compromise).
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion gave us garbage, revert to normal rendering (something is degenerate)
}
}
while (ytop < ybottom) {//scanline loop
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0){ xstart = 0; }
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH){ xend = SCREEN_WIDTH; }
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
//off by one (half, I guess) hack, w/o it the first rows are outside the texture - maybe a mistake somewhere?
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;//OPT - some of this could be brought out of the y-loop since
b = screenx*bx+screeny*by+screenz*bz;//xpixel and ypixel just increment by the same numbers each iteration.
c = screenx*cx+screeny*cy+screenz*cz;//Probably not a big bottleneck, though.
}
//Figure out whether triangle is going further into the screen or not as we move along scanline
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
//Set up linear interpolation between calculated texture points
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
//float fdeltaU = 0; float fdeltaV = 0;//vars for floating point interpolating version of algorithm
//float fiu = 0; float fiv = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
//Bugfix (done): it's a Really Bad Thing to interpolate along a scanline when the triangle goes deeper into the screen,
//because if the angle is severe enough the last control point for interpolation may cross the vanishing
//point. This leads to some pretty nasty artifacts, and ideally we should scan from right to left if the
//triangle is better served that way, or (what we do now) precompute the offset that we'll need so that we end up
//with a control point exactly at the furthest edge of the triangle.
if (accurateMode&&goingIn){
//IMPORTANT!!! Results are horrid without this hack!
//If polygon goes into the screen along scan line, we want to match the control point to the furthest point drawn
//since the control points are less meaningful the closer you are to the vanishing point.
//We'll do this by making the first control point lie before the start of the scanline (safe since it's closer to us)
int rightOffset = (xend-xstart-1)%linearInterpLength; //"off by one" hack...probably means there's a small bug somewhere
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
//Take step to control point to the left of start pixel
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
//Now step to right control point
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
//Get deltas for interpolation
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
//Otherwise the left edge is further, and we pin the first control point to it
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {//pixel loop - keep trim, can execute thousands of times per frame
//boolean drawBlack = false; //used to display control points
if(accurateMode){
/* //Non-interpolating algorithm - slowest version, calculates exact coordinate for each pixel,
//and casts from float->int
float oneoverc = 65536.0f/c; //a bit faster to pre-divide for next two steps
iu = (int)(a*oneoverc);
iv = (int)(b*oneoverc);
a += newax;
b += newbx;
c += newcx;
*/
//Float while calculating, int while interpolating
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
//drawBlack = true;
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv; //ints are used for interpolation, not actual computation
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{ //race through using linear interpolation if we're not at a control point
iu += deltaU;
iv += deltaV;
}
interpCounter++;
/* //Floating point interpolating version - slower than int thanks to casts during interpolation steps
if (interpCounter == 0) {
interpCounter = linearInterpLength;
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu;
oldfv = fv;
fu = (a*oneoverc);
fv = (b*oneoverc);
//oldu = u; oldv = v;
fiu = oldfu;
fiv = oldfv;
fdeltaU = (fu-oldfu)/linearInterpLength;
fdeltaV = (fv-oldfv)/linearInterpLength;
}
else{
fiu += fdeltaU;
fiv += fdeltaV;
}
interpCounter--;
iu = (int)(fiu); iv = (int)(fiv);*/
}
// try-catch just in case pixel offset is out of range
try{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
m_zbuffer[xstart] = iz;
if (m_bilinear) {
//We could (should?) add bounds checking on iu and iv here (keep in mind the 16 bit shift!).
//This would also be the place to add looping texture mode (bounds check == clamped).
//For looping/clamped textures, we'd also need to change PGraphics.textureVertex() to remove
//the texture range check there (it constrains normalized texture coordinates from 0->1).
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
//if(ofs < 0) { ofs += TEX_WIDTH; }
//if(ofs > m_texture.length-2) {ofs -= TEX_WIDTH; }
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH; //quick hack to thwart exceptions
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
int red = up + (((dn-up) * ivi) >> 7);
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
int grn = up + (((dn-up) * ivi) >> 7);
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
int blu = up + (((dn-up) * ivi) >> 7);
m_pixels[xstart] = (red & 0xFF0000) | (grn & 0xFF00) | (blu & 0xFF);
//if (drawBlack){ m_pixels[xstart] = 0; }
} else{
m_pixels[xstart] = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
}
m_stencil[xstart] = p;
}
} catch (Exception e) {/*exCount++;*/}
iz+=izadd;
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
zleft+=zleftadd;
uleft+=uleftadd;
vleft+=vleftadd;
}
// if (exCount>0) System.out.println(exCount+" exceptions in this segment");
}
/**
* Alpha 24-bit texture
*/
private void drawsegment_texture24_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
// get alpha
int al = ia >> 16;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
int red = up + (((dn-up) * ivi) >> 7);
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
int grn = up + (((dn-up) * ivi) >> 7);
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
int blu = up + (((dn-up) * ivi) >> 7);
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |( (bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
} else {
int red = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
int grn = red & 0xFF00;
int blu = red & 0xFF;
red&=0xFF0000;
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
}
m_stencil[xstart] = p;
}
}
catch (Exception e) {}
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ia+=iaadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
zleft+=zleftadd;
aleft+=aleftadd;
}
}
/**
* Plain 32-bit texutre
*/
private void drawsegment_texture32
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// try-catch just in case pixel offset it out of range
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
int red = up + (((dn-up) * ivi) >> 7);
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
int grn = up + (((dn-up) * ivi) >> 7);
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
int blu = up + (((dn-up) * ivi) >> 7);
// alpha
pix0>>>=24;
pix2>>>=24;
up = pix0 + ((((pix1 >>> 24) - pix0) * iui) >> 7);
dn = pix2 + ((((pix3 >>> 24) - pix2) * iui) >> 7);
int al = up + (((dn-up) * ivi) >> 7);
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
} else {
int red = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
int al = red >>> 24;
int grn = red & 0xFF00;
int blu = red & 0xFF;
red&=0xFF0000;
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
}
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
zleft+=zleftadd;
aleft+=aleftadd;
}
}
/**
* Alpha 32-bit texutre
*/
private void drawsegment_texture32_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// try-catch just in case pixel offset it out of range
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
// get alpha
int al = ia >> 16;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
int red = up + (((dn-up) * ivi) >> 7);
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
int grn = up + (((dn-up) * ivi) >> 7);
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
int blu = up + (((dn-up) * ivi) >> 7);
// alpha
pix0>>>=24;
pix2>>>=24;
up = pix0 + ((((pix1 >>> 24) - pix0) * iui) >> 7);
dn = pix2 + ((((pix3 >>> 24) - pix2) * iui) >> 7);
al = al * (up + (((dn-up) * ivi) >> 7)) >> 8;
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
} else {
int red = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
al = al * (red >>> 24) >> 8;
int grn = red & 0xFF00;
int blu = red & 0xFF;
red&=0xFF0000;
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
}
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ia+=iaadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
zleft+=zleftadd;
aleft+=aleftadd;
}
}
/**
* Gouraud blended with 8-bit alpha texture
*/
private void drawsegment_gouraud_texture8
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int al0;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = iu & 0xFFFF;
al0 = m_texture[ofs] & 0xFF;
int al1 = m_texture[ofs + 1] & 0xFF;
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int al2 = m_texture[ofs] & 0xFF;
int al3 = m_texture[ofs + 1] & 0xFF;
al0 = al0 + (((al1-al0) * iui) >> 16);
al2 = al2 + (((al3-al2) * iui) >> 16);
al0 = al0 + (((al2-al0) * (iv & 0xFFFF)) >> 16);
} else {
al0 = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)] & 0xFF;
}
// get RGB colors
int red = ir & 0xFF0000;
int grn = (ig >> 8) & 0xFF00;
int blu = (ib >> 16);
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al0) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al0) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al0) >> 8)) & 0xFF);
// write stencil
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
zleft+=zleftadd;
}
}
/**
* Texture multiplied with gouraud
*/
private void drawsegment_gouraud_texture8_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int al0;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = iu & 0xFFFF;
al0 = m_texture[ofs] & 0xFF;
int al1 = m_texture[ofs + 1] & 0xFF;
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int al2 = m_texture[ofs] & 0xFF;
int al3 = m_texture[ofs + 1] & 0xFF;
al0 = al0 + (((al1-al0) * iui) >> 16);
al2 = al2 + (((al3-al2) * iui) >> 16);
al0 = al0 + (((al2-al0) * (iv & 0xFFFF)) >> 16);
} else {
al0 = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)] & 0xFF;
}
al0 = (al0 * (ia >> 16)) >> 8;
// get RGB colors
int red = ir & 0xFF0000;
int grn = (ig >> 8) & 0xFF00;
int blu = (ib >> 16);
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
m_pixels[xstart] = ((br + (((red - br) * al0) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al0) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al0) >> 8)) & 0xFF);
// write stencil
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
ia+=iaadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
aleft+=aleftadd;
zleft+=zleftadd;
}
}
/**
* Texture multiplied with gouraud
*/
private void drawsegment_gouraud_texture24
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
m_zbuffer[xstart] = iz;
int red;
int grn;
int blu;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
red = up + (((dn-up) * ivi) >> 7);
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
grn = up + (((dn-up) * ivi) >> 7);
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
blu = up + (((dn-up) * ivi) >> 7);
} else {
// get texture pixel color
blu = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
red = (blu & 0xFF0000);
grn = (blu & 0xFF00);
blu = blu & 0xFF;
}
//
int r = (ir >> 16);
int g = (ig >> 16);
int bb2 = (ib >> 16); //oops, namespace collision with accurate texture vector b...sorry [ewjordan]
//
m_pixels[xstart] = ( ((red * r) & 0xFF000000) | ((grn * g) & 0xFF0000) | (blu * bb2) ) >> 8;
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
zleft+=zleftadd;
}
}
/**
* Gouraud*texture blended with interpolating alpha
*/
private void drawsegment_gouraud_texture24_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ;xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// get texture pixel color
try
{
//if (iz < m_zbuffer[xstart]) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) { // [fry 041114]
//m_zbuffer[xstart] = iz;
// blend
int al = ia >> 16;
int red;
int grn;
int blu;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
red = (up + (((dn-up) * ivi) >> 7)) >> 16;
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
grn = (up + (((dn-up) * ivi) >> 7)) >> 8;
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
blu = up + (((dn-up) * ivi) >> 7);
} else {
blu = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
red = (blu & 0xFF0000) >> 16; // 0 - 255
grn = (blu & 0xFF00) >> 8; // 0 - 255
blu = (blu & 0xFF); // 0 - 255
}
// multiply with gouraud color
red = (red * ir) >>> 8; // 0x00FF????
grn = (grn * ig) >>> 16; // 0x0000FF??
blu = (blu * ib) >>> 24; // 0x000000FF
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
//
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
ia+=iaadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
aleft+=aleftadd;
zleft+=zleftadd;
}
}
/**
* Gouraud*texture blended with interpolating alpha
*/
private void drawsegment_gouraud_texture32
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
//int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ; xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
try
{
if (noDepthTest || (iz <= m_zbuffer[xstart])) {
//m_zbuffer[xstart] = iz;
int red;
int grn;
int blu;
int al;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
red = (up + (((dn-up) * ivi) >> 7)) >> 16;
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
grn = (up + (((dn-up) * ivi) >> 7)) >> 8;
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
blu = up + (((dn-up) * ivi) >> 7);
// alpha
pix0>>>=24;
pix2>>>=24;
up = pix0 + ((((pix1 >>> 24) - pix0) * iui) >> 7);
dn = pix2 + ((((pix3 >>> 24) - pix2) * iui) >> 7);
al = up + (((dn-up) * ivi) >> 7);
} else {
// get texture pixel color
blu = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
al = (blu >>> 24);
red = (blu & 0xFF0000) >> 16;
grn = (blu & 0xFF00) >> 8;
blu = blu & 0xFF;
}
// multiply with gouraud color
red = (red * ir) >>> 8; // 0x00FF????
grn = (grn * ig) >>> 16; // 0x0000FF??
blu = (blu * ib) >>> 24; // 0x000000FF
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
//
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
zleft+=zleftadd;
}
}
/**
* Gouraud*texture blended with interpolating alpha
*/
private void drawsegment_gouraud_texture32_alpha
(
float leftadd,
float rghtadd,
int ytop,
int ybottom
) {
//Accurate texture mode added - comments stripped from dupe code, see drawsegment_texture24() for details
int ypixel = ytop;
int lastRowStart = m_texture.length - TEX_WIDTH - 2;
boolean accurateMode = parent.hints[ENABLE_ACCURATE_TEXTURES];
float screenx = 0; float screeny = 0; float screenz = 0;
float a = 0; float b = 0; float c = 0;
int linearInterpPower = TEX_INTERP_POWER;
int linearInterpLength = 1 << linearInterpPower;
if (accurateMode){
if(precomputeAccurateTexturing()){ //see if the precomputation goes well, if so finish the setup
newax *= linearInterpLength;
newbx *= linearInterpLength;
newcx *= linearInterpLength;
screenz = nearPlaneDepth;
firstSegment = false;
} else{
accurateMode = false; //if the matrix inversion screwed up, revert to normal rendering (something is degenerate)
}
}
ytop*=SCREEN_WIDTH;
ybottom*=SCREEN_WIDTH;
int p = m_index;
float iuf = iuadd;
float ivf = ivadd;
float irf = iradd;
float igf = igadd;
float ibf = ibadd;
float iaf = iaadd;
while (ytop < ybottom) {
int xstart = (int) (xleft + PIXEL_CENTER);
if (xstart < 0)
xstart = 0;
int xpixel = xstart;//accurate mode
int xend = (int) (xrght + PIXEL_CENTER);
if (xend > SCREEN_WIDTH)
xend = SCREEN_WIDTH;
float xdiff = (xstart + PIXEL_CENTER) - xleft;
int iu = (int) (iuf * xdiff + uleft);
int iv = (int) (ivf * xdiff + vleft);
int ir = (int) (irf * xdiff + rleft);
int ig = (int) (igf * xdiff + gleft);
int ib = (int) (ibf * xdiff + bleft);
int ia = (int) (iaf * xdiff + aleft);
float iz = izadd * xdiff + zleft;
xstart+=ytop;
xend+=ytop;
if (accurateMode){
screenx = xmult*(xpixel+.5f-(SCREEN_WIDTH/2.0f));
screeny = ymult*(ypixel+.5f-(SCREEN_HEIGHT/2.0f));
a = screenx*ax+screeny*ay+screenz*az;
b = screenx*bx+screeny*by+screenz*bz;
c = screenx*cx+screeny*cy+screenz*cz;
}
boolean goingIn = ( (newcx > 0) == (c > 0) )?false:true;
int interpCounter = 0;
int deltaU = 0; int deltaV = 0;
float fu = 0; float fv = 0;
float oldfu = 0; float oldfv = 0;
if (accurateMode&&goingIn){
int rightOffset = (xend-xstart-1)%linearInterpLength;
int leftOffset = linearInterpLength-rightOffset;
float rightOffset2 = rightOffset / ((float)linearInterpLength);
float leftOffset2 = leftOffset / ((float)linearInterpLength);
interpCounter = leftOffset;
float ao = a-leftOffset2*newax;
float bo = b-leftOffset2*newbx;
float co = c-leftOffset2*newcx;
float oneoverc = 65536.0f/co;
oldfu = (ao*oneoverc); oldfv = (bo*oneoverc);
a += rightOffset2*newax;
b += rightOffset2*newbx;
c += rightOffset2*newcx;
oneoverc = 65536.0f/c;
fu = a*oneoverc; fv = b*oneoverc;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
iu = ( (int)oldfu )+(leftOffset-1)*deltaU; iv = ( (int)oldfv )+(leftOffset-1)*deltaV; //another "off-by-one" hack
} else{
float preoneoverc = 65536.0f/c;
fu = (a*preoneoverc);
fv = (b*preoneoverc);
}
for ( ;xstart < xend; xstart++ ) {
if(accurateMode){
if (interpCounter == linearInterpLength) interpCounter = 0;
if (interpCounter == 0){
a += newax;
b += newbx;
c += newcx;
float oneoverc = 65536.0f/c;
oldfu = fu; oldfv = fv;
fu = (a*oneoverc); fv = (b*oneoverc);
iu = (int)oldfu; iv = (int)oldfv;
deltaU = ((int)(fu - oldfu)) >> linearInterpPower;
deltaV = ((int)(fv - oldfv)) >> linearInterpPower;
} else{
iu += deltaU;
iv += deltaV;
}
interpCounter++;
}
// get texture pixel color
try
{
//if (iz < m_zbuffer[xstart]) {
if (noDepthTest || (iz <= m_zbuffer[xstart])) { // [fry 041114]
//m_zbuffer[xstart] = iz;
// blend
int al = ia >> 16;
int red;
int grn;
int blu;
if (m_bilinear) {
int ofs = (iv >> 16) * TEX_WIDTH + (iu >> 16);
int iui = (iu & 0xFFFF) >> 9;
int ivi = (iv & 0xFFFF) >> 9;
// get texture pixels
int pix0 = m_texture[ofs];
int pix1 = m_texture[ofs + 1];
if (ofs < lastRowStart) ofs+=TEX_WIDTH;
int pix2 = m_texture[ofs];
int pix3 = m_texture[ofs + 1];
// red
int red0 = (pix0 & 0xFF0000);
int red2 = (pix2 & 0xFF0000);
int up = red0 + ((((pix1 & 0xFF0000) - red0) * iui) >> 7);
int dn = red2 + ((((pix3 & 0xFF0000) - red2) * iui) >> 7);
red = (up + (((dn-up) * ivi) >> 7)) >> 16;
// grn
red0 = (pix0 & 0xFF00);
red2 = (pix2 & 0xFF00);
up = red0 + ((((pix1 & 0xFF00) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF00) - red2) * iui) >> 7);
grn = (up + (((dn-up) * ivi) >> 7)) >> 8;
// blu
red0 = (pix0 & 0xFF);
red2 = (pix2 & 0xFF);
up = red0 + ((((pix1 & 0xFF) - red0) * iui) >> 7);
dn = red2 + ((((pix3 & 0xFF) - red2) * iui) >> 7);
blu = up + (((dn-up) * ivi) >> 7);
// alpha
pix0>>>=24;
pix2>>>=24;
up = pix0 + ((((pix1 >>> 24) - pix0) * iui) >> 7);
dn = pix2 + ((((pix3 >>> 24) - pix2) * iui) >> 7);
al = al * (up + (((dn-up) * ivi) >> 7)) >> 8;
} else {
blu = m_texture[(iv >> 16) * TEX_WIDTH + (iu >> 16)];
al = al * (blu >>> 24) >> 8;
red = (blu & 0xFF0000) >> 16; // 0 - 255
grn = (blu & 0xFF00) >> 8; // 0 - 255
blu = (blu & 0xFF); // 0 - 255
}
// multiply with gouraud color
red = (red * ir) >>> 8; // 0x00FF????
grn = (grn * ig) >>> 16; // 0x0000FF??
blu = (blu * ib) >>> 24; // 0x000000FF
// get buffer pixels
int bb = m_pixels[xstart];
int br = (bb & 0xFF0000); // 0x00FF0000
int bg = (bb & 0xFF00); // 0x0000FF00
bb = (bb & 0xFF); // 0x000000FF
//
m_pixels[xstart] = ((br + (((red - br) * al) >> 8)) & 0xFF0000) |((bg + (((grn - bg) * al) >> 8)) & 0xFF00) | ((bb + (((blu - bb) * al) >> 8)) & 0xFF);
m_stencil[xstart] = p;
}
}
catch (Exception e) {
}
//
xpixel++;//accurate mode
if (!accurateMode){
iu+=iuadd;
iv+=ivadd;
}
ir+=iradd;
ig+=igadd;
ib+=ibadd;
ia+=iaadd;
iz+=izadd;
}
ypixel++;//accurate mode
ytop+=SCREEN_WIDTH;
xleft+=leftadd;
xrght+=rghtadd;
uleft+=uleftadd;
vleft+=vleftadd;
rleft+=rleftadd;
gleft+=gleftadd;
bleft+=bleftadd;
aleft+=aleftadd;
zleft+=zleftadd;
}
}
}