budnhead/org.budnhead/core/SquaredMap.cs

334 lines
7.5 KiB
C#

using System;
using System.IO;
using System.Collections.Generic;
using ImageSharp;
using ImageSharp.PixelFormats;
using OpenTK.Graphics.OpenGL4;
using OpenTK;
using org.hwo.contracts;
using org.budnhead.exceptions;
using org.budnhead.graphics;
namespace org.budnhead.core
{
public class SquaredMap : WorldObject
{
public static SquaredMap activeMap;
public static float edge = 5;
public static readonly float maxHeight = 128.0f;
private int width,
height;
public Vector3[] corners;
private MapModel3D model;
public SquaredMap(int width,int height)
{
activeMap = this;
this.width = width;
this.height = height;
generateBaseMap();
}
public override Model3D getModel3D()
{
return this.model;
}
public SquaredMap(Image heightMap)
{
activeMap = this;
this.width = heightMap.Width-1;
this.height = heightMap.Height-1;
generateBaseMap();
loadHeightMap( heightMap );
model.rebind();
}
protected void generateBaseMap(){
this.model = new MapModel3D(this,width,height);
this.corners = new Vector3[8];
this.corners[0] = new Vector3();
this.corners[1] = new Vector3(width * edge,0,0);
this.corners[2] = new Vector3(width * edge,height * edge,0);
this.corners[3] = new Vector3(0,height * edge,0);
this.corners[4] = new Vector3(0,0,maxHeight);
this.corners[5] = new Vector3(width * edge,0,maxHeight);
this.corners[6] = new Vector3(width * edge,height * edge,maxHeight);
this.corners[7] = new Vector3(0,height * edge,maxHeight);
for (int y=0;y<height;y++){
for (int x=0;x<width;x++){
int bi = 4 * (x + (y * width));
float cx = (edge * x) + (edge / 2);
float cy = (edge * y) + (edge / 2);
Vector3 a = new Vector3(),b = new Vector3(),c = new Vector3();
a.X = (edge * (x+1));
a.Y = (edge * y);
b.X = (edge * x);
b.Y = (edge * y);
c.X = cx;
c.Y = cy;
model.triangles[bi].vertexes(c,b,a);
a.X = (edge * (x+1));
a.Y = (edge * (y+1));
b.X = (edge * (x+1));
b.Y = (edge * y);
c.X = cx;
c.Y = cy;
model.triangles[bi+1].vertexes(c,b,a);
a.X = (edge * x);
a.Y = (edge * (y+1));
b.X = (edge * (x+1));
b.Y = (edge * (y+1));
c.X = cx;
c.Y = cy;
model.triangles[bi+2].vertexes(c,b,a);
a.X = (edge * x);
a.Y = (edge * y);
b.X = (edge * x);
b.Y = (edge * (y+1));
c.X = cx;
c.Y = cy;
model.triangles[bi+3].vertexes(c,b,a);
}
}
}
public void loadHeightMap(Image _heightMap){
Rgba32[] pixels = _heightMap.Pixels;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Rgba32[] pixel = new Rgba32[4];
float[] h = new float[4];
float ah = 0;
pixel[0] = pixels[ x + ((y+0) * (width + 1)) + 0 ];
pixel[1] = pixels[ x + ((y+0) * (width + 1)) + 1 ];
pixel[2] = pixels[ x + ((y+1) * (width + 1)) + 1 ];
pixel[3] = pixels[ x + ((y+1) * (width + 1)) + 0 ];
for (int n=0;n<4;n++){
h[n] = (pixel[n].R + pixel[n].G + pixel[n].B) * maxHeight / 768;
ah += h[n]/4;
}
int bi = 12 * (x + (y * width));
model.vertexes[ bi++ ].Z = ah;
model.vertexes[ bi++ ].Z = h[0];
model.vertexes[ bi++ ].Z = h[1];
model.vertexes[ bi++ ].Z = ah;
model.vertexes[ bi++ ].Z = h[1];
model.vertexes[ bi++ ].Z = h[2];
model.vertexes[ bi++ ].Z = ah;
model.vertexes[ bi++ ].Z = h[2];
model.vertexes[ bi++ ].Z = h[3];
model.vertexes[ bi++ ].Z = ah;
model.vertexes[ bi++ ].Z = h[3];
model.vertexes[ bi++ ].Z = h[0];
}
}
model.computeNormals();
model.colorMap();
}
private int tileIndex(int x,int y){
return (x + (width * y)) * 4;
}
public Vector3 ground(Vector2 _xy){
Vector2 xy = _xy / edge;
if ((xy.X < 0)||(xy.Y<0)||(xy.X>=width)||(xy.Y>=height)){
throw new OutOfWorldException();
}
int i1 = tileIndex((int)xy.X,(int)xy.Y);
for (int n=0;n<4;n++){
Vector3 A,B,C,P,V;
Vector3 p = new Vector3();
A = model.triangles[i1+n].VertexA;
B = model.triangles[i1+n].VertexB;
C = model.triangles[i1+n].VertexC;
P = new Vector3(_xy);
V = Vector3.UnitZ;
if (Geometry.intersectTriangle(P,V,A,B,C,out p)){
Console.WriteLine("Grounded to: {0}",p);
return p;
} else {
Console.WriteLine("No Ground at triangle {0}",n);
}
}
throw new OutOfWorldException();
}
public Vector2 toTileBorderless(Vector2 world){
Vector2 tile = world / edge;
return new Vector2((int)tile.X,(int)tile.Y);
}
public Vector2 toTile(Vector2 world){
Vector2 tile = new Vector2();
new BooleanConditional()
.does(delegate { tile = world / edge; })
.requires(tile.X >= 0)
.requires(tile.Y >= 0)
.requires(tile.X < width)
.requires(tile.Y < height)
.throws<OutOfWorldException>();
return new Vector2((int)tile.X,(int)tile.Y);
}
public Vector2 intersectTile(Vector3 P,Vector3 V){
return toTile( intersect(P,V).Xy );
}
public Vector3 intersect(Vector3 P,Vector3 V){
Vector3
A = new Vector3(), // Lower plane intersection
B = new Vector3(); // Upper plane intersection
Console.WriteLine("P: {0} V: {1}",P,V);
A = P + ( V * ( -P.Z / V.Z) );
Console.WriteLine("Lower Plane Intersection: {0}",A);
B = P + ( V * ( (SquaredMap.maxHeight-P.Z) / V.Z) );
Console.WriteLine("Higher Plane Intersection: {0}",B);
Vector2 start = Vector2.ComponentMin(A.Xy,B.Xy);
Vector2 finish = Vector2.ComponentMax(A.Xy,B.Xy);
Vector2 step = finish - start;
float steps = (step.X * step.Y) / 25.0f;
step /= steps;
int isteps = (int)steps;
Vector2 pos = start,
tile = toTileBorderless(pos);
Console.WriteLine("Interpolation: {0} - {1} - {2}",start,step,finish);
for (int n=0;n<=isteps;){
Console.WriteLine("IP RUN[{0}]: {1} Tile: {2}",n,pos,tile);
if (new BooleanConditional()
.requires( tile.X >= 0)
.requires( tile.Y >= 0)
.requires( tile.X < width)
.requires( tile.Y < height)
.isSuccess()
){
Vector3 isect = new Vector3();
for (int nt=0;nt<4;nt++){
try {
Model3D.Triangle t = model.triangles[tileIndex((int)tile.X,(int)tile.Y)];
if (Geometry.intersectTriangle(
P,
V,
t.VertexA,
t.VertexB,
t.VertexC,
out isect
)){
return isect;
}
} catch (OutOfWorldException){
}
}
}
Vector2 nextTile = tile;
while (nextTile.Equals(tile)){
pos += step;
nextTile = toTileBorderless(pos);
n++;
}
tile = nextTile;
}
throw new OutOfWorldException();
}
public void highlight(Vector2 tile){
new BooleanConditional()
.requires(tile.X >= 0)
.requires(tile.Y >= 0)
.requires(tile.X < width)
.requires(tile.Y < height)
.does(delegate {
for (int n=0;n<4;n++){
Model3D.Triangle t = model.triangles[tileIndex((int)tile.X,(int)tile.Y)+n];
t.ColorA *= 2;
t.ColorB *= 2;
t.ColorC *= 2;
}
model.rebind();
});
}
}
class MapModel3D : Model3D {
SquaredMap map;
public MapModel3D(SquaredMap map,int width,int height){
this.map = map;
prepareBuffers(width * height * 4);
colorMap();
}
public void colorMap(){
for (int n=0; n < vertexes.Length; n++){
colors[n] = new Vector4(
0.50f + (0.2f * vertexes[n].Z / SquaredMap.maxHeight),
0.25f + (0.50f * vertexes[n].Z / SquaredMap.maxHeight),
0.10f + (0.80f * vertexes[n].Z / SquaredMap.maxHeight),
1.0f
);
}
}
}
}