<<>> <> <> <> <> DIRECTORY G3dBasic, G3dNormalCoding, G3dVector, Random, Real, RealFns; G3dNormalCodingImpl: CEDAR PROGRAM IMPORTS G3dVector, Random, Real, RealFns EXPORTS G3dNormalCoding ~ BEGIN <> Triple: TYPE ~ G3dBasic.Triple; RandomStream: TYPE ~ Random.RandomStream; <> NtoGTable: TYPE ~ ARRAY [0 .. 17] OF ARRAY [0 ..17] OF INT; GtoNTable: TYPE ~ ARRAY [0 .. 255] OF Triple; <> <<-- NOTE that the order of these calls is important>> ntogTable: NtoGTable ¬ InitNtoGTable[]; gtonTable: GtoNTable ¬ InitGtoNTable[]; rs: RandomStream ¬ Random.Create[range: 500, seed: 1989]; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < 0 >> <> <> <<-LOOPHOLE[scanSeg[v+1][x], INTEGER]/32768.0 >> <<]>> <> <> <> <> <<];>> <> <> <> <> <<];>> <<};>> <> <<}; >> <> EncodeNormal: PUBLIC PROC [dx, dy: REAL, dither: BOOLEAN ¬ TRUE, userRS: RandomStream ¬ NIL] RETURNS [pval: INT] ~ { scale: REAL ¬ 8.5; -- 17/2.0 dz: REAL ¬ 1.0 - ((dx * dx) + (dy * dy)); xentry, yentry: INT; lrs: RandomStream ¬ IF userRS = NIL THEN rs ELSE userRS; IF dz < 0.0 THEN RETURN[0] ELSE { IF dither THEN { slip: REAL ¬ 3.0/17.0; -- use 3.0/17.0 for good results, 1.0/17.0 for debugging scale: REAL ¬ (2.0 * slip) / 499.0; xfuzz: REAL ¬ (scale * Random.NextInt[lrs]) - slip; yfuzz: REAL ¬ (scale * Random.NextInt[lrs]) - slip; dx ¬ dx + xfuzz; dy ¬ dy + yfuzz; dz ¬ (dx * dx) + (dy * dy); IF dz > 1.0 THEN { dz ¬ RealFns.SqRt[dz]; dx ¬ dx / dz; dy ¬ dy / dz; }; }; xentry ¬ MIN[16, Real.Floor[(1.0 + dx) * scale]]; yentry ¬ MIN[16, Real.Floor[(1.0 + dy) * scale]]; RETURN[ntogTable[yentry][xentry]]; }; }; DecodeNormal: PUBLIC PROC [pval: INT] RETURNS [n: Triple] ~ { RETURN[gtonTable[pval]]; }; IsValidNormalIndex: PUBLIC PROC [index: INT] RETURNS [BOOLEAN] ~ { RETURN[index >= 6 AND index < 255]; }; <> <> <> <<0: Foreground color (usually black)>> <<255: Background color (usually white)>> <<1: Light Source Swatch>> <<2: Material Swatch>> <<3-5: Reserved>> <> <<>> BuildNormalTables: PUBLIC PROC [] ~ { <<-- NOTE that the order of these calls is important>> ntogTable ¬ InitNtoGTable[]; gtonTable ¬ InitGtoNTable[]; <> rs ¬ Random.Create[range: 500, seed: 1989]; }; InitNtoGTable: PROC [] RETURNS [ng: NtoGTable] ~ { GridCheck: PROC [centerx, centery, size: REAL] RETURNS [BOOLEAN] ~ { d: REAL ¬ 1.0 - ((centerx * centerx) + (centery * centery)); IF d > 0.0 THEN RETURN [TRUE] ELSE { lx: REAL ¬ centerx - size; hx: REAL ¬ centerx + size; ly: REAL ¬ centery - size; hy: REAL ¬ centery + size; IF (lx*lx) + (ly*ly) < 1.0 THEN RETURN [TRUE]; IF (lx*lx) + (hy*hy) < 1.0 THEN RETURN [TRUE]; IF (hx*hx) + (hy*hy) < 1.0 THEN RETURN [TRUE]; IF (hx*hx) + (ly*ly) < 1.0 THEN RETURN [TRUE]; RETURN [FALSE]; }; }; width: INT ¬ 17; current: INT ¬ 6; iwidth: REAL ¬ 1.0/width; offset: REAL ¬ iwidth - 1.0; inc: REAL ¬ 2.0 * iwidth; FOR y: INT IN [0 .. width) DO ny: REAL ¬ offset + (y * inc); FOR x: INT IN [0 .. width) DO nx: REAL ¬ offset + (x * inc); IF GridCheck[nx, ny, iwidth] THEN { ng[y][x] ¬ current; current ¬ current+1; } ELSE { ng[y][x] ¬ -1; }; ENDLOOP; ENDLOOP; }; <<-- NOTE! You must call InitNtoGTable before calling InitGtoNTable>> InitGtoNTable: PROC [] RETURNS [gn: GtoNTable] ~ { hits: INT; offset: REAL ¬ -16.0/17.0; inc: REAL ¬ 2.0/17.0; FOR a: INT IN [0 .. 255] DO gn[a] ¬ [-1.0, -1.0, -1.0]; ENDLOOP; FOR y: INT IN [0 .. 16] DO FOR x: INT IN [0 .. 16] DO entry: INT ¬ ntogTable[y][x]; IF entry > 0 THEN { ulx: REAL ¬ (x * inc) - 1.0; uly: REAL ¬ (y * inc) - 1.0; wid: REAL ¬ inc / 5.0; norm: Triple ¬ [0.0, 0.0, 0.0]; hits ¬ 0; FOR i: INT IN [0 .. 5] DO fy: REAL ¬ uly + wid*i; FOR j: INT IN [0 .. 5] DO fx: REAL ¬ ulx + wid*j; fz: REAL ¬ (fx*fx)+(fy*fy); IF fz <= 1.0 THEN { fz ¬ RealFns.SqRt[1.0 - fz]; norm ¬ G3dVector.Add[norm, [fx, fy, -fz]]; hits ¬ hits + 1; }; ENDLOOP; ENDLOOP; gn[entry] ¬ G3dVector.Unit[norm]; }; ENDLOOP; ENDLOOP; }; END. <<>>