Simplify code related to entity nametags

This commit is contained in:
UnknownShadow200 2019-07-15 13:31:23 +10:00
parent e267d43976
commit f527fdaa44
4 changed files with 137 additions and 134 deletions

View File

@ -70,7 +70,8 @@ void Entity_Init(struct Entity* e) {
e->ModelScale = Vec3_Create1(1.0f);
e->uScale = 1.0f;
e->vScale = 1.0f;
e->SkinNameRaw[0] = '\0';
e->SkinNameRaw[0] = '\0';
e->DisplayNameRaw[0] = '\0';
}
Vec3 Entity_GetEyePosition(struct Entity* e) {
@ -216,6 +217,105 @@ bool Entity_TouchesAnyWater(struct Entity* e) {
}
/*########################################################################################################################*
*-----------------------------------------------------Entity nametag------------------------------------------------------*
*#########################################################################################################################*/
#define NAME_IS_EMPTY -30000
#define NAME_OFFSET 3 /* offset of back layer of name above an entity */
static void Entity_MakeNameTexture(struct Entity* e) {
String colorlessName; char colorlessBuffer[STRING_SIZE];
BitmapCol shadowCol = BITMAPCOL_CONST(80, 80, 80, 255);
BitmapCol origWhiteCol;
struct DrawTextArgs args;
bool bitmapped;
String name;
Size2D size;
Bitmap bmp;
/* Names are always drawn not using the system font */
bitmapped = Drawer2D_BitmappedText;
Drawer2D_BitmappedText = true;
name = String_FromRawArray(e->DisplayNameRaw);
Drawer2D_MakeFont(&args.font, 24, FONT_STYLE_NORMAL);
DrawTextArgs_Make(&args, &name, &args.font, false);
size = Drawer2D_MeasureText(&args);
if (size.Width == 0) {
e->NameTex.ID = GFX_NULL;
e->NameTex.X = NAME_IS_EMPTY;
} else {
String_InitArray(colorlessName, colorlessBuffer);
size.Width += NAME_OFFSET; size.Height += NAME_OFFSET;
Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
{
origWhiteCol = Drawer2D_Cols['f'];
Drawer2D_Cols['f'] = shadowCol;
String_AppendColorless(&colorlessName, &name);
args.text = colorlessName;
Drawer2D_DrawText(&bmp, &args, NAME_OFFSET, NAME_OFFSET);
Drawer2D_Cols['f'] = origWhiteCol;
args.text = name;
Drawer2D_DrawText(&bmp, &args, 0, 0);
}
Drawer2D_Make2DTexture(&e->NameTex, &bmp, size, 0, 0);
Mem_Free(bmp.Scan0);
}
Drawer2D_BitmappedText = bitmapped;
}
static void Entity_DrawName(struct Entity* e) {
VertexP3fT2fC4b vertices[4];
PackedCol col = PACKEDCOL_WHITE;
struct Model* model;
struct Matrix mat;
Vec3 pos;
float scale;
Vec2 size;
if (e->NameTex.X == NAME_IS_EMPTY) return;
if (!e->NameTex.ID) Entity_MakeNameTexture(e);
Gfx_BindTexture(e->NameTex.ID);
model = e->Model;
Vec3_TransformY(&pos, model->GetNameY(e), &e->Transform);
scale = model->NameScale * e->ModelScale.Y;
scale = scale > 1.0f ? (1.0f/70.0f) : (scale/70.0f);
size.X = e->NameTex.Width * scale; size.Y = e->NameTex.Height * scale;
if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && LocalPlayer_Instance.Hacks.CanSeeAllNames) {
Matrix_Mul(&mat, &Gfx.View, &Gfx.Projection); /* TODO: This mul is slow, avoid it */
/* Get W component of transformed position */
scale = pos.X * mat.Row0.W + pos.Y * mat.Row1.W + pos.Z * mat.Row2.W + mat.Row3.W;
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
}
Particle_DoRender(&size, &pos, &e->NameTex.uv, col, vertices);
Gfx_SetVertexFormat(VERTEX_FORMAT_P3FT2FC4B);
Gfx_UpdateDynamicVb_IndexedTris(Gfx_texVb, vertices, 4);
}
/* Deletes the texture containing the entity's nametag */
CC_NOINLINE static void Entity_DeleteNameTex(struct Entity* e) {
Gfx_DeleteTexture(&e->NameTex.ID);
e->NameTex.X = 0; /* X is used as an 'empty name' flag */
}
void Entity_SetName(struct Entity* e, const String* name) {
Entity_DeleteNameTex(e);
String_CopyToRawArray(e->DisplayNameRaw, name);
/* name texture redraw deferred until necessary */
}
/*########################################################################################################################*
*--------------------------------------------------------Entities---------------------------------------------------------*
*#########################################################################################################################*/
@ -298,11 +398,15 @@ void Entities_RenderHoveredNames(double delta) {
if (hadFog) Gfx_SetFog(true);
}
static void Entity_ContextLost(struct Entity* e) {
Entity_DeleteNameTex(e);
}
static void Entities_ContextLost(void* obj) {
int i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (!Entities.List[i]) continue;
Entities.List[i]->VTABLE->ContextLost(Entities.List[i]);
Entity_ContextLost(Entities.List[i]);
}
Gfx_DeleteTexture(&ShadowComponent_ShadowTex);
}
@ -311,7 +415,7 @@ static void Entities_ContextRecreated(void* obj) {
int i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (!Entities.List[i]) continue;
Entities.List[i]->VTABLE->ContextRecreated(Entities.List[i]);
/* name redraw is deferred until rendered */
}
}
@ -319,8 +423,8 @@ static void Entities_ChatFontChanged(void* obj) {
int i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (!Entities.List[i]) continue;
if (Entities.List[i]->EntityType != ENTITY_TYPE_PLAYER) continue;
Player_UpdateNameTex((struct Player*)Entities.List[i]);
Entity_DeleteNameTex(Entities.List[i]);
/* name redraw is deferred until rendered */
}
}
@ -466,97 +570,6 @@ struct IGameComponent TabList_Component = {
/*########################################################################################################################*
*---------------------------------------------------------Player----------------------------------------------------------*
*#########################################################################################################################*/
#define PLAYER_NAME_EMPTY_TEX -30000
#define NAME_OFFSET 3 /* offset of back layer of name above an entity */
static void Player_MakeNameTexture(struct Player* player) {
String colorlessName; char colorlessBuffer[STRING_SIZE];
BitmapCol shadowCol = BITMAPCOL_CONST(80, 80, 80, 255);
BitmapCol origWhiteCol;
struct DrawTextArgs args;
bool bitmapped;
String name;
Size2D size;
Bitmap bmp;
/* we want names to always be drawn not using the system font */
bitmapped = Drawer2D_BitmappedText;
Drawer2D_BitmappedText = true;
name = String_FromRawArray(player->DisplayNameRaw);
Drawer2D_MakeFont(&args.font, 24, FONT_STYLE_NORMAL);
DrawTextArgs_Make(&args, &name, &args.font, false);
size = Drawer2D_MeasureText(&args);
if (size.Width == 0) {
player->NameTex.ID = GFX_NULL;
player->NameTex.X = PLAYER_NAME_EMPTY_TEX;
} else {
String_InitArray(colorlessName, colorlessBuffer);
size.Width += NAME_OFFSET; size.Height += NAME_OFFSET;
Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height);
{
origWhiteCol = Drawer2D_Cols['f'];
Drawer2D_Cols['f'] = shadowCol;
String_AppendColorless(&colorlessName, &name);
args.text = colorlessName;
Drawer2D_DrawText(&bmp, &args, NAME_OFFSET, NAME_OFFSET);
Drawer2D_Cols['f'] = origWhiteCol;
args.text = name;
Drawer2D_DrawText(&bmp, &args, 0, 0);
}
Drawer2D_Make2DTexture(&player->NameTex, &bmp, size, 0, 0);
Mem_Free(bmp.Scan0);
}
Drawer2D_BitmappedText = bitmapped;
}
void Player_UpdateNameTex(struct Player* player) {
struct Entity* e = &player->Base;
e->VTABLE->ContextLost(e);
if (Gfx.LostContext) return;
Player_MakeNameTexture(player);
}
static void Player_DrawName(struct Player* p) {
VertexP3fT2fC4b vertices[4];
PackedCol col = PACKEDCOL_WHITE;
struct Entity* e = &p->Base;
struct Model* model;
struct Matrix mat;
Vec3 pos;
float scale;
Vec2 size;
if (p->NameTex.X == PLAYER_NAME_EMPTY_TEX) return;
if (!p->NameTex.ID) Player_MakeNameTexture(p);
Gfx_BindTexture(p->NameTex.ID);
model = e->Model;
Vec3_TransformY(&pos, model->GetNameY(e), &e->Transform);
scale = model->NameScale * e->ModelScale.Y;
scale = scale > 1.0f ? (1.0f/70.0f) : (scale/70.0f);
size.X = p->NameTex.Width * scale; size.Y = p->NameTex.Height * scale;
if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && LocalPlayer_Instance.Hacks.CanSeeAllNames) {
Matrix_Mul(&mat, &Gfx.View, &Gfx.Projection); /* TODO: This mul is slow, avoid it */
/* Get W component of transformed position */
scale = pos.X * mat.Row0.W + pos.Y * mat.Row1.W + pos.Z * mat.Row2.W + mat.Row3.W;
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
}
Particle_DoRender(&size, &pos, &p->NameTex.uv, col, vertices);
Gfx_SetVertexFormat(VERTEX_FORMAT_P3FT2FC4B);
Gfx_UpdateDynamicVb_IndexedTris(Gfx_texVb, vertices, 4);
}
static struct Player* Player_FirstOtherWithSameSkin(struct Player* player) {
struct Entity* entity = &player->Base;
struct Player* p;
@ -750,22 +763,10 @@ static void Player_Despawn(struct Entity* e) {
Gfx_DeleteTexture(&e->TextureId);
Player_ResetSkin(player);
}
e->VTABLE->ContextLost(e);
Entity_ContextLost(e);
}
static void Player_ContextLost(struct Entity* e) {
struct Player* player = (struct Player*)e;
Gfx_DeleteTexture(&player->NameTex.ID);
player->NameTex.X = 0; /* X is used as an 'empty name' flag */
}
static void Player_ContextRecreated(struct Entity* e) {
struct Player* player = (struct Player*)e;
Player_UpdateNameTex(player);
}
void Player_SetName(struct Player* p, const String* name, const String* skin) {
String_CopyToRawArray(p->DisplayNameRaw, name);
void Player_SetSkin(struct Player* p, const String* skin) {
String_CopyToRawArray(p->Base.SkinNameRaw, skin);
}
@ -876,7 +877,7 @@ static void LocalPlayer_RenderModel(struct Entity* e, double deltaTime, float t)
static void LocalPlayer_RenderName(struct Entity* e) {
if (!Camera.Active->isThirdPerson) return;
Player_DrawName((struct Player*)e);
Entity_DrawName(e);
}
static void LocalPlayer_CheckJumpVelocity(void* obj) {
@ -888,14 +889,15 @@ static void LocalPlayer_CheckJumpVelocity(void* obj) {
static struct EntityVTABLE localPlayer_VTABLE = {
LocalPlayer_Tick, Player_Despawn, LocalPlayer_SetLocation, Entity_GetCol,
LocalPlayer_RenderModel, LocalPlayer_RenderName, Player_ContextLost, Player_ContextRecreated,
LocalPlayer_RenderModel, LocalPlayer_RenderName
};
static void LocalPlayer_Init(void) {
struct LocalPlayer* p = &LocalPlayer_Instance;
struct HacksComp* hacks = &p->Hacks;
Player_Init(&p->Base);
Player_SetName((struct Player*)p, &Game_Username, &Game_Username);
Entity_SetName(&p->Base, &Game_Username);
Player_SetSkin((struct Player*)p, &Game_Username);
Event_RegisterVoid(&UserEvents.HackPermissionsChanged, NULL, LocalPlayer_CheckJumpVelocity);
p->Collisions.Entity = &p->Base;
@ -1110,17 +1112,17 @@ static void NetPlayer_RenderName(struct Entity* e) {
distance = Model_RenderDistance(e);
threshold = Entities.NamesMode == NAME_MODE_ALL_UNSCALED ? 8192 * 8192 : 32 * 32;
if (distance <= (float)threshold) Player_DrawName((struct Player*)p);
if (distance <= (float)threshold) Entity_DrawName(e);
}
struct EntityVTABLE netPlayer_VTABLE = {
NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetCol,
NetPlayer_RenderModel, NetPlayer_RenderName, Player_ContextLost, Player_ContextRecreated,
NetPlayer_RenderModel, NetPlayer_RenderName
};
void NetPlayer_Init(struct NetPlayer* p, const String* displayName, const String* skinName) {
void NetPlayer_Init(struct NetPlayer* p, const String* skinName) {
Mem_Set(p, 0, sizeof(struct NetPlayer));
Player_Init(&p->Base);
Player_SetName((struct Player*)p, displayName, skinName);
Player_SetSkin((struct Player*)p, skinName);
p->Base.VTABLE = &netPlayer_VTABLE;
}

View File

@ -61,8 +61,6 @@ struct EntityVTABLE {
PackedCol (*GetCol)(struct Entity* e);
void (*RenderModel)(struct Entity* e, double deltaTime, float t);
void (*RenderName)(struct Entity* e);
void (*ContextLost)(struct Entity* e);
void (*ContextRecreated)(struct Entity* e);
};
/* Contains a model, along with position, velocity, and rotation. May also contain other fields and properties. */
@ -87,6 +85,8 @@ struct Entity {
struct AnimatedComp Anim;
char SkinNameRaw[STRING_SIZE];
char DisplayNameRaw[STRING_SIZE];
struct Texture NameTex;
};
typedef bool (*Entity_TouchesCondition)(BlockID block);
@ -115,6 +115,9 @@ bool Entity_TouchesAnyRope(struct Entity* e);
bool Entity_TouchesAnyLava(struct Entity* e);
bool Entity_TouchesAnyWater(struct Entity* e);
/* Sets the nametag above the given entity's head */
void Entity_SetName(struct Entity* e, const String* name);
/* Global data for all entities */
/* (Actual entities may point to NetPlayers_List or elsewhere) */
CC_VAR extern struct _EntitiesData {
@ -162,14 +165,12 @@ CC_API void TabList_Set(EntityID id, const String* player, const String* list, c
#define TabList_UNSAFE_GetPlayer(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.PlayerNames[id]);
#define TabList_UNSAFE_GetList(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.ListNames[id]);
#define TabList_UNSAFE_GetGroup(id) StringsBuffer_UNSAFE_Get(&TabList.Buffer, TabList.GroupNames[id]);
#define Player_Layout struct Entity Base; char DisplayNameRaw[STRING_SIZE]; bool FetchedSkin; struct Texture NameTex;
#define Player_Layout struct Entity Base; bool FetchedSkin;
/* Represents a player entity. */
struct Player { Player_Layout };
/* Sets the display name (name tag above entity) and skin name of the given player. */
void Player_SetName(struct Player* player, const String* name, const String* skin);
/* Remakes the texture for the name tag of the entity. */
void Player_UpdateNameTex(struct Player* player);
void Player_SetSkin(struct Player* player, const String* skin);
/* Resets the skin of the entity to default. */
void Player_ResetSkin(struct Player* player);
@ -179,7 +180,7 @@ struct NetPlayer {
struct NetInterpComp Interp;
bool ShouldRender;
};
void NetPlayer_Init(struct NetPlayer* player, const String* displayName, const String* skinName);
void NetPlayer_Init(struct NetPlayer* player, const String* skinName);
extern struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID];
/* Represents the user/player's own entity. */

View File

@ -231,7 +231,7 @@ void HeldBlockRenderer_Render(double delta) {
static struct EntityVTABLE heldEntity_VTABLE = {
NULL, NULL, NULL, HeldBlockRenderer_GetCol,
NULL, NULL, NULL, NULL,
NULL, NULL
};
static void HeldBlockRenderer_Init(void) {
Entity_Init(&held_entity);

View File

@ -150,27 +150,27 @@ static void Protocol_CheckName(EntityID id, String* name, String* skin) {
static void Classic_ReadAbsoluteLocation(uint8_t* data, EntityID id, bool interpolate);
static void Protocol_AddEntity(uint8_t* data, EntityID id, const String* displayName, const String* skinName, bool readPosition) {
struct LocalPlayer* p;
struct NetPlayer* pl;
struct LocalPlayer* p = &LocalPlayer_Instance;
struct Entity* e;
if (id != ENTITIES_SELF_ID) {
if (Entities.List[id]) Entities_Remove(id);
pl = &NetPlayers_List[id];
e = &NetPlayers_List[id].Base;
NetPlayer_Init(pl, displayName, skinName);
Entities.List[id] = &pl->Base;
NetPlayer_Init((struct NetPlayer*)e, skinName);
Entities.List[id] = e;
Event_RaiseInt(&EntityEvents.Added, id);
} else {
p = &LocalPlayer_Instance;
p->Base.VTABLE->Despawn(&p->Base);
e = &LocalPlayer_Instance.Base;
e->VTABLE->Despawn(e);
/* Always reset the texture here, in case other network players are using the same skin as us */
/* In that case, we don't want the fetching of new skin for us to delete the texture used by them */
Player_ResetSkin((struct Player*)p);
p->FetchedSkin = false;
Player_SetName((struct Player*)p, displayName, skinName);
Player_UpdateNameTex((struct Player*)p);
Player_SetSkin((struct Player*)p, skinName);
}
Entity_SetName(e, displayName);
if (!readPosition) return;
Classic_ReadAbsoluteLocation(data, id, false);