zmon
2012-05-25 17:38:54
not sure if anyone cares for low angle, which is the one that i'm currently testing but this is from my libraries that i'm getting ready for a project of sorts
the numbers in constants are not yet exact and i'll update them and add high angle as well when i have tuned it exactly

relevant code:
ShowcaseMiniMap - just to see it in action.
CHANGE - minimap projection is now ordered (X, Y, Elevation); rather than (X, Y, Z) because Y on minimap is Z in 3d and could have been very confusing.
the numbers in constants are not yet exact and i'll update them and add high angle as well when i have tuned it exactly

relevant code:
ShowcaseMiniMap - just to see it in action.
CHANGE - minimap projection is now ordered (X, Y, Elevation); rather than (X, Y, Z) because Y on minimap is Z in 3d and could have been very confusing.
{$include_once SRL/SRL/core/globals.simba}
{$include_once SRL/SRL/misc/paintsmart.simba}
// general constants
const DDD_ANGLE_LOW = 0.0;
const DDD_ANGLE_HIGH = 1.0;
// used by Y transform
const DDD_LOW_ANGLE_SQUARE = 16; // explicit value
const DDD_CAMERA_CHAMBER_DEPTH = 2; // explicit value
const DDD_TRANSFORM_DEPTH = 1; // explicit value
// distance of camera, every grid square is 4x4 on minimap so multiply by 4
const DDD_LOW_CAMERA_Z = 28; // can be obtained from getcamerapos
const DDD_HIGH_CAMERA_Z = 24; // can be obtained from getcamerapos
// center of the screen is somewhere above ground - this is explicit value
const DDD_LOW_FLOOR_OFFSET = 1.5625; // explicit 200/128
const DDD_HIGH_FLOOR_OFFSET = 2.34375; // explicit 300/128
// can be obtained from getcamerapos - height/128 but subtract floor offset
const DDD_LOW_CAMERA_Y = 13.9609375 - DDD_LOW_FLOOR_OFFSET;
const DDD_HIGH_CAMERA_Y = 46.71875 - DDD_HIGH_FLOOR_OFFSET;
// calculated values for current projection
var DDD_MAP_SQUARE_DIMENSION : Extended;
var DDD_CAMERA_Z : Extended;
var DDD_CAMERA_Y : Extended;
var DDD_FLOOR_OFFSET : Extended;
var DDD_ANGLE_TRANSFORM : Extended;
var DDD_ZERO_CAMERA_DISTANCE : Extended;
procedure InitializeAngle(Angle: Extended);
var LowCameraDistance : Extended;
begin
// assume linear - pretty good approximation
DDD_CAMERA_Z := DDD_LOW_CAMERA_Z + Angle * (DDD_HIGH_CAMERA_Z - DDD_LOW_CAMERA_Z);
DDD_CAMERA_Y := DDD_LOW_CAMERA_Y + Angle * (DDD_HIGH_CAMERA_Y - DDD_LOW_CAMERA_Y);
DDD_FLOOR_OFFSET := DDD_LOW_FLOOR_OFFSET + Angle * (DDD_HIGH_FLOOR_OFFSET - DDD_LOW_FLOOR_OFFSET);
// get low angle distance
LowCameraDistance := Sqrt(Sqr(DDD_LOW_CAMERA_Z) + Sqr(DDD_LOW_CAMERA_Y));
DDD_ZERO_CAMERA_DISTANCE := Sqrt(Sqr(DDD_CAMERA_Z) + Sqr(DDD_CAMERA_Y));
DDD_MAP_SQUARE_DIMENSION := DDD_LOW_ANGLE_SQUARE *
(LowCameraDistance + DDD_TRANSFORM_DEPTH + DDD_CAMERA_CHAMBER_DEPTH) /
(DDD_ZERO_CAMERA_DISTANCE + DDD_TRANSFORM_DEPTH + DDD_CAMERA_CHAMBER_DEPTH);
DDD_ANGLE_TRANSFORM := ArcCos(DDD_CAMERA_Z / DDD_ZERO_CAMERA_DISTANCE);
end;
// based on minimap offsets
function GetPerspectivePointExactMM(X,Y,Z : Extended) : TPoint;
var CAMERA_Z_DISTANCE : Extended;
var CAMERA_Y_DISTANCE : Extended;
var CAMERA_Z_DISTANCE2 : Extended;
var CAMERA_Y_DISTANCE2 : Extended;
var CAMERA_X_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE2 : Extended;
var CAMERA_YZ_DISTANCE2 : Extended;
var CAMERA_XZ_DISTANCE : Extended;
var CAMERA_YZ_DISTANCE : Extended;
var IntegralX : Extended;
var IntegralY : Extended;
var ModZ : Extended;
begin
Result.X := MSCX;
Result.Y := MSCY;
CAMERA_Z_DISTANCE := DDD_CAMERA_Z - Z;
CAMERA_Y_DISTANCE := Y;
if (CAMERA_Z_DISTANCE < 1) then Exit;
CAMERA_Z_DISTANCE2 := Sqr(CAMERA_Z_DISTANCE);
CAMERA_Y_DISTANCE2 := Sqr(CAMERA_Y_DISTANCE);
CAMERA_X_DISTANCE2 := Sqr(X);
CAMERA_XZ_DISTANCE2 := CAMERA_X_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_YZ_DISTANCE2 := CAMERA_Y_DISTANCE2 + CAMERA_Z_DISTANCE2;
CAMERA_XZ_DISTANCE := Sqrt(CAMERA_XZ_DISTANCE2);
CAMERA_YZ_DISTANCE := Sqrt(CAMERA_YZ_DISTANCE2);
// calculate shift
IntegralX := CAMERA_YZ_DISTANCE * ArcSinh(X / CAMERA_YZ_DISTANCE);
IntegralY := CAMERA_XZ_DISTANCE * ArcSinh(Y / CAMERA_XZ_DISTANCE);
// this one is the simple one
ModZ := (DDD_ZERO_CAMERA_DISTANCE + DDD_CAMERA_CHAMBER_DEPTH) /
(CAMERA_Z_DISTANCE + DDD_CAMERA_CHAMBER_DEPTH);
Result.X := MSCX + Round(DDD_MAP_SQUARE_DIMENSION * IntegralX * ModZ);
Result.Y := MSCY - Round(DDD_MAP_SQUARE_DIMENSION * IntegralY * ModZ);
end;
function GetPerspectivePoint(X,Y,Z : Extended) : TPoint;
var Y1, Z1 : Extended;
var PLAYERSHIFTEDY : Extended;
var DistanceZ : Extended;
var DistanceYZ : Extended;
var POINTEXACT : TPoint;
var ANGLE : Extended;
begin
// make runescape transform
DistanceZ := DDD_CAMERA_Z - Z;
PLAYERSHIFTEDY := (Y - DDD_FLOOR_OFFSET);
DistanceYZ := Sqrt(Sqr(DDD_CAMERA_Y - PLAYERSHIFTEDY) + Sqr(DistanceZ));
ANGLE := ArcCos(DistanceZ / DistanceYZ);
Y1 := Sin(DDD_ANGLE_TRANSFORM - ANGLE) * DistanceYZ;
Z1 := DDD_CAMERA_Z - Cos(DDD_ANGLE_TRANSFORM - ANGLE) * DistanceYZ;
POINTEXACT := GetPerspectivePointExactMM(X,Y1,Z1);
Result.x := POINTEXACT.x;
Result.y := POINTEXACT.y;
end;
function GetPerspectivePointMM(X, Y, Elevation : Extended) : TPoint;
var PPoint : TPoint;
begin
// use straight transform
PPoint := GetPerspectivePoint(X, Elevation, Y);
Result.x := PPoint.x;
Result.y := PPoint.y;
end;
procedure ProjectMiniMap(Angle : Extended);
var mmy, mmx : integer;
var mmp : TPoint;
var mmc : integer;
var UP : Integer;
begin
InitializeAngle(Angle);
MMP := GetPerspectivePointMM(0, DDD_FLOOR_OFFSET, 0);
SMART_DrawBoxEx(false, inttobox(mscx-3, mscy-3, mscx+3, mscy+3), clGreen);
for mmy := -80 to 20 do
begin
for mmx := -30 to 30 do
begin
mmc := GetColor(MMCX + mmx, MMCY + mmy);
if SimilarColors(mmc, clWhite, 14) or SimilarColors(mmc, $0008E8, 30) or SimilarColors(mmc, $ECECEC, 30)
or SimilarColors(mmc, clYellow, 30) then
begin
//if SimilarColors(mmc, clWhite, 14) or SimilarColors(mmc, $ECECEC, 20) then
for UP := 0 to 16 do
begin
mmp := GetPerspectivePointMM(mmx, mmy, UP/2.0);
SMART_DrawBoxEx(false, IntToBox(mmp.x -2, mmp.y - 2, mmp.x + 2, mmp.y + 2), mmc);
end;
end;
end;
end;
end;
procedure ShowcaseMiniMap();
begin
while true do
begin
sleep(2000);
SMART_ClearCanvas();
if (RandomE > 0.5) then
begin
ProjectMiniMap(1);
SetAngle(SRL_ANGLE_HIGH);
end
else
begin
ProjectMiniMap(0);
SetAngle(SRL_ANGLE_LOW);
end;
end;
end;
