diff --git a/android/core/src/processing/core/PGraphics3D.java b/android/core/src/processing/core/PGraphics3D.java deleted file mode 100644 index 7bd438125..000000000 --- a/android/core/src/processing/core/PGraphics3D.java +++ /dev/null @@ -1,4196 +0,0 @@ -/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ - -/* - Part of the Processing project - http://processing.org - - Copyright (c) 2004-08 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; - -//import java.awt.Toolkit; -//import java.awt.image.*; -import java.util.*; - - -// TODO this just has all mis/image references commented out - - -/** - * Subclass of PGraphics that handles 3D rendering. - * It can render 3D inside a browser window and requires no plug-ins. - *

- * The renderer is mostly set up based on the structure of the OpenGL API, - * if you have questions about specifics that aren't covered here, - * look for reference on the OpenGL implementation of a similar feature. - *

- * Lighting and camera implementation by Simon Greenwold. - */ -public class PGraphics3D extends PGraphics { - - /** The depth buffer. */ - public float[] zbuffer; - - // ........................................................ - - /** The modelview matrix. */ - public PMatrix3D modelview; - - /** Inverse modelview matrix, used for lighting. */ - public PMatrix3D modelviewInv; - - /** - * The camera matrix, the modelview will be set to this on beginDraw. - */ - public PMatrix3D camera; - - /** Inverse camera matrix */ - protected PMatrix3D cameraInv; - - /** Camera field of view. */ - public float cameraFOV; - - /** Position of the camera. */ - public float cameraX, cameraY, cameraZ; - public float cameraNear, cameraFar; - /** Aspect ratio of camera's view. */ - public float cameraAspect; - - /** Current projection matrix. */ - public PMatrix3D projection; - - - ////////////////////////////////////////////////////////////// - - - /** - * Maximum lights by default is 8, which is arbitrary for this renderer, - * but is the minimum defined by OpenGL - */ - public static final int MAX_LIGHTS = 8; - - public int lightCount = 0; - - /** Light types */ - public int[] lightType; - - /** Light positions */ - //public float[][] lightPosition; - public PVector[] lightPosition; - - /** Light direction (normalized vector) */ - //public float[][] lightNormal; - public PVector[] lightNormal; - - /** Light falloff */ - public float[] lightFalloffConstant; - public float[] lightFalloffLinear; - public float[] lightFalloffQuadratic; - - /** Light spot angle */ - public float[] lightSpotAngle; - - /** Cosine of light spot angle */ - public float[] lightSpotAngleCos; - - /** Light spot concentration */ - public float[] lightSpotConcentration; - - /** Diffuse colors for lights. - * For an ambient light, this will hold the ambient color. - * Internally these are stored as numbers between 0 and 1. */ - public float[][] lightDiffuse; - - /** Specular colors for lights. - Internally these are stored as numbers between 0 and 1. */ - public float[][] lightSpecular; - - /** Current specular color for lighting */ - public float[] currentLightSpecular; - - /** Current light falloff */ - public float currentLightFalloffConstant; - public float currentLightFalloffLinear; - public float currentLightFalloffQuadratic; - - - ////////////////////////////////////////////////////////////// - - - static public final int TRI_DIFFUSE_R = 0; - static public final int TRI_DIFFUSE_G = 1; - static public final int TRI_DIFFUSE_B = 2; - static public final int TRI_DIFFUSE_A = 3; - static public final int TRI_SPECULAR_R = 4; - static public final int TRI_SPECULAR_G = 5; - static public final int TRI_SPECULAR_B = 6; - static public final int TRI_COLOR_COUNT = 7; - - // ........................................................ - - // Whether or not we have to worry about vertex position for lighting calcs - private boolean lightingDependsOnVertexPosition; - - static final int LIGHT_AMBIENT_R = 0; - static final int LIGHT_AMBIENT_G = 1; - static final int LIGHT_AMBIENT_B = 2; - static final int LIGHT_DIFFUSE_R = 3; - static final int LIGHT_DIFFUSE_G = 4; - static final int LIGHT_DIFFUSE_B = 5; - static final int LIGHT_SPECULAR_R = 6; - static final int LIGHT_SPECULAR_G = 7; - static final int LIGHT_SPECULAR_B = 8; - static final int LIGHT_COLOR_COUNT = 9; - - // Used to shuttle lighting calcs around - // (no need to re-allocate all the time) - protected float[] tempLightingContribution = new float[LIGHT_COLOR_COUNT]; -// protected float[] worldNormal = new float[4]; - - /// Used in lightTriangle(). Allocated here once to avoid re-allocating - protected PVector lightTriangleNorm = new PVector(); - - // ........................................................ - - /** - * This is turned on at beginCamera, and off at endCamera - * Currently we don't support nested begin/end cameras. - * If we wanted to, this variable would have to become a stack. - */ - protected boolean manipulatingCamera; - - float[][] matrixStack = new float[MATRIX_STACK_DEPTH][16]; - float[][] matrixInvStack = new float[MATRIX_STACK_DEPTH][16]; - int matrixStackDepth; - - // These two matrices always point to either the modelview - // or the modelviewInv, but they are swapped during - // when in camera manipulation mode. That way camera transforms - // are automatically accumulated in inverse on the modelview matrix. - protected PMatrix3D forwardTransform; - protected PMatrix3D reverseTransform; - - // Added by ewjordan for accurate texturing purposes. Screen plane is - // not scaled to pixel-size, so these manually keep track of its size - // from frustum() calls. Sorry to add public vars, is there a way - // to compute these from something publicly available without matrix ops? - // (used once per triangle in PTriangle with ENABLE_ACCURATE_TEXTURES) - protected float leftScreen; - protected float rightScreen; - protected float topScreen; - protected float bottomScreen; - protected float nearPlane; //depth of near clipping plane - - /** - * Use PSmoothTriangle for rendering instead of PTriangle? - * Usually set by calling smooth() or noSmooth() - */ - static protected boolean s_enableAccurateTextures = false; //maybe just use smooth instead? - - - // ........................................................ - - // pos of first vertex of current shape in vertices array - protected int shapeFirst; - - // i think vertex_end is actually the last vertex in the current shape - // and is separate from vertexCount for occasions where drawing happens - // on endDraw() with all the triangles being depth sorted - protected int shapeLast; - - // vertices may be added during clipping against the near plane. - protected int shapeLastPlusClipped; - - // used for sorting points when triangulating a polygon - // warning - maximum number of vertices for a polygon is DEFAULT_VERTICES - protected int vertexOrder[] = new int[DEFAULT_VERTICES]; - - // ........................................................ - - // This is done to keep track of start/stop information for lines in the - // line array, so that lines can be shown as a single path, rather than just - // individual segments. Currently only in use inside PGraphicsOpenGL. - protected int pathCount; - protected int[] pathOffset = new int[64]; - protected int[] pathLength = new int[64]; - - // ........................................................ - - // line & triangle fields (note that these overlap) -// static protected final int INDEX = 0; // shape index - static protected final int VERTEX1 = 0; - static protected final int VERTEX2 = 1; - static protected final int VERTEX3 = 2; // (triangles only) - /** used to store the strokeColor int for efficient drawing. */ - static protected final int STROKE_COLOR = 1; // (points only) - static protected final int TEXTURE_INDEX = 3; // (triangles only) - //static protected final int STROKE_MODE = 2; // (lines only) - //static protected final int STROKE_WEIGHT = 3; // (lines only) - - static protected final int POINT_FIELD_COUNT = 2; //4 - static protected final int LINE_FIELD_COUNT = 2; //4 - static protected final int TRIANGLE_FIELD_COUNT = 4; - - // points - static final int DEFAULT_POINTS = 512; - protected int[][] points = new int[DEFAULT_POINTS][POINT_FIELD_COUNT]; - protected int pointCount; - - // lines - static final int DEFAULT_LINES = 512; - public PLine line; // used for drawing - protected int[][] lines = new int[DEFAULT_LINES][LINE_FIELD_COUNT]; - protected int lineCount; - - // triangles - static final int DEFAULT_TRIANGLES = 256; - public PTriangle triangle; - protected int[][] triangles = - new int[DEFAULT_TRIANGLES][TRIANGLE_FIELD_COUNT]; - protected float triangleColors[][][] = - new float[DEFAULT_TRIANGLES][3][TRI_COLOR_COUNT]; - protected int triangleCount; // total number of triangles - - // cheap picking someday - //public int shape_index; - - // ........................................................ - - static final int DEFAULT_TEXTURES = 3; - protected PImage[] textures = new PImage[DEFAULT_TEXTURES]; - int textureIndex; - - // ........................................................ - -// DirectColorModel cm; -// MemoryImageSource mis; - - - ////////////////////////////////////////////////////////////// - - - public PGraphics3D() { } - - - //public void setParent(PApplet parent) - - - //public void setPrimary(boolean primary) - - - //public void setPath(String path) - - - /** - * Called in response to a resize event, handles setting the - * new width and height internally, as well as re-allocating - * the pixel buffer for the new size. - * - * Note that this will nuke any cameraMode() settings. - */ - public void setSize(int iwidth, int iheight) { // ignore - width = iwidth; - height = iheight; - width1 = width - 1; - height1 = height - 1; - - allocate(); - reapplySettings(); - - // init lights (in resize() instead of allocate() b/c needed by opengl) - lightType = new int[MAX_LIGHTS]; - lightPosition = new PVector[MAX_LIGHTS]; - lightNormal = new PVector[MAX_LIGHTS]; - for (int i = 0; i < MAX_LIGHTS; i++) { - lightPosition[i] = new PVector(); - lightNormal[i] = new PVector(); - } - lightDiffuse = new float[MAX_LIGHTS][3]; - lightSpecular = new float[MAX_LIGHTS][3]; - lightFalloffConstant = new float[MAX_LIGHTS]; - lightFalloffLinear = new float[MAX_LIGHTS]; - lightFalloffQuadratic = new float[MAX_LIGHTS]; - lightSpotAngle = new float[MAX_LIGHTS]; - lightSpotAngleCos = new float[MAX_LIGHTS]; - lightSpotConcentration = new float[MAX_LIGHTS]; - currentLightSpecular = new float[3]; - - projection = new PMatrix3D(); - modelview = new PMatrix3D(); - modelviewInv = new PMatrix3D(); - -// modelviewStack = new float[MATRIX_STACK_DEPTH][16]; -// modelviewInvStack = new float[MATRIX_STACK_DEPTH][16]; -// modelviewStackPointer = 0; - - forwardTransform = modelview; - reverseTransform = modelviewInv; - - // init perspective projection based on new dimensions - cameraFOV = 60 * DEG_TO_RAD; // at least for now - cameraX = width / 2.0f; - cameraY = height / 2.0f; - cameraZ = cameraY / ((float) Math.tan(cameraFOV / 2.0f)); - cameraNear = cameraZ / 10.0f; - cameraFar = cameraZ * 10.0f; - cameraAspect = (float)width / (float)height; - - camera = new PMatrix3D(); - cameraInv = new PMatrix3D(); - - // set up the default camera - camera(); - - // defaults to perspective, if the user has setup up their - // own projection, they'll need to fix it after resize anyway. - // this helps the people who haven't set up their own projection. - perspective(); - } - - - protected void allocate() { - //System.out.println(this + " allocating for " + width + " " + height); - //new Exception().printStackTrace(); - - pixelCount = width * height; - pixels = new int[pixelCount]; - zbuffer = new float[pixelCount]; - - if (primarySurface) { -// cm = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff);; -// mis = new MemoryImageSource(width, height, pixels, 0, width); -// mis.setFullBufferUpdates(true); -// mis.setAnimated(true); -// image = Toolkit.getDefaultToolkit().createImage(mis); - - } else { - // when not the main drawing surface, need to set the zbuffer, - // because there's a possibility that background() will not be called - Arrays.fill(zbuffer, Float.MAX_VALUE); - } - - line = new PLine(this); - triangle = new PTriangle(this); - } - - - //public void dispose() - - - //////////////////////////////////////////////////////////// - - - //public boolean canDraw() - - - public void beginDraw() { - // need to call defaults(), but can only be done when it's ok - // to draw (i.e. for opengl, no drawing can be done outside - // beginDraw/endDraw). - if (!settingsInited) defaultSettings(); - - resetMatrix(); // reset model matrix - - // reset vertices - vertexCount = 0; - - modelview.set(camera); - modelviewInv.set(cameraInv); - - // clear out the lights, they'll have to be turned on again - lightCount = 0; - lightingDependsOnVertexPosition = false; - lightFalloff(1, 0, 0); - lightSpecular(0, 0, 0); - - /* - // reset lines - lineCount = 0; - if (line != null) line.reset(); // is this necessary? - pathCount = 0; - - // reset triangles - triangleCount = 0; - if (triangle != null) triangle.reset(); // necessary? - */ - - shapeFirst = 0; - - // reset textures - textureIndex = 0; - - normal(0, 0, 1); - } - - - /** - * See notes in PGraphics. - * If z-sorting has been turned on, then the triangles will - * all be quicksorted here (to make alpha work more properly) - * and then blit to the screen. - */ - public void endDraw() { - // no need to z order and render - // shapes were already rendered in endShape(); - // (but can't return, since needs to update memimgsrc) - if (hints[ENABLE_DEPTH_SORT]) { - flush(); - } -// if (mis != null) { -// mis.newPixels(pixels, cm, 0, width); -// } - // mark pixels as having been updated, so that they'll work properly - // when this PGraphics is drawn using image(). - updatePixels(); - } - - - //////////////////////////////////////////////////////////// - - - //protected void checkSettings() - - - protected void defaultSettings() { - super.defaultSettings(); - - manipulatingCamera = false; - forwardTransform = modelview; - reverseTransform = modelviewInv; - - perspective(); - - // easiest for beginners - textureMode(IMAGE); - - emissive(0.0f); - specular(0.5f); - shininess(1.0f); - } - - - //protected void reapplySettings() - - - //////////////////////////////////////////////////////////// - - - public void hint(int which) { - if (which == DISABLE_DEPTH_SORT) { - flush(); - } else if (which == DISABLE_DEPTH_TEST) { - if (zbuffer != null) { // will be null in OpenGL and others - Arrays.fill(zbuffer, Float.MAX_VALUE); - } - } - super.hint(which); - } - - - ////////////////////////////////////////////////////////////// - - - //public void beginShape() - - - public void beginShape(int kind) { - shape = kind; - -// shape_index = shape_index + 1; -// if (shape_index == -1) { -// shape_index = 0; -// } - - if (hints[ENABLE_DEPTH_SORT]) { - // continue with previous vertex, line and triangle count - // all shapes are rendered at endDraw(); - shapeFirst = vertexCount; - shapeLast = 0; - - } else { - // reset vertex, line and triangle information - // every shape is rendered at endShape(); - vertexCount = 0; - if (line != null) line.reset(); // necessary? - lineCount = 0; -// pathCount = 0; - if (triangle != null) triangle.reset(); // necessary? - triangleCount = 0; - } - - textureImage = null; - curveVertexCount = 0; - normalMode = NORMAL_MODE_AUTO; -// normalCount = 0; - } - - - //public void normal(float nx, float ny, float nz) - - - //public void textureMode(int mode) - - - public void texture(PImage image) { - textureImage = image; - - if (textureIndex == textures.length - 1) { - textures = (PImage[]) PApplet.expand(textures); - } - if (textures[textureIndex] != null) { // ??? - textureIndex++; - } - textures[textureIndex] = image; - } - - - public void vertex(float x, float y) { - // override so that the default 3D implementation will be used, - // which will pick up all 3D settings (e.g. emissive, ambient) - vertex(x, y, 0); - } - - - //public void vertex(float x, float y, float z) - - - public void vertex(float x, float y, float u, float v) { - // see vertex(x, y) for note - vertex(x, y, 0, u, v); - } - - - //public void vertex(float x, float y, float z, float u, float v) - - - //public void breakShape() - - - //public void endShape() - - - public void endShape(int mode) { - shapeLast = vertexCount; - shapeLastPlusClipped = shapeLast; - - // don't try to draw if there are no vertices - // (fixes a bug in LINE_LOOP that re-adds a nonexistent vertex) - if (vertexCount == 0) { - shape = 0; - return; - } - - // convert points from model (X/Y/Z) to camera space (VX/VY/VZ). - // Do this now because we will be clipping them on add_triangle. - endShapeModelToCamera(shapeFirst, shapeLast); - - if (stroke) { - endShapeStroke(mode); - } - - if (fill) { - endShapeFill(); - } - - // transform, light, and clip - endShapeLighting(lightCount > 0 && fill); - - // convert points from camera space (VX, VY, VZ) to screen space (X, Y, Z) - // (this appears to be wasted time with the OpenGL renderer) - endShapeCameraToScreen(shapeFirst, shapeLastPlusClipped); - - // render shape and fill here if not saving the shapes for later - // if true, the shapes will be rendered on endDraw - if (!hints[ENABLE_DEPTH_SORT]) { - if (fill) { - renderTriangles(0, triangleCount); - if (raw != null) { - rawTriangles(0, triangleCount); - } - triangleCount = 0; - } - if (stroke) { - renderLines(0, lineCount); - if (raw != null) { - rawLines(0, lineCount); - } - lineCount = 0; - } - pathCount = 0; - } - - shape = 0; - } - - - protected void endShapeModelToCamera(int start, int stop) { - for (int i = start; i < stop; i++) { - float vertex[] = vertices[i]; - - vertex[VX] = - modelview.m00*vertex[X] + modelview.m01*vertex[Y] + - modelview.m02*vertex[Z] + modelview.m03; - vertex[VY] = - modelview.m10*vertex[X] + modelview.m11*vertex[Y] + - modelview.m12*vertex[Z] + modelview.m13; - vertex[VZ] = - modelview.m20*vertex[X] + modelview.m21*vertex[Y] + - modelview.m22*vertex[Z] + modelview.m23; - vertex[VW] = - modelview.m30*vertex[X] + modelview.m31*vertex[Y] + - modelview.m32*vertex[Z] + modelview.m33; - - // normalize - if (vertex[VW] != 0 && vertex[VW] != 1) { - vertex[VX] /= vertex[VW]; - vertex[VY] /= vertex[VW]; - vertex[VZ] /= vertex[VW]; - } - vertex[VW] = 1; - } - } - - - protected void endShapeStroke(int mode) { - switch (shape) { - case POINTS: - { - int stop = shapeLast; - for (int i = shapeFirst; i < stop; i++) { - addLineBreak(); // total overkill for points - addLine(i, i); - } - } - break; - - case LINES: - { - // store index of first vertex - int first = lineCount; - int stop = shapeLast - 1; - //increment = (shape == LINES) ? 2 : 1; - - // for LINE_STRIP and LINE_LOOP, make this all one path - if (shape != LINES) addLineBreak(); - - for (int i = shapeFirst; i < stop; i += 2) { - // for LINES, make a new path for each segment - if (shape == LINES) addLineBreak(); - addLine(i, i+1); - } - - // for LINE_LOOP, close the loop with a final segment - //if (shape == LINE_LOOP) { - if (mode == CLOSE) { - addLine(stop, lines[first][VERTEX1]); - } - } - break; - - case TRIANGLES: - { - for (int i = shapeFirst; i < shapeLast-2; i += 3) { - addLineBreak(); - //counter = i - vertex_start; - addLine(i+0, i+1); - addLine(i+1, i+2); - addLine(i+2, i+0); - } - } - break; - - case TRIANGLE_STRIP: - { - // first draw all vertices as a line strip - int stop = shapeLast-1; - - addLineBreak(); - for (int i = shapeFirst; i < stop; i++) { - //counter = i - vertex_start; - addLine(i, i+1); - } - - // then draw from vertex (n) to (n+2) - stop = shapeLast-2; - for (int i = shapeFirst; i < stop; i++) { - addLineBreak(); - addLine(i, i+2); - } - } - break; - - case TRIANGLE_FAN: - { - // this just draws a series of line segments - // from the center to each exterior point - for (int i = shapeFirst + 1; i < shapeLast; i++) { - addLineBreak(); - addLine(shapeFirst, i); - } - - // then a single line loop around the outside. - addLineBreak(); - for (int i = shapeFirst + 1; i < shapeLast-1; i++) { - addLine(i, i+1); - } - // closing the loop - addLine(shapeLast-1, shapeFirst + 1); - } - break; - - case QUADS: - { - for (int i = shapeFirst; i < shapeLast; i += 4) { - addLineBreak(); - //counter = i - vertex_start; - addLine(i+0, i+1); - addLine(i+1, i+2); - addLine(i+2, i+3); - addLine(i+3, i+0); - } - } - break; - - case QUAD_STRIP: - { - for (int i = shapeFirst; i < shapeLast - 3; i += 2) { - addLineBreak(); - addLine(i+0, i+2); - addLine(i+2, i+3); - addLine(i+3, i+1); - addLine(i+1, i+0); - } - } - break; - - case POLYGON: - { - // store index of first vertex - int stop = shapeLast - 1; - - addLineBreak(); - for (int i = shapeFirst; i < stop; i++) { - addLine(i, i+1); - } - if (mode == CLOSE) { - // draw the last line connecting back to the first point in poly - addLine(stop, shapeFirst); //lines[first][VERTEX1]); - } - } - break; - } - } - - - protected void endShapeFill() { - switch (shape) { - case TRIANGLE_FAN: - { - int stop = shapeLast - 1; - for (int i = shapeFirst + 1; i < stop; i++) { - addTriangle(shapeFirst, i, i+1); - } - } - break; - - case TRIANGLES: - { - int stop = shapeLast - 2; - for (int i = shapeFirst; i < stop; i += 3) { - // have to switch between clockwise/counter-clockwise - // otherwise the feller is backwards and renderer won't draw - if ((i % 2) == 0) { - addTriangle(i, i+2, i+1); - } else { - addTriangle(i, i+1, i+2); - } - } - } - break; - - case TRIANGLE_STRIP: - { - int stop = shapeLast - 2; - for (int i = shapeFirst; i < stop; i++) { - // have to switch between clockwise/counter-clockwise - // otherwise the feller is backwards and renderer won't draw - if ((i % 2) == 0) { - addTriangle(i, i+2, i+1); - } else { - addTriangle(i, i+1, i+2); - } - } - } - break; - - case QUADS: - { - int stop = vertexCount-3; - for (int i = shapeFirst; i < stop; i += 4) { - // first triangle - addTriangle(i, i+1, i+2); - // second triangle - addTriangle(i, i+2, i+3); - } - } - break; - - case QUAD_STRIP: - { - int stop = vertexCount-3; - for (int i = shapeFirst; i < stop; i += 2) { - // first triangle - addTriangle(i+0, i+2, i+1); - // second triangle - addTriangle(i+2, i+3, i+1); - } - } - break; - - case POLYGON: - { - addPolygonTriangles(); - } - break; - } - } - - - protected void endShapeLighting(boolean lights) { - if (lights) { - // If the lighting does not depend on vertex position and there is a single - // normal specified for this shape, go ahead and apply the same lighting - // contribution to every vertex in this shape (one lighting calc!) - if (!lightingDependsOnVertexPosition && normalMode == NORMAL_MODE_SHAPE) { - calcLightingContribution(shapeFirst, tempLightingContribution); - for (int tri = 0; tri < triangleCount; tri++) { - lightTriangle(tri, tempLightingContribution); - } - } else { // Otherwise light each triangle individually... - for (int tri = 0; tri < triangleCount; tri++) { - lightTriangle(tri); - } - } - } else { - for (int tri = 0; tri < triangleCount; tri++) { - int index = triangles[tri][VERTEX1]; - copyPrelitVertexColor(tri, index, 0); - index = triangles[tri][VERTEX2]; - copyPrelitVertexColor(tri, index, 1); - index = triangles[tri][VERTEX3]; - copyPrelitVertexColor(tri, index, 2); - } - } - } - - - protected void endShapeCameraToScreen(int start, int stop) { - for (int i = start; i < stop; i++) { - float vx[] = vertices[i]; - - float ox = - projection.m00*vx[VX] + projection.m01*vx[VY] + - projection.m02*vx[VZ] + projection.m03*vx[VW]; - float oy = - projection.m10*vx[VX] + projection.m11*vx[VY] + - projection.m12*vx[VZ] + projection.m13*vx[VW]; - float oz = - projection.m20*vx[VX] + projection.m21*vx[VY] + - projection.m22*vx[VZ] + projection.m23*vx[VW]; - float ow = - projection.m30*vx[VX] + projection.m31*vx[VY] + - projection.m32*vx[VZ] + projection.m33*vx[VW]; - - if (ow != 0 && ow != 1) { - ox /= ow; oy /= ow; oz /= ow; - } - - vx[TX] = width * (1 + ox) / 2.0f; - vx[TY] = height * (1 + oy) / 2.0f; - vx[TZ] = (oz + 1) / 2.0f; - } - } - - - - ///////////////////////////////////////////////////////////////////////////// - - // POINTS - - - protected void addPoint(int a) { - if (pointCount == points.length) { - int[][] temp = new int[pointCount << 1][LINE_FIELD_COUNT]; - System.arraycopy(lines, 0, temp, 0, lineCount); - lines = temp; - } - points[pointCount][VERTEX1] = a; - //points[pointCount][STROKE_MODE] = strokeCap | strokeJoin; - points[pointCount][STROKE_COLOR] = strokeColor; - //points[pointCount][STROKE_WEIGHT] = (int) (strokeWeight + 0.5f); // hmm - pointCount++; - } - - - protected void renderPoints(int start, int stop) { - for (int i = start; i < stop; i++) { - float[] a = vertices[points[i][VERTEX1]]; - int sx = (int) (a[TX] + 0.4999f); - int sy = (int) (a[TY] + 0.4999f); - int index = sy*width + sx; - pixels[index] = points[i][STROKE_COLOR]; - zbuffer[index] = a[TZ]; - } - } - - - // alternative implementations of point rendering code... - - /* - int sx = (int) (screenX(x, y, z) + 0.5f); - int sy = (int) (screenY(x, y, z) + 0.5f); - - int index = sy*width + sx; - pixels[index] = strokeColor; - zbuffer[index] = screenZ(x, y, z); - - */ - - /* - protected void renderPoints(int start, int stop) { - for (int i = start; i < stop; i++) { - float a[] = vertices[points[i][VERTEX1]]; - - line.reset(); - - line.setIntensities(a[SR], a[SG], a[SB], a[SA], - a[SR], a[SG], a[SB], a[SA]); - - line.setVertices(a[TX], a[TY], a[TZ], - a[TX] + 0.5f, a[TY] + 0.5f, a[TZ] + 0.5f); - - line.draw(); - } - } - */ - - /* - // handle points with an actual stroke weight (or scaled by renderer) - private void point3(float x, float y, float z, int color) { - // need to get scaled version of the stroke - float x1 = screenX(x - 0.5f, y - 0.5f, z); - float y1 = screenY(x - 0.5f, y - 0.5f, z); - float x2 = screenX(x + 0.5f, y + 0.5f, z); - float y2 = screenY(x + 0.5f, y + 0.5f, z); - - float weight = (abs(x2 - x1) + abs(y2 - y1)) / 2f; - if (weight < 1.5f) { - int xx = (int) ((x1 + x2) / 2f); - int yy = (int) ((y1 + y2) / 2f); - //point0(xx, yy, z, color); - zbuffer[yy*width + xx] = screenZ(x, y, z); - //stencil? - - } else { - // actually has some weight, need to draw shapes instead - // these will be - } - } - */ - - - protected void rawPoints(int start, int stop) { - raw.colorMode(RGB, 1); - raw.noFill(); - raw.beginShape(POINTS); - - for (int i = start; i < stop; i++) { - float a[] = vertices[lines[i][VERTEX1]]; - - if (raw.is3D()) { - if (a[VW] != 0) { - raw.stroke(a[SR], a[SG], a[SB], a[SA]); - raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]); - } - } else { // if is2D() - raw.stroke(a[SR], a[SG], a[SB], a[SA]); - raw.vertex(a[TX], a[TY]); - } - } - raw.endShape(); - } - - - - ///////////////////////////////////////////////////////////////////////////// - - // LINES - - - /** - * Begin a new section of stroked geometry. - */ - protected final void addLineBreak() { - if (pathCount == pathOffset.length) { - pathOffset = PApplet.expand(pathOffset); - pathLength = PApplet.expand(pathLength); - } - pathOffset[pathCount] = lineCount; - pathLength[pathCount] = 0; - pathCount++; - } - - - protected void addLine(int a, int b) { - addLineWithClip(a, b); - } - - - protected final void addLineWithClip(int a, int b) { - float az = vertices[a][VZ]; - float bz = vertices[b][VZ]; - if (az > cameraNear) { - if (bz > cameraNear) { - return; - } - int cb = interpolateClipVertex(a, b); - addLineWithoutClip(cb, b); - return; - } - else { - if (bz <= cameraNear) { - addLineWithoutClip(a, b); - return; - } - int cb = interpolateClipVertex(a, b); - addLineWithoutClip(a, cb); - return; - } - } - - - protected final void addLineWithoutClip(int a, int b) { - if (lineCount == lines.length) { - int temp[][] = new int[lineCount<<1][LINE_FIELD_COUNT]; - System.arraycopy(lines, 0, temp, 0, lineCount); - lines = temp; - } - lines[lineCount][VERTEX1] = a; - lines[lineCount][VERTEX2] = b; - - //lines[lineCount][STROKE_MODE] = strokeCap | strokeJoin; - //lines[lineCount][STROKE_WEIGHT] = (int) (strokeWeight + 0.5f); // hmm - lineCount++; - - // mark this piece as being part of the current path - pathLength[pathCount-1]++; - } - - - protected void renderLines(int start, int stop) { - for (int i = start; i < stop; i++) { - float a[] = vertices[lines[i][VERTEX1]]; - float b[] = vertices[lines[i][VERTEX2]]; - - // 2D hack added by ewjordan 6/13/07 - // Offset coordinates by a little bit if drawing 2D graphics. - // http://dev.processing.org/bugs/show_bug.cgi?id=95 - - // This hack fixes a bug caused by numerical precision issues when - // applying the 3D transformations to coordinates in the screen plane - // that should actually not be altered under said transformations. - // It will not be applied if any transformations other than translations - // are active, nor should it apply in OpenGL mode (PGraphicsOpenGL - // overrides render_lines(), so this should be fine). - // This fix exposes a last-pixel bug in the lineClipCode() function - // of PLine.java, so that fix must remain in place if this one is used. - - // Note: the "true" fix for this bug is to change the pixel coverage - // model so that the threshold for display does not lie on an integer - // boundary. Search "diamond exit rule" for info the OpenGL approach. - - /* - // removing for 0149 with the return of P2D - if (drawing2D() && a[Z] == 0) { - a[TX] += 0.01; - a[TY] += 0.01; - a[VX] += 0.01*a[VW]; - a[VY] += 0.01*a[VW]; - b[TX] += 0.01; - b[TY] += 0.01; - b[VX] += 0.01*b[VW]; - b[VY] += 0.01*b[VW]; - } - */ - // end 2d-hack - - if (a[SW] > 1.25f || a[SW] < 0.75f) { - float ox1 = a[TX]; - float oy1 = a[TY]; - float ox2 = b[TX]; - float oy2 = b[TY]; - - float dX = ox2 - ox1 + EPSILON; - float dY = oy2 - oy1 + EPSILON; - float len = (float) Math.sqrt(dX*dX + dY*dY); - - // TODO strokeWidth should be transformed! - float rh = a[SW] / len; - - float dx0 = rh * dY; - float dy0 = rh * dX; - float dx1 = rh * dY; - float dy1 = rh * dX; - - float ax1 = ox1+dx0; - float ay1 = oy1-dy0; - - float ax2 = ox1-dx0; - float ay2 = oy1+dy0; - - float bx1 = ox2+dx1; - float by1 = oy2-dy1; - - float bx2 = ox2-dx1; - float by2 = oy2+dy1; - - triangle.reset(); - - // render first triangle for thick line - triangle.setVertices(ax1, ay1, a[TZ], - bx2, by2, b[TZ], - ax2, ay2, a[TZ]); - triangle.setIntensities(a[SR], a[SG], a[SB], a[SA], - b[SR], b[SG], b[SB], b[SA], - a[SR], a[SG], a[SB], a[SA]); - triangle.render(); - - // render second triangle for thick line - triangle.setVertices(ax1, ay1, a[TZ], - bx2, by2, b[TZ], - bx1, by1, b[TZ]); - triangle.setIntensities(a[SR], a[SG], a[SB], a[SA], - b[SR], b[SG], b[SB], b[SA], - b[SR], b[SG], b[SB], b[SA]); - triangle.render(); - - } else { - line.reset(); - - line.setIntensities(a[SR], a[SG], a[SB], a[SA], - b[SR], b[SG], b[SB], b[SA]); - - line.setVertices(a[TX], a[TY], a[TZ], - b[TX], b[TY], b[TZ]); - - /* - // Seems okay to remove this because these vertices are not used again, - // but if problems arise, this needs to be uncommented because the above - // change is destructive and may need to be undone before proceeding. - if (drawing2D() && a[MZ] == 0) { - a[X] -= 0.01; - a[Y] -= 0.01; - a[VX] -= 0.01*a[VW]; - a[VY] -= 0.01*a[VW]; - b[X] -= 0.01; - b[Y] -= 0.01; - b[VX] -= 0.01*b[VW]; - b[VY] -= 0.01*b[VW]; - } - */ - - line.draw(); - } - } - } - - - /** - * Handle echoing line data to a raw shape recording renderer. This has been - * broken out of the renderLines() procedure so that renderLines() can be - * optimized per-renderer without having to deal with this code. This code, - * for instance, will stay the same when OpenGL is in use, but renderLines() - * can be optimized significantly. - *

- * Values for start and stop are specified, so that in the future, sorted - * rendering can be implemented, which will require sequences of lines, - * triangles, or points to be rendered in the neighborhood of one another. - * That is, if we're gonna depth sort, we can't just draw all the triangles - * and then draw all the lines, cuz that defeats the purpose. - */ - protected void rawLines(int start, int stop) { - raw.colorMode(RGB, 1); - raw.noFill(); - raw.beginShape(LINES); - - //for (int i = 0; i < lineCount; i ++) { - for (int i = start; i < stop; i++) { - float a[] = vertices[lines[i][VERTEX1]]; - float b[] = vertices[lines[i][VERTEX2]]; - - if (raw.is3D()) { - if ((a[VW] != 0) && (b[VW] != 0)) { - raw.stroke(a[SR], a[SG], a[SB], a[SA]); - raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]); - raw.stroke(b[SR], b[SG], b[SB], b[SA]); - raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW]); - } - } else if (raw.is2D()) { - raw.stroke(a[SR], a[SG], a[SB], a[SA]); - raw.vertex(a[TX], a[TY]); - raw.stroke(b[SR], b[SG], b[SB], b[SA]); - raw.vertex(b[TX], b[TY]); - } - } - raw.endShape(); - } - - - - ///////////////////////////////////////////////////////////////////////////// - - // TRIANGLES - - - protected void addTriangle(int a, int b, int c) { - addTriangleWithClip(a, b, c); - } - - - protected final void addTriangleWithClip(int a, int b, int c) { - boolean aClipped = false; - boolean bClipped = false; - int clippedCount = 0; - - cameraNear = -8; - if (vertices[a][VZ] > cameraNear) { - aClipped = true; - clippedCount++; - } - if (vertices[b][VZ] > cameraNear) { - bClipped = true; - clippedCount++; - } - if (vertices[c][VZ] > cameraNear) { - //cClipped = true; - clippedCount++; - } - if (clippedCount == 0) { - addTriangleWithoutClip(a, b, c); - - } else if (clippedCount == 3) { - // In this case there is only one visible point. |/| - // So we'll have to make two new points on the clip line <| | - // and add that triangle instead. |\| - - } else if (clippedCount == 2) { - //System.out.println("Clipped two"); - - int ca, cb, cc, cd, ce; - if (!aClipped) { - ca = a; - cb = b; - cc = c; - } - else if (!bClipped) { - ca = b; - cb = a; - cc = c; - } - else { //if (!cClipped) { - ca = c; - cb = b; - cc = a; - } - - cd = interpolateClipVertex(ca, cb); - ce = interpolateClipVertex(ca, cc); - addTriangleWithoutClip(ca, cd, ce); - - } else { // (clippedCount == 1) { - // . | - // In this case there are two visible points. |\| - // So we'll have to make two new points on the clip line | |> - // and then add two new triangles. |/| - // . | - //System.out.println("Clipped one"); - int ca, cb, cc, cd, ce; - if (aClipped) { - //System.out.println("aClipped"); - ca = c; - cb = b; - cc = a; - } - else if (bClipped) { - //System.out.println("bClipped"); - ca = a; - cb = c; - cc = b; - } - else { //if (cClipped) { - //System.out.println("cClipped"); - ca = a; - cb = b; - cc = c; - } - - cd = interpolateClipVertex(ca, cc); - ce = interpolateClipVertex(cb, cc); - addTriangleWithoutClip(ca, cd, cb); - //System.out.println("ca: " + ca + ", " + vertices[ca][VX] + ", " + vertices[ca][VY] + ", " + vertices[ca][VZ]); - //System.out.println("cd: " + cd + ", " + vertices[cd][VX] + ", " + vertices[cd][VY] + ", " + vertices[cd][VZ]); - //System.out.println("cb: " + cb + ", " + vertices[cb][VX] + ", " + vertices[cb][VY] + ", " + vertices[cb][VZ]); - addTriangleWithoutClip(cb, cd, ce); - } - } - - - protected final int interpolateClipVertex(int a, int b) { - float[] va; - float[] vb; - // Set up va, vb such that va[VZ] >= vb[VZ] - if (vertices[a][VZ] < vertices[b][VZ]) { - va = vertices[b]; - vb = vertices[a]; - } - else { - va = vertices[a]; - vb = vertices[b]; - } - float az = va[VZ]; - float bz = vb[VZ]; - - float dz = az - bz; - // If they have the same z, just use pt. a. - if (dz == 0) { - return a; - } - //float pa = (az - cameraNear) / dz; - //float pb = (cameraNear - bz) / dz; - float pa = (cameraNear - bz) / dz; - float pb = 1 - pa; - - vertex(pa * va[X] + pb * vb[X], - pa * va[Y] + pb * vb[Y], - pa * va[Z] + pb * vb[Z]); - int irv = vertexCount - 1; - shapeLastPlusClipped++; - - float[] rv = vertices[irv]; - - rv[TX] = pa * va[TX] + pb * vb[TX]; - rv[TY] = pa * va[TY] + pb * vb[TY]; - rv[TZ] = pa * va[TZ] + pb * vb[TZ]; - - rv[VX] = pa * va[VX] + pb * vb[VX]; - rv[VY] = pa * va[VY] + pb * vb[VY]; - rv[VZ] = pa * va[VZ] + pb * vb[VZ]; - rv[VW] = pa * va[VW] + pb * vb[VW]; - - rv[R] = pa * va[R] + pb * vb[R]; - rv[G] = pa * va[G] + pb * vb[G]; - rv[B] = pa * va[B] + pb * vb[B]; - rv[A] = pa * va[A] + pb * vb[A]; - - rv[U] = pa * va[U] + pb * vb[U]; - rv[V] = pa * va[V] + pb * vb[V]; - - rv[SR] = pa * va[SR] + pb * vb[SR]; - rv[SG] = pa * va[SG] + pb * vb[SG]; - rv[SB] = pa * va[SB] + pb * vb[SB]; - rv[SA] = pa * va[SA] + pb * vb[SA]; - - rv[NX] = pa * va[NX] + pb * vb[NX]; - rv[NY] = pa * va[NY] + pb * vb[NY]; - rv[NZ] = pa * va[NZ] + pb * vb[NZ]; - -// rv[SW] = pa * va[SW] + pb * vb[SW]; - - rv[AR] = pa * va[AR] + pb * vb[AR]; - rv[AG] = pa * va[AG] + pb * vb[AG]; - rv[AB] = pa * va[AB] + pb * vb[AB]; - - rv[SPR] = pa * va[SPR] + pb * vb[SPR]; - rv[SPG] = pa * va[SPG] + pb * vb[SPG]; - rv[SPB] = pa * va[SPB] + pb * vb[SPB]; - //rv[SPA] = pa * va[SPA] + pb * vb[SPA]; - - rv[ER] = pa * va[ER] + pb * vb[ER]; - rv[EG] = pa * va[EG] + pb * vb[EG]; - rv[EB] = pa * va[EB] + pb * vb[EB]; - - rv[SHINE] = pa * va[SHINE] + pb * vb[SHINE]; - - rv[BEEN_LIT] = 0; - - return irv; - } - - - protected final void addTriangleWithoutClip(int a, int b, int c) { - if (triangleCount == triangles.length) { - int temp[][] = new int[triangleCount<<1][TRIANGLE_FIELD_COUNT]; - System.arraycopy(triangles, 0, temp, 0, triangleCount); - triangles = temp; - //message(CHATTER, "allocating more triangles " + triangles.length); - float ftemp[][][] = new float[triangleCount<<1][3][TRI_COLOR_COUNT]; - System.arraycopy(triangleColors, 0, ftemp, 0, triangleCount); - triangleColors = ftemp; - } - triangles[triangleCount][VERTEX1] = a; - triangles[triangleCount][VERTEX2] = b; - triangles[triangleCount][VERTEX3] = c; - - if (textureImage == null) { - triangles[triangleCount][TEXTURE_INDEX] = -1; - } else { - triangles[triangleCount][TEXTURE_INDEX] = textureIndex; - } - -// triangles[triangleCount][INDEX] = shape_index; - triangleCount++; - } - - - /** - * Triangulate the current polygon. - *

- * Simple ear clipping polygon triangulation adapted from code by - * John W. Ratcliff (jratcliff at verant.com). Presumably - * this - * bit of code from the web. - */ - protected void addPolygonTriangles() { - if (vertexOrder.length != vertices.length) { - int[] temp = new int[vertices.length]; - // since vertex_start may not be zero, might need to keep old stuff around - PApplet.arrayCopy(vertexOrder, temp, vertexCount); - vertexOrder = temp; - } - - // this clipping algorithm only works in 2D, so in cases where a - // polygon is drawn perpendicular to the z-axis, the area will be zero, - // and triangulation will fail. as such, when the area calculates to - // zero, figure out whether x or y is empty, and calculate based on the - // two dimensions that actually contain information. - // http://dev.processing.org/bugs/show_bug.cgi?id=111 - int d1 = X; - int d2 = Y; - // this brings up the nastier point that there may be cases where - // a polygon is irregular in space and will throw off the - // clockwise/counterclockwise calculation. for instance, if clockwise - // relative to x and z, but counter relative to y and z or something - // like that.. will wait to see if this is in fact a problem before - // hurting my head on the math. - - /* - // trying to track down bug #774 - for (int i = vertex_start; i < vertex_end; i++) { - if (i > vertex_start) { - if (vertices[i-1][MX] == vertices[i][MX] && - vertices[i-1][MY] == vertices[i][MY]) { - System.out.print("**** " ); - } - } - System.out.println(i + " " + vertices[i][MX] + " " + vertices[i][MY]); - } - System.out.println(); - */ - - // first we check if the polygon goes clockwise or counterclockwise - float area = 0; - for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) { - area += (vertices[q][d1] * vertices[p][d2] - - vertices[p][d1] * vertices[q][d2]); - } - // rather than checking for the perpendicular case first, only do it - // when the area calculates to zero. checking for perpendicular would be - // a needless waste of time for the 99% case. - if (area == 0) { - // figure out which dimension is the perpendicular axis - boolean foundValidX = false; - boolean foundValidY = false; - - for (int i = shapeFirst; i < shapeLast; i++) { - for (int j = i; j < shapeLast; j++){ - if ( vertices[i][X] != vertices[j][X] ) foundValidX = true; - if ( vertices[i][Y] != vertices[j][Y] ) foundValidY = true; - } - } - - if (foundValidX) { - //d1 = MX; // already the case - d2 = Z; - } else if (foundValidY) { - // ermm.. which is the proper order for cw/ccw here? - d1 = Y; - d2 = Z; - } else { - // screw it, this polygon is just f-ed up - return; - } - - // re-calculate the area, with what should be good values - for (int p = shapeLast - 1, q = shapeFirst; q < shapeLast; p = q++) { - area += (vertices[q][d1] * vertices[p][d2] - - vertices[p][d1] * vertices[q][d2]); - } - } - - // don't allow polygons to come back and meet themselves, - // otherwise it will anger the triangulator - // http://dev.processing.org/bugs/show_bug.cgi?id=97 - float vfirst[] = vertices[shapeFirst]; - float vlast[] = vertices[shapeLast-1]; - if ((abs(vfirst[X] - vlast[X]) < EPSILON) && - (abs(vfirst[Y] - vlast[Y]) < EPSILON) && - (abs(vfirst[Z] - vlast[Z]) < EPSILON)) { - shapeLast--; - } - - // then sort the vertices so they are always in a counterclockwise order - int j = 0; - if (area > 0) { - for (int i = shapeFirst; i < shapeLast; i++) { - j = i - shapeFirst; - vertexOrder[j] = i; - } - } else { - for (int i = shapeFirst; i < shapeLast; i++) { - j = i - shapeFirst; - vertexOrder[j] = (shapeLast - 1) - j; - } - } - - // remove vc-2 Vertices, creating 1 triangle every time - int vc = shapeLast - shapeFirst; - int count = 2*vc; // complex polygon detection - - for (int m = 0, v = vc - 1; vc > 2; ) { - boolean snip = true; - - // if we start over again, is a complex polygon - if (0 >= (count--)) { - break; // triangulation failed - } - - // get 3 consecutive vertices - int u = v ; if (vc <= u) u = 0; // previous - v = u + 1; if (vc <= v) v = 0; // current - int w = v + 1; if (vc <= w) w = 0; // next - - // Upgrade values to doubles, and multiply by 10 so that we can have - // some better accuracy as we tessellate. This seems to have negligible - // speed differences on Windows and Intel Macs, but causes a 50% speed - // drop for PPC Macs with the bug's example code that draws ~200 points - // in a concave polygon. Apple has abandoned PPC so we may as well too. - // http://dev.processing.org/bugs/show_bug.cgi?id=774 - - // triangle A B C - double Ax = -10 * vertices[vertexOrder[u]][d1]; - double Ay = 10 * vertices[vertexOrder[u]][d2]; - double Bx = -10 * vertices[vertexOrder[v]][d1]; - double By = 10 * vertices[vertexOrder[v]][d2]; - double Cx = -10 * vertices[vertexOrder[w]][d1]; - double Cy = 10 * vertices[vertexOrder[w]][d2]; - - // first we check if continues going ccw - if (EPSILON > (((Bx-Ax) * (Cy-Ay)) - ((By-Ay) * (Cx-Ax)))) { - continue; - } - - for (int p = 0; p < vc; p++) { - if ((p == u) || (p == v) || (p == w)) { - continue; - } - - double Px = -10 * vertices[vertexOrder[p]][d1]; - double Py = 10 * vertices[vertexOrder[p]][d2]; - - double ax = Cx - Bx; double ay = Cy - By; - double bx = Ax - Cx; double by = Ay - Cy; - double cx = Bx - Ax; double cy = By - Ay; - double apx = Px - Ax; double apy = Py - Ay; - double bpx = Px - Bx; double bpy = Py - By; - double cpx = Px - Cx; double cpy = Py - Cy; - - double aCROSSbp = ax * bpy - ay * bpx; - double cCROSSap = cx * apy - cy * apx; - double bCROSScp = bx * cpy - by * cpx; - - if ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0)) { - snip = false; - } - } - - if (snip) { - addTriangle(vertexOrder[u], vertexOrder[v], vertexOrder[w]); - - m++; - - // remove v from remaining polygon - for (int s = v, t = v + 1; t < vc; s++, t++) { - vertexOrder[s] = vertexOrder[t]; - } - vc--; - - // reset error detection counter - count = 2 * vc; - } - } - } - - - private void toWorldNormal(float nx, float ny, float nz, float[] out) { - out[0] = - modelviewInv.m00*nx + modelviewInv.m10*ny + - modelviewInv.m20*nz + modelviewInv.m30; - out[1] = - modelviewInv.m01*nx + modelviewInv.m11*ny + - modelviewInv.m21*nz + modelviewInv.m31; - out[2] = - modelviewInv.m02*nx + modelviewInv.m12*ny + - modelviewInv.m22*nz + modelviewInv.m32; - out[3] = - modelviewInv.m03*nx + modelviewInv.m13*ny + - modelviewInv.m23*nz + modelviewInv.m33; - - if (out[3] != 0 && out[3] != 1) { - // divide by perspective coordinate - out[0] /= out[3]; out[1] /= out[3]; out[2] /= out[3]; - } - out[3] = 1; - - float nlen = mag(out[0], out[1], out[2]); // normalize - if (nlen != 0 && nlen != 1) { - out[0] /= nlen; out[1] /= nlen; out[2] /= nlen; - } - } - - - //private PVector calcLightingNorm = new PVector(); - //private PVector calcLightingWorldNorm = new PVector(); - float[] worldNormal = new float[4]; - - - private void calcLightingContribution(int vIndex, - float[] contribution) { - calcLightingContribution(vIndex, contribution, false); - } - - - private void calcLightingContribution(int vIndex, - float[] contribution, - boolean normalIsWorld) { - float[] v = vertices[vIndex]; - - float sr = v[SPR]; - float sg = v[SPG]; - float sb = v[SPB]; - - float wx = v[VX]; - float wy = v[VY]; - float wz = v[VZ]; - float shine = v[SHINE]; - - float nx = v[NX]; - float ny = v[NY]; - float nz = v[NZ]; - - if (!normalIsWorld) { -// System.out.println("um, hello?"); -// calcLightingNorm.set(nx, ny, nz); -// //modelviewInv.mult(calcLightingNorm, calcLightingWorldNorm); -// -//// PMatrix3D mvi = modelViewInv; -//// float ox = mvi.m00*nx + mvi.m10*ny + mvi*m20+nz + -// modelviewInv.cmult(calcLightingNorm, calcLightingWorldNorm); -// -// calcLightingWorldNorm.normalize(); -// nx = calcLightingWorldNorm.x; -// ny = calcLightingWorldNorm.y; -// nz = calcLightingWorldNorm.z; - - toWorldNormal(v[NX], v[NY], v[NZ], worldNormal); - nx = worldNormal[X]; - ny = worldNormal[Y]; - nz = worldNormal[Z]; - -// float wnx = modelviewInv.multX(nx, ny, nz); -// float wny = modelviewInv.multY(nx, ny, nz); -// float wnz = modelviewInv.multZ(nx, ny, nz); -// float wnw = modelviewInv.multW(nx, ny, nz); - -// if (wnw != 0 && wnw != 1) { -// wnx /= wnw; -// wny /= wnw; -// wnz /= wnw; -// } -// float nlen = mag(wnx, wny, wnw); -// if (nlen != 0 && nlen != 1) { -// nx = wnx / nlen; -// ny = wny / nlen; -// nz = wnz / nlen; -// } else { -// nx = wnx; -// ny = wny; -// nz = wnz; -// } -// */ - } else { - nx = v[NX]; - ny = v[NY]; - nz = v[NZ]; - } - - // Since the camera space == world space, - // we can test for visibility by the dot product of - // the normal with the direction from pt. to eye. - float dir = dot(nx, ny, nz, -wx, -wy, -wz); - // If normal is away from camera, choose its opposite. - // If we add backface culling, this will be backfacing - // (but since this is per vertex, it's more complicated) - if (dir < 0) { - nx = -nx; - ny = -ny; - nz = -nz; - } - - // These two terms will sum the contributions from the various lights - contribution[LIGHT_AMBIENT_R] = 0; - contribution[LIGHT_AMBIENT_G] = 0; - contribution[LIGHT_AMBIENT_B] = 0; - - contribution[LIGHT_DIFFUSE_R] = 0; - contribution[LIGHT_DIFFUSE_G] = 0; - contribution[LIGHT_DIFFUSE_B] = 0; - - contribution[LIGHT_SPECULAR_R] = 0; - contribution[LIGHT_SPECULAR_G] = 0; - contribution[LIGHT_SPECULAR_B] = 0; - - // for (int i = 0; i < MAX_LIGHTS; i++) { - // if (!light[i]) continue; - for (int i = 0; i < lightCount; i++) { - - float denom = lightFalloffConstant[i]; - float spotTerm = 1; - - if (lightType[i] == AMBIENT) { - if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) { - // Falloff depends on distance - float distSq = mag(lightPosition[i].x - wx, - lightPosition[i].y - wy, - lightPosition[i].z - wz); - denom += - lightFalloffQuadratic[i] * distSq + - lightFalloffLinear[i] * sqrt(distSq); - } - if (denom == 0) denom = 1; - - contribution[LIGHT_AMBIENT_R] += lightDiffuse[i][0] / denom; - contribution[LIGHT_AMBIENT_G] += lightDiffuse[i][1] / denom; - contribution[LIGHT_AMBIENT_B] += lightDiffuse[i][2] / denom; - - } else { - // If not ambient, we must deal with direction - - // li is the vector from the vertex to the light - float lix, liy, liz; - float lightDir_dot_li = 0; - float n_dot_li = 0; - - if (lightType[i] == DIRECTIONAL) { - lix = -lightNormal[i].x; - liy = -lightNormal[i].y; - liz = -lightNormal[i].z; - denom = 1; - n_dot_li = (nx * lix + ny * liy + nz * liz); - // If light is lighting the face away from the camera, ditch - if (n_dot_li <= 0) { - continue; - } - } else { // Point or spot light (must deal also with light location) - lix = lightPosition[i].x - wx; - liy = lightPosition[i].y - wy; - liz = lightPosition[i].z - wz; - // normalize - float distSq = mag(lix, liy, liz); - if (distSq != 0) { - lix /= distSq; - liy /= distSq; - liz /= distSq; - } - n_dot_li = (nx * lix + ny * liy + nz * liz); - // If light is lighting the face away from the camera, ditch - if (n_dot_li <= 0) { - continue; - } - - if (lightType[i] == SPOT) { // Must deal with spot cone - lightDir_dot_li = - -(lightNormal[i].x * lix + - lightNormal[i].y * liy + - lightNormal[i].z * liz); - // Outside of spot cone - if (lightDir_dot_li <= lightSpotAngleCos[i]) { - continue; - } - spotTerm = (float) Math.pow(lightDir_dot_li, lightSpotConcentration[i]); - } - - if (lightFalloffQuadratic[i] != 0 || lightFalloffLinear[i] != 0) { - // Falloff depends on distance - denom += - lightFalloffQuadratic[i] * distSq + - lightFalloffLinear[i] * (float) sqrt(distSq); - } - } - // Directional, point, or spot light: - - // We know n_dot_li > 0 from above "continues" - - if (denom == 0) - denom = 1; - float mul = n_dot_li * spotTerm / denom; - contribution[LIGHT_DIFFUSE_R] += lightDiffuse[i][0] * mul; - contribution[LIGHT_DIFFUSE_G] += lightDiffuse[i][1] * mul; - contribution[LIGHT_DIFFUSE_B] += lightDiffuse[i][2] * mul; - - // SPECULAR - - // If the material and light have a specular component. - if ((sr > 0 || sg > 0 || sb > 0) && - (lightSpecular[i][0] > 0 || - lightSpecular[i][1] > 0 || - lightSpecular[i][2] > 0)) { - - float vmag = mag(wx, wy, wz); - if (vmag != 0) { - wx /= vmag; - wy /= vmag; - wz /= vmag; - } - float sx = lix - wx; - float sy = liy - wy; - float sz = liz - wz; - vmag = mag(sx, sy, sz); - if (vmag != 0) { - sx /= vmag; - sy /= vmag; - sz /= vmag; - } - float s_dot_n = (sx * nx + sy * ny + sz * nz); - - if (s_dot_n > 0) { - s_dot_n = (float) Math.pow(s_dot_n, shine); - mul = s_dot_n * spotTerm / denom; - contribution[LIGHT_SPECULAR_R] += lightSpecular[i][0] * mul; - contribution[LIGHT_SPECULAR_G] += lightSpecular[i][1] * mul; - contribution[LIGHT_SPECULAR_B] += lightSpecular[i][2] * mul; - } - - } - } - } - return; - } - - - // Multiply the lighting contribution into the vertex's colors. - // Only do this when there is ONE lighting per vertex - // (MANUAL_VERTEX_NORMAL or SHAPE_NORMAL mode). - private void applyLightingContribution(int vIndex, float[] contribution) { - float[] v = vertices[vIndex]; - - v[R] = clamp(v[ER] + v[AR] * contribution[LIGHT_AMBIENT_R] + v[DR] * contribution[LIGHT_DIFFUSE_R]); - v[G] = clamp(v[EG] + v[AG] * contribution[LIGHT_AMBIENT_G] + v[DG] * contribution[LIGHT_DIFFUSE_G]); - v[B] = clamp(v[EB] + v[AB] * contribution[LIGHT_AMBIENT_B] + v[DB] * contribution[LIGHT_DIFFUSE_B]); - v[A] = clamp(v[DA]); - - v[SPR] = clamp(v[SPR] * contribution[LIGHT_SPECULAR_R]); - v[SPG] = clamp(v[SPG] * contribution[LIGHT_SPECULAR_G]); - v[SPB] = clamp(v[SPB] * contribution[LIGHT_SPECULAR_B]); - //v[SPA] = min(1, v[SPA]); - - v[BEEN_LIT] = 1; - } - - - private void lightVertex(int vIndex, float[] contribution) { - calcLightingContribution(vIndex, contribution); - applyLightingContribution(vIndex, contribution); - } - - - private void lightUnlitVertex(int vIndex, float[] contribution) { - if (vertices[vIndex][BEEN_LIT] == 0) { - lightVertex(vIndex, contribution); - } - } - - - private void copyPrelitVertexColor(int triIndex, int index, int colorIndex) { - float[] triColor = triangleColors[triIndex][colorIndex]; - float[] v = vertices[index]; - - triColor[TRI_DIFFUSE_R] = v[R]; - triColor[TRI_DIFFUSE_G] = v[G]; - triColor[TRI_DIFFUSE_B] = v[B]; - triColor[TRI_DIFFUSE_A] = v[A]; - triColor[TRI_SPECULAR_R] = v[SPR]; - triColor[TRI_SPECULAR_G] = v[SPG]; - triColor[TRI_SPECULAR_B] = v[SPB]; - //triColor[TRI_SPECULAR_A] = v[SPA]; - } - - - private void copyVertexColor(int triIndex, int index, int colorIndex, - float[] contrib) { - float[] triColor = triangleColors[triIndex][colorIndex]; - float[] v = vertices[index]; - - triColor[TRI_DIFFUSE_R] = - clamp(v[ER] + v[AR] * contrib[LIGHT_AMBIENT_R] + v[DR] * contrib[LIGHT_DIFFUSE_R]); - triColor[TRI_DIFFUSE_G] = - clamp(v[EG] + v[AG] * contrib[LIGHT_AMBIENT_G] + v[DG] * contrib[LIGHT_DIFFUSE_G]); - triColor[TRI_DIFFUSE_B] = - clamp(v[EB] + v[AB] * contrib[LIGHT_AMBIENT_B] + v[DB] * contrib[LIGHT_DIFFUSE_B]); - triColor[TRI_DIFFUSE_A] = clamp(v[DA]); - - triColor[TRI_SPECULAR_R] = clamp(v[SPR] * contrib[LIGHT_SPECULAR_R]); - triColor[TRI_SPECULAR_G] = clamp(v[SPG] * contrib[LIGHT_SPECULAR_G]); - triColor[TRI_SPECULAR_B] = clamp(v[SPB] * contrib[LIGHT_SPECULAR_B]); - } - - - private void lightTriangle(int triIndex, float[] lightContribution) { - int vIndex = triangles[triIndex][VERTEX1]; - copyVertexColor(triIndex, vIndex, 0, lightContribution); - vIndex = triangles[triIndex][VERTEX2]; - copyVertexColor(triIndex, vIndex, 1, lightContribution); - vIndex = triangles[triIndex][VERTEX3]; - copyVertexColor(triIndex, vIndex, 2, lightContribution); - } - - - private void lightTriangle(int triIndex) { - int vIndex; - - // Handle lighting on, but no lights (in this case, just use emissive) - // This wont be used currently because lightCount == 0 is don't use - // lighting at all... So. OK. If that ever changes, use the below: - /* - if (lightCount == 0) { - vIndex = triangles[triIndex][VERTEX1]; - copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 0); - vIndex = triangles[triIndex][VERTEX2]; - copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 1); - vIndex = triangles[triIndex][VERTEX3]; - copy_emissive_vertex_color_to_triangle(triIndex, vIndex, 2); - return; - } - */ - - // In MANUAL_VERTEX_NORMAL mode, we have a specific normal - // for each vertex. In that case, we light any verts that - // haven't already been lit and copy their colors straight - // into the triangle. - if (normalMode == NORMAL_MODE_VERTEX) { - vIndex = triangles[triIndex][VERTEX1]; - lightUnlitVertex(vIndex, tempLightingContribution); - copyPrelitVertexColor(triIndex, vIndex, 0); - - vIndex = triangles[triIndex][VERTEX2]; - lightUnlitVertex(vIndex, tempLightingContribution); - copyPrelitVertexColor(triIndex, vIndex, 1); - - vIndex = triangles[triIndex][VERTEX3]; - lightUnlitVertex(vIndex, tempLightingContribution); - copyPrelitVertexColor(triIndex, vIndex, 2); - - } - - // If the lighting doesn't depend on the vertex position, do the - // following: We've already dealt with NORMAL_MODE_SHAPE mode before - // we got into this function, so here we only have to deal with - // NORMAL_MODE_AUTO. So we calculate the normal for this triangle, - // and use that for the lighting. - else if (!lightingDependsOnVertexPosition) { - vIndex = triangles[triIndex][VERTEX1]; - int vIndex2 = triangles[triIndex][VERTEX2]; - int vIndex3 = triangles[triIndex][VERTEX3]; - - /* - dv1[0] = vertices[vIndex2][VX] - vertices[vIndex][VX]; - dv1[1] = vertices[vIndex2][VY] - vertices[vIndex][VY]; - dv1[2] = vertices[vIndex2][VZ] - vertices[vIndex][VZ]; - - dv2[0] = vertices[vIndex3][VX] - vertices[vIndex][VX]; - dv2[1] = vertices[vIndex3][VY] - vertices[vIndex][VY]; - dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ]; - - cross(dv1, dv2, norm); - */ - - cross(vertices[vIndex2][VX] - vertices[vIndex][VX], - vertices[vIndex2][VY] - vertices[vIndex][VY], - vertices[vIndex2][VZ] - vertices[vIndex][VZ], - vertices[vIndex3][VX] - vertices[vIndex][VX], - vertices[vIndex3][VY] - vertices[vIndex][VY], - vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm); - - lightTriangleNorm.normalize(); - vertices[vIndex][NX] = lightTriangleNorm.x; - vertices[vIndex][NY] = lightTriangleNorm.y; - vertices[vIndex][NZ] = lightTriangleNorm.z; - - // The true at the end says the normal is already in world coordinates - calcLightingContribution(vIndex, tempLightingContribution, true); - copyVertexColor(triIndex, vIndex, 0, tempLightingContribution); - copyVertexColor(triIndex, vIndex2, 1, tempLightingContribution); - copyVertexColor(triIndex, vIndex3, 2, tempLightingContribution); - } - - // If lighting is position-dependent - else { - if (normalMode == NORMAL_MODE_SHAPE) { - vIndex = triangles[triIndex][VERTEX1]; - vertices[vIndex][NX] = vertices[shapeFirst][NX]; - vertices[vIndex][NY] = vertices[shapeFirst][NY]; - vertices[vIndex][NZ] = vertices[shapeFirst][NZ]; - calcLightingContribution(vIndex, tempLightingContribution); - copyVertexColor(triIndex, vIndex, 0, tempLightingContribution); - - vIndex = triangles[triIndex][VERTEX2]; - vertices[vIndex][NX] = vertices[shapeFirst][NX]; - vertices[vIndex][NY] = vertices[shapeFirst][NY]; - vertices[vIndex][NZ] = vertices[shapeFirst][NZ]; - calcLightingContribution(vIndex, tempLightingContribution); - copyVertexColor(triIndex, vIndex, 1, tempLightingContribution); - - vIndex = triangles[triIndex][VERTEX3]; - vertices[vIndex][NX] = vertices[shapeFirst][NX]; - vertices[vIndex][NY] = vertices[shapeFirst][NY]; - vertices[vIndex][NZ] = vertices[shapeFirst][NZ]; - calcLightingContribution(vIndex, tempLightingContribution); - copyVertexColor(triIndex, vIndex, 2, tempLightingContribution); - } - - // lighting mode is AUTO_NORMAL - else { - vIndex = triangles[triIndex][VERTEX1]; - int vIndex2 = triangles[triIndex][VERTEX2]; - int vIndex3 = triangles[triIndex][VERTEX3]; - - /* - dv1[0] = vertices[vIndex2][VX] - vertices[vIndex][VX]; - dv1[1] = vertices[vIndex2][VY] - vertices[vIndex][VY]; - dv1[2] = vertices[vIndex2][VZ] - vertices[vIndex][VZ]; - - dv2[0] = vertices[vIndex3][VX] - vertices[vIndex][VX]; - dv2[1] = vertices[vIndex3][VY] - vertices[vIndex][VY]; - dv2[2] = vertices[vIndex3][VZ] - vertices[vIndex][VZ]; - - cross(dv1, dv2, norm); - */ - - cross(vertices[vIndex2][VX] - vertices[vIndex][VX], - vertices[vIndex2][VY] - vertices[vIndex][VY], - vertices[vIndex2][VZ] - vertices[vIndex][VZ], - vertices[vIndex3][VX] - vertices[vIndex][VX], - vertices[vIndex3][VY] - vertices[vIndex][VY], - vertices[vIndex3][VZ] - vertices[vIndex][VZ], lightTriangleNorm); -// float nmag = mag(norm[X], norm[Y], norm[Z]); -// if (nmag != 0 && nmag != 1) { -// norm[X] /= nmag; norm[Y] /= nmag; norm[Z] /= nmag; -// } - lightTriangleNorm.normalize(); - vertices[vIndex][NX] = lightTriangleNorm.x; - vertices[vIndex][NY] = lightTriangleNorm.y; - vertices[vIndex][NZ] = lightTriangleNorm.z; - // The true at the end says the normal is already in world coordinates - calcLightingContribution(vIndex, tempLightingContribution, true); - copyVertexColor(triIndex, vIndex, 0, tempLightingContribution); - - vertices[vIndex2][NX] = lightTriangleNorm.x; - vertices[vIndex2][NY] = lightTriangleNorm.y; - vertices[vIndex2][NZ] = lightTriangleNorm.z; - // The true at the end says the normal is already in world coordinates - calcLightingContribution(vIndex2, tempLightingContribution, true); - copyVertexColor(triIndex, vIndex2, 1, tempLightingContribution); - - vertices[vIndex3][NX] = lightTriangleNorm.x; - vertices[vIndex3][NY] = lightTriangleNorm.y; - vertices[vIndex3][NZ] = lightTriangleNorm.z; - // The true at the end says the normal is already in world coordinates - calcLightingContribution(vIndex3, tempLightingContribution, true); - copyVertexColor(triIndex, vIndex3, 2, tempLightingContribution); - } - } - } - - - protected void renderTriangles(int start, int stop) { - for (int i = start; i < stop; i++) { - float a[] = vertices[triangles[i][VERTEX1]]; - float b[] = vertices[triangles[i][VERTEX2]]; - float c[] = vertices[triangles[i][VERTEX3]]; - int tex = triangles[i][TEXTURE_INDEX]; - - /* - // removing for 0149 with the return of P2D - // ewjordan: hack to 'fix' accuracy issues when drawing in 2d - // see also render_lines() where similar hack is employed - float shift = 0.15f;//was 0.49f - boolean shifted = false; - if (drawing2D() && (a[Z] == 0)) { - shifted = true; - a[TX] += shift; - a[TY] += shift; - a[VX] += shift*a[VW]; - a[VY] += shift*a[VW]; - b[TX] += shift; - b[TY] += shift; - b[VX] += shift*b[VW]; - b[VY] += shift*b[VW]; - c[TX] += shift; - c[TY] += shift; - c[VX] += shift*c[VW]; - c[VY] += shift*c[VW]; - } - */ - - triangle.reset(); - - // This is only true when not textured. - // We really should pass specular straight through to triangle rendering. - float ar = clamp(triangleColors[i][0][TRI_DIFFUSE_R] + triangleColors[i][0][TRI_SPECULAR_R]); - float ag = clamp(triangleColors[i][0][TRI_DIFFUSE_G] + triangleColors[i][0][TRI_SPECULAR_G]); - float ab = clamp(triangleColors[i][0][TRI_DIFFUSE_B] + triangleColors[i][0][TRI_SPECULAR_B]); - float br = clamp(triangleColors[i][1][TRI_DIFFUSE_R] + triangleColors[i][1][TRI_SPECULAR_R]); - float bg = clamp(triangleColors[i][1][TRI_DIFFUSE_G] + triangleColors[i][1][TRI_SPECULAR_G]); - float bb = clamp(triangleColors[i][1][TRI_DIFFUSE_B] + triangleColors[i][1][TRI_SPECULAR_B]); - float cr = clamp(triangleColors[i][2][TRI_DIFFUSE_R] + triangleColors[i][2][TRI_SPECULAR_R]); - float cg = clamp(triangleColors[i][2][TRI_DIFFUSE_G] + triangleColors[i][2][TRI_SPECULAR_G]); - float cb = clamp(triangleColors[i][2][TRI_DIFFUSE_B] + triangleColors[i][2][TRI_SPECULAR_B]); - - // Normal triangle rendering - if (tex > -1 && textures[tex] != null) { - triangle.setTexture(textures[tex]); - triangle.setUV(a[U], a[V], b[U], b[V], c[U], c[V]); - } - - triangle.setIntensities(ar, ag, ab, a[A], - br, bg, bb, b[A], - cr, cg, cb, c[A]); - - triangle.setVertices(a[TX], a[TY], a[TZ], - b[TX], b[TY], b[TZ], - c[TX], c[TY], c[TZ]); - - triangle.render(); - } - } - - - protected void rawTriangles(int start, int stop) { - raw.colorMode(RGB, 1); - raw.noStroke(); - raw.beginShape(TRIANGLES); - - //for (int i = 0; i < triangleCount; i ++) { - for (int i = start; i < stop; i++) { - float a[] = vertices[triangles[i][VERTEX1]]; - float b[] = vertices[triangles[i][VERTEX2]]; - float c[] = vertices[triangles[i][VERTEX3]]; - - float ar = clamp(triangleColors[i][0][TRI_DIFFUSE_R] + triangleColors[i][0][TRI_SPECULAR_R]); - float ag = clamp(triangleColors[i][0][TRI_DIFFUSE_G] + triangleColors[i][0][TRI_SPECULAR_G]); - float ab = clamp(triangleColors[i][0][TRI_DIFFUSE_B] + triangleColors[i][0][TRI_SPECULAR_B]); - float br = clamp(triangleColors[i][1][TRI_DIFFUSE_R] + triangleColors[i][1][TRI_SPECULAR_R]); - float bg = clamp(triangleColors[i][1][TRI_DIFFUSE_G] + triangleColors[i][1][TRI_SPECULAR_G]); - float bb = clamp(triangleColors[i][1][TRI_DIFFUSE_B] + triangleColors[i][1][TRI_SPECULAR_B]); - float cr = clamp(triangleColors[i][2][TRI_DIFFUSE_R] + triangleColors[i][2][TRI_SPECULAR_R]); - float cg = clamp(triangleColors[i][2][TRI_DIFFUSE_G] + triangleColors[i][2][TRI_SPECULAR_G]); - float cb = clamp(triangleColors[i][2][TRI_DIFFUSE_B] + triangleColors[i][2][TRI_SPECULAR_B]); - - int tex = triangles[i][TEXTURE_INDEX]; - PImage texImage = (tex > -1) ? textures[tex] : null; - if (texImage != null) { - if (raw.is3D()) { - if ((a[VW] != 0) && (b[VW] != 0) && (c[VW] != 0)) { - raw.fill(ar, ag, ab, a[A]); - raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW], a[U], a[V]); - raw.fill(br, bg, bb, b[A]); - raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW], b[U], b[V]); - raw.fill(cr, cg, cb, c[A]); - raw.vertex(c[VX] / c[VW], c[VY] / c[VW], c[VZ] / c[VW], c[U], c[V]); - } - } else if (raw.is2D()) { - raw.fill(ar, ag, ab, a[A]); - raw.vertex(a[TX], a[TY], a[U], a[V]); - raw.fill(br, bg, bb, b[A]); - raw.vertex(b[TX], b[TY], b[U], b[V]); - raw.fill(cr, cg, cb, c[A]); - raw.vertex(c[TX], c[TY], c[U], c[V]); - } - } else { // no texture - if (raw.is3D()) { - if ((a[VW] != 0) && (b[VW] != 0) && (c[VW] != 0)) { - raw.fill(ar, ag, ab, a[A]); - raw.vertex(a[VX] / a[VW], a[VY] / a[VW], a[VZ] / a[VW]); - raw.fill(br, bg, bb, b[A]); - raw.vertex(b[VX] / b[VW], b[VY] / b[VW], b[VZ] / b[VW]); - raw.fill(cr, cg, cb, c[A]); - raw.vertex(c[VX] / c[VW], c[VY] / c[VW], c[VZ] / c[VW]); - } - } else if (raw.is2D()){ - raw.fill(ar, ag, ab, a[A]); - raw.vertex(a[TX], a[TY]); - raw.fill(br, bg, bb, b[A]); - raw.vertex(b[TX], b[TY]); - raw.fill(cr, cg, cb, c[A]); - raw.vertex(c[TX], c[TY]); - } - } - } - - raw.endShape(); - } - - - ////////////////////////////////////////////////////////////// - - - //public void bezierVertex(float x2, float y2, - // float x3, float y3, - // float x4, float y4) - - - //public void bezierVertex(float x2, float y2, float z2, - // float x3, float y3, float z3, - // float x4, float y4, float z4) - - - - ////////////////////////////////////////////////////////////// - - - //public void curveVertex(float x, float y) - - - //public void curveVertex(float x, float y, float z) - - - - //////////////////////////////////////////////////////////// - - - /** - * Emit any sorted geometry that's been collected on this frame. - */ - public void flush() { - if (hints[ENABLE_DEPTH_SORT]) { - sort(); - } - render(); - - /* - if (triangleCount > 0) { - if (hints[ENABLE_DEPTH_SORT]) { - sortTriangles(); - } - renderTriangles(); - } - if (lineCount > 0) { - if (hints[ENABLE_DEPTH_SORT]) { - sortLines(); - } - renderLines(); - } - // Clear this out in case flush() is called again. - // For instance, with hint(ENABLE_DEPTH_SORT), it will be called - // once on endRaw(), and once again at endDraw(). - triangleCount = 0; - lineCount = 0; - */ - } - - - protected void render() { - if (pointCount > 0) { - renderPoints(0, pointCount); - if (raw != null) { - rawPoints(0, pointCount); - } - pointCount = 0; - } - if (lineCount > 0) { - renderLines(0, lineCount); - if (raw != null) { - rawLines(0, lineCount); - } - lineCount = 0; - pathCount = 0; - } - if (triangleCount > 0) { - renderTriangles(0, triangleCount); - if (raw != null) { - rawTriangles(0, triangleCount); - } - triangleCount = 0; - } - } - - - /** - * Handle depth sorting of geometry. Currently this only handles triangles, - * however in the future it will be expanded for points and lines, which - * will also need to be interspersed with one another while rendering. - */ - protected void sort() { - if (triangleCount > 0) { - sortTrianglesInternal(0, triangleCount-1); - } - } - - - private void sortTrianglesInternal(int i, int j) { - int pivotIndex = (i+j)/2; - sortTrianglesSwap(pivotIndex, j); - int k = sortTrianglesPartition(i-1, j); - sortTrianglesSwap(k, j); - if ((k-i) > 1) sortTrianglesInternal(i, k-1); - if ((j-k) > 1) sortTrianglesInternal(k+1, j); - } - - - private int sortTrianglesPartition(int left, int right) { - int pivot = right; - do { - while (sortTrianglesCompare(++left, pivot) < 0) { } - while ((right != 0) && - (sortTrianglesCompare(--right, pivot) > 0)) { } - sortTrianglesSwap(left, right); - } while (left < right); - sortTrianglesSwap(left, right); - return left; - } - - - private void sortTrianglesSwap(int a, int b) { - int tempi[] = triangles[a]; - triangles[a] = triangles[b]; - triangles[b] = tempi; - float tempf[][] = triangleColors[a]; - triangleColors[a] = triangleColors[b]; - triangleColors[b] = tempf; - } - - - private float sortTrianglesCompare(int a, int b) { - /* - if (Float.isNaN(vertices[triangles[a][VERTEX1]][TZ]) || - Float.isNaN(vertices[triangles[a][VERTEX2]][TZ]) || - Float.isNaN(vertices[triangles[a][VERTEX3]][TZ]) || - Float.isNaN(vertices[triangles[b][VERTEX1]][TZ]) || - Float.isNaN(vertices[triangles[b][VERTEX2]][TZ]) || - Float.isNaN(vertices[triangles[b][VERTEX3]][TZ])) { - System.err.println("NaN values in triangle"); - } - */ - return ((vertices[triangles[b][VERTEX1]][TZ] + - vertices[triangles[b][VERTEX2]][TZ] + - vertices[triangles[b][VERTEX3]][TZ]) - - (vertices[triangles[a][VERTEX1]][TZ] + - vertices[triangles[a][VERTEX2]][TZ] + - vertices[triangles[a][VERTEX3]][TZ])); - } - - - - ////////////////////////////////////////////////////////////// - - // POINT, LINE, TRIANGLE, QUAD - - // Because vertex(x, y) is mapped to vertex(x, y, 0), none of these commands - // need to be overridden from their default implementation in PGraphics. - - - //public void point(float x, float y) - - - //public void point(float x, float y, float z) - - - //public void line(float x1, float y1, float x2, float y2) - - - //public void line(float x1, float y1, float z1, - // float x2, float y2, float z2) - - - //public void triangle(float x1, float y1, float x2, float y2, - // float x3, float y3) - - - //public void quad(float x1, float y1, float x2, float y2, - // float x3, float y3, float x4, float y4) - - - - ////////////////////////////////////////////////////////////// - - // RECT - - - //public void rectMode(int mode) - - - //public void rect(float a, float b, float c, float d) - - - //protected void rectImpl(float x1, float y1, float x2, float y2) - - - - ////////////////////////////////////////////////////////////// - - // ELLIPSE - - - //public void ellipseMode(int mode) - - - //public void ellipse(float a, float b, float c, float d) - - - protected void ellipseImpl(float x, float y, float w, float h) { - float radiusH = w / 2; - float radiusV = h / 2; - - float centerX = x + radiusH; - float centerY = y + radiusV; - - float sx1 = screenX(x, y); - float sy1 = screenY(x, y); - float sx2 = screenX(x+w, y+h); - float sy2 = screenY(x+w, y+h); - - if (fill) { - int accuracy = (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / 20); - if (accuracy < 6) accuracy = 6; - - float inc = (float)SINCOS_LENGTH / accuracy; - float val = 0; - - boolean strokeSaved = stroke; - stroke = false; - boolean smoothSaved = smooth; - if (smooth && stroke) { - smooth = false; - } - - beginShape(TRIANGLE_FAN); - normal(0, 0, 1); - vertex(centerX, centerY); - for (int i = 0; i < accuracy; i++) { - vertex(centerX + cosLUT[(int) val] * radiusH, - centerY + sinLUT[(int) val] * radiusV); - val = (val + inc) % SINCOS_LENGTH; - } - // back to the beginning - vertex(centerX + cosLUT[0] * radiusH, - centerY + sinLUT[0] * radiusV); - endShape(); - - stroke = strokeSaved; - smooth = smoothSaved; - } - - if (stroke) { - int accuracy = (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / 8); - if (accuracy < 6) accuracy = 6; - - float inc = (float)SINCOS_LENGTH / accuracy; - float val = 0; - - boolean savedFill = fill; - fill = false; - - val = 0; - beginShape(); - for (int i = 0; i < accuracy; i++) { - vertex(centerX + cosLUT[(int) val] * radiusH, - centerY + sinLUT[(int) val] * radiusV); - val = (val + inc) % SINCOS_LENGTH; - } - endShape(CLOSE); - - fill = savedFill; - } - } - - - //public void arc(float a, float b, float c, float d, - // float start, float stop) - - - protected void arcImpl(float x, float y, float w, float h, - float start, float stop) { - float hr = w / 2f; - float vr = h / 2f; - - float centerX = x + hr; - float centerY = y + vr; - - if (fill) { - // shut off stroke for a minute - boolean savedStroke = stroke; - stroke = false; - - int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH); - int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH); - - beginShape(TRIANGLE_FAN); - vertex(centerX, centerY); - int increment = 1; // what's a good algorithm? stopLUT - startLUT; - for (int i = startLUT; i < stopLUT; i += increment) { - int ii = i % SINCOS_LENGTH; - // modulo won't make the value positive - if (ii < 0) ii += SINCOS_LENGTH; - vertex(centerX + cosLUT[ii] * hr, - centerY + sinLUT[ii] * vr); - } - // draw last point explicitly for accuracy - vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr, - centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr); - endShape(); - - stroke = savedStroke; - } - - if (stroke) { - // Almost identical to above, but this uses a LINE_STRIP - // and doesn't include the first (center) vertex. - - boolean savedFill = fill; - fill = false; - - int startLUT = (int) (0.5f + (start / TWO_PI) * SINCOS_LENGTH); - int stopLUT = (int) (0.5f + (stop / TWO_PI) * SINCOS_LENGTH); - - beginShape(); //LINE_STRIP); - int increment = 1; // what's a good algorithm? stopLUT - startLUT; - for (int i = startLUT; i < stopLUT; i += increment) { - int ii = i % SINCOS_LENGTH; - if (ii < 0) ii += SINCOS_LENGTH; - vertex(centerX + cosLUT[ii] * hr, - centerY + sinLUT[ii] * vr); - } - // draw last point explicitly for accuracy - vertex(centerX + cosLUT[stopLUT % SINCOS_LENGTH] * hr, - centerY + sinLUT[stopLUT % SINCOS_LENGTH] * vr); - endShape(); - - fill = savedFill; - } - } - - - - ////////////////////////////////////////////////////////////// - - // BOX - - - //public void box(float size) - - - public void box(float w, float h, float d) { - if (triangle != null) { // triangle is null in gl - triangle.setCulling(true); - } - - super.box(w, h, d); - - if (triangle != null) { // triangle is null in gl - triangle.setCulling(false); - } - } - - - - ////////////////////////////////////////////////////////////// - - // SPHERE - - - //public void sphereDetail(int res) - - - //public void sphereDetail(int ures, int vres) - - - public void sphere(float r) { - if (triangle != null) { // triangle is null in gl - triangle.setCulling(true); - } - - super.sphere(r); - - if (triangle != null) { // triangle is null in gl - triangle.setCulling(false); - } - } - - - - ////////////////////////////////////////////////////////////// - - // BEZIER - - - //public float bezierPoint(float a, float b, float c, float d, float t) - - - //public float bezierTangent(float a, float b, float c, float d, float t) - - - //public void bezierDetail(int detail) - - - //public void bezier(float x1, float y1, - // float x2, float y2, - // float x3, float y3, - // float x4, float y4) - - - //public void bezier(float x1, float y1, float z1, - // float x2, float y2, float z2, - // float x3, float y3, float z3, - // float x4, float y4, float z4) - - - - ////////////////////////////////////////////////////////////// - - // CATMULL-ROM CURVES - - - //public float curvePoint(float a, float b, float c, float d, float t) - - - //public float curveTangent(float a, float b, float c, float d, float t) - - - //public void curveDetail(int detail) - - - //public void curveTightness(float tightness) - - - //public void curve(float x1, float y1, - // float x2, float y2, - // float x3, float y3, - // float x4, float y4) - - - //public void curve(float x1, float y1, float z1, - // float x2, float y2, float z2, - // float x3, float y3, float z3, - // float x4, float y4, float z4) - - - - ////////////////////////////////////////////////////////////// - - // SMOOTH - - - public void smooth() { - //showMethodWarning("smooth"); - s_enableAccurateTextures = true; - smooth = true; - } - - - public void noSmooth() { - s_enableAccurateTextures = false; - smooth = false; - } - - - - ////////////////////////////////////////////////////////////// - - // IMAGES - - - //public void imageMode(int mode) - - - //public void image(PImage image, float x, float y) - - - //public void image(PImage image, float x, float y, float c, float d) - - - //public void image(PImage image, - // float a, float b, float c, float d, - // int u1, int v1, int u2, int v2) - - - //protected void imageImpl(PImage image, - // float x1, float y1, float x2, float y2, - // int u1, int v1, int u2, int v2) - - - - ////////////////////////////////////////////////////////////// - - // SHAPE - - - //public void shapeMode(int mode) - - - //public void shape(PShape shape) - - - //public void shape(PShape shape, float x, float y) - - - //public void shape(PShape shape, float x, float y, float c, float d) - - - - ////////////////////////////////////////////////////////////// - - // TEXT SETTINGS - - // Only textModeCheck overridden from PGraphics, no textAlign, textAscent, - // textDescent, textFont, textLeading, textMode, textSize, textWidth - - - protected boolean textModeCheck(int mode) { - return (textMode == MODEL) || (textMode == SCREEN); - } - - - - ////////////////////////////////////////////////////////////// - - // TEXT - - // None of the variations of text() are overridden from PGraphics. - - - - ////////////////////////////////////////////////////////////// - - // TEXT IMPL - - // Not even the text drawing implementation stuff is overridden. - - - - ////////////////////////////////////////////////////////////// - - // MATRIX STACK - - - public void pushMatrix() { - if (matrixStackDepth == MATRIX_STACK_DEPTH) { - throw new RuntimeException(ERROR_PUSHMATRIX_OVERFLOW); - } - modelview.get(matrixStack[matrixStackDepth]); - modelviewInv.get(matrixInvStack[matrixStackDepth]); - matrixStackDepth++; - } - - - public void popMatrix() { - if (matrixStackDepth == 0) { - throw new RuntimeException(ERROR_PUSHMATRIX_UNDERFLOW); - } - matrixStackDepth--; - modelview.set(matrixStack[matrixStackDepth]); - modelviewInv.set(matrixInvStack[matrixStackDepth]); - } - - - - ////////////////////////////////////////////////////////////// - - // MATRIX TRANSFORMATIONS - - - public void translate(float tx, float ty) { - translate(tx, ty, 0); - } - - - public void translate(float tx, float ty, float tz) { - forwardTransform.translate(tx, ty, tz); - reverseTransform.invTranslate(tx, ty, tz); - } - - - /** - * Two dimensional rotation. Same as rotateZ (this is identical - * to a 3D rotation along the z-axis) but included for clarity -- - * it'd be weird for people drawing 2D graphics to be using rotateZ. - * And they might kick our a-- for the confusion. - */ - public void rotate(float angle) { - rotateZ(angle); - } - - - public void rotateX(float angle) { - forwardTransform.rotateX(angle); - reverseTransform.invRotateX(angle); - } - - - public void rotateY(float angle) { - forwardTransform.rotateY(angle); - reverseTransform.invRotateY(angle); - } - - - public void rotateZ(float angle) { - forwardTransform.rotateZ(angle); - reverseTransform.invRotateZ(angle); - } - - - /** - * Rotate around an arbitrary vector, similar to glRotate(), - * except that it takes radians (instead of degrees). - */ - public void rotate(float angle, float v0, float v1, float v2) { - forwardTransform.rotate(angle, v0, v1, v2); - reverseTransform.invRotate(angle, v0, v1, v2); - } - - - /** - * Same as scale(s, s, s). - */ - public void scale(float s) { - scale(s, s, s); - } - - - /** - * Same as scale(sx, sy, 1). - */ - public void scale(float sx, float sy) { - scale(sx, sy, 1); - } - - - /** - * Scale in three dimensions. - */ - public void scale(float x, float y, float z) { - forwardTransform.scale(x, y, z); - reverseTransform.invScale(x, y, z); - } - - - - ////////////////////////////////////////////////////////////// - - // MATRIX MORE! - - - public void resetMatrix() { - forwardTransform.reset(); - reverseTransform.reset(); - } - - - public void applyMatrix(PMatrix2D source) { - applyMatrix(source.m00, source.m01, source.m02, - source.m10, source.m11, source.m12); - } - - - public void applyMatrix(float n00, float n01, float n02, - float n10, float n11, float n12) { - applyMatrix(n00, n01, n02, 0, - n10, n11, n12, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - } - - - public void applyMatrix(PMatrix3D source) { - applyMatrix(source.m00, source.m01, source.m02, source.m03, - source.m10, source.m11, source.m12, source.m13, - source.m20, source.m21, source.m22, source.m23, - source.m30, source.m31, source.m32, source.m33); - } - - - /** - * Apply a 4x4 transformation matrix. Same as glMultMatrix(). - * This call will be slow because it will try to calculate the - * inverse of the transform. So avoid it whenever possible. - */ - public void applyMatrix(float n00, float n01, float n02, float n03, - float n10, float n11, float n12, float n13, - float n20, float n21, float n22, float n23, - float n30, float n31, float n32, float n33) { - - forwardTransform.apply(n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23, - n30, n31, n32, n33); - - reverseTransform.invApply(n00, n01, n02, n03, - n10, n11, n12, n13, - n20, n21, n22, n23, - n30, n31, n32, n33); - } - - - - ////////////////////////////////////////////////////////////// - - // MATRIX GET/SET/PRINT - - - public PMatrix getMatrix() { - return modelview.get(); - } - - - //public PMatrix2D getMatrix(PMatrix2D target) - - - public PMatrix3D getMatrix(PMatrix3D target) { - if (target == null) { - target = new PMatrix3D(); - } - target.set(modelview); - return target; - } - - - //public void setMatrix(PMatrix source) - - - public void setMatrix(PMatrix2D source) { - // not efficient, but at least handles the inverse stuff. - resetMatrix(); - applyMatrix(source); - } - - - /** - * Set the current transformation to the contents of the specified source. - */ - public void setMatrix(PMatrix3D source) { - // not efficient, but at least handles the inverse stuff. - resetMatrix(); - applyMatrix(source); - } - - - /** - * Print the current model (or "transformation") matrix. - */ - public void printMatrix() { - modelview.print(); - } - - - /* - * This function checks if the modelview matrix is set up to likely be - * drawing in 2D. It merely checks if the non-translational piece of the - * matrix is unity. If this is to be used, it should be coupled with a - * check that the raw vertex coordinates lie in the z=0 plane. - * Mainly useful for applying sub-pixel shifts to avoid 2d artifacts - * in the screen plane. - * Added by ewjordan 6/13/07 - * - * TODO need to invert the logic here so that we can simply return - * the value, rather than calculating true/false and returning it. - */ - /* - private boolean drawing2D() { - if (modelview.m00 != 1.0f || - modelview.m11 != 1.0f || - modelview.m22 != 1.0f || // check scale - modelview.m01 != 0.0f || - modelview.m02 != 0.0f || // check rotational pieces - modelview.m10 != 0.0f || - modelview.m12 != 0.0f || - modelview.m20 != 0.0f || - modelview.m21 != 0.0f || - !((camera.m23-modelview.m23) <= EPSILON && - (camera.m23-modelview.m23) >= -EPSILON)) { // check for z-translation - // Something about the modelview matrix indicates 3d drawing - // (or rotated 2d, in which case 2d subpixel fixes probably aren't needed) - return false; - } else { - //The matrix is mapping z=0 vertices to the screen plane, - // which means it's likely that 2D drawing is happening. - return true; - } - } - */ - - - - ////////////////////////////////////////////////////////////// - - // CAMERA - - - /** - * Set matrix mode to the camera matrix (instead of the current - * transformation matrix). This means applyMatrix, resetMatrix, etc. - * will affect the camera. - *

- * Note that the camera matrix is *not* the perspective matrix, - * it is in front of the modelview matrix (hence the name "model" - * and "view" for that matrix). - *

- * beginCamera() specifies that all coordinate transforms until endCamera() - * should be pre-applied in inverse to the camera transform matrix. - * Note that this is only challenging when a user specifies an arbitrary - * matrix with applyMatrix(). Then that matrix will need to be inverted, - * which may not be possible. But take heart, if a user is applying a - * non-invertible matrix to the camera transform, then he is clearly - * up to no good, and we can wash our hands of those bad intentions. - *

- * begin/endCamera clauses do not automatically reset the camera transform - * matrix. That's because we set up a nice default camera transform int - * setup(), and we expect it to hold through draw(). So we don't reset - * the camera transform matrix at the top of draw(). That means that an - * innocuous-looking clause like - *

-   * beginCamera();
-   * translate(0, 0, 10);
-   * endCamera();
-   * 
- * at the top of draw(), will result in a runaway camera that shoots - * infinitely out of the screen over time. In order to prevent this, - * it is necessary to call some function that does a hard reset of the - * camera transform matrix inside of begin/endCamera. Two options are - *
-   * camera(); // sets up the nice default camera transform
-   * resetMatrix(); // sets up the identity camera transform
-   * 
- * So to rotate a camera a constant amount, you might try - *
-   * beginCamera();
-   * camera();
-   * rotateY(PI/8);
-   * endCamera();
-   * 
- */ - public void beginCamera() { - if (manipulatingCamera) { - throw new RuntimeException("beginCamera() cannot be called again " + - "before endCamera()"); - } else { - manipulatingCamera = true; - forwardTransform = cameraInv; - reverseTransform = camera; - } - } - - - /** - * Record the current settings into the camera matrix, and set - * the matrix mode back to the current transformation matrix. - *

- * Note that this will destroy any settings to scale(), translate(), - * or whatever, because the final camera matrix will be copied - * (not multiplied) into the modelview. - */ - public void endCamera() { - if (!manipulatingCamera) { - throw new RuntimeException("Cannot call endCamera() " + - "without first calling beginCamera()"); - } - // reset the modelview to use this new camera matrix - modelview.set(camera); - modelviewInv.set(cameraInv); - - // set matrix mode back to modelview - forwardTransform = modelview; - reverseTransform = modelviewInv; - - // all done - manipulatingCamera = false; - } - - - /** - * Set camera to the default settings. - *

- * Processing camera behavior: - *

- * Camera behavior can be split into two separate components, camera - * transformation, and projection. The transformation corresponds to the - * physical location, orientation, and scale of the camera. In a physical - * camera metaphor, this is what can manipulated by handling the camera - * body (with the exception of scale, which doesn't really have a physcial - * analog). The projection corresponds to what can be changed by - * manipulating the lens. - *

- * We maintain separate matrices to represent the camera transform and - * projection. An important distinction between the two is that the camera - * transform should be invertible, where the projection matrix should not, - * since it serves to map three dimensions to two. It is possible to bake - * the two matrices into a single one just by multiplying them together, - * but it isn't a good idea, since lighting, z-ordering, and z-buffering - * all demand a true camera z coordinate after modelview and camera - * transforms have been applied but before projection. If the camera - * transform and projection are combined there is no way to recover a - * good camera-space z-coordinate from a model coordinate. - *

- * Fortunately, there are no functions that manipulate both camera - * transformation and projection. - *

- * camera() sets the camera position, orientation, and center of the scene. - * It replaces the camera transform with a new one. This is different from - * gluLookAt(), but I think the only reason that GLU's lookat doesn't fully - * replace the camera matrix with the new one, but instead multiplies it, - * is that GL doesn't enforce the separation of camera transform and - * projection, so it wouldn't be safe (you'd probably stomp your projection). - *

- * The transformation functions are the same ones used to manipulate the - * modelview matrix (scale, translate, rotate, etc.). But they are bracketed - * with beginCamera(), endCamera() to indicate that they should apply - * (in inverse), to the camera transformation matrix. - *

- * This differs considerably from camera transformation in OpenGL. - * OpenGL only lets you say, apply everything from here out to the - * projection or modelview matrix. This makes it very hard to treat camera - * manipulation as if it were a physical camera. Imagine that you want to - * move your camera 100 units forward. In OpenGL, you need to apply the - * inverse of that transformation or else you'll move your scene 100 units - * forward--whether or not you've specified modelview or projection matrix. - * Remember they're just multiplied by model coods one after another. - * So in order to treat a camera like a physical camera, it is necessary - * to pre-apply inverse transforms to a matrix that will be applied to model - * coordinates. OpenGL provides nothing of this sort, but Processing does! - * This is the camera transform matrix. - */ - public void camera() { - camera(cameraX, cameraY, cameraZ, - cameraX, cameraY, 0, - 0, 1, 0); - } - - - /** - * More flexible method for dealing with camera(). - *

- * The actual call is like gluLookat. Here's the real skinny on - * what does what: - *

-   * camera(); or
-   * camera(ex, ey, ez, cx, cy, cz, ux, uy, uz);
-   * 
- * do not need to be called from with beginCamera();/endCamera(); - * That's because they always apply to the camera transformation, - * and they always totally replace it. That means that any coordinate - * transforms done before camera(); in draw() will be wiped out. - * It also means that camera() always operates in untransformed world - * coordinates. Therefore it is always redundant to call resetMatrix(); - * before camera(); This isn't technically true of gluLookat, but it's - * pretty much how it's used. - *

- * Now, beginCamera(); and endCamera(); are useful if you want to move - * the camera around using transforms like translate(), etc. They will - * wipe out any coordinate system transforms that occur before them in - * draw(), but they will not automatically wipe out the camera transform. - * This means that they should be at the top of draw(). It also means - * that the following: - *

-   * beginCamera();
-   * rotateY(PI/8);
-   * endCamera();
-   * 
- * will result in a camera that spins without stopping. If you want to - * just rotate a small constant amount, try this: - *
-   * beginCamera();
-   * camera(); // sets up the default view
-   * rotateY(PI/8);
-   * endCamera();
-   * 
- * That will rotate a little off of the default view. Note that this - * is entirely equivalent to - *
-   * camera(); // sets up the default view
-   * beginCamera();
-   * rotateY(PI/8);
-   * endCamera();
-   * 
- * because camera() doesn't care whether or not it's inside a - * begin/end clause. Basically it's safe to use camera() or - * camera(ex, ey, ez, cx, cy, cz, ux, uy, uz) as naked calls because - * they do all the matrix resetting automatically. - */ - public void camera(float eyeX, float eyeY, float eyeZ, - float centerX, float centerY, float centerZ, - float upX, float upY, float upZ) { - float z0 = eyeX - centerX; - float z1 = eyeY - centerY; - float z2 = eyeZ - centerZ; - float mag = sqrt(z0*z0 + z1*z1 + z2*z2); - - if (mag != 0) { - z0 /= mag; - z1 /= mag; - z2 /= mag; - } - - float y0 = upX; - float y1 = upY; - float y2 = upZ; - - float x0 = y1*z2 - y2*z1; - float x1 = -y0*z2 + y2*z0; - float x2 = y0*z1 - y1*z0; - - y0 = z1*x2 - z2*x1; - y1 = -z0*x2 + z2*x0; - y2 = z0*x1 - z1*x0; - - mag = sqrt(x0*x0 + x1*x1 + x2*x2); - if (mag != 0) { - x0 /= mag; - x1 /= mag; - x2 /= mag; - } - - mag = sqrt(y0*y0 + y1*y1 + y2*y2); - if (mag != 0) { - y0 /= mag; - y1 /= mag; - y2 /= mag; - } - - // just does an apply to the main matrix, - // since that'll be copied out on endCamera - camera.set(x0, x1, x2, 0, - y0, y1, y2, 0, - z0, z1, z2, 0, - 0, 0, 0, 1); - camera.translate(-eyeX, -eyeY, -eyeZ); - - cameraInv.reset(); - cameraInv.invApply(x0, x1, x2, 0, - y0, y1, y2, 0, - z0, z1, z2, 0, - 0, 0, 0, 1); - cameraInv.translate(eyeX, eyeY, eyeZ); - - modelview.set(camera); - modelviewInv.set(cameraInv); - } - - - /** - * Print the current camera matrix. - */ - public void printCamera() { - camera.print(); - } - - - ////////////////////////////////////////////////////////////// - - // PROJECTION - - - /** - * Calls ortho() with the proper parameters for Processing's - * standard orthographic projection. - */ - public void ortho() { - ortho(0, width, 0, height, -10, 10); - } - - - /** - * Similar to gluOrtho(), but wipes out the current projection matrix. - *

- * Implementation partially based on Mesa's matrix.c. - */ - public void ortho(float left, float right, - float bottom, float top, - float near, float far) { - float x = 2.0f / (right - left); - float y = 2.0f / (top - bottom); - float z = -2.0f / (far - near); - - float tx = -(right + left) / (right - left); - float ty = -(top + bottom) / (top - bottom); - float tz = -(far + near) / (far - near); - - projection.set(x, 0, 0, tx, - 0, y, 0, ty, - 0, 0, z, tz, - 0, 0, 0, 1); - } - - - /** - * Calls perspective() with Processing's standard coordinate projection. - *

- * Projection functions: - *

- * Each of these three functions completely replaces the projection - * matrix with a new one. They can be called inside setup(), and their - * effects will be felt inside draw(). At the top of draw(), the projection - * matrix is not reset. Therefore the last projection function to be - * called always dominates. On resize, the default projection is always - * established, which has perspective. - *

- * This behavior is pretty much familiar from OpenGL, except where - * functions replace matrices, rather than multiplying against the - * previous. - *

- */ - public void perspective() { - perspective(cameraFOV, cameraAspect, cameraNear, cameraFar); - } - - - /** - * Similar to gluPerspective(). Implementation based on Mesa's glu.c - */ - public void perspective(float fov, float aspect, float zNear, float zFar) { - //float ymax = zNear * tan(fovy * PI / 360.0f); - float ymax = zNear * (float) Math.tan(fov / 2); - float ymin = -ymax; - - float xmin = ymin * aspect; - float xmax = ymax * aspect; - - frustum(xmin, xmax, ymin, ymax, zNear, zFar); - } - - - /** - * Same as glFrustum(), except that it wipes out (rather than - * multiplies against) the current perspective matrix. - *

- * Implementation based on the explanation in the OpenGL blue book. - */ - public void frustum(float left, float right, float bottom, - float top, float znear, float zfar) { - - leftScreen = left; - rightScreen = right; - bottomScreen = bottom; - topScreen = top; - nearPlane = znear; - - //System.out.println(projection); - projection.set((2*znear)/(right-left), 0, (right+left)/(right-left), 0, - 0, (2*znear)/(top-bottom), (top+bottom)/(top-bottom), 0, - 0, 0, -(zfar+znear)/(zfar-znear),-(2*zfar*znear)/(zfar-znear), - 0, 0, -1, 0); - } - - - /** - * Print the current projection matrix. - */ - public void printProjection() { - projection.print(); - } - - - - ////////////////////////////////////////////////////////////// - - // SCREEN AND MODEL COORDS - - - public float screenX(float x, float y) { - return screenX(x, y, 0); - } - - - public float screenY(float x, float y) { - return screenY(x, y, 0); - } - - - public float screenX(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float ox = - projection.m00*ax + projection.m01*ay + - projection.m02*az + projection.m03*aw; - float ow = - projection.m30*ax + projection.m31*ay + - projection.m32*az + projection.m33*aw; - - if (ow != 0) ox /= ow; - return width * (1 + ox) / 2.0f; - } - - - public float screenY(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float oy = - projection.m10*ax + projection.m11*ay + - projection.m12*az + projection.m13*aw; - float ow = - projection.m30*ax + projection.m31*ay + - projection.m32*az + projection.m33*aw; - - if (ow != 0) oy /= ow; - return height * (1 + oy) / 2.0f; - } - - - public float screenZ(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float oz = - projection.m20*ax + projection.m21*ay + - projection.m22*az + projection.m23*aw; - float ow = - projection.m30*ax + projection.m31*ay + - projection.m32*az + projection.m33*aw; - - if (ow != 0) oz /= ow; - return (oz + 1) / 2.0f; - } - - - public float modelX(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float ox = - cameraInv.m00*ax + cameraInv.m01*ay + - cameraInv.m02*az + cameraInv.m03*aw; - float ow = - cameraInv.m30*ax + cameraInv.m31*ay + - cameraInv.m32*az + cameraInv.m33*aw; - - return (ow != 0) ? ox / ow : ox; - } - - - public float modelY(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float oy = - cameraInv.m10*ax + cameraInv.m11*ay + - cameraInv.m12*az + cameraInv.m13*aw; - float ow = - cameraInv.m30*ax + cameraInv.m31*ay + - cameraInv.m32*az + cameraInv.m33*aw; - - return (ow != 0) ? oy / ow : oy; - } - - - public float modelZ(float x, float y, float z) { - float ax = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - float ay = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - float az = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - float aw = - modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33; - - float oz = - cameraInv.m20*ax + cameraInv.m21*ay + - cameraInv.m22*az + cameraInv.m23*aw; - float ow = - cameraInv.m30*ax + cameraInv.m31*ay + - cameraInv.m32*az + cameraInv.m33*aw; - - return (ow != 0) ? oz / ow : oz; - } - - - - ////////////////////////////////////////////////////////////// - - // STYLE - - // pushStyle(), popStyle(), style() and getStyle() inherited. - - - - ////////////////////////////////////////////////////////////// - - // STROKE CAP/JOIN/WEIGHT - - -// public void strokeWeight(float weight) { -// if (weight != DEFAULT_STROKE_WEIGHT) { -// showMethodWarning("strokeWeight"); -// } -// } - - - public void strokeJoin(int join) { - if (join != DEFAULT_STROKE_JOIN) { - showMethodWarning("strokeJoin"); - } - } - - - public void strokeCap(int cap) { - if (cap != DEFAULT_STROKE_CAP) { - showMethodWarning("strokeCap"); - } - } - - - - ////////////////////////////////////////////////////////////// - - // STROKE COLOR - - // All methods inherited from PGraphics. - - - - ////////////////////////////////////////////////////////////// - - // TINT COLOR - - // All methods inherited from PGraphics. - - - - ////////////////////////////////////////////////////////////// - - // FILL COLOR - - - protected void fillFromCalc() { - super.fillFromCalc(); - ambientFromCalc(); - } - - - - ////////////////////////////////////////////////////////////// - - // MATERIAL PROPERTIES - - // ambient, specular, shininess, and emissive all inherited. - - - - ////////////////////////////////////////////////////////////// - - // LIGHTS - - - PVector lightPositionVec = new PVector(); - PVector lightDirectionVec = new PVector(); - - /** - * Sets up an ambient and directional light. - *

-   * The Lighting Skinny:
-   *
-   * The way lighting works is complicated enough that it's worth
-   * producing a document to describe it. Lighting calculations proceed
-   * pretty much exactly as described in the OpenGL red book.
-   *
-   * Light-affecting material properties:
-   *
-   *   AMBIENT COLOR
-   *   - multiplies by light's ambient component
-   *   - for believability this should match diffuse color
-   *
-   *   DIFFUSE COLOR
-   *   - multiplies by light's diffuse component
-   *
-   *   SPECULAR COLOR
-   *   - multiplies by light's specular component
-   *   - usually less colored than diffuse/ambient
-   *
-   *   SHININESS
-   *   - the concentration of specular effect
-   *   - this should be set pretty high (20-50) to see really
-   *     noticeable specularity
-   *
-   *   EMISSIVE COLOR
-   *   - constant additive color effect
-   *
-   * Light types:
-   *
-   *   AMBIENT
-   *   - one color
-   *   - no specular color
-   *   - no direction
-   *   - may have falloff (constant, linear, and quadratic)
-   *   - may have position (which matters in non-constant falloff case)
-   *   - multiplies by a material's ambient reflection
-   *
-   *   DIRECTIONAL
-   *   - has diffuse color
-   *   - has specular color
-   *   - has direction
-   *   - no position
-   *   - no falloff
-   *   - multiplies by a material's diffuse and specular reflections
-   *
-   *   POINT
-   *   - has diffuse color
-   *   - has specular color
-   *   - has position
-   *   - no direction
-   *   - may have falloff (constant, linear, and quadratic)
-   *   - multiplies by a material's diffuse and specular reflections
-   *
-   *   SPOT
-   *   - has diffuse color
-   *   - has specular color
-   *   - has position
-   *   - has direction
-   *   - has cone angle (set to half the total cone angle)
-   *   - has concentration value
-   *   - may have falloff (constant, linear, and quadratic)
-   *   - multiplies by a material's diffuse and specular reflections
-   *
-   * Normal modes:
-   *
-   * All of the primitives (rect, box, sphere, etc.) have their normals
-   * set nicely. During beginShape/endShape normals can be set by the user.
-   *
-   *   AUTO-NORMAL
-   *   - if no normal is set during the shape, we are in auto-normal mode
-   *   - auto-normal calculates one normal per triangle (face-normal mode)
-   *
-   *   SHAPE-NORMAL
-   *   - if one normal is set during the shape, it will be used for
-   *     all vertices
-   *
-   *   VERTEX-NORMAL
-   *   - if multiple normals are set, each normal applies to
-   *     subsequent vertices
-   *   - (except for the first one, which applies to previous
-   *     and subsequent vertices)
-   *
-   * Efficiency consequences:
-   *
-   *   There is a major efficiency consequence of position-dependent
-   *   lighting calculations per vertex. (See below for determining
-   *   whether lighting is vertex position-dependent.) If there is no
-   *   position dependency then the only factors that affect the lighting
-   *   contribution per vertex are its colors and its normal.
-   *   There is a major efficiency win if
-   *
-   *   1) lighting is not position dependent
-   *   2) we are in AUTO-NORMAL or SHAPE-NORMAL mode
-   *
-   *   because then we can calculate one lighting contribution per shape
-   *   (SHAPE-NORMAL) or per triangle (AUTO-NORMAL) and simply multiply it
-   *   into the vertex colors. The converse is our worst-case performance when
-   *
-   *   1) lighting is position dependent
-   *   2) we are in AUTO-NORMAL mode
-   *
-   *   because then we must calculate lighting per-face * per-vertex.
-   *   Each vertex has a different lighting contribution per face in
-   *   which it appears. Yuck.
-   *
-   * Determining vertex position dependency:
-   *
-   *   If any of the following factors are TRUE then lighting is
-   *   vertex position dependent:
-   *
-   *   1) Any lights uses non-constant falloff
-   *   2) There are any point or spot lights
-   *   3) There is a light with specular color AND there is a
-   *      material with specular color
-   *
-   * So worth noting is that default lighting (a no-falloff ambient
-   * and a directional without specularity) is not position-dependent.
-   * We should capitalize.
-   *
-   * Simon Greenwold, April 2005
-   * 
- */ - public void lights() { - // need to make sure colorMode is RGB 255 here - int colorModeSaved = colorMode; - colorMode = RGB; - - lightFalloff(1, 0, 0); - lightSpecular(0, 0, 0); - - ambientLight(colorModeX * 0.5f, - colorModeY * 0.5f, - colorModeZ * 0.5f); - directionalLight(colorModeX * 0.5f, - colorModeY * 0.5f, - colorModeZ * 0.5f, - 0, 0, -1); - - colorMode = colorModeSaved; - - lightingDependsOnVertexPosition = false; - } - - - /** - * Turn off all lights. - */ - public void noLights() { - // write any queued geometry, because lighting will be goofed after - flush(); - // set the light count back to zero - lightCount = 0; - } - - - /** - * Add an ambient light based on the current color mode. - */ - public void ambientLight(float r, float g, float b) { - ambientLight(r, g, b, 0, 0, 0); - } - - - /** - * Add an ambient light based on the current color mode. - * This version includes an (x, y, z) position for situations - * where the falloff distance is used. - */ - public void ambientLight(float r, float g, float b, - float x, float y, float z) { - if (lightCount == MAX_LIGHTS) { - throw new RuntimeException("can only create " + MAX_LIGHTS + " lights"); - } - colorCalc(r, g, b); - lightDiffuse[lightCount][0] = calcR; - lightDiffuse[lightCount][1] = calcG; - lightDiffuse[lightCount][2] = calcB; - - lightType[lightCount] = AMBIENT; - lightFalloffConstant[lightCount] = currentLightFalloffConstant; - lightFalloffLinear[lightCount] = currentLightFalloffLinear; - lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic; - lightPosition(lightCount, x, y, z); - lightCount++; - //return lightCount-1; - } - - - public void directionalLight(float r, float g, float b, - float nx, float ny, float nz) { - if (lightCount == MAX_LIGHTS) { - throw new RuntimeException("can only create " + MAX_LIGHTS + " lights"); - } - colorCalc(r, g, b); - lightDiffuse[lightCount][0] = calcR; - lightDiffuse[lightCount][1] = calcG; - lightDiffuse[lightCount][2] = calcB; - - lightType[lightCount] = DIRECTIONAL; - lightFalloffConstant[lightCount] = currentLightFalloffConstant; - lightFalloffLinear[lightCount] = currentLightFalloffLinear; - lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic; - lightSpecular[lightCount][0] = currentLightSpecular[0]; - lightSpecular[lightCount][1] = currentLightSpecular[1]; - lightSpecular[lightCount][2] = currentLightSpecular[2]; - lightDirection(lightCount, nx, ny, nz); - lightCount++; - } - - - public void pointLight(float r, float g, float b, - float x, float y, float z) { - if (lightCount == MAX_LIGHTS) { - throw new RuntimeException("can only create " + MAX_LIGHTS + " lights"); - } - colorCalc(r, g, b); - lightDiffuse[lightCount][0] = calcR; - lightDiffuse[lightCount][1] = calcG; - lightDiffuse[lightCount][2] = calcB; - - lightType[lightCount] = POINT; - lightFalloffConstant[lightCount] = currentLightFalloffConstant; - lightFalloffLinear[lightCount] = currentLightFalloffLinear; - lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic; - lightSpecular[lightCount][0] = currentLightSpecular[0]; - lightSpecular[lightCount][1] = currentLightSpecular[1]; - lightSpecular[lightCount][2] = currentLightSpecular[2]; - lightPosition(lightCount, x, y, z); - lightCount++; - - lightingDependsOnVertexPosition = true; - } - - - public void spotLight(float r, float g, float b, - float x, float y, float z, - float nx, float ny, float nz, - float angle, float concentration) { - if (lightCount == MAX_LIGHTS) { - throw new RuntimeException("can only create " + MAX_LIGHTS + " lights"); - } - colorCalc(r, g, b); - lightDiffuse[lightCount][0] = calcR; - lightDiffuse[lightCount][1] = calcG; - lightDiffuse[lightCount][2] = calcB; - - lightType[lightCount] = SPOT; - lightFalloffConstant[lightCount] = currentLightFalloffConstant; - lightFalloffLinear[lightCount] = currentLightFalloffLinear; - lightFalloffQuadratic[lightCount] = currentLightFalloffQuadratic; - lightSpecular[lightCount][0] = currentLightSpecular[0]; - lightSpecular[lightCount][1] = currentLightSpecular[1]; - lightSpecular[lightCount][2] = currentLightSpecular[2]; - lightPosition(lightCount, x, y, z); - lightDirection(lightCount, nx, ny, nz); - lightSpotAngle[lightCount] = angle; - lightSpotAngleCos[lightCount] = Math.max(0, (float) Math.cos(angle)); - lightSpotConcentration[lightCount] = concentration; - lightCount++; - - lightingDependsOnVertexPosition = true; - } - - - /** - * Set the light falloff rates for the last light that was created. - * Default is lightFalloff(1, 0, 0). - */ - public void lightFalloff(float constant, float linear, float quadratic) { - currentLightFalloffConstant = constant; - currentLightFalloffLinear = linear; - currentLightFalloffQuadratic = quadratic; - - lightingDependsOnVertexPosition = true; - } - - - /** - * Set the specular color of the last light created. - */ - public void lightSpecular(float x, float y, float z) { - colorCalc(x, y, z); - currentLightSpecular[0] = calcR; - currentLightSpecular[1] = calcG; - currentLightSpecular[2] = calcB; - - lightingDependsOnVertexPosition = true; - } - - - /** - * internal function to set the light position - * based on the current modelview matrix. - */ - protected void lightPosition(int num, float x, float y, float z) { - lightPositionVec.set(x, y, z); - modelview.mult(lightPositionVec, lightPosition[num]); - /* - lightPosition[num][0] = - modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03; - lightPosition[num][1] = - modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13; - lightPosition[num][2] = - modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23; - */ - } - - - /** - * internal function to set the light direction - * based on the current modelview matrix. - */ - protected void lightDirection(int num, float x, float y, float z) { - lightNormal[num].set(modelviewInv.m00*x + modelviewInv.m10*y + modelviewInv.m20*z + modelviewInv.m30, - modelviewInv.m01*x + modelviewInv.m11*y + modelviewInv.m21*z + modelviewInv.m31, - modelviewInv.m02*x + modelviewInv.m12*y + modelviewInv.m22*z + modelviewInv.m32); - lightNormal[num].normalize(); - - /* - lightDirectionVec.set(x, y, z); - System.out.println("dir vec " + lightDirectionVec); - //modelviewInv.mult(lightDirectionVec, lightNormal[num]); - modelviewInv.cmult(lightDirectionVec, lightNormal[num]); - System.out.println("cmult vec " + lightNormal[num]); - lightNormal[num].normalize(); - System.out.println("setting light direction " + lightNormal[num]); - */ - - /* - // Multiply by inverse transpose. - lightNormal[num][0] = - modelviewInv.m00*x + modelviewInv.m10*y + - modelviewInv.m20*z + modelviewInv.m30; - lightNormal[num][1] = - modelviewInv.m01*x + modelviewInv.m11*y + - modelviewInv.m21*z + modelviewInv.m31; - lightNormal[num][2] = - modelviewInv.m02*x + modelviewInv.m12*y + - modelviewInv.m22*z + modelviewInv.m32; - - float n = mag(lightNormal[num][0], lightNormal[num][1], lightNormal[num][2]); - if (n == 0 || n == 1) return; - - lightNormal[num][0] /= n; - lightNormal[num][1] /= n; - lightNormal[num][2] /= n; - */ - } - - - - ////////////////////////////////////////////////////////////// - - // BACKGROUND - - // Base background() variations inherited from PGraphics. - - - protected void backgroundImpl(PImage image) { - System.arraycopy(image.pixels, 0, pixels, 0, pixels.length); - Arrays.fill(zbuffer, Float.MAX_VALUE); - } - - - /** - * Clear pixel buffer. With P3D and OPENGL, this also clears the zbuffer. - */ - protected void backgroundImpl() { - Arrays.fill(pixels, backgroundColor); - Arrays.fill(zbuffer, Float.MAX_VALUE); - } - - - - ////////////////////////////////////////////////////////////// - - // COLOR MODE - - // all colorMode() variations inherited from PGraphics. - - - - ////////////////////////////////////////////////////////////// - - // COLOR CALCULATIONS - - // protected colorCalc and colorCalcARGB inherited. - - - - ////////////////////////////////////////////////////////////// - - // COLOR DATATYPE STUFFING - - // final color() variations inherited. - - - - ////////////////////////////////////////////////////////////// - - // COLOR DATATYPE EXTRACTION - - // final methods alpha, red, green, blue, - // hue, saturation, and brightness all inherited. - - - - ////////////////////////////////////////////////////////////// - - // COLOR DATATYPE INTERPOLATION - - // both lerpColor variants inherited. - - - - ////////////////////////////////////////////////////////////// - - // BEGIN/END RAW - - // beginRaw, endRaw() both inherited. - - - - ////////////////////////////////////////////////////////////// - - // WARNINGS and EXCEPTIONS - - // showWarning and showException inherited. - - - - ////////////////////////////////////////////////////////////// - - // RENDERER SUPPORT QUERIES - - - //public boolean displayable() - - - public boolean is2D() { - return false; - } - - - public boolean is3D() { - return true; - } - - - - ////////////////////////////////////////////////////////////// - - // PIMAGE METHODS - - // All these methods are inherited, because this render has a - // pixels[] array that can be accessed directly. - - // getImage - // setCache, getCache, removeCache - // isModified, setModified - // loadPixels, updatePixels - // resize - // get, getImpl, set, setImpl - // mask - // filter - // copy - // blendColor, blend - - - - ////////////////////////////////////////////////////////////// - - // MATH (internal use only) - - - private final float sqrt(float a) { - return (float) Math.sqrt(a); - } - - - private final float mag(float a, float b, float c) { - return (float) Math.sqrt(a*a + b*b + c*c); - } - - - private final float clamp(float a) { - return (a < 1) ? a : 1; - } - - - private final float abs(float a) { - return (a < 0) ? -a : a; - } - - - private float dot(float ax, float ay, float az, - float bx, float by, float bz) { - return ax*bx + ay*by + az*bz; - } - - - /* - private final void cross(float a0, float a1, float a2, - float b0, float b1, float b2, - float[] out) { - out[0] = a1*b2 - a2*b1; - out[1] = a2*b0 - a0*b2; - out[2] = a0*b1 - a1*b0; - } - */ - - - private final void cross(float a0, float a1, float a2, - float b0, float b1, float b2, - PVector out) { - out.x = a1*b2 - a2*b1; - out.y = a2*b0 - a0*b2; - out.z = a0*b1 - a1*b0; - } - - - /* - private final void cross(float[] a, float[] b, float[] out) { - out[0] = a[1]*b[2] - a[2]*b[1]; - out[1] = a[2]*b[0] - a[0]*b[2]; - out[2] = a[0]*b[1] - a[1]*b[0]; - } - */ -} - diff --git a/android/core/src/processing/core/PLine.java b/android/core/src/processing/core/PLine.java deleted file mode 100644 index a18afda9c..000000000 --- a/android/core/src/processing/core/PLine.java +++ /dev/null @@ -1,1278 +0,0 @@ -/* -*- 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; - - -/** - * Code for rendering lines with P2D and P3D. - * @author rocha - * @author fry - */ -public class PLine implements PConstants -{ - private int[] m_pixels; - private float[] m_zbuffer; - //private int[] m_stencil; - - private int m_index; - - static final int R_COLOR = 0x1; - static final int R_ALPHA = 0x2; - static final int R_SPATIAL = 0x8; - static final int R_THICK = 0x4; - static final int R_SMOOTH = 0x10; - - private int SCREEN_WIDTH; - private int SCREEN_HEIGHT; - private int SCREEN_WIDTH1; - private int SCREEN_HEIGHT1; - - public boolean INTERPOLATE_RGB; - public boolean INTERPOLATE_ALPHA; - public boolean INTERPOLATE_Z; - public boolean INTERPOLATE_THICK; - - // antialias - private boolean SMOOTH; - - // blender - //private boolean BLENDER; - - // stroke color - private int m_stroke; - - // draw flags - public int m_drawFlags; - - // vertex coordinates - private float[] x_array; - private float[] y_array; - private float[] z_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; - - // start values - private float m_r0; - private float m_g0; - private float m_b0; - private float m_a0; - private float m_z0; - - // deltas - private float dz; - - // rgba deltas - private float dr; - private float dg; - private float db; - private float da; - - private PGraphics parent; - - - public PLine(PGraphics g) { - INTERPOLATE_Z = false; - - x_array = new float[2]; - y_array = new float[2]; - z_array = new float[2]; - r_array = new float[2]; - g_array = new float[2]; - b_array = new float[2]; - a_array = new float[2]; - - this.parent = g; - } - - - 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; - if (parent instanceof PGraphics3D) { - m_zbuffer = ((PGraphics3D) parent).zbuffer; - } - - // other things to reset - - INTERPOLATE_RGB = false; - INTERPOLATE_ALPHA = false; - //INTERPOLATE_Z = false; - m_drawFlags = 0; - m_index = 0; - //BLENDER = false; - } - - - public void setVertices(float x0, float y0, float z0, - float x1, float y1, float z1) { - // [rocha] fixed z drawing, so whenever a line turns on - // z interpolation, all the lines are z interpolated - if (z0 != z1 || z0 != 0.0f || z1 != 0.0f || INTERPOLATE_Z) { - INTERPOLATE_Z = true; - m_drawFlags |= R_SPATIAL; - } else { - INTERPOLATE_Z = false; - m_drawFlags &= ~R_SPATIAL; - } - - z_array[0] = z0; - z_array[1] = z1; - - x_array[0] = x0; - x_array[1] = x1; - - y_array[0] = y0; - y_array[1] = y1; - } - - - public void setIntensities(float r0, float g0, float b0, float a0, - float r1, float g1, float b1, float a1) { - a_array[0] = (a0 * 253f + 1.0f) * 65536f; - a_array[1] = (a1 * 253f + 1.0f) * 65536f; - - // check if we need alpha or not? - if ((a0 != 1.0f) || (a1 != 1.0f)) { - INTERPOLATE_ALPHA = true; - m_drawFlags |= R_ALPHA; - } else { - INTERPOLATE_ALPHA = false; - m_drawFlags &= ~R_ALPHA; - } - - // extra scaling added to prevent color "overflood" due to rounding errors - r_array[0] = (r0 * 253f + 1.0f) * 65536f; - r_array[1] = (r1 * 253f + 1.0f) * 65536f; - - g_array[0] = (g0 * 253f + 1.0f) * 65536f; - g_array[1] = (g1 * 253f + 1.0f) * 65536f; - - b_array[0] = (b0 * 253f + 1.0f) * 65536f; - b_array[1] = (b1 * 253f + 1.0f) * 65536f; - - // check if we need to interpolate the intensity values - if (r0 != r1) { - INTERPOLATE_RGB = true; - m_drawFlags |= R_COLOR; - - } else if (g0 != g1) { - INTERPOLATE_RGB = true; - m_drawFlags |= R_COLOR; - - } else if (b0 != b1) { - INTERPOLATE_RGB = true; - m_drawFlags |= R_COLOR; - - } else { - // when plain we use the stroke color of the first vertex - m_stroke = 0xFF000000 | - ((int)(255*r0) << 16) | ((int)(255*g0) << 8) | (int)(255*b0); - INTERPOLATE_RGB = false; - m_drawFlags &= ~R_COLOR; - } - } - - - public void setIndex(int index) { - m_index = index; - //BLENDER = false; - if (m_index != -1) { - //BLENDER = true; - } else { - m_index = 0; - } - } - - - public void draw() { - int xi; - int yi; - int length; - boolean visible = true; - - if (parent.smooth) { - SMOOTH = true; - m_drawFlags |= R_SMOOTH; - - } else { - SMOOTH = false; - m_drawFlags &= ~R_SMOOTH; - } - - /* - // line hack - if (parent.hints[DISABLE_FLYING_POO]) { - float nwidth2 = -SCREEN_WIDTH; - float nheight2 = -SCREEN_HEIGHT; - float width2 = SCREEN_WIDTH * 2; - float height2 = SCREEN_HEIGHT * 2; - if ((x_array[1] < nwidth2) || - (x_array[1] > width2) || - (x_array[0] < nwidth2) || - (x_array[0] > width2) || - (y_array[1] < nheight2) || - (y_array[1] > height2) || - (y_array[0] < nheight2) || - (y_array[0] > height2)) { - return; // this is a bad line - } - } - */ - - /////////////////////////////////////// - // line clipping - visible = lineClipping(); - if (!visible) { - return; - } - - /////////////////////////////////////// - // calculate line values - int shortLen; - int longLen; - boolean yLonger; - int dt; - - yLonger = false; - - // HACK for drawing lines left-to-right for rev 0069 - // some kind of bug exists with the line-stepping algorithm - // that causes strange patterns in the anti-aliasing. - // [040228 fry] - // - // swap rgba as well as the coords.. oops - // [040712 fry] - // - if (x_array[1] < x_array[0]) { - float t; - - t = x_array[1]; x_array[1] = x_array[0]; x_array[0] = t; - t = y_array[1]; y_array[1] = y_array[0]; y_array[0] = t; - t = z_array[1]; z_array[1] = z_array[0]; z_array[0] = t; - - t = r_array[1]; r_array[1] = r_array[0]; r_array[0] = t; - t = g_array[1]; g_array[1] = g_array[0]; g_array[0] = t; - t = b_array[1]; b_array[1] = b_array[0]; b_array[0] = t; - t = a_array[1]; a_array[1] = a_array[0]; a_array[0] = t; - } - - // important - don't change the casts - // is needed this way for line drawing algorithm - longLen = (int)x_array[1] - (int)x_array[0]; - shortLen = (int)y_array[1] - (int)y_array[0]; - - if (Math.abs(shortLen) > Math.abs(longLen)) { - int swap = shortLen; - shortLen = longLen; - longLen = swap; - yLonger = true; - } - - // now we sort points so longLen is always positive - // and we always start drawing from x[0], y[0] - if (longLen < 0) { - // swap order - o0 = 1; - o1 = 0; - - xi = (int) x_array[1]; - yi = (int) y_array[1]; - - length = -longLen; - - } else { - o0 = 0; - o1 = 1; - - xi = (int) x_array[0]; - yi = (int) y_array[0]; - - length = longLen; - } - - // calculate dt - if (length == 0) { - dt = 0; - } else { - dt = (shortLen << 16) / longLen; - } - - m_r0 = r_array[o0]; - m_g0 = g_array[o0]; - m_b0 = b_array[o0]; - - if (INTERPOLATE_RGB) { - dr = (r_array[o1] - r_array[o0]) / length; - dg = (g_array[o1] - g_array[o0]) / length; - db = (b_array[o1] - b_array[o0]) / length; - } else { - dr = 0; - dg = 0; - db = 0; - } - - m_a0 = a_array[o0]; - - if (INTERPOLATE_ALPHA) { - da = (a_array[o1] - a_array[o0]) / length; - } else { - da = 0; - } - - m_z0 = z_array[o0]; - //z0 += -0.001f; // [rocha] ugly fix for z buffer precision - - if (INTERPOLATE_Z) { - dz = (z_array[o1] - z_array[o0]) / length; - } else { - dz = 0; - } - - // draw thin points - if (length == 0) { - if (INTERPOLATE_ALPHA) { - drawPoint_alpha(xi, yi); - } else { - drawPoint(xi, yi); - } - return; - } - - /* - // draw antialias polygon lines for non stroked polygons - if (BLENDER && SMOOTH) { - // fix for endpoints not being drawn - // [rocha] - drawPoint_alpha((int)x_array[0], (int)x_array[0]); - drawPoint_alpha((int)x_array[1], (int)x_array[1]); - - drawline_blender(x_array[0], y_array[0], x_array[1], y_array[1]); - return; - } - */ - - // draw normal strokes - if (SMOOTH) { -// if ((m_drawFlags & R_SPATIAL) != 0) { -// drawLine_smooth_spatial(xi, yi, dt, length, yLonger); -// } else { - drawLine_smooth(xi, yi, dt, length, yLonger); -// } - - } else { - if (m_drawFlags == 0) { - drawLine_plain(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == R_ALPHA) { - drawLine_plain_alpha(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == R_COLOR) { - drawLine_color(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == (R_COLOR + R_ALPHA)) { - drawLine_color_alpha(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == R_SPATIAL) { - drawLine_plain_spatial(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == (R_SPATIAL + R_ALPHA)) { - drawLine_plain_alpha_spatial(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == (R_SPATIAL + R_COLOR)) { - drawLine_color_spatial(xi, yi, dt, length, yLonger); - - } else if (m_drawFlags == (R_SPATIAL + R_COLOR + R_ALPHA)) { - drawLine_color_alpha_spatial(xi, yi, dt, length, yLonger); - } - } - } - - - public boolean lineClipping() { - // new cohen-sutherland clipping code, as old one was buggy [toxi] - // get the "dips" for the points to clip - int code1 = lineClipCode(x_array[0], y_array[0]); - int code2 = lineClipCode(x_array[1], y_array[1]); - int dip = code1 | code2; - - if ((code1 & code2)!=0) { - - return false; - - } else if (dip != 0) { - - // now calculate the clipped points - float a0 = 0, a1 = 1, a = 0; - - for (int i = 0; i < 4; i++) { - if (((dip>>i)%2)==1){ - a = lineSlope(x_array[0], y_array[0], x_array[1], y_array[1], i+1); - if (((code1 >> i) % 2) == 1) { - a0 = (a>a0)?a:a0; // max(a,a0) - } else { - a1 = (a a1) { - return false; - } else { - float xt = x_array[0]; - float yt = y_array[0]; - - x_array[0] = xt + a0 * (x_array[1] - xt); - y_array[0] = yt + a0 * (y_array[1] - yt); - x_array[1] = xt + a1 * (x_array[1] - xt); - y_array[1] = yt + a1 * (y_array[1] - yt); - - // interpolate remaining parameters - if (INTERPOLATE_RGB) { - float t = r_array[0]; - r_array[0] = t + a0 * (r_array[1] - t); - r_array[1] = t + a1 * (r_array[1] - t); - t = g_array[0]; - g_array[0] = t + a0 * (g_array[1] - t); - g_array[1] = t + a1 * (g_array[1] - t); - t = b_array[0]; - b_array[0] = t + a0 * (b_array[1] - t); - b_array[1] = t + a1 * (b_array[1] - t); - } - - if (INTERPOLATE_ALPHA) { - float t = a_array[0]; - a_array[0] = t + a0 * (a_array[1] - t); - a_array[1] = t + a1 * (a_array[1] - t); - } - } - } - return true; - } - - - private int lineClipCode(float xi, float yi) { - int xmin = 0; - int ymin = 0; - int xmax = SCREEN_WIDTH1; - int ymax = SCREEN_HEIGHT1; - - //return ((yi < ymin ? 8 : 0) | (yi > ymax ? 4 : 0) | - // (xi < xmin ? 2 : 0) | (xi > xmax ? 1 : 0)); - //(int) added by ewjordan 6/13/07 because otherwise we sometimes clip last pixel when it should actually be displayed. - //Currently the min values are okay because values less than 0 should not be rendered; however, bear in mind that - //(int) casts towards zero, so without this clipping, values between -1+eps and +1-eps would all be rendered as 0. - return ((yi < ymin ? 8 : 0) | ((int)yi > ymax ? 4 : 0) | - (xi < xmin ? 2 : 0) | ((int)xi > xmax ? 1 : 0)); - } - - - private float lineSlope(float x1, float y1, float x2, float y2, int border) { - int xmin = 0; - int ymin = 0; - int xmax = SCREEN_WIDTH1; - int ymax = SCREEN_HEIGHT1; - - switch (border) { - case 4: return (ymin-y1)/(y2-y1); - case 3: return (ymax-y1)/(y2-y1); - case 2: return (xmin-x1)/(x2-x1); - case 1: return (xmax-x1)/(x2-x1); - } - return -1f; - } - - - private void drawPoint(int x0, int y0) { - float iz = m_z0; - int offset = y0 * SCREEN_WIDTH + x0; - - if (m_zbuffer == null) { - m_pixels[offset] = m_stroke; - - } else { - if (iz <= m_zbuffer[offset]) { - m_pixels[offset] = m_stroke; - m_zbuffer[offset] = iz; - } - } - } - - - private void drawPoint_alpha(int x0, int y0) { - int ia = (int) a_array[0]; - int pr = m_stroke & 0xFF0000; - int pg = m_stroke & 0xFF00; - int pb = m_stroke & 0xFF; - float iz = m_z0; - int offset = y0 * SCREEN_WIDTH + x0; - - if ((m_zbuffer == null) || iz <= m_zbuffer[offset]) { - int alpha = ia >> 16; - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = iz; - } - } - - - private void drawLine_plain(int x0, int y0, int dt, - int length, boolean vertical) { - // new "extremely fast" line code - // adapted from http://www.edepot.com/linee.html - // first version modified by [toxi] - // simplified by [rocha] - // length must be >= 0 - - //assert length>=0:length; - - int offset = 0; - - if (vertical) { - // vertical - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - m_pixels[offset] = m_stroke; - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - j+=dt; - } - - } else { - // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - m_pixels[offset] = m_stroke; - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - j+=dt; - } - } - } - - - private void drawLine_plain_alpha(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - - int pr = m_stroke & 0xFF0000; - int pg = m_stroke & 0xFF00; - int pb = m_stroke & 0xFF; - - int ia = (int) (m_a0); - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - - int alpha = ia >> 16; - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - //m_zbuffer[offset] = m_z0; // don't set zbuffer w/ alpha lines - - ia += da; - j += dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - - int alpha = ia >> 16; - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - //m_zbuffer[offset] = m_z0; // no zbuffer w/ alpha lines - - ia += da; - j += dt; - } - } - } - - - private void drawLine_color(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - m_pixels[offset] = 0xFF000000 | - ((ir & 0xFF0000) | ((ig >> 8) & 0xFF00) | (ib >> 16)); - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - ir += dr; - ig += dg; - ib += db; - j +=dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - m_pixels[offset] = 0xFF000000 | - ((ir & 0xFF0000) | ((ig >> 8) & 0xFF00) | (ib >> 16)); - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - ir += dr; - ig += dg; - ib += db; - j += dt; - } - } - } - - - private void drawLine_color_alpha(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - int ia = (int) m_a0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - - int alpha = ia >> 16; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - - ir+= dr; - ig+= dg; - ib+= db; - ia+= da; - j+=dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - - int alpha = ia >> 16; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = m_z0; - - ir+= dr; - ig+= dg; - ib+= db; - ia+= da; - j+=dt; - } - } - } - - - private void drawLine_plain_spatial(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - float iz = m_z0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - if (offset < m_pixels.length) { - if (iz <= m_zbuffer[offset]) { - m_pixels[offset] = m_stroke; - m_zbuffer[offset] = iz; - } - } - iz+=dz; - j+=dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - if (offset < m_pixels.length) { - if (iz <= m_zbuffer[offset]) { - m_pixels[offset] = m_stroke; - m_zbuffer[offset] = iz; - } - } - iz+=dz; - j+=dt; - } - } - } - - - private void drawLine_plain_alpha_spatial(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - float iz = m_z0; - - int pr = m_stroke & 0xFF0000; - int pg = m_stroke & 0xFF00; - int pb = m_stroke & 0xFF; - - int ia = (int) m_a0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - if (offset < m_pixels.length) { - if (iz <= m_zbuffer[offset]) { - int alpha = ia >> 16; - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - m_zbuffer[offset] = iz; - } - } - iz +=dz; - ia += da; - j += dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - - if (offset < m_pixels.length) { - if (iz <= m_zbuffer[offset]) { - int alpha = ia >> 16; - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - m_zbuffer[offset] = iz; - } - } - iz += dz; - ia += da; - j += dt; - } - } - } - - - private void drawLine_color_spatial(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - float iz = m_z0; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - - if (iz <= m_zbuffer[offset]) { - m_pixels[offset] = 0xFF000000 | - ((ir & 0xFF0000) | ((ig >> 8) & 0xFF00) | (ib >> 16)); - m_zbuffer[offset] = iz; - } - iz +=dz; - ir += dr; - ig += dg; - ib += db; - j += dt; - } - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - if (iz <= m_zbuffer[offset]) { - m_pixels[offset] = 0xFF000000 | - ((ir & 0xFF0000) | ((ig >> 8) & 0xFF00) | (ib >> 16)); - m_zbuffer[offset] = iz; - } - iz += dz; - ir += dr; - ig += dg; - ib += db; - j += dt; - } - return; - } - } - - - private void drawLine_color_alpha_spatial(int x0, int y0, int dt, - int length, boolean vertical) { - int offset = 0; - float iz = m_z0; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - int ia = (int) m_a0; - - if (vertical) { - length += y0; - for (int j = 0x8000 + (x0<<16); y0 <= length; ++y0) { - offset = y0 * SCREEN_WIDTH + (j>>16); - - if (iz <= m_zbuffer[offset]) { - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - - int alpha = ia >> 16; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - m_zbuffer[offset] = iz; - } - iz+=dz; - ir+= dr; - ig+= dg; - ib+= db; - ia+= da; - j+=dt; - } - - } else { // horizontal - length += x0; - for (int j = 0x8000 + (y0<<16); x0 <= length; ++x0) { - offset = (j>>16) * SCREEN_WIDTH + x0; - - if (iz <= m_zbuffer[offset]) { - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - int alpha = ia >> 16; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - m_zbuffer[offset] = iz; - } - iz += dz; - ir += dr; - ig += dg; - ib += db; - ia += da; - j += dt; - } - } - } - - - private void drawLine_smooth(int x0, int y0, int dt, - int length, boolean vertical) { - int xi, yi; // these must be >=32 bits - int offset = 0; - int temp; - int end; - - float iz = m_z0; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - int ia = (int) m_a0; - - if (vertical) { - xi = x0 << 16; - yi = y0 << 16; - - end = length + y0; - - while ((yi >> 16) < end) { - - offset = (yi>>16) * SCREEN_WIDTH + (xi>>16); - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - if ((m_zbuffer == null) || (iz <= m_zbuffer[offset])) { - int alpha = (((~xi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = iz; - } - - // this if() makes things slow. there should be a better way to check - // if the second pixel is within the image array [rocha] - temp = ((xi>>16)+1); - if (temp >= SCREEN_WIDTH) { - xi += dt; - yi += (1 << 16); - continue; - } - - offset = (yi>>16) * SCREEN_WIDTH + temp; - - if ((m_zbuffer == null) || (iz <= m_zbuffer[offset])) { - int alpha = (((xi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = iz; - } - - xi += dt; - yi += (1 << 16); - - iz+=dz; - ir+= dr; - ig+= dg; - ib+= db; - ia+= da; - } - - } else { // horizontal - xi = x0 << 16; - yi = y0 << 16; - end = length + x0; - - while ((xi >> 16) < end) { - offset = (yi>>16) * SCREEN_WIDTH + (xi>>16); - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - if ((m_zbuffer == null) || (iz <= m_zbuffer[offset])) { - int alpha = (((~yi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = iz; - } - - // see above [rocha] - temp = ((yi>>16)+1); - if (temp >= SCREEN_HEIGHT) { - xi += (1 << 16); - yi += dt; - continue; - } - - offset = temp * SCREEN_WIDTH + (xi>>16); - - if ((m_zbuffer == null) || (iz <= m_zbuffer[offset])) { - int alpha = (((yi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0&=0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - if (m_zbuffer != null) m_zbuffer[offset] = iz; - } - - xi += (1 << 16); - yi += dt; - - iz += dz; - ir += dr; - ig += dg; - ib += db; - ia += da; - } - } - } - - - /* - void drawLine_smooth(int x0, int y0, int dt, - int length, boolean vertical) { - int xi, yi; // these must be >=32 bits - int offset = 0; - int temp; - int end; - - int ir = (int) m_r0; - int ig = (int) m_g0; - int ib = (int) m_b0; - int ia = (int) m_a0; - - if (vertical) { - xi = x0 << 16; - yi = y0 << 16; - - end = length + y0; - - while ((yi >> 16) < end) { - offset = (yi>>16) * SCREEN_WIDTH + (xi>>16); - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int alpha = (((~xi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - - // this if() makes things slow. there should be a better way to check - // if the second pixel is within the image array [rocha] - temp = ((xi>>16)+1); - if (temp >= SCREEN_WIDTH) { - xi += dt; - yi += (1 << 16); - continue; - } - - offset = (yi>>16) * SCREEN_WIDTH + temp; - - alpha = (((xi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - r0 = m_pixels[offset]; - g0 = r0 & 0xFF00; - b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - - xi += dt; - yi += (1 << 16); - - ir += dr; - ig += dg; - ib += db; - ia += da; - } - - } else { // horizontal - xi = x0 << 16; - yi = y0 << 16; - end = length + x0; - - while ((xi >> 16) < end) { - offset = (yi>>16) * SCREEN_WIDTH + (xi>>16); - - int pr = ir & 0xFF0000; - int pg = (ig >> 8) & 0xFF00; - int pb = (ib >> 16); - - int alpha = (((~yi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - int r0 = m_pixels[offset]; - int g0 = r0 & 0xFF00; - int b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - - // see above [rocha] - temp = ((yi>>16)+1); - if (temp >= SCREEN_HEIGHT) { - xi += (1 << 16); - yi += dt; - continue; - } - - offset = temp * SCREEN_WIDTH + (xi>>16); - - alpha = (((yi >> 8) & 0xFF) * (ia >> 16)) >> 8; - - r0 = m_pixels[offset]; - g0 = r0 & 0xFF00; - b0 = r0 & 0xFF; - r0 &= 0xFF0000; - - r0 = r0 + (((pr - r0) * alpha) >> 8); - g0 = g0 + (((pg - g0) * alpha) >> 8); - b0 = b0 + (((pb - b0) * alpha) >> 8); - - m_pixels[offset] = 0xFF000000 | - (r0 & 0xFF0000) | (g0 & 0xFF00) | (b0 & 0xFF); - - xi += (1 << 16); - yi += dt; - - ir+= dr; - ig+= dg; - ib+= db; - ia+= da; - } - } - } - */ -} diff --git a/android/core/src/processing/core/PTriangle.java b/android/core/src/processing/core/PTriangle.java deleted file mode 100644 index 97c4fed2e..000000000 --- a/android/core/src/processing/core/PTriangle.java +++ /dev/null @@ -1,3850 +0,0 @@ -/* -*- 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. - *

- * 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; - } - } -}