Render Entity Shadows

This commit is contained in:
TheBrokenRail 2024-10-03 20:29:24 -04:00
parent d4ab0099f0
commit 5668dcc852
10 changed files with 211 additions and 68 deletions

View File

@ -47,6 +47,7 @@
* `Fix Crash When Generating Certain Seeds` (Enabled By Default)
* `Click Buttons On Mouse Down` (Enabled By Default)
* `3D Dropped Items` (Enabled By Default)
* `Render Entity Shadows` (Enabled By Default)
* Existing Functionality (All Enabled By Default)
* `Fix Screen Rendering When Hiding HUD`
* `Sanitize Usernames`

View File

@ -19,6 +19,12 @@ install(
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
)
# Entity Shadow
install(
FILES "shadow.png"
DESTINATION "${MCPI_INSTALL_DIR}/data/images/misc"
)
# Icon
set(ICON_DIR "${MCPI_SHARE_DIR}/icons/hicolor/512x512/apps")
install(

BIN
images/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

View File

@ -109,4 +109,5 @@ TRUE Use Updated Title
TRUE Hide Block Outline When GUI Is Hidden
TRUE Fix Crash When Generating Certain Seeds
TRUE Click Buttons On Mouse Down
TRUE 3D Dropped Items
TRUE 3D Dropped Items
TRUE Render Entity Shadows

View File

@ -135,6 +135,7 @@ static std::vector<std::string> get_debug_info_right(const Minecraft *minecraft)
}
xyz_precision = debug_precision;
}
minecraft->command_server->pos_translator.to(x, y, z);
info.push_back("");
info.push_back("Target X: " + to_string_with_precision(x, xyz_precision));
info.push_back("Target Y: " + to_string_with_precision(y, xyz_precision));

View File

