mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-17 03:25:14 -04:00
Optimise ShadowComponent rendering
This commit is contained in:
parent
fdd620aba6
commit
36f2dec36e
@ -25,42 +25,37 @@ namespace ClassicalSharp.Entities {
|
||||
if (Position.Y < 0) return;
|
||||
|
||||
float posX = Position.X, posZ = Position.Z;
|
||||
int posY = Math.Min((int)Position.Y, game.World.Height - 1);
|
||||
int posY = Math.Min((int)Position.Y, game.World.MaxY);
|
||||
int index = 0, vb = 0;
|
||||
radius = 7f * Math.Min(entity.ModelScale.Y, 1) * entity.Model.ShadowScale;
|
||||
|
||||
VertexP3fT2fC4b[] verts = null;
|
||||
int posCount = 0, dataCount = 0;
|
||||
Vector3I* coords = stackalloc Vector3I[4];
|
||||
int dataCount = 0;
|
||||
ShadowData* data = stackalloc ShadowData[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
coords[i] = new Vector3I(int.MinValue);
|
||||
}
|
||||
|
||||
if (game.Entities.ShadowMode == EntityShadow.SnapToBlock) {
|
||||
vb = game.Graphics.texVb; verts = game.Graphics.texVerts;
|
||||
if (!GetBlocks(coords, ref posCount, posX, posZ, posY, data, ref dataCount)) return;
|
||||
int x1 = Utils.Floor(posX), z1 = Utils.Floor(posZ);
|
||||
|
||||
float x1 = Utils.Floor(posX), z1 = Utils.Floor(posZ);
|
||||
if (!GetBlocks(x1, posY, z1, data, ref dataCount)) return;
|
||||
DrawSquareShadow(verts, ref index, data[0].Y, x1, z1);
|
||||
} else {
|
||||
vb = game.ModelCache.vb; verts = game.ModelCache.vertices;
|
||||
int x1 = Utils.Floor(posX - radius/16f), z1 = Utils.Floor(posZ - radius/16f);
|
||||
int x2 = Utils.Floor(posX + radius/16f), z2 = Utils.Floor(posZ + radius/16f);
|
||||
|
||||
float x = posX - radius/16f, z = posZ - radius/16f;
|
||||
if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
|
||||
DrawCircle(verts, ref index, data, dataCount, x, z);
|
||||
|
||||
x = Math.Max(posX - radius/16f, Utils.Floor(posX + radius/16f));
|
||||
if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
|
||||
DrawCircle(verts, ref index, data, dataCount, x, z);
|
||||
|
||||
z = Math.Max(posZ - radius/16f, Utils.Floor(posZ + radius/16f));
|
||||
if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
|
||||
DrawCircle(verts, ref index, data, dataCount, x, z);
|
||||
|
||||
x = posX - radius/16f;
|
||||
if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0)
|
||||
DrawCircle(verts, ref index, data, dataCount, x, z);
|
||||
if (GetBlocks(x1, posY, z1, data, ref dataCount) && data[0].A > 0) {
|
||||
DrawCircle(verts, ref index, data, dataCount, x1, z1);
|
||||
}
|
||||
if (x1 != x2 && GetBlocks(x2, posY, z1, data, ref dataCount) && data[0].A > 0) {
|
||||
DrawCircle(verts, ref index, data, dataCount, x2, z1);
|
||||
}
|
||||
if (z1 != z2 && GetBlocks(x1, posY, z2, data, ref dataCount) && data[0].A > 0) {
|
||||
DrawCircle(verts, ref index, data, dataCount, x1, z2);
|
||||
}
|
||||
if (x1 != x2 && z1 != z2 && GetBlocks(x2, posY, z2, data, ref dataCount) && data[0].A > 0) {
|
||||
DrawCircle(verts, ref index, data, dataCount, x2, z2);
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) return;
|
||||
@ -86,7 +81,6 @@ namespace ClassicalSharp.Entities {
|
||||
|
||||
static void DrawCircle(VertexP3fT2fC4b[] verts, ref int index,
|
||||
ShadowData* data, int dataCount, float x, float z) {
|
||||
x = Utils.Floor(x); z = Utils.Floor(z);
|
||||
Vector3 min = BlockInfo.MinBB[data[0].Block], max = BlockInfo.MaxBB[data[0].Block];
|
||||
|
||||
DrawCoords(verts, ref index, data[0], x + min.X, z + min.Z, x + max.X, z + max.Z);
|
||||
@ -112,44 +106,46 @@ namespace ClassicalSharp.Entities {
|
||||
float v2 = (z2 - cen.Z) * 16/(radius * 2) + 0.5f;
|
||||
if (u2 <= 0 || v2 <= 0 || u1 >= 1 || v1 >= 1) return;
|
||||
|
||||
x1 = Math.Max(x1, cen.X - radius/16f); u1 = Math.Max(u1, 0);
|
||||
z1 = Math.Max(z1, cen.Z - radius/16f); v1 = Math.Max(v1, 0);
|
||||
x2 = Math.Min(x2, cen.X + radius/16f); u2 = Math.Min(u2, 1);
|
||||
z2 = Math.Min(z2, cen.Z + radius/16f); v2 = Math.Min(v2, 1);
|
||||
x1 = Math.Max(x1, cen.X - radius/16f); u1 = u1 >= 0 ? u1 : 0;
|
||||
z1 = Math.Max(z1, cen.Z - radius/16f); v1 = v1 >= 0 ? v1 : 0;
|
||||
x2 = Math.Min(x2, cen.X + radius/16f); u2 = u2 <= 1 ? u2 : 1;
|
||||
z2 = Math.Min(z2, cen.Z + radius/16f); v2 = v2 <= 1 ? v2 : 1;
|
||||
|
||||
int col = new FastColour(c, c, c, data.A).Pack();
|
||||
verts[index++] = new VertexP3fT2fC4b(x1, data.Y, z1, u1, v1, col);
|
||||
verts[index++] = new VertexP3fT2fC4b(x2, data.Y, z1, u2, v1, col);
|
||||
verts[index++] = new VertexP3fT2fC4b(x2, data.Y, z2, u2, v2, col);
|
||||
verts[index++] = new VertexP3fT2fC4b(x1, data.Y, z2, u1, v2, col);
|
||||
VertexP3fT2fC4b v; v.Y = data.Y; v.Colour = col;
|
||||
v.X = x1; v.Z = z1; v.U = u1; v.V = v1; verts[index++] = v;
|
||||
v.X = x2; v.U = u2; verts[index++] = v;
|
||||
v.Z = z2; v.V = v2; verts[index++] = v;
|
||||
v.X = x1; v.U = u1; verts[index++] = v;
|
||||
}
|
||||
|
||||
static bool GetBlocks(Vector3I* coords, ref int posCount, float x, float z,
|
||||
int posY, ShadowData* data, ref int index) {
|
||||
int blockX = Utils.Floor(x), blockZ = Utils.Floor(z);
|
||||
Vector3I p = new Vector3I(blockX, 0, blockZ);
|
||||
Vector3 Position = entity.Position;
|
||||
static bool GetBlocks(int x, int y, int z, ShadowData* data, ref int index) {
|
||||
float posY = entity.Position.Y;
|
||||
index = 0;
|
||||
bool outside = x < 0 || z < 0 || x >= game.World.Width || z >= game.World.Length;
|
||||
|
||||
// Check we have not processed this particular block already.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (coords[i] == p) return false;
|
||||
data[i] = new ShadowData();
|
||||
}
|
||||
coords[posCount] = p; posCount++;
|
||||
|
||||
while (posY >= 0 && index < 4) {
|
||||
BlockID block = GetShadowBlock(blockX, posY, blockZ);
|
||||
posY--;
|
||||
while (y >= 0 && index < 4) {
|
||||
BlockID block;
|
||||
if (!outside) {
|
||||
block = game.World.GetBlock(x, y, z);
|
||||
} else if (y == game.World.Env.EdgeHeight - 1) {
|
||||
block = BlockInfo.Draw[game.World.Env.EdgeBlock] == DrawType.Gas ? Block.Air : Block.Bedrock;
|
||||
} else if (y == game.World.Env.SidesHeight - 1) {
|
||||
block = BlockInfo.Draw[game.World.Env.SidesBlock] == DrawType.Gas ? Block.Air : Block.Bedrock;
|
||||
} else {
|
||||
block = Block.Air;
|
||||
}
|
||||
y--;
|
||||
|
||||
byte draw = BlockInfo.Draw[block];
|
||||
if (draw == DrawType.Gas || draw == DrawType.Sprite || BlockInfo.IsLiquid[block]) continue;
|
||||
float blockY = posY + 1 + BlockInfo.MaxBB[block].Y;
|
||||
if (blockY >= Position.Y + 0.01f) continue;
|
||||
float blockY = (y + 1) + BlockInfo.MaxBB[block].Y;
|
||||
if (blockY >= posY + 0.01f) continue;
|
||||
|
||||
data[index].Block = block; data[index].Y = blockY;
|
||||
CalcAlpha(Position.Y, ref data[index]);
|
||||
CalcAlpha(posY, ref data[index]);
|
||||
index++;
|
||||
|
||||
// Check if the casted shadow will continue on further down.
|
||||
if (BlockInfo.MinBB[block].X == 0 && BlockInfo.MaxBB[block].X == 1 &&
|
||||
BlockInfo.MinBB[block].Z == 0 && BlockInfo.MaxBB[block].Z == 1) return true;
|
||||
@ -157,23 +153,12 @@ namespace ClassicalSharp.Entities {
|
||||
|
||||
if (index < 4) {
|
||||
data[index].Block = game.World.Env.EdgeBlock; data[index].Y = 0;
|
||||
CalcAlpha(Position.Y, ref data[index]);
|
||||
CalcAlpha(posY, ref data[index]);
|
||||
index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static BlockID GetShadowBlock(int x, int y, int z) {
|
||||
if (x < 0 || z < 0 || x >= game.World.Width || z >= game.World.Length) {
|
||||
if (y == game.World.Env.EdgeHeight - 1)
|
||||
return BlockInfo.Draw[game.World.Env.EdgeBlock] == DrawType.Gas ? Block.Air : Block.Bedrock;
|
||||
if (y == game.World.Env.SidesHeight - 1)
|
||||
return BlockInfo.Draw[game.World.Env.SidesBlock] == DrawType.Gas ? Block.Air : Block.Bedrock;
|
||||
return Block.Air;
|
||||
}
|
||||
return game.World.GetBlock(x, y, z);
|
||||
}
|
||||
|
||||
struct ShadowData {
|
||||
public BlockID Block;
|
||||
public float Y;
|
||||
|
@ -199,7 +199,7 @@ namespace ClassicalSharp {
|
||||
}
|
||||
|
||||
void Stretch(int x1, int y1, int z1) {
|
||||
int xMax = Math.Min(width, x1 + chunkSize);
|
||||
int xMax = Math.Min(width, x1 + chunkSize);
|
||||
int yMax = Math.Min(height, y1 + chunkSize);
|
||||
int zMax = Math.Min(length, z1 + chunkSize);
|
||||
#if OCCLUSION
|
||||
|
@ -460,10 +460,10 @@ void ShadowComponent_DrawCoords(VertexP3fT2fC4b** vertices, Entity* entity, Shad
|
||||
if (u2 <= 0.0f || v2 <= 0.0f || u1 >= 1.0f || v1 >= 1.0f) return;
|
||||
|
||||
radius /= 16.0f;
|
||||
x1 = max(x1, cen.X - radius); u1 = max(u1, 0.0f);
|
||||
z1 = max(z1, cen.Z - radius); v1 = max(v1, 0.0f);
|
||||
x2 = min(x2, cen.X + radius); u2 = min(u2, 1.0f);
|
||||
z2 = min(z2, cen.Z + radius); v2 = min(v2, 1.0f);
|
||||
x1 = max(x1, cen.X - radius); u1 = u1 >= 0.0f ? u1 : 0.0f;
|
||||
z1 = max(z1, cen.Z - radius); v1 = v1 >= 0.0f ? v1 : 0.0f;
|
||||
x2 = min(x2, cen.X + radius); u2 = u2 <= 1.0f ? u2 : 1.0f;
|
||||
z2 = min(z2, cen.Z + radius); v2 = v2 <= 1.0f ? v2 : 1.0f;
|
||||
|
||||
PackedCol col = PACKEDCOL_CONST(255, 255, 255, data->A);
|
||||
VertexP3fT2fC4b* ptr = *vertices;
|
||||
@ -509,17 +509,6 @@ void ShadowComponent_DrawCircle(VertexP3fT2fC4b** vertices, Entity* entity, Shad
|
||||
}
|
||||
}
|
||||
|
||||
BlockID ShadowComponent_GetBlock(Int32 x, Int32 y, Int32 z) {
|
||||
if (x < 0 || z < 0 || x >= World_Width || z >= World_Length) {
|
||||
if (y == WorldEnv_EdgeHeight - 1)
|
||||
return Block_Draw[WorldEnv_EdgeBlock] == DRAW_GAS ? BLOCK_AIR : BLOCK_BEDROCK;
|
||||
if (y == WorldEnv_SidesHeight - 1)
|
||||
return Block_Draw[WorldEnv_SidesBlock] == DRAW_GAS ? BLOCK_AIR : BLOCK_BEDROCK;
|
||||
return BLOCK_AIR;
|
||||
}
|
||||
return World_GetBlock(x, y, z);
|
||||
}
|
||||
|
||||
void ShadowComponent_CalcAlpha(Real32 playerY, ShadowData* data) {
|
||||
Real32 height = playerY - data->Y;
|
||||
if (height <= 6.0f) {
|
||||
@ -534,35 +523,36 @@ void ShadowComponent_CalcAlpha(Real32 playerY, ShadowData* data) {
|
||||
else data->Y += 1.0f / 4.0f;
|
||||
}
|
||||
|
||||
bool ShadowComponent_GetBlocks(Entity* entity, Vector3I* coords, Real32 x, Real32 z, Int32 posY, ShadowData* data) {
|
||||
Int32 blockX = Math_Floor(x), blockZ = Math_Floor(z);
|
||||
Vector3I p = { blockX, 0, blockZ };
|
||||
|
||||
/* Check we have not processed this particular block already */
|
||||
UInt32 i, posCount = 0;
|
||||
bool ShadowComponent_GetBlocks(Entity* entity, Int32 x, Int32 y, Int32 z, ShadowData* data) {
|
||||
Int32 count;
|
||||
ShadowData zeroData = { 0.0f, 0, 0 };
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (Vector3I_Equals(&coords[i], &p)) return false;
|
||||
if (coords[i].X != Int32_MinValue) posCount++;
|
||||
data[i] = zeroData;
|
||||
}
|
||||
coords[posCount] = p;
|
||||
for (count = 0; count < 4; count++) { data[count] = zeroData; }
|
||||
count = 0;
|
||||
|
||||
UInt32 count = 0;
|
||||
ShadowData* cur = data;
|
||||
Vector3 Position = entity->Position;
|
||||
Real32 posY = entity->Position.Y;
|
||||
bool outside = x < 0 || z < 0 || x >= World_Width || z >= World_Length;
|
||||
|
||||
while (posY >= 0 && count < 4) {
|
||||
BlockID block = ShadowComponent_GetBlock(blockX, posY, blockZ);
|
||||
posY--;
|
||||
while (y >= 0 && count < 4) {
|
||||
BlockID block;
|
||||
if (!outside) {
|
||||
block = World_GetBlock(x, y, z);
|
||||
} else if (y == WorldEnv_EdgeHeight - 1) {
|
||||
block = Block_Draw[WorldEnv_EdgeBlock] == DRAW_GAS ? BLOCK_AIR : BLOCK_BEDROCK;
|
||||
} else if (y == WorldEnv_SidesHeight - 1) {
|
||||
block = Block_Draw[WorldEnv_SidesBlock] == DRAW_GAS ? BLOCK_AIR : BLOCK_BEDROCK;
|
||||
} else {
|
||||
block = BLOCK_AIR;
|
||||
}
|
||||
y--;
|
||||
|
||||
UInt8 draw = Block_Draw[block];
|
||||
if (draw == DRAW_GAS || draw == DRAW_SPRITE || Block_IsLiquid[block]) continue;
|
||||
Real32 blockY = posY + 1.0f + Block_MaxBB[block].Y;
|
||||
if (blockY >= Position.Y + 0.01f) continue;
|
||||
Real32 blockY = (y + 1.0f) + Block_MaxBB[block].Y;
|
||||
if (blockY >= posY + 0.01f) continue;
|
||||
|
||||
cur->Block = block; cur->Y = blockY;
|
||||
ShadowComponent_CalcAlpha(Position.Y, cur);
|
||||
ShadowComponent_CalcAlpha(posY, cur);
|
||||
count++; cur++;
|
||||
|
||||
/* Check if the casted shadow will continue on further down. */
|
||||
@ -572,7 +562,7 @@ bool ShadowComponent_GetBlocks(Entity* entity, Vector3I* coords, Real32 x, Real3
|
||||
|
||||
if (count < 4) {
|
||||
cur->Block = WorldEnv_EdgeBlock; cur->Y = 0.0f;
|
||||
ShadowComponent_CalcAlpha(Position.Y, cur);
|
||||
ShadowComponent_CalcAlpha(posY, cur);
|
||||
count++; cur++;
|
||||
}
|
||||
return true;
|
||||
@ -610,42 +600,33 @@ void ShadowComponent_Draw(Entity* entity) {
|
||||
ShadowComponent_radius = 7.0f * min(entity->ModelScale.Y, 1.0f) * entity->Model->ShadowScale;
|
||||
|
||||
VertexP3fT2fC4b vertices[128];
|
||||
Vector3I coords[4];
|
||||
ShadowData data[4];
|
||||
for (Int32 i = 0; i < 4; i++) {
|
||||
coords[i] = Vector3I_Create1(Int32_MinValue);
|
||||
}
|
||||
|
||||
/* TODO: Should shadow component use its own VB? */
|
||||
VertexP3fT2fC4b* ptr = vertices;
|
||||
if (Entities_ShadowMode == SHADOW_MODE_SNAP_TO_BLOCK) {
|
||||
vb = GfxCommon_texVb;
|
||||
if (!ShadowComponent_GetBlocks(entity, coords, posX, posZ, posY, data)) return;
|
||||
Int32 x1 = Math_Floor(posX), z1 = Math_Floor(posZ);
|
||||
if (!ShadowComponent_GetBlocks(entity, x1, posY, z1, data)) return;
|
||||
|
||||
Real32 x1 = (Real32)Math_Floor(posX), z1 = (Real32)Math_Floor(posZ);
|
||||
ShadowComponent_DrawSquareShadow(&ptr, data[0].Y, x1, z1);
|
||||
} else {
|
||||
vb = ModelCache_Vb;
|
||||
Real32 radius = ShadowComponent_radius / 16.0f;
|
||||
Int32 x1 = Math_Floor(posX - radius), z1 = Math_Floor(posZ - radius);
|
||||
Int32 x2 = Math_Floor(posX + radius), z2 = Math_Floor(posZ + radius);
|
||||
|
||||
Real32 x = posX - radius, z = posZ - radius;
|
||||
if (ShadowComponent_GetBlocks(entity, coords, x, z, posY, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, x, z);
|
||||
if (ShadowComponent_GetBlocks(entity, x1, posY, z1, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, (Real32)x1, (Real32)z1);
|
||||
}
|
||||
|
||||
x = max(posX - radius, Math_Floor(posX + radius));
|
||||
if (ShadowComponent_GetBlocks(entity, coords, x, z, posY, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, x, z);
|
||||
if (x1 != x2 && ShadowComponent_GetBlocks(entity, x2, posY, z1, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, (Real32)x2, (Real32)z1);
|
||||
}
|
||||
|
||||
z = max(posZ - radius, Math_Floor(posZ + radius));
|
||||
if (ShadowComponent_GetBlocks(entity, coords, x, z, posY, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, x, z);
|
||||
if (z1 != z2 && ShadowComponent_GetBlocks(entity, x1, posY, z2, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, (Real32)x1, (Real32)z2);
|
||||
}
|
||||
|
||||
x = posX - radius;
|
||||
if (ShadowComponent_GetBlocks(entity, coords, x, z, posY, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, x, z);
|
||||
if (x1 != x2 && z1 != z2 && ShadowComponent_GetBlocks(entity, x2, posY, z2, data) && data[0].A > 0) {
|
||||
ShadowComponent_DrawCircle(&ptr, entity, data, (Real32)x2, (Real32)z2);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user