/* JWildfire - an image and animation processor written in Java Copyright (C) 1995-2011 Andreas Maschke This 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 software 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 software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jwildfire.transform; import org.jwildfire.base.mathlib.MathLib; import org.jwildfire.image.Pixel; import org.jwildfire.image.SimpleImage; import org.jwildfire.transform.Mesh3DTransformer.Faces; import org.jwildfire.transform.Mesh3DTransformer.Light; public abstract class Mesh3DRenderer { public abstract void renderImage(Mesh3D pMesh3D, Mesh3DTransformer pMesh3DTransformer, SimpleImage pImg); protected static final double PZERO = 0.000001; protected static final int MAXLIGHT = 4; protected int x12[], y12[], z12[]; protected int x23[], y23[], z23[]; protected int x41[], y41[], z41[]; protected int f3Count; protected int p31[], p32[], p33[]; protected int coloro[]; protected double x[], y[], z[]; protected int width, height; protected double cx, cy; protected int fInd[]; protected double fZSortArray[]; protected final Pixel toolPixel = new Pixel(); protected Light doLight; protected Faces faces; protected double reff, rr; protected double refx, refy, refz; protected double nfx, nfy, nfz, cosa; protected double viewz; protected int min, max, zMin, zMax; protected int pr, pg, pb; protected double ttfr, ttfg, ttfb; protected int havex, k12r, k23r, n23, n, k, k41r, n41; protected int lux, luy, luz; protected int rux, ruy, ruz; protected int rbx, rby, rbz; protected int n12, iv; protected int r, g, b; protected double lightX[]; protected double lightY[]; protected double lightZ[]; protected double lightRed[]; protected double lightGreen[]; protected double lightBlue[]; protected double ambient, diffuse, phong, phongSize; protected int lightCount; protected double[] u; protected double[] v; protected SimpleImage texture; protected void init(Mesh3D pMesh3D, Mesh3DTransformer pMesh3DTransformer, SimpleImage pImg) { /* allocate the structures */ int bsize = 1024; x12 = new int[bsize]; y12 = new int[bsize]; z12 = new int[bsize]; x23 = new int[bsize]; y23 = new int[bsize]; z23 = new int[bsize]; x41 = new int[bsize]; y41 = new int[bsize]; z41 = new int[bsize]; f3Count = pMesh3D.getFCount(); p31 = pMesh3D.getPP1(); p32 = pMesh3D.getPP2(); p33 = pMesh3D.getPP3(); x = pMesh3D.getX(); y = pMesh3D.getY(); z = pMesh3D.getZ(); width = pImg.getImageWidth(); height = pImg.getImageHeight(); cx = (double) width / 2.0; cy = (double) height / 2.0; coloro = pMesh3D.getColor(); u = pMesh3D.getU(); v = pMesh3D.getV(); texture = pMesh3D.getTexture(); fInd = new int[f3Count]; fZSortArray = new double[f3Count]; // TODO cFunc // doColorFunc=obj->colorFunc; lightX = new double[MAXLIGHT]; lightY = new double[MAXLIGHT]; lightZ = new double[MAXLIGHT]; lightRed = new double[MAXLIGHT]; lightGreen = new double[MAXLIGHT]; lightBlue = new double[MAXLIGHT]; lightX[0] = pMesh3DTransformer.getLight1X(); lightY[0] = pMesh3DTransformer.getLight1Y(); lightZ[0] = pMesh3DTransformer.getLight1Z(); lightRed[0] = (double) pMesh3DTransformer.getLight1Color().getRed() / 255.0; lightGreen[0] = (double) pMesh3DTransformer.getLight1Color().getGreen() / 255.0; lightBlue[0] = (double) pMesh3DTransformer.getLight1Color().getBlue() / 255.0; lightX[1] = pMesh3DTransformer.getLight2X(); lightY[1] = pMesh3DTransformer.getLight2Y(); lightZ[1] = pMesh3DTransformer.getLight2Z(); lightRed[1] = (double) pMesh3DTransformer.getLight2Color().getRed() / 255.0; lightGreen[1] = (double) pMesh3DTransformer.getLight2Color().getGreen() / 255.0; lightBlue[1] = (double) pMesh3DTransformer.getLight2Color().getBlue() / 255.0; lightX[2] = pMesh3DTransformer.getLight3X(); lightY[2] = pMesh3DTransformer.getLight3Y(); lightZ[2] = pMesh3DTransformer.getLight3Z(); lightRed[2] = (double) pMesh3DTransformer.getLight3Color().getRed() / 255.0; lightGreen[2] = (double) pMesh3DTransformer.getLight3Color().getGreen() / 255.0; lightBlue[2] = (double) pMesh3DTransformer.getLight3Color().getBlue() / 255.0; lightX[3] = pMesh3DTransformer.getLight4X(); lightY[3] = pMesh3DTransformer.getLight4Y(); lightZ[3] = pMesh3DTransformer.getLight4Z(); lightRed[3] = (double) pMesh3DTransformer.getLight4Color().getRed() / 255.0; lightGreen[3] = (double) pMesh3DTransformer.getLight4Color().getGreen() / 255.0; lightBlue[3] = (double) pMesh3DTransformer.getLight4Color().getBlue() / 255.0; lightCount = MAXLIGHT; for (int i = MAXLIGHT - 1; i > 0; i--) { if ((lightRed[i] < MathLib.EPSILON) && (lightGreen[i] < MathLib.EPSILON) && (lightBlue[i] < MathLib.EPSILON)) lightCount--; else break; } ambient = pMesh3DTransformer.getAmbient(); if (ambient < 0.0) ambient = 0.0; else if (ambient > 1.0) ambient = 1.0; diffuse = pMesh3DTransformer.getDiffuse(); if (diffuse < 0.0) diffuse = 0.0; else if (diffuse > 1.0) diffuse = 1.0; phong = pMesh3DTransformer.getPhong(); if (phong < 0.0) phong = 0.0; phongSize = pMesh3DTransformer.getPhongSize(); if (phongSize < 0.0) phongSize = 0.0; faces = pMesh3DTransformer.getFaces(); doLight = pMesh3DTransformer.getLight(); if (doLight != Light.OFF) { initPhongArray(phong, phongSize); } else faces = Faces.DOUBLE; } protected void heapSortFloat1(double[] f, int[] ind, int count) { int j, help; for (j = count / 2; j >= 0; j--) correctFloat1(j, count - 1, f, ind); for (j = count - 1; j > 0; j--) { help = ind[0]; ind[0] = ind[j]; ind[j] = help; correctFloat1(0, j - 1, f, ind); } } private void correctFloat1(int i, int n, double[] ff, int[] ind) { int j, help; j = i * 2; if (j <= n) { if (((j + 1) <= n) && (ff[ind[j + 1]] > ff[ind[j]])) j++; if (ff[ind[j]] > ff[ind[i]]) { help = ind[i]; ind[i] = ind[j]; ind[j] = help; correctFloat1(j, n, ff, ind); } } } protected int bresenham3D(int x1, int y1, int z1, int x2, int y2, int z2, int[] x, int[] y, int[] z) { int dx, dy, xf, yf, a, b, c, i; double zz, dz; if (x2 > x1) { dx = x2 - x1; xf = 1; } else { dx = x1 - x2; xf = -1; } if (y2 > y1) { dy = y2 - y1; yf = 1; } else { dy = y1 - y2; yf = -1; } if (dx > dy) { zz = (double) z1; if (dx > 0) dz = (double) (z2 - z1) / (double) dx; else dz = 0.0; a = dy + dy; c = a - dx; b = c - dx; for (i = 0; i <= dx; i++) { x[i] = x1; y[i] = y1; z[i] = (int) (zz + 0.5); zz += dz; x1 += xf; if (c < 0) { c += a; } else { c += b; y1 += yf; } } return ((int) (dx + 1)); } else { zz = (double) z1; if (dy > 0) dz = (double) (z2 - z1) / (double) dy; else dz = 0.0; a = dx + dx; c = a - dy; b = c - dy; for (i = 0; i <= dy; i++) { x[i] = x1; y[i] = y1; z[i] = (int) (zz + 0.5); zz += dz; y1 += yf; if (c < 0) { c += a; } else { c += b; x1 += xf; } } return ((int) (dy + 1)); } } protected void reflectViewVector() { reff = nfz + nfz; refx = reff * nfx; refy = reff * nfy; refz = reff * nfz - viewz; rr = Math.sqrt(refx * refx + refy * refy + refz * refz); if (Math.abs(rr) < PZERO) { refx = refy = refz = 0; } else { refx /= rr; refy /= rr; refz /= rr; } /* reff=nfz+nfz; refx=reff*nfx; refy=reff*nfy; refz=reff*nfz-viewz; reff=nfx*viewx+nfy*viewy+nfz*viewz;reff+=reff; refx=reff*nfx-viewx; refy=reff*nfy-viewy; refz=reff*nfz-viewz; if(TESTLMB()!=0) { printf("*n: %g %g %g\n",nfx,nfy,nfz); printf("*ref: %g %g %g\n",refx,refy,refz); } */ } protected void rFill3() { /* search the left and right x-value */ havex = 0; if (((k >= luy) && (k <= ruy)) || ((k >= ruy) && (k <= luy))) { havex++; n = -1; do { n++; } while (y12[n] != k); min = max = x12[n]; zMin = zMax = z12[n]; k12r = n + 1; while (k12r < n12) { if (y12[k12r] != k) break; k12r++; } if ((--k12r) > n) { iv = x12[k12r]; if (iv < min) { min = iv; zMin = z12[k12r]; } else if (iv > max) { max = iv; zMax = z12[k12r]; } } } if (((k >= ruy) && (k <= rby)) || ((k >= rby) && (k <= ruy))) { if (havex == 0) { havex++; n = -1; do { n++; } while (y23[n] != k); min = max = x23[n]; zMin = zMax = z23[n]; k23r = n + 1; while (k23r < n23) { if (y23[k23r] != k) break; k23r++; } if ((--k23r) > n) { iv = x23[k23r]; if (iv < min) { min = iv; zMin = z23[k23r]; } else if (iv > max) { max = iv; zMax = z23[k23r]; } } } else { n = -1; do { n++; } while (y23[n] != k); iv = x23[n]; if (iv < min) { min = iv; zMin = z23[n]; } else if (iv > max) { max = iv; zMax = z23[n]; } k23r = n + 1; while (k23r < n23) { if (y23[k23r] != k) break; k23r++; } if ((--k23r) > n) { iv = x23[k23r]; if (iv < min) { min = iv; zMin = z23[k23r]; } else if (iv > max) { max = iv; zMax = z23[k23r]; } } } } if (((k >= rby) && (k <= luy)) || ((k >= luy) && (k <= rby))) { if (havex == 0) { havex++; n = -1; do { n++; } while (y41[n] != k); min = max = x41[n]; zMin = zMax = z41[n]; k41r = n + 1; while (k41r < n41) { if (y41[k41r] != k) break; k41r++; } if ((--k41r) > n) { iv = x41[k41r]; if (iv < min) { min = iv; zMin = z41[k41r]; } else if (iv > max) { max = iv; zMax = z41[k41r]; } } } else { n = -1; do { n++; } while (y41[n] != k); iv = x41[n]; if (iv < min) { min = iv; zMin = z41[n]; } else if (iv > max) { max = iv; zMax = z41[n]; } k41r = n + 1; while (k41r < n41) { if (y41[k41r] != k) break; k41r++; } if ((--k41r) > n) { iv = x41[k41r]; if (iv < min) { min = iv; zMin = z41[k41r]; } else if (iv > max) { max = iv; zMax = z41[k41r]; } } } } } protected void addLight(double px, double py, double pz) { ttfr = ttfg = ttfb = 0.0; double rn = (double) r / 255.0; double gn = (double) g / 255.0; double bn = (double) b / 255.0; for (int q = 0; q < lightCount; q++) { double dint = 0.0; double pint = 0.0; double lx = px - lightX[q]; double ly = py - lightY[q]; double lz = pz - lightZ[q]; rr = Math.sqrt(lx * lx + ly * ly + lz * lz); if (Math.abs(rr) <= PZERO) { lx = ly = 0.0; lz = -1.0; } else { lx /= rr; ly /= rr; lz /= rr; } cosa = nfx * lx + nfy * ly + nfz * lz; if (faces != Faces.DOUBLE) { if (cosa < 0.0) cosa = 0.0; } else { if (cosa < 0.0) { cosa = 0.0 - cosa; nfx = 0.0 - nfx; nfy = 0.0 - nfy; nfz = 0.0 - nfz; reflectViewVector(); } } dint = diffuse * cosa; cosa = refx * lx + refy * ly + refz * lz; if (cosa > 0.0) pint = phongInt(cosa); dint = (dint > 1.0 ? 1.0 : dint); pint = (pint > 1.0 ? 1.0 : pint); ttfr += ((dint * rn + pint) * lightRed[q]); ttfg += ((dint * gn + pint) * lightGreen[q]); ttfb += ((dint * bn + pint) * lightBlue[q]); } ttfr += rn * ambient; ttfg += gn * ambient; ttfb += bn * ambient; //System.out.println(ttfr + " " + ttfg + " " + ttfb); int tt = (int) (ttfr * 255.0 + 0.5); if (tt < 0) tt = 0; else if (tt > 255) tt = 255; pr = tt; tt = (int) (ttfg * 255.0 + 0.5); if (tt < 0) tt = 0; else if (tt > 255) tt = 255; pg = tt; tt = (int) (ttfb * 255.0 + 0.5); if (tt < 0) tt = 0; else if (tt > 255) tt = 255; pb = tt; /* cosa=refx*lx+refy*ly+refz*lz; \ if(cosa>0.0) { \ pint=phong*pow(cosa,phongSize); \ } \*/ } protected static final int PASIZE = 4096; protected double dPhong = 0.0; protected double phongArray[] = new double[PASIZE + 4]; protected void initPhongArray(double pPhong, double pPhongSize) { dPhong = 1.0 / (double) (PASIZE - 1); double a = 0.0; for (int i = 0; i < (PASIZE + 4); i++) { phongArray[i] = pPhong * Math.pow(a, pPhongSize); a += dPhong; } } protected double phongInt(double cosa) { /* PTFLOAT res,fi; WORD i1,i2; fi=cosa/dPhong; i1=(WORD)fi; i2=i1+1; res=phongArray[i1]+(fi-(PTFLOAT)i1)*(phongArray[i2]-phongArray[i1]); if(TESTLMB()!=0) { printf("res: %f, exact: %f, res2: %f\n",res,oldPhong*pow(cosa,oldPhongSize),phongArray[(WORD)(cosa/dPhong+0.5)]); } return(res); */ /* System.out.println(cosa + "/" + ((int) (cosa / dPhong + 0.5)) + ": " + (phongArray[(int) (cosa / dPhong + 0.5)])); */ return phongArray[(int) (cosa / dPhong + 0.5)]; } }