| /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ |
| |
| /* |
| Part of the Processing project - http://processing.org |
| |
| Copyright (c) 2004-07 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> |
| * Originally written by sami (www.sumea.com) |
| */ |
| public class PTriangle implements PConstants |
| { |
| static final float PIXEL_CENTER = 0.5f; // for polygon aa |
| |
| 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 argbSurface; |
| |
| /** */ |
| private boolean m_culling; |
| |
| /** */ |
| private boolean m_singleRight; |
| |
| /** |
| * True if using bilinear interpolation for textures. |
| * Always set to true. If this is ever changed (maybe with a hint()?) |
| * will need to write code for texture8/24/32 et al that will handle mixing |
| * the m_fill color in with the texture color. |
| */ |
| private boolean m_bilinear = true; // always set to true |
| |
| |
| // 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; |
| // optimization vars...not pretty, but save a couple mults per pixel |
| private float newax,newbx,newcx; |
| // are we currently drawing the first piece of the triangle, |
| // or have we already done so? |
| private boolean firstSegment; |
| |
| |
| public PTriangle(PGraphics3D g) { |
| 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]; |
| //argbSurface = parent.format == PConstants.ARGB; |
| |
| // 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 hint(ENABLE_ACCURATE_TEXTURES) enabled. |
| * Generally this will not need to be called manually, |
| * currently called from PGraphics3D.render_triangles() |
| */ |
| public void setCamVertices(float x0, float y0, float z0, |
| float x1, float y1, float z1, |
| float x2, float y2, float z2) { |
| 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 = 0xFF000000 | |
| ((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; |
| } |
| } |
| |
| |
| /** |
| * |
| */ |
| 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() { |
| float x0, x1, x2; |
| float z0, z1, z2; |
| |
| float y0 = y_array[0]; |
| float y1 = y_array[1]; |
| float y2 = y_array[2]; |
| |
| //System.out.println(PApplet.hex(m_drawFlags)); |
| |
| // 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. |
| * Sets all class variables relevant to accurate texture computation |
| * Should be called once per triangle - checks firstSegment to see if |
| * we've already called. |
| */ |
| private boolean precomputeAccurateTexturing() { |
| // rescale u/v_array values when inverting matrix and performing other calcs |
| float myFact = 65500.0f; |
| 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){ |
| PMatrix3D myMatrix = |
| new PMatrix3D(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); |
| // A 3x3 inversion would be more efficient here, |
| // given that the fourth r/c are unity |
| myMatrix.invert(); |
| // if the matrix inversion had trouble, let the caller know |
| if (myMatrix == null) return false; |
| |
| 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; |
| // Bugfix: possibly we should use F_TEX_WIDTH/HEIGHT instead? |
| // Seems to read off end of array in that case, though... |
| float resultT0x = m00*TEX_WIDTH+m02; |
| 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; |
| // one pixel width in nearPlane coordinates |
| xmult = nearPlaneWidth / SCREEN_WIDTH; |
| ymult = nearPlaneHeight / SCREEN_HEIGHT; |
| // Extra scalings to map screen plane units to pixel units |
| newax = ax*xmult; |
| 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] = m_fill; |
| // 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; |
| |
| //int ma0 = 0xFF000000; |
| |
| for ( ; xstart < xend; xstart++ ) { |
| if (noDepthTest || (iz <= m_zbuffer[xstart])) { |
| // don't set zbuffer when not fully opaque |
| //m_zbuffer[xstart] = iz; |
| |
| int alpha = ia >> 16; |
| int mr0 = m_pixels[xstart]; |
| /* |
| if (argbSurface) { |
| ma0 = (((mr0 >>> 24) * alpha) << 16) & 0xFF000000; |
| if (ma0 == 0) ma0 = alpha << 24; |
| } |
| */ |
| 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] = 0xFF000000 | |
| (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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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) { |
| // see if the precomputation goes well, if so finish the setup |
| if (precomputeAccurateTexturing()) { |
| newax *= linearInterpLength; |
| newbx *= linearInterpLength; |
| newcx *= linearInterpLength; |
| screenz = nearPlaneDepth; |
| firstSegment = false; |
| } else{ |
| // if the matrix inversion screwed up, revert to normal rendering |
| // (something is degenerate) |
| accurateMode = false; |
| } |
| } |
| 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] = 0xFF000000 | |
| ((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) { |
| // see if the precomputation goes well, if so finish the setup |
| if (precomputeAccurateTexturing()) { |
| newax *= linearInterpLength; |
| newbx *= linearInterpLength; |
| newcx *= linearInterpLength; |
| screenz = nearPlaneDepth; |
| firstSegment = false; |
| } else { |
| // if the matrix inversion screwed up, |
| // revert to normal rendering (something is degenerate) |
| accurateMode = false; |
| } |
| } |
| 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] = 0xFF000000 | |
| ((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; |
| |
| boolean tint = (m_fill & 0xFFFFFF) != 0xFFFFFF; |
| int rtint = (m_fill >> 16) & 0xff; |
| int gtint = (m_fill >> 8) & 0xff; |
| int btint = m_fill & 0xFF; |
| |
| 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); |
| if (tint) red = ((red * rtint) >> 8) & 0xFF0000; |
| |
| // 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); |
| if (tint) grn = ((grn * gtint) >> 8) & 0xFF00; |
| |
| // 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); |
| if (tint) blu = ((blu * btint) >> 8) & 0xFF; |
| |
| //m_pixels[xstart] = (red & 0xFF0000) | (grn & 0xFF00) | (blu & 0xFF); |
| m_pixels[xstart] = 0xFF000000 | |
| (red & 0xFF0000) | (grn & 0xFF00) | (blu & 0xFF); |
| |
| } 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) |
| } |
| } |
| |
| boolean tint = (m_fill & 0xFFFFFF) != 0xFFFFFF; |
| int rtint = (m_fill >> 16) & 0xff; |
| int gtint = (m_fill >> 8) & 0xff; |
| int btint = m_fill & 0xFF; |
| |
| 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); |
| if (tint) red = ((red * rtint) >> 8) & 0xFF0000; |
| |
| // 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); |
| if (tint) grn = ((grn * gtint) >> 8) & 0xFF00; |
| |
| // 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); |
| if (tint) blu = ((blu * btint) >> 8) & 0xFF; |
| |
| // 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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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; |
| |
| boolean tint = m_fill != 0xFFFFFFFF; |
| int rtint = (m_fill >> 16) & 0xff; |
| int gtint = (m_fill >> 8) & 0xff; |
| int btint = m_fill & 0xFF; |
| |
| 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); |
| if (tint) red = ((red * rtint) >> 8) & 0xFF0000; |
| |
| // 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); |
| if (tint) grn = ((grn * gtint) >> 8) & 0xFF00; |
| |
| // 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); |
| if (tint) blu = ((blu * btint) >> 8) & 0xFF; |
| |
| // 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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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; |
| |
| boolean tint = (m_fill & 0xFFFFFF) != 0xFFFFFF; |
| int rtint = (m_fill >> 16) & 0xff; |
| int gtint = (m_fill >> 8) & 0xff; |
| int btint = m_fill & 0xFF; |
| |
| 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); |
| if (tint) red = ((red * rtint) >> 8) & 0xFF0000; |
| |
| // 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); |
| if (tint) grn = ((grn * gtint) >> 8) & 0xFF00; |
| |
| // 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); |
| if (tint) blu = ((blu * btint) >> 8) & 0xFF; |
| |
| // 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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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) { |
| // see if the precomputation goes well, if so finish the setup |
| if (precomputeAccurateTexturing()) { |
| newax *= linearInterpLength; |
| newbx *= linearInterpLength; |
| newcx *= linearInterpLength; |
| screenz = nearPlaneDepth; |
| firstSegment = false; |
| } else{ |
| // if the matrix inversion screwed up, |
| // revert to normal rendering (something is degenerate) |
| accurateMode = false; |
| } |
| } |
| |
| 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] = 0xFF000000 | |
| ((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); |
| // oops, namespace collision with accurate |
| // texture vector b...sorry [ewjordan] |
| int bb2 = (ib >> 16); |
| |
| m_pixels[xstart] = 0xFF000000 | |
| ((((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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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] = 0xFF000000 | |
| ((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; |
| } |
| } |
| } |