Port entity shadow component to C.

This commit is contained in:
UnknownShadow200 2017-12-05 17:35:43 +11:00
parent 1fcdeabb98
commit fe8580aea8
10 changed files with 259 additions and 45 deletions

View File

@ -26,8 +26,9 @@ namespace ClassicalSharp.Entities {
ShadowComponent.game = game;
ShadowComponent.entity = entity;
EntityShadow mode = game.Entities.ShadowMode;
Vector3 Position = entity.Position;
if (Position.Y < 0) return;
float posX = Position.X, posZ = Position.Z;
int posY = Math.Min((int)Position.Y, game.World.Height - 1);
int index = 0, vb = 0;
@ -39,15 +40,14 @@ namespace ClassicalSharp.Entities {
ShadowData* data = stackalloc ShadowData[4];
for (int i = 0; i < 4; i++) {
coords[i] = new Vector3I(int.MinValue);
data[i] = new ShadowData();
}
if (mode == EntityShadow.SnapToBlock) {
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;
float x1 = Utils.Floor(posX), z1 = Utils.Floor(posZ);
DraqSquareShadow(verts, ref index, data[0].Y, 220, x1, z1);
DrawSquareShadow(verts, ref index, data[0].Y, x1, z1);
} else {
vb = game.ModelCache.vb; verts = game.ModelCache.vertices;
@ -79,9 +79,9 @@ namespace ClassicalSharp.Entities {
}
const byte c = 255; // avoids 'ambiguous match' compile errors.
static void DraqSquareShadow(VertexP3fT2fC4b[] verts, ref int index,
float y, byte alpha, float x, float z) {
int col = new FastColour(c, c, c, alpha).Pack();
static void DrawSquareShadow(VertexP3fT2fC4b[] verts, ref int index,
float y, float x, float z) {
int col = new FastColour(c, c, c, (byte)220).Pack();
TextureRec rec = new TextureRec(63/128f, 63/128f, 1/128f, 1/128f);
verts[index++] = new VertexP3fT2fC4b(x, y, z, rec.U1, rec.V1, col);
verts[index++] = new VertexP3fT2fC4b(x + 1, y, z, rec.U2, rec.V1, col);
@ -137,7 +137,6 @@ namespace ClassicalSharp.Entities {
index = 0;
// Check we have not processed this particular block already.
if (Position.Y < 0) return false;
for (int i = 0; i < 4; i++) {
if (coords[i] == p) return false;
data[i] = new ShadowData();
@ -187,16 +186,16 @@ namespace ClassicalSharp.Entities {
}
static void CalcAlpha(float playerY, ref ShadowData data) {
float y = data.Y;
if ((playerY - y) <= 6) {
data.A = (byte)(160 - 160 * (playerY - y) / 6);
float height = playerY - data.Y;
if (height <= 6) {
data.A = (byte)(160 - 160 * height / 6);
data.Y += 1/64f; return;
}
data.A = 0;
if ((playerY - y) <= 16) data.Y += 1/64f;
else if ((playerY - y) <= 32) data.Y += 1/16f;
else if ((playerY - y) <= 96) data.Y += 1/8f;
if (height <= 16) data.Y += 1/64f;
else if (height <= 32) data.Y += 1/16f;
else if (height <= 96) data.Y += 1/8f;
else data.Y += 1/4f;
}

View File

@ -90,7 +90,8 @@ void Chat_OpenLog(DateTime* now) {
}
Chat_LogStream.Data = NULL;
ErrorHandler_LogError("creating chat log", "Failed to open chat log file after 20 tries, giving up");
String failedMsg = String_FromConst("Failed to open chat log file after 20 tries, giving up");
ErrorHandler_Log(&failedMsg);
}
void Chat_AppendLog(STRING_PURE String* text) {

View File

@ -314,8 +314,8 @@ void Entities_Free(void) {
Event_UnregisterVoid(&GfxEvents_ContextRecreated, Entities_ContextRecreated);
Event_UnregisterVoid(&ChatEvents_FontChanged, Entities_ChatFontChanged);
if (ShadowComponent.shadowTex > 0) {
game.Graphics.DeleteTexture(ref ShadowComponent.shadowTex);
if (ShadowComponent_ShadowTex != NULL) {
Gfx_DeleteTexture(&ShadowComponent_ShadowTex);
}
}
@ -347,7 +347,7 @@ EntityID Entities_GetCloset(Entity* src) {
void Entities_DrawShadows(void) {
if (Entities_ShadowMode == SHADOW_MODE_NONE) return;
ShadowComponent.boundShadowTex = false;
ShadowComponent_BoundShadowTex = false;
Gfx_SetAlphaArgBlend(true);
Gfx_SetDepthWrite(false);
@ -355,13 +355,13 @@ void Entities_DrawShadows(void) {
Gfx_SetTexturing(true);
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
ShadowComponent.Draw(Entities_List[ENTITIES_SELF_ID]);
ShadowComponent_Draw(Entities_List[ENTITIES_SELF_ID]);
if (Entities_ShadowMode == SHADOW_MODE_CIRCLE_ALL) {
UInt32 i;
for (i = 0; i < ENTITIES_MAX_COUNT; i++) {
if (Entities_List[i] == NULL) continue;
Player p = List[i] as Player;
if (p != null) ShadowComponent.Draw(p);
if (p != null) ShadowComponent_Draw(p);
}
}

View File

@ -8,6 +8,10 @@
#include "Platform.h"
#include "Camera.h"
#include "Funcs.h"
#include "VertexStructs.h"
#include "GraphicsAPI.h"
#include "GraphicsCommon.h"
#include "ModelCache.h"
#define ANIM_MAX_ANGLE (110 * MATH_DEG2RAD)
#define ANIM_ARM_MAX (60.0f * MATH_DEG2RAD)
@ -436,3 +440,223 @@ void LocalInterpComp_AdvanceState(InterpComp* interp) {
entity->Position = interp->Next.Pos;
InterpComp_AdvanceRotY(interp);
}
Real32 ShadowComponent_radius = 7.0f;
typedef struct ShadowData_ { Real32 Y; BlockID Block; UInt8 A; } ShadowData;
bool lequal(Real32 a, Real32 b) { return a < b || Math_AbsF(a - b) < 0.001f; }
void ShadowComponent_DrawCoords(VertexP3fT2fC4b** vertices, Entity* entity, ShadowData* data, Real32 x1, Real32 z1, Real32 x2, Real32 z2) {
Vector3 cen = entity->Position;
if (lequal(x2, x1) || lequal(z2, z1)) return;
Real32 radius = ShadowComponent_radius;
Real32 u1 = (x1 - cen.X) * 16.0f / (radius * 2) + 0.5f;
Real32 v1 = (z1 - cen.Z) * 16.0f / (radius * 2) + 0.5f;
Real32 u2 = (x2 - cen.X) * 16.0f / (radius * 2) + 0.5f;
Real32 v2 = (z2 - cen.Z) * 16.0f / (radius * 2) + 0.5f;
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);
PackedCol col = PACKEDCOL_CONST(255, 255, 255, data->A);
VertexP3fT2fC4b* ptr = *vertices;
VertexP3fT2fC4b v; v.Y = data->Y; v.Col = col;
v.X = x1; v.Z = z1; v.U = u1; v.V = v1; *ptr = v; ptr++;
v.X = x2; v.U = u2; *ptr = v; ptr++;
v.Z = z2; v.V = v2; *ptr = v; ptr++;
v.X = x1; v.U = u1; *ptr = v; ptr++;
*vertices = ptr;
}
void ShadowComponent_DrawSquareShadow(VertexP3fT2fC4b** vertices, Real32 y, Real32 x, Real32 z) {
PackedCol col = PACKEDCOL_CONST(255, 255, 255, 220);
TextureRec rec = TextureRec_FromRegion(63.0f / 128.0f, 63.0f / 128.0f, 1.0f / 128.0f, 1.0f / 128.0f);
VertexP3fT2fC4b* ptr = *vertices;
VertexP3fT2fC4b v; v.Y = y; v.Col = col;
v.X = x; v.Z = z; v.U = rec.U1; v.V = rec.V1; *ptr = v; ptr++;
v.X = x + 1.0f; v.U = rec.U2; *ptr = v; ptr++;
v.Z = z + 1.0f; v.V = rec.V2; *ptr = v; ptr++;
v.X = x; v.U = rec.U1; *ptr = v; ptr++;
*vertices = ptr;
}
void ShadowComponent_DrawCircle(VertexP3fT2fC4b** vertices, Entity* entity, ShadowData* data, Real32 x, Real32 z) {
x = (Real32)Math_Floor(x); z = (Real32)Math_Floor(z);
Vector3 min = Block_MinBB[data[0].Block], max = Block_MaxBB[data[0].Block];
ShadowComponent_DrawCoords(vertices, entity, &data[0], x + min.X, z + min.Z, x + max.X, z + max.Z);
UInt32 i;
for (i = 1; i < 4; i++) {
if (data[i].Block == BLOCK_AIR) return;
Vector3 nMin = Block_MinBB[data[i].Block], nMax = Block_MaxBB[data[i].Block];
ShadowComponent_DrawCoords(vertices, entity, &data[i], x + min.X, z + nMin.Z, x + max.X, z + min.Z);
ShadowComponent_DrawCoords(vertices, entity, &data[i], x + min.X, z + max.Z, x + max.X, z + nMax.Z);
ShadowComponent_DrawCoords(vertices, entity, &data[i], x + nMin.X, z + nMin.Z, x + min.X, z + nMax.Z);
ShadowComponent_DrawCoords(vertices, entity, &data[i], x + max.X, z + nMin.Z, x + nMax.X, z + nMax.Z);
min = nMin; max = nMax;
}
}
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) {
data->A = (UInt8)(160 - 160 * height / 6.0f);
data->Y += 1.0f / 64.0f; return;
}
data->A = 0;
if (height <= 16.0f) data->Y += 1.0f / 64.0f;
else if (height <= 32.0f) data->Y += 1.0f / 16.0f;
else if (height <= 96.0f) data->Y += 1.0f / 8.0f;
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 = Vector3I_Create3(blockX, 0, blockZ);
/* Check we have not processed this particular block already */
UInt32 i, posCount = 0;
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;
UInt32 count = 0;
ShadowData* cur = data;
Vector3 Position = entity->Position;
while (posY >= 0 && count < 4) {
BlockID block = ShadowComponent_GetBlock(blockX, posY, blockZ);
posY--;
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;
cur->Block = block; cur->Y = blockY;
ShadowComponent_CalcAlpha(Position.Y, cur);
count++; cur++;
/* Check if the casted shadow will continue on further down. */
if (Block_MinBB[block].X == 0.0f && Block_MaxBB[block].X == 1.0f &&
Block_MinBB[block].Z == 0.0f && Block_MaxBB[block].Z == 1.0f) return true;
}
if (count < 4) {
cur->Block = WorldEnv_EdgeBlock; cur->Y = 0.0f;
ShadowComponent_CalcAlpha(Position.Y, cur);
count++; cur++;
}
return true;
}
#define size 128
#define half (size / 2)
void ShadowComponent_MakeTex(void) {
UInt8 pixels[Bitmap_DataSize(size, size)];
Bitmap bmp; Bitmap_Create(&bmp, size, size, pixels);
UInt32 inPix = PackedCol_ARGB(0, 0, 0, 200);
UInt32 outPix = PackedCol_ARGB(0, 0, 0, 0);
UInt32 x, y;
for (y = 0; y < size; y++) {
UInt32* row = Bitmap_GetRow(&bmp, y);
for (x = 0; x < size; x++) {
Real64 dist =
(half - (x + 0.5)) * (half - (x + 0.5)) +
(half - (y + 0.5)) * (half - (y + 0.5));
row[x] = dist < half * half ? inPix : outPix;
}
}
ShadowComponent_ShadowTex = Gfx_CreateTexture(&bmp, true, false);
}
void ShadowComponent_Draw(Entity* entity) {
Vector3 Position = entity->Position;
if (Position.Y < 0.0f) return;
Real32 posX = Position.X, posZ = Position.Z;
Int32 posY = min((Int32)Position.Y, World_MaxY);
GfxResourceID vb;
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;
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;
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);
}
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);
}
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);
}
x = posX - radius;
if (ShadowComponent_GetBlocks(entity, coords, x, z, posY, data) && data[0].A > 0) {
ShadowComponent_DrawCircle(&ptr, entity, data, x, z);
}
}
if (ptr == vertices) return;
if (ShadowComponent_ShadowTex == NULL) {
ShadowComponent_MakeTex();
}
if (!ShadowComponent_BoundShadowTex) {
Gfx_BindTexture(ShadowComponent_ShadowTex);
ShadowComponent_BoundShadowTex = true;
}
UInt32 vCount = (UInt32)(ptr - vertices) / VertexP3fT2fC4b_Size;
GfxCommon_UpdateDynamicVb_IndexedTris(vb, vertices, vCount);
}

View File

@ -72,7 +72,6 @@ void HacksComp_SetUserType(HacksComp* hacks, UInt8 value);
void HacksComp_CheckConsistency(HacksComp* hacks);
void HacksComp_UpdateState(HacksComp* hacks);
/* Represents a position and orientation state. */
typedef struct InterpState_ {
Vector3 Pos;
@ -104,4 +103,11 @@ typedef struct NetInterpComp_ {
void NetInterpComp_SetLocation(NetInterpComp* interp, LocationUpdate* update, bool interpolate);
void NetInterpComp_AdvanceState(NetInterpComp* interp);
/* Entity component that draws square and circle shadows beneath entities. */
bool ShadowComponent_BoundShadowTex;
GfxResourceID ShadowComponent_ShadowTex;
void ShadowComponent_Draw(Entity* entity);
#endif

View File

@ -140,7 +140,7 @@ void EnvRenderer_Render(Real64 deltaTime) {
if (EnvRenderer_Minimal) {
EnvRenderer_RenderMinimal(deltaTime);
} else {
if (env_skyVb == 0 || env_cloudsVb == 0) return;
if (env_skyVb == NULL || env_cloudsVb == NULL) return;
if (!SkyboxRenderer_ShouldRender()) {
EnvRenderer_RenderSky(deltaTime);
EnvRenderer_RenderClouds(deltaTime);

View File

@ -25,32 +25,18 @@ typedef struct CachedTexture_ {
public CustomModel[] CustomModels = new CustomModel[256];
#endif
/* Maximum number of models (or textures) that can be registered. */
#define MODELCACHE_MAX_MODELS 24
/* The models that have been registered previously.
The first model (index 0) is the humanoid model. */
CachedModel ModelCache_Models[MODELCACHE_MAX_MODELS];
/* The textures that have been registered previously. */
CachedTexture ModelCache_Textures[MODELCACHE_MAX_MODELS];
/* Maximum number of vertices a model can have. */
#define MODELCACHE_MAX_VERTICES (24 * 12)
/* Dynamic vertex buffer for model rendering. */
GfxResourceID ModelCache_Vb;
/* Raw vertices for model rendering. */
VertexP3fT2fC4b ModelCache_Vertices[MODELCACHE_MAX_VERTICES];
/* Initalises the model cache and hooks events. */
void ModelCache_Init(void);
/* Frees textures and vertex buffer of the model cache, and then unhooks events. */
void ModelCache_Free(void);
/* Gets the model which has the given name, or pointer to humanoid model if not found. */
IModel* ModelCache_Get(STRING_PURE String* name);
/* Gets the index of the texture which has the given name, or -1 if not found. */
Int32 ModelCache_GetTextureIndex(STRING_PURE String* texName);
/* Registers the given model to be able to be used as a model for entities.
You can use ModelCache_Get to get pointer to the model. */
void ModelCache_Register(STRING_REF const UInt8* name, STRING_PURE const UInt8* defaultTexName, IModel* instance);
/* Registers the given texture to be tracked by the model cache.
You can use ModelCache_GetTextureIndex to get the index of this texture. */
void ModelCache_RegisterTexture(STRING_REF const UInt8* texName);
#endif

View File

@ -207,19 +207,19 @@ bool InventoryScreen_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, MouseB
bool InventoryScreen_HandlesMouseUp(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) {
InventoryScreen* screen = (InventoryScreen*)elem;
GuiElement* elem = &screen->Table.Base.Base;
elem = &screen->Table.Base.Base;
return elem->HandlesMouseUp(elem, x, y, btn);
}
bool InventoryScreen_HandlesMouseMove(GuiElement* elem, Int32 x, Int32 y) {
InventoryScreen* screen = (InventoryScreen*)elem;
GuiElement* elem = &screen->Table.Base.Base;
elem = &screen->Table.Base.Base;
return elem->HandlesMouseMove(elem, x, y);
}
bool InventoryScreen_HandlesMouseScroll(GuiElement* elem, Real32 delta) {
InventoryScreen* screen = (InventoryScreen*)elem;
GuiElement* elem = &screen->Table.Base.Base;
elem = &screen->Table.Base.Base;
bool hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed();
if (hotbar) return false;

View File

@ -119,7 +119,6 @@ void WeatherRenderer_Render(Real64 deltaTime) {
weather_accumulator += deltaTime;
bool particles = weather == Weather_Rainy;
Int32 vCount = 0;
PackedCol col = WorldEnv_SunCol;
VertexP3fT2fC4b v;
VertexP3fT2fC4b vertices[weather_verticesCount];
@ -161,21 +160,20 @@ void WeatherRenderer_Render(Real64 deltaTime) {
v.Y = y2; v.V = v2; *ptr = v; ptr++;
v.X = x1; v.Z = z2; v.U = 0.0f; *ptr = v; ptr++;
v.Y = y1; v.V = v1; *ptr = v; ptr++;
vCount += 8;
}
}
if (particles && (weather_accumulator >= 0.25f || moved)) {
weather_accumulator = 0;
}
if (vCount == 0) return;
if (ptr == vertices) return;
Gfx_SetAlphaTest(false);
Gfx_SetDepthWrite(false);
Gfx_SetAlphaArgBlend(true);
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
UInt32 vCount = (UInt32)(ptr - vertices) / VertexP3fT2fC4b_Size;
GfxCommon_UpdateDynamicVb_IndexedTris(weather_vb, vertices, vCount);
Gfx_SetAlphaArgBlend(false);