@ -90,69 +90,193 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, const Distance
}
// Fire Rendering
static void render_fire(EntityRenderer *self, Entity *entity, const float x, float y, const float z) {
// Check If Entity Is On Fire
if (!entity->isOnFire()) {
return;
}
// Here Be Decompiled Code
y -= entity->height_offset;
const int texture = Tile::fire->texture;
const int xt = (texture & 0xf) << 4;
const int yt = texture & 0xf0;
glPushMatrix();
glTranslatef(x, y, z);
const float s = entity->hitbox_width * 1.4f;
glScalef(s, s, s);
self->bindTexture("terrain.png");
Tesselator &t = Tesselator::instance;
float r = 0.5f;
float h = entity->hitbox_height / s;
float yo = entity->y - entity->height_offset - entity->hitbox.y1;
float player_rot_y = EntityRenderer::entityRenderDispatcher->player_rot_y;
if (EntityRenderer::entityRenderDispatcher->minecraft->options.third_person == 2) {
// Handle Front-Facing
player_rot_y -= 180.f;
}
glRotatef(-player_rot_y, 0, 1, 0);
glTranslatef(0, 0, -0.3f + float(int(h)) * 0.02f);
glColor4f(1, 1, 1, 1);
float zo = 0;
int ss = 0;
t.begin(7);
while (h > 0) {
constexpr float xo = 0.0f;
float u0;
float u1;
float v0;
float v1;
if (ss % 2 == 0) {
u0 = float(xt) / 256.0f;
u1 = (float(xt) + 15.99f) / 256.0f;
v0 = float(yt) / 256.0f;
v1 = (float(yt) + 15.99f) / 256.0f;
} else {
u0 = float(xt) / 256.0f;
u1 = (float(xt) + 15.99f) / 256.0f;
v0 = (float(yt) + 16) / 256.0f;
v1 = (float(yt) + 16 + 15.99f) / 256.0f;
}
if (ss / 2 % 2 == 0) {
std::swap(u1, u0);
}
t.vertexUV(r - xo, 0 - yo, zo, u1, v1);
t.vertexUV(-r - xo, 0 - yo, zo, u0, v1);
t.vertexUV(-r - xo, 1.4f - yo, zo, u0, v0);
t.vertexUV(r - xo, 1.4f - yo, zo, u1, v0);
h -= 0.45f;
yo -= 0.45f;
r *= 0.9f;
zo += 0.03f;
ss++;
}
t.draw();
glPopMatrix();
}
// Entity Shadows
static void render_shadow_tile(Tile *tile, const float x, const float y, const float z, int xt, int yt, int zt, const float pow, const float r, const float xo, const float yo, const float zo) {
Tesselator &t = Tesselator::instance;
if (!tile->isCubeShaped()) {
return;
}
float a = ((pow - (y - (float(yt) + yo)) / 2) * 0.5f) * EntityRenderer::entityRenderDispatcher->level->getBrightness(xt, yt, zt);
if (a < 0) {
return;
} else if (a > 1) {
a = 1;
}
t.color(255, 255, 255, int(a * 255));
float x0 = float(xt) + tile->x1 + xo;
float x1 = float(xt) + tile->x2 + xo;
float y0 = float(yt) + tile->y1 + yo + 1.0f / 64.0f;
float z0 = float(zt) + tile->z1 + zo;
float z1 = float(zt) + tile->z2 + zo;
float u0 = (x - x0) / 2 / r + 0.5f;
float u1 = (x - x1) / 2 / r + 0.5f;
float v0 = (z - z0) / 2 / r + 0.5f;
float v1 = (z - z1) / 2 / r + 0.5f;
t.vertexUV(x0, y0, z0, u0, v0);
t.vertexUV(x0, y0, z1, u0, v1);
t.vertexUV(x1, y0, z1, u1, v1);
t.vertexUV(x1, y0, z0, u1, v0);
}
static void render_shadow(const EntityRenderer *self, Entity *entity, float x, float y, float z, const float a) {
// Calculate Power
float pow = 0;
if (self->shadow_radius > 0) {
const float dist = EntityRenderer::entityRenderDispatcher->distanceToSqr(entity->x, entity->y, entity->z);
pow = (1 - dist / (16.0f * 16.0f)) * self->shadow_strength;
}
if (pow <= 0) {
return;
}
// Render
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Textures *textures = EntityRenderer::entityRenderDispatcher->textures;
textures->loadAndBindTexture("misc/shadow.png");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
Level *level = EntityRenderer::entityRenderDispatcher->level;
glDepthMask(false);
const float r = self->shadow_radius;
const float ex = entity->old_x + (entity->x - entity->old_x) * a;
float ey = entity->old_y + (entity->y - entity->old_y) * a + entity->getShadowHeightOffs() - entity->height_offset;
const float ez = entity->old_z + (entity->z - entity->old_z) * a;
const int x0 = Mth::floor(ex - r);
const int x1 = Mth::floor(ex + r);
const int y0 = Mth::floor(ey - r);
const int y1 = Mth::floor(ey);
const int z0 = Mth::floor(ez - r);
const int z1 = Mth::floor(ez + r);
const float xo = x - ex;
const float yo = y - ey;
const float zo = z - ez;
Tesselator &tt = Tesselator::instance;
tt.begin(7);
for (int xt = x0; xt <= x1; xt++) {
for (int yt = y0; yt <= y1; yt++) {
for (int zt = z0; zt <= z1; zt++) {
const int t = level->getTile(xt, yt - 1, zt);
if (t > 0 && level->getRawBrightness(xt, yt, zt) > 3) {
render_shadow_tile(
Tile::tiles[t],
x, y + entity->getShadowHeightOffs() - entity->height_offset, z,
xt, yt, zt,
pow, r,
xo, yo + entity->getShadowHeightOffs() - entity->height_offset, zo
);
}
}
}
}
tt.draw();
glColor4f(1, 1, 1, 1);
glDisable(GL_BLEND);
glDepthMask(true);
}
static void EntityRenderDispatcher_assign_injection(EntityRenderDispatcher_assign_t original, EntityRenderDispatcher *self, const uchar entity_id, EntityRenderer *renderer) {
// Modify Shadow Size
float new_radius;
switch (entity_id) {
case 16:
case 3: {
new_radius = 0.5f;
break;
}
case 9:
case 7:
case 8: {
new_radius = 0.7f;
break;
}
case 6: {
new_radius = 0.3f;
break;
}
default: {
new_radius = renderer->shadow_radius;
}
}
renderer->shadow_radius = new_radius;
// Call Original Method
original(self, entity_id, renderer);
}
// Modify Entity Rendering
static bool should_render_fire;
static bool should_render_shadows;
static void EntityRenderDispatcher_render_EntityRenderer_render_injection(EntityRenderer *self, Entity *entity, float x, float y, float z, float rot, float unknown) {
// Call Original Method
self->render(entity, x, y, z, rot, unknown);
// Render Shadow
if (should_render_shadows) {
render_shadow(self, entity, x, y, z, unknown);
}
// Render Fire
if (entity->isOnFire()) {
// Here Be Decompiled Code
y -= entity->height_offset;
const int texture = Tile::fire->texture;
const int xt = (texture & 0xf) << 4;
const int yt = texture & 0xf0;
glPushMatrix();
glTranslatef(x, y, z);
const float s = entity->hitbox_width * 1.4f;
glScalef(s, s, s);
self->bindTexture("terrain.png");
Tesselator &t = Tesselator::instance;
float r = 0.5f;
float h = entity->hitbox_height / s;
float yo = entity->y - entity->height_offset - entity->hitbox.y1;
float player_rot_y = EntityRenderer::entityRenderDispatcher->player_rot_y;
if (EntityRenderer::entityRenderDispatcher->minecraft->options.third_person == 2) {
// Handle Front-Facing
player_rot_y -= 180.f;
}
glRotatef(-player_rot_y, 0, 1, 0);
glTranslatef(0, 0, -0.3f + float(int(h)) * 0.02f);
glColor4f(1, 1, 1, 1);
float zo = 0;
int ss = 0;
t.begin(7);
while (h > 0) {
constexpr float xo = 0.0f;
float u0;
float u1;
float v0;
float v1;
if (ss % 2 == 0) {
u0 = float(xt) / 256.0f;
u1 = (float(xt) + 15.99f) / 256.0f;
v0 = float(yt) / 256.0f;
v1 = (float(yt) + 15.99f) / 256.0f;
} else {
u0 = float(xt) / 256.0f;
u1 = (float(xt) + 15.99f) / 256.0f;
v0 = (float(yt) + 16) / 256.0f;
v1 = (float(yt) + 16 + 15.99f) / 256.0f;
}
if (ss / 2 % 2 == 0) {
std::swap(u1, u0);
}
t.vertexUV(r - xo, 0 - yo, zo, u1, v1);
t.vertexUV(-r - xo, 0 - yo, zo, u0, v1);
t.vertexUV(-r - xo, 1.4f - yo, zo, u0, v0);
t.vertexUV(r - xo, 1.4f - yo, zo, u1, v0);
h -= 0.45f;
yo -= 0.45f;
r *= 0.9f;
zo += 0.03f;
ss++;
}
t.draw();
glPopMatrix();
if (should_render_fire) {
render_fire(self, entity, x, y, z);
}
}
@ -377,9 +501,12 @@ void _init_misc_graphics() {
overwrite_calls_manual((void *) 0x51fac, (void *) sort_chunks);
}
// Render Fire In Third-Person
if (feature_has("Render Fire In Third-Person", server_disabled)) {
overwrite_call((void *) 0x606c0, (void *) EntityRenderDispatcher_render_EntityRenderer_render_injection);
// Modify Entity Rendering
overwrite_call((void *) 0x606c0, (void *) EntityRenderDispatcher_render_EntityRenderer_render_injection);
should_render_fire = feature_has("Render Fire In Third-Person", server_disabled);
should_render_shadows = feature_has("Render Entity Shadows", server_disabled);
if (should_render_shadows) {
overwrite_calls(EntityRenderDispatcher_assign, EntityRenderDispatcher_assign_injection);
}
// Slightly Nicer Water Rendering

View File

@ -22,15 +22,16 @@ virtual-method int getAuxData() = 0xf4;
virtual-method bool isOnFire() = 0x90;
virtual-method void baseTick() = 0x38;
virtual-method bool isSneaking() = 0x88;
virtual-method float getShadowHeightOffs() = 0x60;
property float x = 0x4;
property float y = 0x8;
property float z = 0xc;
property int id = 0x1c;
property Level *level = 0x24;
property float old_x = 0x28;
property float old_y = 0x2c;
property float old_z = 0x30;
property float old_x = 0x7c;
property float old_y = 0x80;
property float old_z = 0x84;
property float vel_x = 0x34;
property float vel_y = 0x38;
property float vel_z = 0x3c;

View File

@ -2,8 +2,11 @@ constructor () = 0x6096c;
method void assign(uchar entity_id, EntityRenderer *renderer) = 0x6094c;
method void render(Entity *entity, float x, float y, float z, float rot, float unknown) = 0x60674;
method float distanceToSqr(float x, float y, float z) = 0x60790;
static-method EntityRenderDispatcher *getInstance() = 0x60e90;
property ItemInHandRenderer *item_renderer = 0x0;
property float player_rot_y = 0x14;
property Minecraft *minecraft = 0xc;
property Minecraft *minecraft = 0xc;
property Level *level = 0x8;
property Textures *textures = 0x4;

View File

@ -5,5 +5,8 @@ virtual-method void render(Entity *entity, float param_2, float param_3, float p
// Can be called without an EntityRenderer, just do EntityRenderer_bindTexture->get(false)(NULL, &file);
method void bindTexture(const std::string &file) = 0x62540;
property float shadow_radius = 0x4;
property float shadow_strength = 0x8;
// Globals
static-property EntityRenderDispatcher *entityRenderDispatcher = 0x137bc0;

View File

@ -1,6 +1,6 @@
virtual-method int getTile(int x, int y, int z) = 0x8;
virtual-method int isEmptyTile(int x, int y, int z) = 0xc;
virtual-method int getBrightness(int x, int y, int z) = 0x10;
virtual-method float getBrightness(int x, int y, int z) = 0x10;
virtual-method int getData(int x, int y, int z) = 0x14;
virtual-method Material *getMaterial(int x, int y, int z) = 0x18;
virtual-method bool isSolidRenderTile(int x, int y, int z) = 0x1c;