Merge branch 'master' of github.com:UnknownShadow200/ClassicalSharp

This commit is contained in:
UnknownShadow200 2017-04-10 10:46:30 +10:00
commit f9d011af6e
26 changed files with 202 additions and 232 deletions

View File

@ -19,7 +19,6 @@ namespace ClassicalSharp {
TerrainAtlas1D atlas;
int index;
float scale;
const float invElemSize = TerrainAtlas2D.invElementSize;
bool bright;
VertexP3fT2fC4b[] vertices;
int vb;

View File

@ -48,7 +48,7 @@ namespace ClassicalSharp.Gui.Screens {
return true;
}
bool hotbar = game.IsKeyDown(Key.AltLeft) || game.IsKeyDown(Key.AltRight);
bool hotbar = game.Input.ControlDown;
if (!hotbar)
game.Gui.SetNewScreen(null);
}

View File

@ -118,7 +118,7 @@ namespace ClassicalSharp.Gui.Screens {
int length = GetInt(2), seed = GetSeedInt(3);
long volume = (long)width * height * length;
if (volume > 800 * 800 * 800) {
if (volume > int.MaxValue) {
game.Chat.Add("&cThe generated map's volume is too big.");
} else if (width == 0 || height == 0 || length == 0) {
game.Chat.Add("&cOne of the map dimensions is invalid.");

View File

@ -120,12 +120,12 @@ namespace ClassicalSharp.Gui.Screens {
public override void Init() {
base.Init();
left = new KeyBind[3];
left[0] = KeyBind.ExtInput; left[1] = KeyBind.HideFps; left[2] = KeyBind.HideGui;
left = new KeyBind[4];
left[0] = KeyBind.ExtInput; left[1] = KeyBind.HideFps; left[2] = KeyBind.HideGui; left[3] = KeyBind.HotbarSwitching;
right = new KeyBind[4];
right[0] = KeyBind.Screenshot; right[1] = KeyBind.Fullscreen; right[2] = KeyBind.AxisLines; right[3] = KeyBind.Autorotate;
leftDesc = new string[] { "Show ext input", "Hide FPS", "Hide gui" };
rightDesc = new string[] { "Screenshot", "Fullscreen", "Show axis lines", "Toggle auto-rotate" };
leftDesc = new string[] { "Show ext input", "Hide FPS", "Hide gui", "Hotbar switching" };
rightDesc = new string[] { "Screenshot", "Fullscreen", "Show axis lines", "Toggle auto-rotate", };
title = "Other controls";
leftPage = (g, w) => g.Gui.SetNewScreen(new HacksKeyBindingsScreen(g));

View File

@ -103,7 +103,7 @@ namespace ClassicalSharp.Gui.Widgets {
if (key >= Key.Number1 && key <= Key.Number9) {
int index = (int)key - (int)Key.Number1;
if (game.Input.AltDown) {
if (game.IsKeyDown(KeyBind.HotbarSwitching)) {
// Pick from first to ninth row
game.Inventory.Offset = index * Inventory.BlocksPerRow;
altHandled = true;
@ -120,7 +120,7 @@ namespace ClassicalSharp.Gui.Widgets {
// a) user presses alt then number
// b) user presses alt
// thus we only do case b) if case a) did not happen
if (!(key == Key.AltLeft || key == Key.AltRight)) return false;
if (key != game.Input.Keys[KeyBind.HotbarSwitching]) return false;
if (altHandled) { altHandled = false; return true; } // handled already
// Alternate between first and second row

View File

@ -14,13 +14,13 @@ namespace ClassicalSharp.Entities {
this.game = game;
this.entity = entity;
}
public float legXRot, armXRot, armZRot;
public float bobbingHor, bobbingVer, bobbingModel, tiltX, tiltY;
public float walkTime, swing, bobStrength = 1, velTiltStrength = 1;
public float walkTime, swing, bobStrength = 1, velTiltStrength = 1;
internal float walkTimeO, walkTimeN, swingO, swingN;
internal float leftXRot, leftZRot, rightXRot, rightZRot;
public float leftLegX, leftLegZ, rightLegX, rightLegZ;
public float leftArmX, leftArmZ, rightArmX, rightArmZ;
/// <summary> Calculates the next animation state based on old and new position. </summary>
public void UpdateAnimState(Vector3 oldPos, Vector3 newPos, double delta) {
@ -54,9 +54,13 @@ namespace ClassicalSharp.Entities {
float idleXRot = (float)(Math.Sin(idleTime * idleXPeriod) * idleMax);
float idleZRot = (float)(idleMax + Math.Cos(idleTime * idleZPeriod) * idleMax);
armXRot = (float)(Math.Cos(walkTime) * swing * armMax) - idleXRot;
legXRot = -(float)(Math.Cos(walkTime) * swing * legMax);
armZRot = -idleZRot;
leftArmX = (float)(Math.Cos(walkTime) * swing * armMax) - idleXRot;
leftArmZ = -idleZRot;
leftLegX = -(float)(Math.Cos(walkTime) * swing * legMax);
leftLegZ = 0;
rightLegX = -leftLegX; rightLegZ = -leftLegZ;
rightArmX = -leftArmX; rightArmZ = -leftArmZ;
bobbingHor = (float)(Math.Cos(walkTime) * swing * (2.5f/16f));
bobbingVer = (float)(Math.Abs(Math.Sin(walkTime)) * swing * (2.5f/16f));
@ -71,7 +75,7 @@ namespace ClassicalSharp.Entities {
tiltY = (float)Math.Sin(walkTime) * swing * (0.15f * Utils.Deg2Rad);
}
if (entity.Model is HumanoidModel)
if (entity.Model.CalcHumanAnims && !game.SimpleArmsAnim)
CalcHumanAnim(idleXRot, idleZRot);
}
@ -82,14 +86,9 @@ namespace ClassicalSharp.Entities {
}
void CalcHumanAnim(float idleXRot, float idleZRot) {
if (game.SimpleArmsAnim) {
leftXRot = armXRot; leftZRot = armZRot;
rightXRot = -armXRot; rightZRot = -armZRot;
} else {
PerpendicularAnim(0.23f, idleXRot, idleZRot, out leftXRot, out leftZRot);
PerpendicularAnim(0.28f, idleXRot, idleZRot, out rightXRot, out rightZRot);
rightXRot = -rightXRot; rightZRot = -rightZRot;
}
PerpendicularAnim(0.23f, idleXRot, idleZRot, out leftArmX, out leftArmZ);
PerpendicularAnim(0.28f, idleXRot, idleZRot, out rightArmX, out rightArmZ);
rightArmX = -rightArmX; rightArmZ = -rightArmZ;
}
const float maxAngle = 110 * Utils.Deg2Rad;

View File

@ -71,6 +71,7 @@ namespace ClassicalSharp.Entities {
public bool HalfSpeeding;
public bool CanJumpHigher { get { return Enabled && CanAnyHacks && CanSpeed; } }
public bool Floating { get { return Noclip || Flying; } }
/// <summary> Parses hack flags specified in the motd and/or name of the server. </summary>
/// <remarks> Recognises +/-hax, +/-fly, +/-noclip, +/-speed, +/-respawn, +/-ophax, and horspeed=xyz </remarks>

View File

@ -33,7 +33,7 @@ namespace ClassicalSharp.Entities {
}
public void UpdateVelocityState() {
if (hacks.Flying || hacks.Noclip) {
if (hacks.Floating) {
entity.Velocity.Y = 0; // eliminate the effect of gravity
int dir = (hacks.FlyingUp || jumping) ? 1 : (hacks.FlyingDown ? -1 : 0);
@ -109,34 +109,34 @@ namespace ClassicalSharp.Entities {
public void PhysicsTick(Vector3 vel) {
if (hacks.Noclip) entity.onGround = false;
float multiply = GetBaseMultiply(true);
float yMultiply = GetBaseMultiply(hacks.CanSpeed);
float modifier = LowestSpeedModifier();
float baseSpeed = GetBaseSpeed();
float verSpeed = baseSpeed * Math.Max(1, GetSpeed(hacks.CanSpeed, 8f) / 5);
float horSpeed = baseSpeed * GetSpeed(true, 8f/5);
// previously horSpeed used to be multiplied by factor of 0.02 in last case
// it's now multiplied by 0.1, so need to divide by 5 so user speed modifier comes out same
float yMul = Math.Max(1f, yMultiply / 5) * modifier;
float horMul = multiply * modifier;
if (!(hacks.Flying || hacks.Noclip)) {
if (secondJump) { horMul *= 93f; yMul *= 10f; }
else if (firstJump) { horMul *= 46.5f; yMul *= 7.5f; }
if (!hacks.Floating) {
if (secondJump) { horSpeed *= 93f; verSpeed *= 10f; }
else if (firstJump) { horSpeed *= 46.5f; verSpeed *= 7.5f; }
}
if (entity.TouchesAnyWater() && !hacks.Flying && !hacks.Noclip) {
MoveNormal(vel, 0.02f * horMul, waterDrag, liquidGrav, yMul);
} else if (entity.TouchesAnyLava() && !hacks.Flying && !hacks.Noclip) {
MoveNormal(vel, 0.02f * horMul, lavaDrag, liquidGrav, yMul);
} else if (entity.TouchesAnyRope() && !hacks.Flying && !hacks.Noclip) {
MoveNormal(vel, 0.02f * 1.7f, ropeDrag, ropeGrav, yMul);
if (entity.TouchesAnyWater() && !hacks.Floating) {
MoveNormal(vel, 0.02f * horSpeed, waterDrag, liquidGrav, verSpeed);
} else if (entity.TouchesAnyLava() && !hacks.Floating) {
MoveNormal(vel, 0.02f * horSpeed, lavaDrag, liquidGrav, verSpeed);
} else if (entity.TouchesAnyRope() && !hacks.Floating) {
MoveNormal(vel, 0.02f * 1.7f, ropeDrag, ropeGrav, verSpeed);
} else {
float factor = !(hacks.Flying || hacks.Noclip) && entity.onGround ? 0.1f : 0.02f;
float factor = hacks.Floating || entity.onGround ? 0.1f : 0.02f;
float gravity = useLiquidGravity ? liquidGrav : entity.Model.Gravity;
if (hacks.Flying || hacks.Noclip) {
MoveFlying(vel, factor * horMul, entity.Model.Drag, gravity, yMul);
if (hacks.Floating) {
MoveFlying(vel, factor * horSpeed, entity.Model.Drag, gravity, verSpeed);
} else {
MoveNormal(vel, factor * horMul, entity.Model.Drag, gravity, yMul);
MoveNormal(vel, factor * horSpeed, entity.Model.Drag, gravity, verSpeed);
}
if (entity.BlockUnderFeet == Block.Ice && !(hacks.Flying || hacks.Noclip)) {
if (entity.BlockUnderFeet == Block.Ice && !hacks.Floating) {
// limit components to +-0.25f by rescaling vector to [-0.25, 0.25]
if (Math.Abs(entity.Velocity.X) > 0.25f || Math.Abs(entity.Velocity.Z) > 0.25f) {
float scale = Math.Min(
@ -189,19 +189,15 @@ namespace ClassicalSharp.Entities {
entity.Velocity.Y -= gravity;
}
float GetBaseMultiply(bool canSpeed) {
float multiply = 0;
float speed = (hacks.Flying || hacks.Noclip) ? 8 : 1;
if (hacks.Speeding && canSpeed) multiply += speed * hacks.SpeedMultiplier;
if (hacks.HalfSpeeding && canSpeed) multiply += speed * hacks.SpeedMultiplier / 2;
if (multiply == 0) multiply = speed;
return hacks.CanSpeed ? multiply : Math.Min(multiply, hacks.MaxSpeedMultiplier);
float GetSpeed(bool canSpeed, float speedMul) {
float factor = hacks.Floating ? speedMul : 1, speed = factor;
if (hacks.Speeding && canSpeed) speed += factor * hacks.SpeedMultiplier;
if (hacks.HalfSpeeding && canSpeed) speed += factor * hacks.SpeedMultiplier / 2;
return hacks.CanSpeed ? speed : Math.Min(speed, hacks.MaxSpeedMultiplier);
}
const float inf = float.PositiveInfinity;
float LowestSpeedModifier() {
float GetBaseSpeed() {
AABB bounds = entity.Bounds;
useLiquidGravity = false;
float baseModifier = LowestModifier(bounds, false);

View File

@ -109,7 +109,7 @@ namespace ClassicalSharp.Entities {
return game.World.SafeGetBlock(Vector3I.Floor(coords));
}
internal Matrix4 TransformMatrix(float scale, Vector3 pos) {
public Matrix4 TransformMatrix(float scale, Vector3 pos) {
return
Matrix4.RotateZ(-RotZ * Utils.Deg2Rad) *
Matrix4.RotateX(-RotX * Utils.Deg2Rad) *

View File

@ -75,8 +75,8 @@ namespace ClassicalSharp.Model {
return base.RenderDistance(p);
}
int lastTexId = -1;
protected override void DrawModel(Entity p) {
int lastTexId = -1, col;
public override void DrawModel(Entity p) {
// TODO: using 'is' is ugly, but means we can avoid creating
// a string every single time held block changes.
if (p is FakePlayer) {
@ -94,6 +94,7 @@ namespace ClassicalSharp.Model {
col = FastColour.ScalePacked(col, colScale);
block = ((FakePlayer)p).Block;
} else {
col = cols[0];
block = Utils.FastByte(p.ModelName);
}

View File

@ -55,21 +55,22 @@ namespace ClassicalSharp.Model {
get { return new AABB(-4/16f, 0, -8/16f, 4/16f, 15/16f, 4/16f); }
}
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawRotate(-p.HeadXRadians, 0, 0, Head2, true);
DrawRotate(-p.HeadXRadians, 0, 0, Head3, true);
DrawPart(Torso);
DrawRotate(0, 0, -Math.Abs(p.anim.armXRot), LeftWing, false);
DrawRotate(0, 0, Math.Abs(p.anim.armXRot), RightWing, false);
DrawRotate(0, 0, -Math.Abs(p.anim.leftArmX), LeftWing, false);
DrawRotate(0, 0, Math.Abs(p.anim.leftArmX), RightWing, false);
int col = cols[0];
for (int i = 0; i < cols.Length; i++) {
cols[i] = FastColour.ScalePacked(col, 0.7f);
}
DrawRotate(p.anim.legXRot, 0, 0, LeftLeg, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLeg, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLeg, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLeg, false);
UpdateVB();
}

View File

@ -50,15 +50,15 @@ namespace ClassicalSharp.Model {
}
/// <inheritdoc/>
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawPart(Torso);
DrawRotate(p.anim.legXRot, 0, 0, LeftLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.legXRot, 0, 0, RightLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, RightLegBack, false);
UpdateVB();
}

View File

@ -29,7 +29,7 @@ namespace ClassicalSharp.Model {
internal AABB pickingBounds;
public override AABB PickingBounds { get { return pickingBounds; } }
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
int texId = p.TextureId <= 0 ? cache.HumanoidTexId : p.TextureId;
}

View File

@ -38,85 +38,44 @@ namespace ClassicalSharp.Model {
}
}
public class SittingModel : HumanoidModel {
public class SittingModel : IModel {
public SittingModel(Game window) : base(window) { }
public SittingModel(Game window) : base(window) {
CalcHumanAnims = true;
}
const int sitOffset = 10;
protected override void MakeDescriptions() {
head = MakeBoxBounds(-4, 24-sitOffset, -4, 4, 32-sitOffset, 4).RotOrigin(0, (sbyte)(24-sitOffset), 0);
torso = MakeBoxBounds(-4, 12-sitOffset, -2, 4, 24-sitOffset, 2);
lLeg = MakeBoxBounds(-4, 0-sitOffset, -2, 0, 12-sitOffset, 2).RotOrigin(0, (sbyte)(12-sitOffset), 0);
rLeg = MakeBoxBounds(0, 0-sitOffset, -2, 4, 12-sitOffset, 2).RotOrigin(0, (sbyte)(12-sitOffset), 0);
lArm = MakeBoxBounds(-8, 12-sitOffset, -2, -4, 24-sitOffset, 2).RotOrigin(-5, (sbyte)(22-sitOffset), 0);
rArm = MakeBoxBounds(4, 12-sitOffset, -2, 8, 24-sitOffset, 2).RotOrigin(5, (sbyte)(22-sitOffset), 0);
}
public override void CreateParts() { }
public override float MaxScale { get { return 2; } }
public override float ShadowScale { get { return 0.5f; } }
public override float NameYOffset { get { return (32-sitOffset)/16f + 0.5f/16f; } }
public override float NameYOffset { get { return (32 - sitOffset)/16f + 0.5f/16f; } }
public override float GetEyeY(Entity entity) { return (26-sitOffset)/16f; }
public override float GetEyeY(Entity entity) { return (26 - sitOffset)/16f; }
public override Vector3 CollisionSize {
get { return new Vector3(8/16f + 0.6f/16f, (28.1f-sitOffset)/16f, 8/16f + 0.6f/16f); }
get { return new Vector3(8/16f + 0.6f/16f, (28.1f - sitOffset)/16f, 8/16f + 0.6f/16f); }
}
public override AABB PickingBounds {
get { return new AABB(-8/16f, 0, -4/16f, 8/16f, (32-sitOffset)/16f, 4/16f); }
get { return new AABB(-8/16f, 0, -4/16f, 8/16f, (32 - sitOffset)/16f, 4/16f); }
}
protected override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.TextureId));
game.Graphics.AlphaTest = false;
bool _64x64 = p.SkinType != SkinType.Type64x32;
uScale = p.uScale / 64f;
vScale = p.vScale / (_64x64 ? 64 : 32);
RenderParts(p);
protected override Matrix4 TransformMatrix(Entity p, Vector3 pos) {
pos.Y -= sitOffset / 16f;
return p.TransformMatrix(p.ModelScale, pos);
}
protected override void RenderParts(Entity p) {
SkinType skinType = p.SkinType;
ModelSet model = skinType == SkinType.Type64x64Slim ? SetSlim :
(skinType == SkinType.Type64x64 ? Set64 : Set);
public override void DrawModel(Entity p) {
p.anim.leftLegX = 1.5f; p.anim.rightLegX = 1.5f;
p.anim.leftLegZ = -0.1f; p.anim.rightLegZ = 0.1f;
DrawRotate(-p.HeadXRadians, 0, 0, model.Head, true);
DrawPart(model.Torso);
float legRotateX = 1.5f;
float legRotateZ = 0.1f;
DrawRotate(legRotateX, 0, -legRotateZ, model.LeftLeg, false);
DrawRotate(legRotateX, 0, legRotateZ, model.RightLeg, false);
Rotate = RotateOrder.XZY;
//DrawRotate(0, 0, -legRotateZ, model.LeftArm, false);
//DrawRotate(0, 0, legRotateZ, model.RightArm, false);
DrawRotate(p.anim.leftXRot, 0, p.anim.leftZRot, model.LeftArm, false);
DrawRotate(p.anim.rightXRot, 0, p.anim.rightZRot, model.RightArm, false);
Rotate = RotateOrder.ZYX;
UpdateVB();
game.Graphics.AlphaTest = true;
index = 0;
if (skinType != SkinType.Type64x32) {
DrawPart(model.TorsoLayer);
DrawRotate(legRotateX, 0, -legRotateZ, model.LeftLegLayer, false);
DrawRotate(legRotateX, 0, legRotateZ, model.RightLegLayer, false);
Rotate = RotateOrder.XZY;
DrawRotate(p.anim.leftXRot, 0, p.anim.leftZRot, model.LeftArmLayer, false);
DrawRotate(p.anim.rightXRot, 0, p.anim.rightZRot, model.RightArmLayer, false);
//DrawRotate(0, 0, -legRotateZ, model.LeftArmLayer, false);
//DrawRotate(0, 0, legRotateZ, model.RightArmLayer, false);
Rotate = RotateOrder.ZYX;
}
DrawRotate(-p.HeadXRadians, 0, 0, model.Hat, true);
UpdateVB();
}
IModel model = game.ModelCache.Models[0].Instance;
model.SetupState(p);
model.DrawModel(p);
}
}
public class HumanoidHeadModel : HumanoidModel {

View File

@ -10,7 +10,9 @@ namespace ClassicalSharp.Model {
public class HumanoidModel : IModel {
public ModelSet Set, SetSlim, Set64;
public HumanoidModel(Game window) : base(window) { }
public HumanoidModel(Game window) : base(window) {
CalcHumanAnims = true;
}
protected BoxDesc head, torso, lLeg, rLeg, lArm, rArm;
protected float offset = 0.5f;
@ -82,7 +84,7 @@ namespace ClassicalSharp.Model {
get { return new AABB(-8/16f, 0, -4/16f, 8/16f, 32/16f, 4/16f); }
}
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.TextureId));
game.Graphics.AlphaTest = false;
@ -100,11 +102,11 @@ namespace ClassicalSharp.Model {
DrawRotate(-p.HeadXRadians, 0, 0, model.Head, true);
DrawPart(model.Torso);
DrawRotate(p.anim.legXRot, 0, 0, model.LeftLeg, false);
DrawRotate(-p.anim.legXRot, 0, 0, model.RightLeg, false);
DrawRotate(p.anim.leftLegX, 0, p.anim.leftLegZ, model.LeftLeg, false);
DrawRotate(p.anim.rightLegX, 0, p.anim.rightLegZ, model.RightLeg, false);
Rotate = RotateOrder.XZY;
DrawRotate(p.anim.leftXRot, 0, p.anim.leftZRot, model.LeftArm, false);
DrawRotate(p.anim.rightXRot, 0, p.anim.rightZRot, model.RightArm, false);
DrawRotate(p.anim.leftArmX, 0, p.anim.leftArmZ, model.LeftArm, false);
DrawRotate(p.anim.rightArmX, 0, p.anim.rightArmZ, model.RightArm, false);
Rotate = RotateOrder.ZYX;
UpdateVB();
@ -112,11 +114,11 @@ namespace ClassicalSharp.Model {
index = 0;
if (skinType != SkinType.Type64x32) {
DrawPart(model.TorsoLayer);
DrawRotate(p.anim.legXRot, 0, 0, model.LeftLegLayer, false);
DrawRotate(-p.anim.legXRot, 0, 0, model.RightLegLayer, false);
DrawRotate(p.anim.leftLegX, 0, 0, model.LeftLegLayer, false);
DrawRotate(p.anim.rightLegX, 0, 0, model.RightLegLayer, false);
Rotate = RotateOrder.XZY;
DrawRotate(p.anim.leftXRot, 0, p.anim.leftZRot, model.LeftArmLayer, false);
DrawRotate(p.anim.rightXRot, 0, p.anim.rightZRot, model.RightArmLayer, false);
DrawRotate(p.anim.leftArmX, 0, p.anim.leftArmZ, model.LeftArmLayer, false);
DrawRotate(p.anim.rightArmX, 0, p.anim.rightArmZ, model.RightArmLayer, false);
Rotate = RotateOrder.ZYX;
}
DrawRotate(-p.HeadXRadians, 0, 0, model.Hat, true);

View File

@ -30,6 +30,9 @@ namespace ClassicalSharp.Model {
/// <summary> Whether this entity requires downloading of a skin texture. </summary>
public bool UsesSkin = true;
/// <summary> Whether humanoid animations should be calculated, instead of normal animations. </summary>
public bool CalcHumanAnims;
/// <summary> Gravity applied to this entity. </summary>
public virtual float Gravity { get { return 0.08f; } }
@ -64,7 +67,6 @@ namespace ClassicalSharp.Model {
/// assuming that the model is not rotated at all.</summary>
public abstract AABB PickingBounds { get; }
protected Vector3 pos;
protected float cosHead, sinHead;
protected float uScale, vScale;
@ -100,14 +102,25 @@ namespace ClassicalSharp.Model {
/// <summary> Sets up the state for, then renders an entity model,
/// based on the given entity's position and orientation. </summary>
public void Render(Entity p) {
index = 0;
pos = p.Position;
Vector3 pos = p.Position;
if (Bobbing) pos.Y += p.anim.bobbingModel;
Vector3I P = Vector3I.Floor(p.EyePosition);
col = game.World.IsValidPos(P) ? game.Lighting.LightCol(P.X, P.Y, P.Z) : game.Lighting.Outside;
uScale = 1 / 64f; vScale = 1 / 32f;
SetupState(p);
game.Graphics.SetBatchFormat(VertexFormat.P3fT2fC4b);
game.Graphics.PushMatrix();
Matrix4 m = TransformMatrix(p, pos);
game.Graphics.MultiplyMatrix(ref m);
DrawModel(p);
game.Graphics.PopMatrix();
}
public void SetupState(Entity p) {
index = 0;
Vector3I P = Vector3I.Floor(p.EyePosition);
int col = game.World.IsValidPos(P) ? game.Lighting.LightCol(P.X, P.Y, P.Z) : game.Lighting.Outside;
uScale = 1 / 64f; vScale = 1 / 32f;
cols[0] = col;
cols[1] = FastColour.ScalePacked(col, FastColour.ShadeYBottom);
cols[2] = FastColour.ScalePacked(col, FastColour.ShadeZ); cols[3] = cols[2];
@ -116,18 +129,10 @@ namespace ClassicalSharp.Model {
float yawDelta = p.HeadY - p.RotY;
cosHead = (float)Math.Cos(yawDelta * Utils.Deg2Rad);
sinHead = (float)Math.Sin(yawDelta * Utils.Deg2Rad);
game.Graphics.SetBatchFormat(VertexFormat.P3fT2fC4b);
game.Graphics.PushMatrix();
Matrix4 m = p.TransformMatrix(p.ModelScale, pos);
game.Graphics.MultiplyMatrix(ref m);
DrawModel(p);
game.Graphics.PopMatrix();
}
/// <summary> Performs the actual rendering of an entity model. </summary>
protected abstract void DrawModel(Entity p);
public abstract void DrawModel(Entity p);
/// <summary> Sends the updated vertex data to the GPU. </summary>
protected void UpdateVB() {
@ -140,7 +145,11 @@ namespace ClassicalSharp.Model {
/// <summary> Disposes of any native resources tied to this entity model. </summary>
public virtual void Dispose() { }
protected int col;
protected virtual Matrix4 TransformMatrix(Entity p, Vector3 pos) {
return p.TransformMatrix(p.ModelScale, pos);
}
protected int[] cols = new int[6];
protected internal ModelVertex[] vertices;
protected internal int index, texIndex;

View File

@ -49,15 +49,15 @@ namespace ClassicalSharp.Model {
}
/// <inheritdoc/>
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawPart(Torso);
DrawRotate(p.anim.legXRot, 0, 0, LeftLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.legXRot, 0, 0, RightLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, RightLegBack, false);
UpdateVB();
}

View File

@ -82,16 +82,16 @@ namespace ClassicalSharp.Model {
}
/// <inheritdoc/>
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
IGraphicsApi gfx = game.Graphics;
gfx.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawPart(Torso);
DrawRotate(p.anim.legXRot, 0, 0, LeftLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.legXRot, 0, 0, RightLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, LeftLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, RightLegBack, false);
UpdateVB();
if (Utils.CaselessEquals(p.ModelName, "sheep_nofur")) return;
@ -100,10 +100,10 @@ namespace ClassicalSharp.Model {
DrawRotate(-p.HeadXRadians, 0, 0, FurHead, true);
DrawPart(FurTorso);
DrawRotate(p.anim.legXRot, 0, 0, FurLeftLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, FurRightLegFront, false);
DrawRotate(-p.anim.legXRot, 0, 0, FurLeftLegBack, false);
DrawRotate(p.anim.legXRot, 0, 0, FurRightLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, FurLeftLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, FurRightLegFront, false);
DrawRotate(p.anim.rightLegX, 0, 0, FurLeftLegBack, false);
DrawRotate(p.anim.leftLegX, 0, 0, FurRightLegBack, false);
UpdateVB();
}

View File

@ -44,15 +44,15 @@ namespace ClassicalSharp.Model {
get { return new AABB(-4/16f, 0, -4/16f, 4/16f, 32/16f, 4/16f); }
}
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawPart(Torso);
DrawRotate(p.anim.legXRot, 0, 0, LeftLeg, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLeg, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.armZRot, LeftArm, false);
DrawRotate(90 * Utils.Deg2Rad, 0, -p.anim.armZRot, RightArm, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLeg, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLeg, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.leftArmZ, LeftArm, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.rightArmZ, RightArm, false);
UpdateVB();
}

View File

@ -48,7 +48,7 @@ namespace ClassicalSharp.Model {
const float eighthPi = (float)(Math.PI / 8);
/// <inheritdoc/>
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);

View File

@ -47,15 +47,15 @@ namespace ClassicalSharp.Model {
get { return new AABB(-4/16f, 0, -4/16f, 4/16f, 32/16f, 4/16f); }
}
protected override void DrawModel(Entity p) {
public override void DrawModel(Entity p) {
game.Graphics.BindTexture(GetTexture(p.MobTextureId));
DrawRotate(-p.HeadXRadians, 0, 0, Head, true);
DrawPart(Torso);
DrawRotate(p.anim.legXRot, 0, 0, LeftLeg, false);
DrawRotate(-p.anim.legXRot, 0, 0, RightLeg, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.armZRot, LeftArm, false);
DrawRotate(90 * Utils.Deg2Rad, 0, -p.anim.armZRot, RightArm, false);
DrawRotate(p.anim.leftLegX, 0, 0, LeftLeg, false);
DrawRotate(p.anim.rightLegX, 0, 0, RightLeg, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.leftArmZ, LeftArm, false);
DrawRotate(90 * Utils.Deg2Rad, 0, p.anim.rightArmZ, RightArm, false);
DrawRotate(-p.HeadXRadians, 0, 0, Hat, true);
UpdateVB();
}

View File

@ -11,7 +11,8 @@ namespace ClassicalSharp {
Inventory, ToggleFog, SendChat, PauseOrExit, PlayerList,
Speed, NoClip, Fly, FlyUp, FlyDown, ExtInput, HideFps,
Screenshot, Fullscreen, ThirdPerson, HideGui, AxisLines,
ZoomScrolling, HalfSpeed, MouseLeft, MouseMiddle, MouseRight, Autorotate,
ZoomScrolling, HalfSpeed, MouseLeft, MouseMiddle, MouseRight,
Autorotate, HotbarSwitching
#pragma warning restore 1591
}
@ -34,7 +35,7 @@ namespace ClassicalSharp {
public KeyMap() {
// We can't use enum array initaliser because this causes problems when building with mono
// and running on default .NET (https://bugzilla.xamarin.com/show_bug.cgi?id=572)
keys = new Key[31];
keys = new Key[32];
keys[0] = Key.W; keys[1] = Key.S; keys[2] = Key.A; keys[3] = Key.D;
keys[4] = Key.Space; keys[5] = Key.R; keys[6] = Key.Enter; keys[7] = Key.T;
keys[8] = Key.B; keys[9] = Key.F; keys[10] = Key.Enter;
@ -42,9 +43,10 @@ namespace ClassicalSharp {
keys[14] = Key.X; keys[15] = Key.Z; keys[16] = Key.Q;
keys[17] = Key.E; keys[18] = Key.AltLeft; keys[19] = Key.F3;
keys[20] = Key.F12; keys[21] = Key.F11; keys[22] = Key.F5;
keys[23] = Key.F1; keys[24] = Key.F7; keys[25] = Key.C;
keys[26] = Key.ControlLeft;
keys[27] = Key.Unknown; keys[28] = Key.Unknown; keys[29] = Key.Unknown; keys[30] = Key.F6;
keys[23] = Key.F1; keys[24] = Key.F7; keys[25] = Key.C;
keys[26] = Key.ControlLeft;
keys[27] = Key.Unknown; keys[28] = Key.Unknown; keys[29] = Key.Unknown;
keys[30] = Key.F6; keys[31] = Key.AltLeft;
defaultKeys = new Key[keys.Length];
for (int i = 0; i < defaultKeys.Length; i++)

View File

@ -170,8 +170,9 @@ namespace ClassicalSharp.Renderers {
sidesVertices += Utils.CountVertices(map.Width, map.Length, axisSize); // YQuads beneath map
sidesVertices += 2 * Utils.CountVertices(map.Width, Math.Abs(y), axisSize); // ZQuads
sidesVertices += 2 * Utils.CountVertices(map.Length, Math.Abs(y), axisSize); // XQuads
VertexP3fT2fC4b* v = stackalloc VertexP3fT2fC4b[sidesVertices];
IntPtr ptr = (IntPtr)v;
VertexP3fT2fC4b[] v = new VertexP3fT2fC4b[sidesVertices];
int index = 0;
fullColSides = game.BlockInfo.FullBright[block];
int col = fullColSides ? FastColour.WhitePacked : map.Env.Shadow;
@ -181,18 +182,18 @@ namespace ClassicalSharp.Renderers {
for (int i = 0; i < rects.Length; i++) {
Rectangle r = rects[i];
DrawY(r.X, r.Y, r.X + r.Width, r.Y + r.Height, y, axisSize, col, 0, YOffset(block), ref v);
DrawY(r.X, r.Y, r.X + r.Width, r.Y + r.Height, y, axisSize, col, 0, YOffset(block), v, ref index);
}
// Work properly for when ground level is below 0
int y1 = 0, y2 = y;
if (y < 0) { y1 = y; y2 = 0; }
DrawY(0, 0, map.Width, map.Length, 0, axisSize, col, 0, 0, ref v);
DrawZ(0, 0, map.Width, y1, y2, axisSize, col, ref v);
DrawZ(map.Length, 0, map.Width, y1, y2, axisSize, col, ref v);
DrawX(0, 0, map.Length, y1, y2, axisSize, col, ref v);
DrawX(map.Width, 0, map.Length, y1, y2, axisSize, col, ref v);
sidesVb = gfx.CreateVb(ptr, VertexFormat.P3fT2fC4b, sidesVertices);
DrawY(0, 0, map.Width, map.Length, 0, axisSize, col, 0, 0, v, ref index);
DrawZ(0, 0, map.Width, y1, y2, axisSize, col, v, ref index);
DrawZ(map.Length, 0, map.Width, y1, y2, axisSize, col, v, ref index);
DrawX(0, 0, map.Length, y1, y2, axisSize, col, v, ref index);
DrawX(map.Width, 0, map.Length, y1, y2, axisSize, col, v, ref index);
sidesVb = gfx.CreateVb(v, VertexFormat.P3fT2fC4b, sidesVertices);
}
void RebuildEdges(int y, int axisSize) {
@ -202,8 +203,8 @@ namespace ClassicalSharp.Renderers {
Rectangle r = rects[i];
edgesVertices += Utils.CountVertices(r.Width, r.Height, axisSize); // YPlanes outside
}
VertexP3fT2fC4b* v = stackalloc VertexP3fT2fC4b[edgesVertices];
IntPtr ptr = (IntPtr)v;
VertexP3fT2fC4b[] v = new VertexP3fT2fC4b[edgesVertices];
int index = 0;
fullColEdge = game.BlockInfo.FullBright[block];
int col = fullColEdge ? FastColour.WhitePacked : map.Env.Sun;
@ -214,9 +215,9 @@ namespace ClassicalSharp.Renderers {
for (int i = 0; i < rects.Length; i++) {
Rectangle r = rects[i];
DrawY(r.X, r.Y, r.X + r.Width, r.Y + r.Height, y, axisSize, col,
HorOffset(block), YOffset(block), ref v);
HorOffset(block), YOffset(block), v, ref index);
}
edgesVb = gfx.CreateVb(ptr, VertexFormat.P3fT2fC4b, edgesVertices);
edgesVb = gfx.CreateVb(v, VertexFormat.P3fT2fC4b, edgesVertices);
}
float HorOffset(BlockID block) {
@ -230,7 +231,7 @@ namespace ClassicalSharp.Renderers {
}
void DrawX(int x, int z1, int z2, int y1, int y2, int axisSize,
int col, ref VertexP3fT2fC4b* v) {
int col, VertexP3fT2fC4b[] v, ref int i) {
int endZ = z2, endY = y2, startY = y1;
for (; z1 < endZ; z1 += axisSize) {
z2 = z1 + axisSize;
@ -241,16 +242,16 @@ namespace ClassicalSharp.Renderers {
if (y2 > endY) y2 = endY;
TextureRec rec = new TextureRec(0, 0, z2 - z1, y2 - y1);
*v = new VertexP3fT2fC4b(x, y1, z1, rec.U1, rec.V2, col); v++;
*v = new VertexP3fT2fC4b(x, y2, z1, rec.U1, rec.V1, col); v++;
*v = new VertexP3fT2fC4b(x, y2, z2, rec.U2, rec.V1, col); v++;
*v = new VertexP3fT2fC4b(x, y1, z2, rec.U2, rec.V2, col); v++;
v[i++] = new VertexP3fT2fC4b(x, y1, z1, rec.U1, rec.V2, col);
v[i++] = new VertexP3fT2fC4b(x, y2, z1, rec.U1, rec.V1, col);
v[i++] = new VertexP3fT2fC4b(x, y2, z2, rec.U2, rec.V1, col);
v[i++] = new VertexP3fT2fC4b(x, y1, z2, rec.U2, rec.V2, col);
}
}
}
void DrawZ(int z, int x1, int x2, int y1, int y2, int axisSize,
int col, ref VertexP3fT2fC4b* v) {
int col, VertexP3fT2fC4b[] v, ref int i) {
int endX = x2, endY = y2, startY = y1;
for (; x1 < endX; x1 += axisSize) {
x2 = x1 + axisSize;
@ -261,16 +262,16 @@ namespace ClassicalSharp.Renderers {
if (y2 > endY) y2 = endY;
TextureRec rec = new TextureRec(0, 0, x2 - x1, y2 - y1);
*v = new VertexP3fT2fC4b(x1, y1, z, rec.U1, rec.V2, col); v++;
*v = new VertexP3fT2fC4b(x1, y2, z, rec.U1, rec.V1, col); v++;
*v = new VertexP3fT2fC4b(x2, y2, z, rec.U2, rec.V1, col); v++;
*v = new VertexP3fT2fC4b(x2, y1, z, rec.U2, rec.V2, col); v++;
v[i++] = new VertexP3fT2fC4b(x1, y1, z, rec.U1, rec.V2, col);
v[i++] = new VertexP3fT2fC4b(x1, y2, z, rec.U1, rec.V1, col);
v[i++] = new VertexP3fT2fC4b(x2, y2, z, rec.U2, rec.V1, col);
v[i++] = new VertexP3fT2fC4b(x2, y1, z, rec.U2, rec.V2, col);
}
}
}
void DrawY(int x1, int z1, int x2, int z2, float y, int axisSize,
int col, float offset, float yOffset, ref VertexP3fT2fC4b* v) {
int col, float offset, float yOffset, VertexP3fT2fC4b[] v, ref int i) {
int endX = x2, endZ = z2, startZ = z1;
for (; x1 < endX; x1 += axisSize) {
x2 = x1 + axisSize;
@ -281,10 +282,10 @@ namespace ClassicalSharp.Renderers {
if (z2 > endZ) z2 = endZ;
TextureRec rec = new TextureRec(0, 0, x2 - x1, z2 - z1);
*v = new VertexP3fT2fC4b(x1 + offset, y + yOffset, z1 + offset, rec.U1, rec.V1, col); v++;
*v = new VertexP3fT2fC4b(x1 + offset, y + yOffset, z2 + offset, rec.U1, rec.V2, col); v++;
*v = new VertexP3fT2fC4b(x2 + offset, y + yOffset, z2 + offset, rec.U2, rec.V2, col); v++;
*v = new VertexP3fT2fC4b(x2 + offset, y + yOffset, z1 + offset, rec.U2, rec.V1, col); v++;
v[i++] = new VertexP3fT2fC4b(x1 + offset, y + yOffset, z1 + offset, rec.U1, rec.V1, col);
v[i++] = new VertexP3fT2fC4b(x1 + offset, y + yOffset, z2 + offset, rec.U1, rec.V2, col);
v[i++] = new VertexP3fT2fC4b(x2 + offset, y + yOffset, z2 + offset, rec.U2, rec.V2, col);
v[i++] = new VertexP3fT2fC4b(x2 + offset, y + yOffset, z1 + offset, rec.U2, rec.V1, col);
}
}
}

View File

@ -57,11 +57,11 @@ namespace ClassicalSharp.Textures {
/// <summary> Runs through all animations and if necessary updates the terrain atlas. </summary>
public void Tick(ScheduledTask task) {
if (useLavaAnim) {
int size = Math.Min(game.TerrainAtlas.elementSize, 64);
int size = Math.Min(game.TerrainAtlas.TileSize, 64);
DrawAnimation(null, 30, size);
}
if (useWaterAnim) {
int size = Math.Min(game.TerrainAtlas.elementSize, 64);
int size = Math.Min(game.TerrainAtlas.TileSize, 64);
DrawAnimation(null, 14, size);
}
@ -160,7 +160,7 @@ namespace ClassicalSharp.Textures {
FastBitmap.MovePortion(data.FrameX + data.State * size,
data.FrameY, 0, 0, animsBuffer, animPart, size);
}
gfx.UpdateTexturePart(atlas.TexIds[index], 0, rowNum * game.TerrainAtlas.elementSize, animPart);
gfx.UpdateTexturePart(atlas.TexIds[index], 0, rowNum * game.TerrainAtlas.TileSize, animPart);
}
bool IsDefaultZip() {

View File

@ -41,15 +41,15 @@ namespace ClassicalSharp.Textures {
public void UpdateState(TerrainAtlas2D atlas2D) {
int maxVerticalSize = Math.Min(4096, gfx.MaxTextureDimensions);
int elementsPerFullAtlas = maxVerticalSize / atlas2D.elementSize;
int totalElements = TerrainAtlas2D.RowsCount * TerrainAtlas2D.ElementsPerRow;
int elementsPerFullAtlas = maxVerticalSize / atlas2D.TileSize;
int totalElements = TerrainAtlas2D.RowsCount * TerrainAtlas2D.TilesPerRow;
int atlasesCount = Utils.CeilDiv(totalElements, elementsPerFullAtlas);
elementsPerAtlas1D = Math.Min(elementsPerFullAtlas, totalElements);
int atlas1DHeight = Utils.NextPowerOf2(elementsPerAtlas1D * atlas2D.elementSize);
int atlas1DHeight = Utils.NextPowerOf2(elementsPerAtlas1D * atlas2D.TileSize);
Convert2DTo1D(atlas2D, atlasesCount, atlas1DHeight);
elementsPerBitmap = atlas1DHeight / atlas2D.elementSize;
elementsPerBitmap = atlas1DHeight / atlas2D.TileSize;
invElementSize = 1f / elementsPerBitmap;
}
@ -65,8 +65,8 @@ namespace ClassicalSharp.Textures {
}
void Make1DTexture(int i, FastBitmap atlas, TerrainAtlas2D atlas2D, int atlas1DHeight, ref int index) {
int elemSize = atlas2D.elementSize;
using (Bitmap atlas1d = Platform.CreateBmp(atlas2D.elementSize, atlas1DHeight))
int elemSize = atlas2D.TileSize;
using (Bitmap atlas1d = Platform.CreateBmp(atlas2D.TileSize, atlas1DHeight))
using (FastBitmap dst = new FastBitmap(atlas1d, true, false))
{
for (int index1D = 0; index1D < elementsPerAtlas1D; index1D++) {
@ -80,8 +80,8 @@ namespace ClassicalSharp.Textures {
public int CalcMaxUsedRow(TerrainAtlas2D atlas2D, BlockInfo info) {
int maxVerSize = Math.Min(4096, gfx.MaxTextureDimensions);
int verElements = maxVerSize / atlas2D.elementSize;
int totalElements = GetMaxUsedRow(info.textures) * TerrainAtlas2D.ElementsPerRow;
int verElements = maxVerSize / atlas2D.TileSize;
int totalElements = GetMaxUsedRow(info.textures) * TerrainAtlas2D.TilesPerRow;
return Utils.CeilDiv(totalElements, verElements);
}

View File

@ -11,10 +11,10 @@ namespace ClassicalSharp {
/// <summary> Represents a 2D packed texture atlas, specifically for terrain.png. </summary>
public class TerrainAtlas2D : IDisposable {
public const int ElementsPerRow = 16, RowsCount = 16;
public const float invElementSize = 1 / 16f;
public const int TilesPerRow = 16, RowsCount = 16;
public Bitmap AtlasBitmap;
public int elementSize;
public int TileSize;
IGraphicsApi gfx;
IDrawer2D drawer;
@ -26,19 +26,19 @@ namespace ClassicalSharp {
/// <summary> Updates the underlying atlas bitmap, fields, and texture. </summary>
public void UpdateState(BlockInfo info, Bitmap bmp) {
AtlasBitmap = bmp;
elementSize = bmp.Width / ElementsPerRow;
TileSize = bmp.Width / TilesPerRow;
using (FastBitmap fastBmp = new FastBitmap(bmp, true, true))
info.RecalculateSpriteBB(fastBmp);
}
/// <summary> Creates a new texture that contains the tile at the specified index. </summary>
public int LoadTextureElement(int index) {
int size = elementSize;
int size = TileSize;
using (FastBitmap atlas = new FastBitmap(AtlasBitmap, true, true))
using (Bitmap bmp = Platform.CreateBmp(size, size))
using (FastBitmap dst = new FastBitmap(bmp, true, false))
{
int x = index % ElementsPerRow, y = index / ElementsPerRow;
int x = index % TilesPerRow, y = index / TilesPerRow;
FastBitmap.MovePortion(x * size, y * size, 0, 0, atlas, dst, size);
return gfx.CreateTexture(dst, true);
}