using System; using System.Drawing; namespace Voxelcat { public class Frustum { public double lx, ly, mx, my; public double Width { get { return mx - lx; } } public double Height { get { return my - ly; } } public double SpreadFactor = 1.05; public double Z = 1.0; public Frustum() { lx = -Blitman.Width / 2.0; ly = -Blitman.Height / 2.0; mx = Blitman.Width / 2.0; my = Blitman.Height / 2.0; } public void Advance(double z) { Z += z; double hz = z * (1.0 + ((SpreadFactor - 1.0) / 2.0)); lx *= hz; ly *= hz; mx *= hz; my *= hz; } } public interface VoxelStructure { int TryGetVoxelInRayPath(double rsx, double rsy, double rsz, double rfx, double rfy, double rfz); } public class Octree : VoxelStructure { // 0 = front top left, 1 = front top right, 2 = front bottom left, 3 = front bottom right, // 4 = back top left, ... etc. public VoxelStructure[] Friends = new VoxelStructure[8]; // dimensions MUST BE POSITIVELY ALONG AXES! m_ always greater than l_. public double lx, ly, lz, mx, my, mz; public Octree(double olx, double oly, double olz, double omx, double omy, double omz) { this.lx = (olx < omx ? olx : omx); this.ly = (oly < omy ? oly : omy); this.lz = (olz < omz ? olz : omz); this.mx = (omx > olx ? omx : olx); this.my = (omy > oly ? omy : oly); this.mz = (omz > olz ? omz : olz); } public int TryGetVoxelInRayPath(double rsx, double rsy, double rsz, double rfx, double rfy, double rfz) { // Input ray MUST BE GOING POSITIVELY ALONG AXES! rf_ always greater than rs_. // if, for every dimension, ray contains octree or octree contains ray: if ((rsz <= lz) && (rfz >= mz) || (lz < rsz) && (mz > rfz)) if ((rsy <= ly) && (rfy >= my) || (ly < rsy) && (my > rfy)) if ((rsx <= lx) && (rfx >= mx) || (lx < rsx) && (mx > rfx)) { // ok, so we should search internally then. foreach (VoxelStructure oct in Friends) { if (oct == null) continue; int c = oct.TryGetVoxelInRayPath(rsx, rsy, rsz, rfx, rfy, rfz); if (c != 0) return c; } // crap accuracy has screwed us over, or just a sparse octree. //Console.WriteLine(string.Format("crap accuracy screwed us over in octree with bounds ({0},{1},{2}::{3},{4},{5})")); return 0; // TODO: return red? } return 0; } } public class Voxel : VoxelStructure { public double lx, ly, lz, mx, my, mz; public int c; public Voxel(double olx, double oly, double olz, double omx, double omy, double omz, int oc) { this.lx = olx; this.ly = oly; this.lz = olz; this.mx = omx; this.my = omy; this.mz = omz; this.c = oc; } #region VoxelStructure implementation public int TryGetVoxelInRayPath(double rsx, double rsy, double rsz, double rfx, double rfy, double rfz) { if ((rsz <= lz) && (rfz >= mz) || (lz < rsz) && (mz > rfz)) if ((rsy <= ly) && (rfy >= my) || (ly < rsy) && (my > rfy)) if ((rsx <= lx) && (rfx >= mx) || (lx < rsx) && (mx > rfx)) return c; return 0; } #endregion } public class SimpleVox { const double maxz = 100.0; VoxelStructure world; private void SubconstructVoxelsForOctree(Octree oct) { double hx = (oct.lx + oct.mx) / 2.0; double hy = (oct.ly + oct.my) / 2.0; double hz = (oct.lz + oct.mz) / 2.0; oct.Friends[0] = new Voxel(oct.lx ,oct.ly , oct.lz, hx, hy, hz, 0); oct.Friends[1] = new Voxel(hx , oct.ly, oct.lz, oct.mx, hy, hz, 0); oct.Friends[2] = new Voxel(oct.lx , hy, oct.lz, hx, oct.my, hz, 0); oct.Friends[3] = new Voxel(hx, hy, oct.lz, oct.mx, oct.my, hz, 0); oct.Friends[4] = new Voxel(oct.lx ,oct.ly , hz, hx, hy, oct.mz, 0); oct.Friends[5] = new Voxel(hx , oct.ly, hz, oct.mx, hy, oct.mz, 0); oct.Friends[6] = new Voxel(oct.lx , hy, hz, hx, oct.my, oct.mz, 0); oct.Friends[7] = new Voxel(hx, hy, hz, oct.mx, oct.my, oct.mz, 0); } private void SubconstructOctree(Octree oct) { double hx = (oct.lx + oct.mx) / 2.0; double hy = (oct.ly + oct.my) / 2.0; double hz = (oct.lz + oct.mz) / 2.0; oct.Friends[0] = new Octree(oct.lx ,oct.ly , oct.lz, hx, hy, hz); oct.Friends[1] = new Octree(hx , oct.ly, oct.lz, oct.mx, hy, hz); oct.Friends[2] = new Octree(oct.lx , hy, oct.lz, hx, oct.my, hz); oct.Friends[3] = new Octree(hx, hy, oct.lz, oct.mx, oct.my, hz); //oct.Friends[4] = new Octree(oct.lx ,oct.ly , hz, hx, hy, oct.mz); //oct.Friends[5] = new Octree(hx , oct.ly, hz, oct.mx, hy, oct.mz); //oct.Friends[6] = new Octree(oct.lx , hy, hz, hx, oct.my, oct.mz); //oct.Friends[7] = new Octree(hx, hy, hz, oct.mx, oct.my, oct.mz); } public SimpleVox () { Octree oct = new Octree(0.0, 0.0, 1.0, 1.0, 1.0, 2.0); SubconstructOctree(oct); for (int i = 0; i < 4; i++) { SubconstructVoxelsForOctree((Octree)oct.Friends[i]); ((Voxel)(((Octree)oct.Friends[i]).Friends[3-i])).c = int.MaxValue; for (int y = 0; y < 8; y++) if (y != 3-i) (((Octree)oct.Friends[i])).Friends[y] = null; } world = oct; } public int[] Render(int w, int h) { int[] results = new int[w * h]; double sy = 1.0/(2*h); double sx = 1.0/(2*w); double mz = 5.0; double spr = 0.00; for (int iy = 0; iy < h; iy++) for (int ix = 0; ix < w; ix++) { double x = ix * (1.0/w) + sx; double y = iy * (1.0/h) + sy; int i =(int)(iy * w + ix) ; results[i] = world.TryGetVoxelInRayPath(x, y, 0.0, x + x * spr, y + y* spr, mz); } return results; } public bool voxExistsAt(double x, double y, double z) { return (x > 0.5 && x < 0.7 && y > 0.5 && y < 0.7); } } }