mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-12 17:17:09 -04:00
Move entity name rendering into more general EntityRenderers module
This commit is contained in:
parent
a81d9d7ee9
commit
776906ebce
@ -34,7 +34,7 @@ void AxisLinesRenderer_Render(void) {
|
||||
if (!AxisLinesRenderer_Enabled) return;
|
||||
/* Don't do it in a ContextRecreated handler, because we only want VB recreated if ShowAxisLines in on. */
|
||||
if (!axisLines_vb) {
|
||||
Gfx_RecreateDynamicVb(&axisLines_vb, VERTEX_FORMAT_COLOURED, AXISLINES_NUM_VERTICES);
|
||||
axisLines_vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_COLOURED, AXISLINES_NUM_VERTICES);
|
||||
}
|
||||
|
||||
if (Camera.Active->isThirdPerson) {
|
||||
|
204
src/Entity.c
204
src/Entity.c
@ -9,8 +9,6 @@
|
||||
#include "Funcs.h"
|
||||
#include "Graphics.h"
|
||||
#include "Lighting.h"
|
||||
#include "Drawer2D.h"
|
||||
#include "Particle.h"
|
||||
#include "Http.h"
|
||||
#include "Chat.h"
|
||||
#include "Model.h"
|
||||
@ -22,6 +20,7 @@
|
||||
#include "Options.h"
|
||||
#include "Errors.h"
|
||||
#include "Utils.h"
|
||||
#include "EntityRenderers.h"
|
||||
|
||||
const char* const NameMode_Names[NAME_MODE_COUNT] = { "None", "Hovered", "All", "AllHovered", "AllUnscaled" };
|
||||
const char* const ShadowMode_Names[SHADOW_MODE_COUNT] = { "None", "SnapToBlock", "Circle", "CircleAll" };
|
||||
@ -47,6 +46,11 @@ void Entity_Init(struct Entity* e) {
|
||||
Entity_SetModel(e, &model);
|
||||
}
|
||||
|
||||
void Entity_SetName(struct Entity* e, const cc_string* name) {
|
||||
EntityNames_Delete(e);
|
||||
String_CopyToRawArray(e->NameRaw, name);
|
||||
}
|
||||
|
||||
Vec3 Entity_GetEyePosition(struct Entity* e) {
|
||||
Vec3 pos = e->Position; pos.Y += Entity_GetEyeHeight(e); return pos;
|
||||
}
|
||||
@ -191,107 +195,6 @@ cc_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 MakeNameTexture(struct Entity* e) {
|
||||
cc_string colorlessName; char colorlessBuffer[STRING_SIZE];
|
||||
BitmapCol shadowColor = BitmapCol_Make(80, 80, 80, 255);
|
||||
BitmapCol origWhiteColor;
|
||||
|
||||
struct DrawTextArgs args;
|
||||
struct FontDesc font;
|
||||
struct Context2D ctx;
|
||||
int width, height;
|
||||
cc_string name;
|
||||
|
||||
/* Names are always drawn using default.png font */
|
||||
Font_MakeBitmapped(&font, 24, FONT_FLAGS_NONE);
|
||||
/* Don't want DPI scaling or padding */
|
||||
font.size = 24; font.height = 24;
|
||||
|
||||
name = String_FromRawArray(e->NameRaw);
|
||||
DrawTextArgs_Make(&args, &name, &font, false);
|
||||
width = Drawer2D_TextWidth(&args);
|
||||
|
||||
if (!width) {
|
||||
e->NameTex.ID = 0;
|
||||
e->NameTex.X = NAME_IS_EMPTY;
|
||||
} else {
|
||||
String_InitArray(colorlessName, colorlessBuffer);
|
||||
width += NAME_OFFSET;
|
||||
height = Drawer2D_TextHeight(&args) + NAME_OFFSET;
|
||||
|
||||
Context2D_Alloc(&ctx, width, height);
|
||||
{
|
||||
origWhiteColor = Drawer2D.Colors['f'];
|
||||
|
||||
Drawer2D.Colors['f'] = shadowColor;
|
||||
Drawer2D_WithoutColors(&colorlessName, &name);
|
||||
args.text = colorlessName;
|
||||
Context2D_DrawText(&ctx, &args, NAME_OFFSET, NAME_OFFSET);
|
||||
|
||||
Drawer2D.Colors['f'] = origWhiteColor;
|
||||
args.text = name;
|
||||
Context2D_DrawText(&ctx, &args, 0, 0);
|
||||
}
|
||||
Context2D_MakeTexture(&e->NameTex, &ctx);
|
||||
Context2D_Free(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawName(struct Entity* e) {
|
||||
struct VertexTextured* vertices;
|
||||
struct Model* model;
|
||||
struct Matrix mat;
|
||||
Vec3 pos;
|
||||
float scale;
|
||||
Vec2 size;
|
||||
|
||||
if (e->NameTex.X == NAME_IS_EMPTY) return;
|
||||
if (!e->NameTex.ID) 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.row1.W + pos.Y * mat.row2.W + pos.Z * mat.row3.W + mat.row4.W;
|
||||
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
|
||||
}
|
||||
|
||||
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
|
||||
|
||||
vertices = (struct VertexTextured*)Gfx_LockDynamicVb(Gfx_texVb, VERTEX_FORMAT_TEXTURED, 4);
|
||||
Particle_DoRender(&size, &pos, &e->NameTex.uv, PACKEDCOL_WHITE, vertices);
|
||||
Gfx_UnlockDynamicVb(Gfx_texVb);
|
||||
|
||||
Gfx_DrawVb_IndexedTris(4);
|
||||
}
|
||||
|
||||
/* Deletes the texture containing the entity's nametag */
|
||||
CC_NOINLINE static void 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 cc_string* name) {
|
||||
DeleteNameTex(e);
|
||||
String_CopyToRawArray(e->NameRaw, name);
|
||||
/* name texture redraw deferred until necessary */
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Entity skins-------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
@ -531,7 +434,6 @@ void Entity_LerpAngles(struct Entity* e, float t) {
|
||||
*--------------------------------------------------------Entities---------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
struct _EntitiesData Entities;
|
||||
static EntityID entities_closestId;
|
||||
|
||||
void Entities_Tick(struct ScheduledTask* task) {
|
||||
int i;
|
||||
@ -551,83 +453,17 @@ void Entities_RenderModels(double delta, float t) {
|
||||
}
|
||||
Gfx_SetAlphaTest(false);
|
||||
}
|
||||
|
||||
|
||||
void Entities_RenderNames(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
cc_bool hadFog;
|
||||
int i;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_NONE) return;
|
||||
entities_closestId = Entities_GetClosest(&p->Base);
|
||||
if (!p->Hacks.CanSeeAllNames || Entities.NamesMode != NAME_MODE_ALL) return;
|
||||
|
||||
Gfx_SetAlphaTest(true);
|
||||
hadFog = Gfx_GetFog();
|
||||
if (hadFog) Gfx_SetFog(false);
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
if (i != entities_closestId || i == ENTITIES_SELF_ID) {
|
||||
Entities.List[i]->VTABLE->RenderName(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Gfx_SetAlphaTest(false);
|
||||
if (hadFog) Gfx_SetFog(true);
|
||||
}
|
||||
|
||||
void Entities_RenderHoveredNames(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
cc_bool allNames, hadFog;
|
||||
int i;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_NONE) return;
|
||||
allNames = !(Entities.NamesMode == NAME_MODE_HOVERED || Entities.NamesMode == NAME_MODE_ALL)
|
||||
&& p->Hacks.CanSeeAllNames;
|
||||
|
||||
Gfx_SetAlphaTest(true);
|
||||
Gfx_SetDepthTest(false);
|
||||
hadFog = Gfx_GetFog();
|
||||
if (hadFog) Gfx_SetFog(false);
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
if ((i == entities_closestId || allNames) && i != ENTITIES_SELF_ID) {
|
||||
Entities.List[i]->VTABLE->RenderName(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Gfx_SetAlphaTest(false);
|
||||
Gfx_SetDepthTest(true);
|
||||
if (hadFog) Gfx_SetFog(true);
|
||||
}
|
||||
|
||||
static void Entity_ContextLost(struct Entity* e) { DeleteNameTex(e); }
|
||||
|
||||
static void Entities_ContextLost(void* obj) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
Entity_ContextLost(Entities.List[i]);
|
||||
}
|
||||
|
||||
if (Gfx.ManagedTextures) return;
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
DeleteSkin(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
/* No OnContextCreated, names/skin textures remade when needed */
|
||||
|
||||
static void Entities_ChatFontChanged(void* obj) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
|
||||
if (!Entities.List[i]) continue;
|
||||
DeleteNameTex(Entities.List[i]);
|
||||
/* name redraw is deferred until rendered */
|
||||
}
|
||||
}
|
||||
/* No OnContextCreated, skin textures remade when needed */
|
||||
|
||||
void Entities_Remove(EntityID id) {
|
||||
struct Entity* e = Entities.List[id];
|
||||
@ -749,7 +585,7 @@ struct IGameComponent TabList_Component = {
|
||||
|
||||
static void Player_Despawn(struct Entity* e) {
|
||||
DeleteSkin(e);
|
||||
Entity_ContextLost(e);
|
||||
EntityNames_Delete(e);
|
||||
}
|
||||
|
||||
|
||||
@ -870,9 +706,8 @@ static void LocalPlayer_RenderModel(struct Entity* e, double deltaTime, float t)
|
||||
Model_Render(e->Model, e);
|
||||
}
|
||||
|
||||
static void LocalPlayer_RenderName(struct Entity* e) {
|
||||
if (!Camera.Active->isThirdPerson) return;
|
||||
DrawName(e);
|
||||
static cc_bool LocalPlayer_ShouldRenderName(struct Entity* e) {
|
||||
return Camera.Active->isThirdPerson;
|
||||
}
|
||||
|
||||
static void LocalPlayer_CheckJumpVelocity(void* obj) {
|
||||
@ -896,7 +731,7 @@ static void LocalPlayer_GetMovement(float* xMoving, float* zMoving) {
|
||||
|
||||
static const struct EntityVTABLE localPlayer_VTABLE = {
|
||||
LocalPlayer_Tick, Player_Despawn, LocalPlayer_SetLocation, Entity_GetColor,
|
||||
LocalPlayer_RenderModel, LocalPlayer_RenderName
|
||||
LocalPlayer_RenderModel, LocalPlayer_ShouldRenderName
|
||||
};
|
||||
static void LocalPlayer_Init(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
@ -1152,19 +987,19 @@ static void NetPlayer_RenderModel(struct Entity* e, double deltaTime, float t) {
|
||||
if (e->ShouldRender) Model_Render(e->Model, e);
|
||||
}
|
||||
|
||||
static void NetPlayer_RenderName(struct Entity* e) {
|
||||
static cc_bool NetPlayer_ShouldRenderName(struct Entity* e) {
|
||||
float distance;
|
||||
int threshold;
|
||||
if (!e->ShouldRender) return;
|
||||
if (!e->ShouldRender) return false;
|
||||
|
||||
distance = Model_RenderDistance(e);
|
||||
threshold = Entities.NamesMode == NAME_MODE_ALL_UNSCALED ? 8192 * 8192 : 32 * 32;
|
||||
if (distance <= (float)threshold) DrawName(e);
|
||||
return distance <= (float)threshold;
|
||||
}
|
||||
|
||||
static const struct EntityVTABLE netPlayer_VTABLE = {
|
||||
NetPlayer_Tick, Player_Despawn, NetPlayer_SetLocation, Entity_GetColor,
|
||||
NetPlayer_RenderModel, NetPlayer_RenderName
|
||||
NetPlayer_RenderModel, NetPlayer_ShouldRenderName
|
||||
};
|
||||
void NetPlayer_Init(struct NetPlayer* p) {
|
||||
Mem_Set(p, 0, sizeof(struct NetPlayer));
|
||||
@ -1177,10 +1012,9 @@ void NetPlayer_Init(struct NetPlayer* p) {
|
||||
*---------------------------------------------------Entities component----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static void Entities_Init(void) {
|
||||
Event_Register_(&GfxEvents.ContextLost, NULL, Entities_ContextLost);
|
||||
Event_Register_(&ChatEvents.FontChanged, NULL, Entities_ChatFontChanged);
|
||||
Event_Register_(&InputEvents.Down, NULL, LocalPlayer_InputDown);
|
||||
Event_Register_(&InputEvents.Up, NULL, LocalPlayer_InputUp);
|
||||
Event_Register_(&GfxEvents.ContextLost, NULL, Entities_ContextLost);
|
||||
Event_Register_(&InputEvents.Down, NULL, LocalPlayer_InputDown);
|
||||
Event_Register_(&InputEvents.Up, NULL, LocalPlayer_InputUp);
|
||||
|
||||
Entities.NamesMode = Options_GetEnum(OPT_NAMES_MODE, NAME_MODE_HOVERED,
|
||||
NameMode_Names, Array_Elems(NameMode_Names));
|
||||
|
@ -71,7 +71,7 @@ struct EntityVTABLE {
|
||||
void (*SetLocation)(struct Entity* e, struct LocationUpdate* update);
|
||||
PackedCol (*GetCol)(struct Entity* e);
|
||||
void (*RenderModel)(struct Entity* e, double deltaTime, float t);
|
||||
void (*RenderName)(struct Entity* e);
|
||||
cc_bool (*ShouldRenderName)(struct Entity* e);
|
||||
};
|
||||
|
||||
/* Skin is still being downloaded asynchronously */
|
||||
@ -155,10 +155,6 @@ CC_VAR extern struct _EntitiesData {
|
||||
void Entities_Tick(struct ScheduledTask* task);
|
||||
/* Renders all entities */
|
||||
void Entities_RenderModels(double delta, float t);
|
||||
/* Renders the name tags of entities, depending on Entities.NamesMode */
|
||||
void Entities_RenderNames(void);
|
||||
/* Renders hovered entity name tags (these appears through blocks) */
|
||||
void Entities_RenderHoveredNames(void);
|
||||
/* Removes the given entity, raising EntityEvents.Removed event */
|
||||
void Entities_Remove(EntityID id);
|
||||
/* Gets the ID of the closest entity to the given entity */
|
||||
|
@ -9,15 +9,29 @@
|
||||
#include "Graphics.h"
|
||||
#include "Model.h"
|
||||
#include "World.h"
|
||||
#include "Particle.h"
|
||||
#include "Drawer2D.h"
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------------Entity Shadow------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static cc_bool shadows_boundTex;
|
||||
static GfxResourceID shadows_VB;
|
||||
static GfxResourceID shadows_tex;
|
||||
static float shadow_radius, shadow_uvScale;
|
||||
struct ShadowData { float Y; BlockID Block; cc_uint8 A; };
|
||||
|
||||
/* Circle shadows extend at most 4 blocks vertically */
|
||||
#define SHADOW_MAX_RANGE 4
|
||||
/* Circle shadows on blocks underneath the top block can be chopped up into at most 4 pieces */
|
||||
#define SHADOW_MAX_PER_SUB_BLOCK (4 * 4)
|
||||
/* Circle shadows use at most:
|
||||
- 4 vertices for top most block
|
||||
- MAX_PER_SUB_BLOCK for everyblock underneath the top block */
|
||||
#define SHADOW_MAX_PER_COLUMN (4 + SHADOW_MAX_PER_SUB_BLOCK * (SHADOW_MAX_RANGE - 1))
|
||||
/* Circle shadows may be split across (x,z), (x,z+1), (x+1,z), (x+1,z+1) */
|
||||
#define SHADOW_MAX_VERTS 4 * SHADOW_MAX_PER_COLUMN
|
||||
|
||||
static cc_bool lequal(float a, float b) { return a < b || Math_AbsF(a - b) < 0.001f; }
|
||||
static void EntityShadow_DrawCoords(struct VertexTextured** vertices, struct Entity* e, struct ShadowData* data, float x1, float z1, float x2, float z2) {
|
||||
PackedCol col;
|
||||
@ -72,7 +86,8 @@ static void EntityShadow_DrawCircle(struct VertexTextured** vertices, struct Ent
|
||||
min = Blocks.MinBB[data[0].Block]; max = Blocks.MaxBB[data[0].Block];
|
||||
|
||||
EntityShadow_DrawCoords(vertices, e, &data[0], x + min.X, z + min.Z, x + max.X, z + max.Z);
|
||||
for (i = 1; i < 4; i++) {
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
if (data[i].Block == BLOCK_AIR) return;
|
||||
nMin = Blocks.MinBB[data[i].Block]; nMax = Blocks.MaxBB[data[i].Block];
|
||||
|
||||
@ -112,7 +127,8 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str
|
||||
posY = e->Position.Y;
|
||||
outside = !World_ContainsXZ(x, z);
|
||||
|
||||
for (i = 0; y >= 0 && i < 4; y--) {
|
||||
for (i = 0; y >= 0 && i < 4; y--)
|
||||
{
|
||||
if (!outside) {
|
||||
block = World_GetBlock(x, y, z);
|
||||
} else if (y == Env.EdgeHeight - 1) {
|
||||
@ -146,10 +162,9 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str
|
||||
}
|
||||
|
||||
static void EntityShadow_Draw(struct Entity* e) {
|
||||
struct VertexTextured vertices[128];
|
||||
struct VertexTextured vertices[128]; /* TODO this is less than maxVertes */
|
||||
struct VertexTextured* ptr;
|
||||
struct ShadowData data[4];
|
||||
GfxResourceID vb;
|
||||
Vec3 pos;
|
||||
float radius;
|
||||
int y, count;
|
||||
@ -163,16 +178,13 @@ static void EntityShadow_Draw(struct Entity* e) {
|
||||
shadow_radius = radius / 16.0f;
|
||||
shadow_uvScale = 16.0f / (radius * 2.0f);
|
||||
|
||||
/* TODO: Should shadow component use its own VB? */
|
||||
ptr = vertices;
|
||||
if (Entities.ShadowsMode == SHADOW_MODE_SNAP_TO_BLOCK) {
|
||||
vb = Gfx_texVb;
|
||||
x1 = Math_Floor(pos.X); z1 = Math_Floor(pos.Z);
|
||||
if (!EntityShadow_GetBlocks(e, x1, y, z1, data)) return;
|
||||
|
||||
EntityShadow_DrawSquareShadow(&ptr, data[0].Y, x1, z1);
|
||||
} else {
|
||||
vb = Models.Vb;
|
||||
x1 = Math_Floor(pos.X - shadow_radius); z1 = Math_Floor(pos.Z - shadow_radius);
|
||||
x2 = Math_Floor(pos.X + shadow_radius); z2 = Math_Floor(pos.Z + shadow_radius);
|
||||
|
||||
@ -198,7 +210,7 @@ static void EntityShadow_Draw(struct Entity* e) {
|
||||
}
|
||||
|
||||
count = (int)(ptr - vertices);
|
||||
Gfx_SetDynamicVbData(vb, vertices, count);
|
||||
Gfx_SetDynamicVbData(shadows_VB, vertices, count);
|
||||
Gfx_DrawVb_IndexedTris(count);
|
||||
}
|
||||
|
||||
@ -226,7 +238,7 @@ static void EntityShadows_MakeTexture(void) {
|
||||
row[x] = dist < sh_half * sh_half ? color : 0;
|
||||
}
|
||||
}
|
||||
Gfx_RecreateTexture(&shadows_tex, &bmp, 0, false);
|
||||
shadows_tex = Gfx_CreateTexture(&bmp, 0, false);
|
||||
}
|
||||
|
||||
void EntityShadows_Render(void) {
|
||||
@ -234,7 +246,10 @@ void EntityShadows_Render(void) {
|
||||
if (Entities.ShadowsMode == SHADOW_MODE_NONE) return;
|
||||
|
||||
shadows_boundTex = false;
|
||||
if (!shadows_tex) EntityShadows_MakeTexture();
|
||||
if (!shadows_tex)
|
||||
EntityShadows_MakeTexture();
|
||||
if (!shadows_VB)
|
||||
shadows_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, SHADOW_MAX_VERTS);
|
||||
|
||||
Gfx_SetAlphaArgBlend(true);
|
||||
Gfx_SetDepthWrite(false);
|
||||
@ -257,19 +272,193 @@ void EntityShadows_Render(void) {
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Entity nametag------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static GfxResourceID names_VB;
|
||||
#define NAME_IS_EMPTY -30000
|
||||
#define NAME_OFFSET 3 /* offset of back layer of name above an entity */
|
||||
|
||||
static void MakeNameTexture(struct Entity* e) {
|
||||
cc_string colorlessName; char colorlessBuffer[STRING_SIZE];
|
||||
BitmapCol shadowColor = BitmapCol_Make(80, 80, 80, 255);
|
||||
BitmapCol origWhiteColor;
|
||||
|
||||
struct DrawTextArgs args;
|
||||
struct FontDesc font;
|
||||
struct Context2D ctx;
|
||||
int width, height;
|
||||
cc_string name;
|
||||
|
||||
/* Names are always drawn using default.png font */
|
||||
Font_MakeBitmapped(&font, 24, FONT_FLAGS_NONE);
|
||||
/* Don't want DPI scaling or padding */
|
||||
font.size = 24; font.height = 24;
|
||||
|
||||
name = String_FromRawArray(e->NameRaw);
|
||||
DrawTextArgs_Make(&args, &name, &font, false);
|
||||
width = Drawer2D_TextWidth(&args);
|
||||
|
||||
if (!width) {
|
||||
e->NameTex.ID = 0;
|
||||
e->NameTex.X = NAME_IS_EMPTY;
|
||||
} else {
|
||||
String_InitArray(colorlessName, colorlessBuffer);
|
||||
width += NAME_OFFSET;
|
||||
height = Drawer2D_TextHeight(&args) + NAME_OFFSET;
|
||||
|
||||
Context2D_Alloc(&ctx, width, height);
|
||||
{
|
||||
origWhiteColor = Drawer2D.Colors['f'];
|
||||
|
||||
Drawer2D.Colors['f'] = shadowColor;
|
||||
Drawer2D_WithoutColors(&colorlessName, &name);
|
||||
args.text = colorlessName;
|
||||
Context2D_DrawText(&ctx, &args, NAME_OFFSET, NAME_OFFSET);
|
||||
|
||||
Drawer2D.Colors['f'] = origWhiteColor;
|
||||
args.text = name;
|
||||
Context2D_DrawText(&ctx, &args, 0, 0);
|
||||
}
|
||||
Context2D_MakeTexture(&e->NameTex, &ctx);
|
||||
Context2D_Free(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawName(struct Entity* e) {
|
||||
struct VertexTextured* vertices;
|
||||
struct Model* model;
|
||||
struct Matrix mat;
|
||||
Vec3 pos;
|
||||
float scale;
|
||||
Vec2 size;
|
||||
|
||||
if (!e->VTABLE->ShouldRenderName(e)) return;
|
||||
if (e->NameTex.X == NAME_IS_EMPTY) return;
|
||||
if (!e->NameTex.ID) MakeNameTexture(e);
|
||||
Gfx_BindTexture(e->NameTex.ID);
|
||||
|
||||
if (!names_VB)
|
||||
names_VB = Gfx_CreateDynamicVb(VERTEX_FORMAT_TEXTURED, 4);
|
||||
|
||||
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.row1.W + pos.Y * mat.row2.W + pos.Z * mat.row3.W + mat.row4.W;
|
||||
size.X *= scale * 0.2f; size.Y *= scale * 0.2f;
|
||||
}
|
||||
|
||||
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
|
||||
|
||||
vertices = (struct VertexTextured*)Gfx_LockDynamicVb(names_VB, VERTEX_FORMAT_TEXTURED, 4);
|
||||
Particle_DoRender(&size, &pos, &e->NameTex.uv, PACKEDCOL_WHITE, vertices);
|
||||
Gfx_UnlockDynamicVb(names_VB);
|
||||
|
||||
Gfx_DrawVb_IndexedTris(4);
|
||||
}
|
||||
|
||||
void EntityNames_Delete(struct Entity* e) {
|
||||
Gfx_DeleteTexture(&e->NameTex.ID);
|
||||
e->NameTex.X = 0; /* X is used as an 'empty name' flag */
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------------Names rendering-----------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static EntityID closestEntityId;
|
||||
|
||||
void EntityNames_Render(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
cc_bool hadFog;
|
||||
int i;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_NONE) return;
|
||||
closestEntityId = Entities_GetClosest(&p->Base);
|
||||
if (!p->Hacks.CanSeeAllNames || Entities.NamesMode != NAME_MODE_ALL) return;
|
||||
|
||||
Gfx_SetAlphaTest(true);
|
||||
hadFog = Gfx_GetFog();
|
||||
if (hadFog) Gfx_SetFog(false);
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++)
|
||||
{
|
||||
if (!Entities.List[i]) continue;
|
||||
if (i != closestEntityId || i == ENTITIES_SELF_ID) {
|
||||
DrawName(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Gfx_SetAlphaTest(false);
|
||||
if (hadFog) Gfx_SetFog(true);
|
||||
}
|
||||
|
||||
void EntityNames_RenderHovered(void) {
|
||||
struct LocalPlayer* p = &LocalPlayer_Instance;
|
||||
cc_bool allNames, hadFog;
|
||||
int i;
|
||||
|
||||
if (Entities.NamesMode == NAME_MODE_NONE) return;
|
||||
allNames = !(Entities.NamesMode == NAME_MODE_HOVERED || Entities.NamesMode == NAME_MODE_ALL)
|
||||
&& p->Hacks.CanSeeAllNames;
|
||||
|
||||
Gfx_SetAlphaTest(true);
|
||||
Gfx_SetDepthTest(false);
|
||||
hadFog = Gfx_GetFog();
|
||||
if (hadFog) Gfx_SetFog(false);
|
||||
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++)
|
||||
{
|
||||
if (!Entities.List[i]) continue;
|
||||
if ((i == closestEntityId || allNames) && i != ENTITIES_SELF_ID) {
|
||||
DrawName(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Gfx_SetAlphaTest(false);
|
||||
Gfx_SetDepthTest(true);
|
||||
if (hadFog) Gfx_SetFog(true);
|
||||
}
|
||||
|
||||
static void DeleteAllNameTextures(void) {
|
||||
int i;
|
||||
for (i = 0; i < ENTITIES_MAX_COUNT; i++)
|
||||
{
|
||||
if (!Entities.List[i]) continue;
|
||||
EntityNames_Delete(Entities.List[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void EntityNames_ChatFontChanged(void* obj) {
|
||||
DeleteAllNameTextures();
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-----------------------------------------------Entity renderers component------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
static void EntityRenderers_ContextLost(void* obj) {
|
||||
Gfx_DeleteTexture(&shadows_tex);
|
||||
Gfx_DeleteDynamicVb(&shadows_VB);
|
||||
|
||||
Gfx_DeleteDynamicVb(&names_VB);
|
||||
DeleteAllNameTextures();
|
||||
}
|
||||
|
||||
static void EntityRenderers_Init(void) {
|
||||
Event_Register_(&GfxEvents.ContextLost, NULL, EntityRenderers_ContextLost);
|
||||
Event_Register_(&GfxEvents.ContextLost, NULL, EntityRenderers_ContextLost);
|
||||
Event_Register_(&ChatEvents.FontChanged, NULL, EntityNames_ChatFontChanged);
|
||||
}
|
||||
|
||||
static void EntityRenderers_Free(void) {
|
||||
Gfx_DeleteTexture(&shadows_tex);
|
||||
EntityRenderers_ContextLost(NULL);
|
||||
}
|
||||
|
||||
struct IGameComponent EntityRenderers_Component = {
|
||||
|
@ -1,13 +1,21 @@
|
||||
#ifndef CC_ENTITYRENDERERS_H
|
||||
#define CC_ENTITYRENDERERS_H
|
||||
#include "Core.h"
|
||||
/* Renders supporting objects for entities (shadows)
|
||||
/* Renders supporting objects for entities (shadows and names)
|
||||
Copyright 2014-2023 ClassiCube | Licensed under BSD-3
|
||||
*/
|
||||
struct IGameComponent;
|
||||
extern struct IGameComponent EntityRenderers_Component;
|
||||
struct Entity;
|
||||
|
||||
/* Draws shadows under entities, depending on Entities.ShadowsMode */
|
||||
void EntityShadows_Render(void);
|
||||
|
||||
/* Deletes the texture containing the entity's nametag */
|
||||
void EntityNames_Delete(struct Entity* e);
|
||||
/* Renders the name tags of entities, depending on Entities.NamesMode */
|
||||
void EntityNames_Render(void);
|
||||
/* Renders hovered entity name tags (these appears through blocks) */
|
||||
void EntityNames_RenderHovered(void);
|
||||
|
||||
#endif
|
||||
|
@ -272,11 +272,42 @@ static GfxResourceID skybox_tex, skybox_vb;
|
||||
#define SKYBOX_COUNT (6 * 4)
|
||||
cc_bool EnvRenderer_ShouldRenderSkybox(void) { return skybox_tex && !EnvRenderer_Minimal; }
|
||||
|
||||
static void AllocateSkyboxVB(void) {
|
||||
static const struct VertexTextured vertices[SKYBOX_COUNT] = {
|
||||
/* Front quad */
|
||||
{ -1, -1, -1, 0, 0.25f, 1.00f }, { 1, -1, -1, 0, 0.50f, 1.00f },
|
||||
{ 1, 1, -1, 0, 0.50f, 0.50f }, { -1, 1, -1, 0, 0.25f, 0.50f },
|
||||
/* Left quad */
|
||||
{ -1, -1, 1, 0, 0.00f, 1.00f }, { -1, -1, -1, 0, 0.25f, 1.00f },
|
||||
{ -1, 1, -1, 0, 0.25f, 0.50f }, { -1, 1, 1, 0, 0.00f, 0.50f },
|
||||
/* Back quad */
|
||||
{ 1, -1, 1, 0, 0.75f, 1.00f }, { -1, -1, 1, 0, 1.00f, 1.00f },
|
||||
{ -1, 1, 1, 0, 1.00f, 0.50f }, { 1, 1, 1, 0, 0.75f, 0.50f },
|
||||
/* Right quad */
|
||||
{ 1, -1, -1, 0, 0.50f, 1.00f }, { 1, -1, 1, 0, 0.75f, 1.00f },
|
||||
{ 1, 1, 1, 0, 0.75f, 0.50f }, { 1, 1, -1, 0, 0.50f, 0.50f },
|
||||
/* Top quad */
|
||||
{ 1, 1, -1, 0, 0.50f, 0.50f }, { 1, 1, 1, 0, 0.50f, 0.00f },
|
||||
{ -1, 1, 1, 0, 0.25f, 0.00f }, { -1, 1, -1, 0, 0.25f, 0.50f },
|
||||
/* Bottom quad */
|
||||
{ 1, -1, -1, 0, 0.75f, 0.50f }, { 1, -1, 1, 0, 0.75f, 0.00f },
|
||||
{ -1, -1, 1, 0, 0.50f, 0.00f }, { -1, -1, -1, 0, 0.50f, 0.50f },
|
||||
};
|
||||
struct VertexTextured* data;
|
||||
int i;
|
||||
|
||||
data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&skybox_vb,
|
||||
VERTEX_FORMAT_TEXTURED, SKYBOX_COUNT);
|
||||
Mem_Copy(data, vertices, sizeof(vertices));
|
||||
for (i = 0; i < SKYBOX_COUNT; i++) { data[i].Col = Env.SkyboxCol; }
|
||||
Gfx_UnlockVb(skybox_vb);
|
||||
}
|
||||
|
||||
void EnvRenderer_RenderSkybox(void) {
|
||||
struct Matrix m, rotX, rotY, view;
|
||||
float rotTime;
|
||||
Vec3 pos;
|
||||
if (!skybox_vb) return;
|
||||
if (!skybox_vb) AllocateSkyboxVB();
|
||||
|
||||
Gfx_SetDepthWrite(false);
|
||||
Gfx_BindTexture(skybox_tex);
|
||||
@ -302,42 +333,6 @@ void EnvRenderer_RenderSkybox(void) {
|
||||
Gfx_SetDepthWrite(true);
|
||||
}
|
||||
|
||||
static void UpdateSkybox(void) {
|
||||
static const struct VertexTextured vertices[SKYBOX_COUNT] = {
|
||||
/* Front quad */
|
||||
{ -1, -1, -1, 0, 0.25f, 1.00f }, { 1, -1, -1, 0, 0.50f, 1.00f },
|
||||
{ 1, 1, -1, 0, 0.50f, 0.50f }, { -1, 1, -1, 0, 0.25f, 0.50f },
|
||||
/* Left quad */
|
||||
{ -1, -1, 1, 0, 0.00f, 1.00f }, { -1, -1, -1, 0, 0.25f, 1.00f },
|
||||
{ -1, 1, -1, 0, 0.25f, 0.50f }, { -1, 1, 1, 0, 0.00f, 0.50f },
|
||||
/* Back quad */
|
||||
{ 1, -1, 1, 0, 0.75f, 1.00f }, { -1, -1, 1, 0, 1.00f, 1.00f },
|
||||
{ -1, 1, 1, 0, 1.00f, 0.50f }, { 1, 1, 1, 0, 0.75f, 0.50f },
|
||||
/* Right quad */
|
||||
{ 1, -1, -1, 0, 0.50f, 1.00f }, { 1, -1, 1, 0, 0.75f, 1.00f },
|
||||
{ 1, 1, 1, 0, 0.75f, 0.50f }, { 1, 1, -1, 0, 0.50f, 0.50f },
|
||||
/* Top quad */
|
||||
{ 1, 1, -1, 0, 0.50f, 0.50f }, { 1, 1, 1, 0, 0.50f, 0.00f },
|
||||
{ -1, 1, 1, 0, 0.25f, 0.00f }, { -1, 1, -1, 0, 0.25f, 0.50f },
|
||||
/* Bottom quad */
|
||||
{ 1, -1, -1, 0, 0.75f, 0.50f }, { 1, -1, 1, 0, 0.75f, 0.00f },
|
||||
{ -1, -1, 1, 0, 0.50f, 0.00f }, { -1, -1, -1, 0, 0.50f, 0.50f },
|
||||
};
|
||||
struct VertexTextured* data;
|
||||
int i;
|
||||
|
||||
Gfx_DeleteVb(&skybox_vb);
|
||||
if (Gfx.LostContext) return;
|
||||
if (EnvRenderer_Minimal) return;
|
||||
|
||||
data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&skybox_vb,
|
||||
VERTEX_FORMAT_TEXTURED, SKYBOX_COUNT);
|
||||
Mem_Copy(data, vertices, sizeof(vertices));
|
||||
for (i = 0; i < SKYBOX_COUNT; i++) { data[i].Col = Env.SkyboxCol; }
|
||||
Gfx_UnlockVb(skybox_vb);
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*----------------------------------------------------------Weather--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
@ -834,7 +829,7 @@ static void UpdateAll(void) {
|
||||
UpdateMapEdges();
|
||||
UpdateClouds();
|
||||
UpdateSky();
|
||||
UpdateSkybox();
|
||||
Gfx_DeleteVb(&skybox_vb);
|
||||
EnvRenderer_UpdateFog();
|
||||
|
||||
Gfx_DeleteDynamicVb(&weather_vb);
|
||||
@ -898,7 +893,7 @@ static void OnEnvVariableChanged(void* obj, int envVar) {
|
||||
UpdateSky();
|
||||
UpdateClouds();
|
||||
} else if (envVar == ENV_VAR_SKYBOX_COLOR) {
|
||||
UpdateSkybox();
|
||||
Gfx_DeleteVb(&skybox_vb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,7 +463,7 @@ static void Game_Render3D(double delta, float t) {
|
||||
|
||||
AxisLinesRenderer_Render();
|
||||
Entities_RenderModels(delta, t);
|
||||
Entities_RenderNames();
|
||||
EntityNames_Render();
|
||||
|
||||
Particles_Render(t);
|
||||
Camera.Active->GetPickedBlock(&Game_SelectedPos); /* TODO: only pick when necessary */
|
||||
@ -496,7 +496,7 @@ static void Game_Render3D(double delta, float t) {
|
||||
}
|
||||
|
||||
Selections_Render();
|
||||
Entities_RenderHoveredNames();
|
||||
EntityNames_RenderHovered();
|
||||
Camera_KeyLookUpdate();
|
||||
InputHandler_Tick();
|
||||
if (!Game_HideGui) HeldBlockRenderer_Render(delta);
|
||||
@ -573,6 +573,7 @@ static void Game_RenderFrame(double delta) {
|
||||
Gfx_RecreateContext();
|
||||
/* all good, context is back */
|
||||
} else {
|
||||
Game.Time += delta; /* TODO: Not set in two places? */
|
||||
Server.Tick(NULL);
|
||||
Thread_Sleep(16);
|
||||
return;
|
||||
|
@ -56,7 +56,6 @@ CC_VAR extern struct _GfxData {
|
||||
} Gfx;
|
||||
|
||||
extern GfxResourceID Gfx_defaultIb;
|
||||
extern GfxResourceID Gfx_quadVb, Gfx_texVb;
|
||||
extern const cc_string Gfx_LowPerfMessage;
|
||||
|
||||
#define ICOUNT(verticesCount) (((verticesCount) >> 2) * 6)
|
||||
|
@ -434,6 +434,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return AllocBuffer(maxVertices, strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
return vb;
|
||||
}
|
||||
|
@ -190,6 +190,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return memalign(16, maxVertices * strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
vb_size = count * strideSizes[fmt];
|
||||
return vb;
|
||||
|
@ -320,6 +320,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return memalign(16, maxVertices * strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
vb_size = count * strideSizes[fmt];
|
||||
return vb;
|
||||
|
@ -538,6 +538,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices)
|
||||
return rsxMemalign(128, maxVertices * strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
vb_size = count * strideSizes[fmt];
|
||||
return vb;
|
||||
|
@ -311,6 +311,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return memalign(16, maxVertices * strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
vb_size = count * strideSizes[fmt];
|
||||
return vb;
|
||||
|
@ -915,6 +915,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return GPUBuffer_Alloc(maxVertices * strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
struct GPUBuffer* buffer = (struct GPUBuffer*)vb;
|
||||
return buffer->data;
|
||||
|
@ -453,6 +453,8 @@ static GfxResourceID Gfx_AllocDynamicVb(VertexFormat fmt, int maxVertices) {
|
||||
return AllocBuffer(maxVertices, strideSizes[fmt]);
|
||||
}
|
||||
|
||||
void Gfx_BindDynamicVb(GfxResourceID vb) { Gfx_BindVb(vb); }
|
||||
|
||||
void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) {
|
||||
return vb;
|
||||
}
|
||||
|
@ -77,8 +77,8 @@ static int RunProgram(int argc, char** argv) {
|
||||
#ifdef _MSC_VER
|
||||
/* NOTE: Make sure to comment this out before pushing a commit */
|
||||
//cc_string rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565");
|
||||
cc_string rawArgs = String_FromConst("UnknownShadow200");
|
||||
argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4);
|
||||
//cc_string rawArgs = String_FromConst("UnknownShadow200");
|
||||
//argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4);
|
||||
#endif
|
||||
|
||||
if (argsCount == 0) {
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
struct _GfxData Gfx;
|
||||
GfxResourceID Gfx_defaultIb;
|
||||
GfxResourceID Gfx_quadVb, Gfx_texVb;
|
||||
static GfxResourceID Gfx_quadVb, Gfx_texVb;
|
||||
const cc_string Gfx_LowPerfMessage = String_FromConst("&eRunning in reduced performance mode (game minimised or hidden)");
|
||||
|
||||
static const int strideSizes[] = { SIZEOF_VERTEX_COLOURED, SIZEOF_VERTEX_TEXTURED };
|
||||
|
Loading…
x
Reference in New Issue
Block a user