ClassiCube/ClassicalSharp/Entities/Player.cs
UnknownShadow200 0121a1820f More fixes III
2017-02-11 18:30:30 +11:00

180 lines
No EOL
5.5 KiB
C#

// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using System.Drawing;
using ClassicalSharp.GraphicsAPI;
using ClassicalSharp.Model;
using ClassicalSharp.Network;
using OpenTK;
#if ANDROID
using Android.Graphics;
#endif
namespace ClassicalSharp.Entities {
public abstract partial class Player : Entity {
public string DisplayName, SkinName, SkinIdentifier;
internal ShadowComponent shadow;
protected Texture nameTex;
internal bool fetchedSkin;
public Player(Game game) : base(game) {
StepSize = 0.5f;
shadow = new ShadowComponent(game, this);
SetModel("humanoid");
}
public override void Despawn() {
game.Graphics.DeleteTexture(ref TextureId);
game.Graphics.DeleteTexture(ref nameTex.ID);
}
public override void ContextLost() {
game.Graphics.DeleteTexture(ref nameTex.ID);
}
public override void ContextRecreated() { UpdateName(); }
protected void MakeNameTexture() {
using (Font font = new Font(game.FontName, 24)) {
DrawTextArgs args = new DrawTextArgs(DisplayName, font, false);
Size size = game.Drawer2D.MeasureBitmappedSize(ref args);
if (size.Width == 0) { nameTex = new Texture(-1, 0, 0, 0, 0, 1, 1); return; }
size.Width += 3; size.Height += 3;
using (IDrawer2D drawer = game.Drawer2D)
using (Bitmap bmp = IDrawer2D.CreatePow2Bitmap(size))
{
drawer.SetBitmap(bmp);
args.Text = "&\xFF" + Utils.StripColours(args.Text);
game.Drawer2D.Colours['\xFF'] = new FastColour(80, 80, 80);
game.Drawer2D.DrawBitmappedText(ref args, 3, 3);
game.Drawer2D.Colours['\xFF'] = default(FastColour);
args.Text = DisplayName;
game.Drawer2D.DrawBitmappedText(ref args, 0, 0);
nameTex = game.Drawer2D.Make2DTexture(bmp, size, 0, 0);
}
}
}
public void UpdateName() {
ContextLost();
if (game.Graphics.LostContext) return;
MakeNameTexture();
}
protected void DrawName() {
if (nameTex.ID == 0) MakeNameTexture();
if (nameTex.ID == -1) return;
IGraphicsApi gfx = game.Graphics;
gfx.BindTexture(nameTex.ID);
Vector3 pos = Position; pos.Y += Model.NameYOffset * ModelScale;
float scale = Math.Min(1, Model.NameScale * ModelScale) / 70f;
Vector3 p111, p121, p212, p222;
int col = FastColour.WhitePacked;
Vector2 size = new Vector2(nameTex.Width * scale, nameTex.Height * scale);
Utils.CalcBillboardPoints(size, pos, ref game.View, out p111, out p121, out p212, out p222);
gfx.texVerts[0] = new VertexP3fT2fC4b(ref p111, nameTex.U1, nameTex.V2, col);
gfx.texVerts[1] = new VertexP3fT2fC4b(ref p121, nameTex.U1, nameTex.V1, col);
gfx.texVerts[2] = new VertexP3fT2fC4b(ref p222, nameTex.U2, nameTex.V1, col);
gfx.texVerts[3] = new VertexP3fT2fC4b(ref p212, nameTex.U2, nameTex.V2, col);
gfx.SetBatchFormat(VertexFormat.P3fT2fC4b);
gfx.UpdateDynamicIndexedVb(DrawMode.Triangles, gfx.texVb, gfx.texVerts, 4);
}
protected void CheckSkin() {
if (!fetchedSkin && Model.UsesSkin) {
game.AsyncDownloader.DownloadSkin(SkinIdentifier, SkinName);
fetchedSkin = true;
}
DownloadedItem item;
if (!game.AsyncDownloader.TryGetItem(SkinIdentifier, out item)) return;
if (item == null || item.Data == null) { ResetSkin(); return; }
Bitmap bmp = (Bitmap)item.Data;
game.Graphics.DeleteTexture(ref TextureId);
uScale = 1; vScale = 1;
EnsurePow2(ref bmp);
SkinType = Utils.GetSkinType(bmp);
if (SkinType == SkinType.Invalid) {
string format = "Skin {0} has unsupported dimensions({1}, {2}), reverting to default.";
Utils.LogDebug(format, SkinName, bmp.Width, bmp.Height);
bmp.Dispose();
ResetSkin(); return;
}
if (Model is HumanoidModel)
ClearHat(bmp, SkinType);
TextureId = game.Graphics.CreateTexture(bmp, true);
MobTextureId = -1;
// Custom mob textures.
if (Utils.IsUrlPrefix(SkinName, 0) && item.TimeAdded > lastModelChange)
MobTextureId = TextureId;
bmp.Dispose();
}
void ResetSkin() {
MobTextureId = -1;
TextureId = -1;
SkinType = game.DefaultPlayerSkinType;
}
unsafe static void ClearHat(Bitmap bmp, SkinType skinType) {
using (FastBitmap fastBmp = new FastBitmap(bmp, true, false)) {
int sizeX = (bmp.Width / 64) * 32;
int yScale = skinType == SkinType.Type64x32 ? 32 : 64;
int sizeY = (bmp.Height / yScale) * 16;
// determine if we actually need filtering
for (int y = 0; y < sizeY; y++) {
int* row = fastBmp.GetRowPtr(y);
row += sizeX;
for (int x = 0; x < sizeX; x++) {
byte alpha = (byte)(row[x] >> 24);
if (alpha != 255) return;
}
}
// only perform filtering when the entire hat is opaque
int fullWhite = FastColour.White.ToArgb();
int fullBlack = FastColour.Black.ToArgb();
for (int y = 0; y < sizeY; y++) {
int* row = fastBmp.GetRowPtr(y);
row += sizeX;
for (int x = 0; x < sizeX; x++) {
int pixel = row[x];
if (pixel == fullWhite || pixel == fullBlack) row[x] = 0;
}
}
}
}
void EnsurePow2(ref Bitmap bmp) {
int width = Utils.NextPowerOf2(bmp.Width);
int height = Utils.NextPowerOf2(bmp.Height);
if (width == bmp.Width && height == bmp.Height) return;
Bitmap scaled = Platform.CreateBmp(width, height);
using (FastBitmap src = new FastBitmap(bmp, true, true))
using (FastBitmap dst = new FastBitmap(scaled, true, false))
{
for (int y = 0; y < src.Height; y++)
FastBitmap.CopyRow(y, y, src, dst, src.Width);
}
uScale = (float)bmp.Width / width;
vScale = (float)bmp.Height / height;
bmp.Dispose();
bmp = scaled;
}
}
}