mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-18 20:15:35 -04:00
Port Picking to C.
This commit is contained in:
parent
fb18b2fe6f
commit
fccc7dad12
@ -161,6 +161,12 @@ void ChunkUpdater_OnNewMapLoaded(void) {
|
||||
}
|
||||
|
||||
|
||||
Int32 ChunkUpdater_AdjustViewDist(Real32 dist) {
|
||||
if (dist < CHUNK_SIZE) dist = CHUNK_SIZE;
|
||||
Int32 viewDist = Math_AdjViewDist(dist);
|
||||
return (viewDist + 24) * (viewDist + 24);
|
||||
}
|
||||
|
||||
Int32 ChunkUpdater_UpdateChunksAndVisibility(Int32* chunkUpdates) {
|
||||
Int32 i, j = 0;
|
||||
Int32 viewDistSqr = ChunkUpdater_AdjustViewDist(Game_ViewDistance);
|
||||
@ -349,12 +355,6 @@ void ChunkUpdater_BuildChunk(ChunkInfo* info, Int32* chunkUpdates) {
|
||||
ChunkUpdater_AddParts(info->TranslucentParts, MapRenderer_TranslucentPartsCount);
|
||||
}
|
||||
|
||||
Int32 ChunkUpdater_AdjustViewDist(Real32 dist) {
|
||||
if (dist < CHUNK_SIZE) dist = CHUNK_SIZE;
|
||||
Int32 viewDist = Math_AdjViewDist(dist);
|
||||
return (viewDist + 24) * (viewDist + 24);
|
||||
}
|
||||
|
||||
void ChunkUpdater_QuickSort(Int32 left, Int32 right) {
|
||||
ChunkInfo** values = MapRenderer_SortedChunks;
|
||||
Int32* keys = ChunkUpdater_Distances;
|
||||
|
@ -257,6 +257,7 @@
|
||||
<ClCompile Include="EnvRenderer.c" />
|
||||
<ClCompile Include="Event.c" />
|
||||
<ClCompile Include="ExtMath.c" />
|
||||
<ClCompile Include="Game.c" />
|
||||
<ClCompile Include="MapGenerator.c" />
|
||||
<ClCompile Include="FrustumCulling.c" />
|
||||
<ClCompile Include="GameStructs.c" />
|
||||
@ -278,6 +279,7 @@
|
||||
<ClCompile Include="Noise.c" />
|
||||
<ClCompile Include="Physics.c" />
|
||||
<ClCompile Include="PickedPosRenderer.c" />
|
||||
<ClCompile Include="Picking.c" />
|
||||
<ClCompile Include="Program.c" />
|
||||
<ClCompile Include="Random.c" />
|
||||
<ClCompile Include="Respawn.c" />
|
||||
|
@ -518,5 +518,11 @@
|
||||
<ClCompile Include="Camera.c">
|
||||
<Filter>Source Files\Utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Picking.c">
|
||||
<Filter>Source Files\Math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Game.c">
|
||||
<Filter>Source Files\Game</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -14,6 +14,14 @@
|
||||
GfxResourceID env_cloudsVb = -1, env_skyVb = -1, env_cloudsTex = -1;
|
||||
GfxResourceID env_cloudVertices, env_skyVertices;
|
||||
|
||||
Real32 EnvRenderer_BlendFactor(Real32 x) {
|
||||
/* return -0.05 + 0.22 * (Math_LogE(x) * 0.25f); */
|
||||
Real32 blend = -0.13f + 0.28f * (Math_LogE(x) * 0.25f);
|
||||
if (blend < 0.0f) blend = 0.0f;
|
||||
if (blend > 1.0f) blend = 1.0f;
|
||||
return blend;
|
||||
}
|
||||
|
||||
BlockID EnvRenderer_BlockOn(Real32* fogDensity, PackedCol* fogCol) {
|
||||
Vector3 pos = Game_CurrentCameraPos;
|
||||
Vector3I coords;
|
||||
@ -37,14 +45,6 @@ BlockID EnvRenderer_BlockOn(Real32* fogDensity, PackedCol* fogCol) {
|
||||
return block;
|
||||
}
|
||||
|
||||
Real32 EnvRenderer_BlendFactor(Real32 x) {
|
||||
/* return -0.05 + 0.22 * (Math_LogE(x) * 0.25f); */
|
||||
Real32 blend = -0.13f + 0.28f * (Math_LogE(x) * 0.25f);
|
||||
if (blend < 0.0f) blend = 0.0f;
|
||||
if (blend > 1.0f) blend = 1.0f;
|
||||
return blend;
|
||||
}
|
||||
|
||||
|
||||
void EnvRenderer_RenderMinimal(Real64 deltaTime) {
|
||||
if (World_Blocks == NULL) return;
|
||||
|
@ -15,6 +15,12 @@ Int32 Math_CeilDiv(Int32 a, Int32 b) {
|
||||
return a / b + (a % b != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
Int32 Math_Sign(Real32 value) {
|
||||
if (value > 0.0f) return +1;
|
||||
if (value < 0.0f) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Real32 Math_Lerp(Real32 a, Real32 b, Real32 t) {
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define MATH_PI 3.1415926535897931f
|
||||
#define MATH_DEG2RAD (MATH_PI / 180.0f)
|
||||
#define MATH_RAD2DEG (180.0f / MATH_PI)
|
||||
#define MATH_LARGENUM 1000000000.0f
|
||||
|
||||
#define Math_AbsF(x) fabsf(x)
|
||||
#define Math_AbsI(x) abs(x)
|
||||
@ -31,6 +32,8 @@ Int32 Math_Floor(Real32 value);
|
||||
Int32 Math_Log2(Int32 value);
|
||||
/* Performs rounding upwards integer division.*/
|
||||
Int32 Math_CeilDiv(Int32 a, Int32 b);
|
||||
/* Returns sign of the given value. */
|
||||
Int32 Math_Sign(Real32 value);
|
||||
|
||||
/* Performs linear interpolation between two values. */
|
||||
Real32 Math_Lerp(Real32 a, Real32 b, Real32 t);
|
||||
|
@ -11,29 +11,21 @@
|
||||
|
||||
/* Total rendering time(in seconds) elapsed since the client was started. */
|
||||
Real64 Game_Accumulator;
|
||||
|
||||
/* Accumulator for the number of chunk updates performed. Reset every second. */
|
||||
Int32 Game_ChunkUpdates;
|
||||
|
||||
/* Whether the third person camera should have their camera position clipped so as to not intersect blocks.*/
|
||||
bool Game_CameraClipping;
|
||||
|
||||
/* Whether colour clear gfx call should be skipped. */
|
||||
bool Game_SkipClear;
|
||||
|
||||
/* Picked pos instance used for block selection. */
|
||||
PickedPos Game_SelectedPos;
|
||||
|
||||
/* Picked pos instance used for camera clipping. */
|
||||
PickedPos Game_CameraClipPos;
|
||||
|
||||
/* Default index buffer ID. */
|
||||
Int32 Game_DefaultIb;
|
||||
|
||||
|
||||
/* Whether cobblestone slab to stone brick tiles should be used. */
|
||||
bool Game_UseCPEBlocks;
|
||||
|
||||
/* Account username of the player.*/
|
||||
String Game_Username;
|
||||
/* Verification key used for multiplayer, unique for the username and individual server. */
|
||||
@ -42,36 +34,27 @@ String Game_Mppass;
|
||||
String Game_IPAddress;
|
||||
/* Port of multiplayer server connected to, 0 if singleplayer. */
|
||||
Int32 Game_Port;
|
||||
|
||||
/* Radius of the sphere the player can see around the position of the current camera. */
|
||||
Real32 Game_ViewDistance;
|
||||
/* Maximum view distance player can view up to. */
|
||||
Real32 Game_MaxViewDistance;
|
||||
/* 'Real' view distance the player has selected. */
|
||||
Real32 Game_UserViewDistance;
|
||||
|
||||
/* Field of view for the current camera in degrees. */
|
||||
Int32 Game_Fov;
|
||||
Int32 Game_DefaultFov, Game_ZoomFov;
|
||||
|
||||
/* Strategy used to limit how many frames should be displayed at most each second. */
|
||||
FpsLimitMethod FpsLimit;
|
||||
|
||||
/* Whether lines should be rendered for each axis. */
|
||||
bool Game_ShowAxisLines;
|
||||
|
||||
/* Whether players should animate using simple swinging parallel to their bodies. */
|
||||
bool Game_SimpleArmsAnim;
|
||||
|
||||
/* Whether the arm model should use the classic position. */
|
||||
bool Game_ClassicArmModel;
|
||||
|
||||
/* Whether mouse rotation on the y axis should be inverted. */
|
||||
bool Game_InvertMouse;
|
||||
|
||||
/* Number of vertices used for rendering terrain this frame. */
|
||||
Int32 Game_Vertices;
|
||||
|
||||
/* Model view matrix. */
|
||||
Matrix Game_View;
|
||||
/* Projection matrix. */
|
||||
@ -79,39 +62,30 @@ Matrix Game_Projection;
|
||||
|
||||
/* How sensitive the client is to changes in the player's mouse position. */
|
||||
Int32 Game_MouseSensitivity;
|
||||
|
||||
/* Whether tab names autocomplete. */
|
||||
bool Game_TabAutocomplete;
|
||||
|
||||
bool Game_UseClassicGui;
|
||||
bool Game_UseClassicTabList;
|
||||
bool Game_UseClassicOptions;
|
||||
bool Game_ClassicMode;
|
||||
bool Game_ClassicHacks;
|
||||
#define Game_PureClassic (Game_ClassicMode && !Game_ClassicHacks)
|
||||
|
||||
/* Whether suport for custom blocks is indicated to the server. */
|
||||
bool Game_AllowCustomBlocks;
|
||||
/* Whether CPE is used at all. */
|
||||
bool Game_UseCPE;
|
||||
/* Whether all texture packs are ignored from the server or not. */
|
||||
bool Game_AllowServerTextures;
|
||||
|
||||
/* Whether advanced/smooth lighting mesh builder is used. */
|
||||
bool Game_SmoothLighting;
|
||||
|
||||
/* Whether chat logging to disc is enabled. */
|
||||
bool Game_ChatLogging;
|
||||
|
||||
/* Whether auto rotation of blocks with special suffixes is enabled. */
|
||||
bool Game_AutoRotate;
|
||||
|
||||
/* Whether camera has smooth rotation. */
|
||||
bool Game_SmoothCamera;
|
||||
|
||||
/* Font name used for text rendering. */
|
||||
String Game_FontName;
|
||||
|
||||
/* Max number of chatlines drawn in chat. */
|
||||
Int32 Game_ChatLines;
|
||||
/* Whether clicking on chatlines copies into chat input is enabled. */
|
||||
@ -165,22 +139,19 @@ static bool Game_realCursorVisible;
|
||||
/* Sets whether the cursor is visible. */
|
||||
void Game_SetCursorVisible(bool visible);
|
||||
|
||||
|
||||
/* Called when projection matrix is updated. */
|
||||
void Game_UpdateProjection(void);
|
||||
|
||||
/* Updates the block at the given coordinates. */
|
||||
void Game_UpdateBlock(Int32 x, Int32 y, Int32 z, BlockID block);
|
||||
|
||||
/* Updates the given texture. */
|
||||
void Game_UpdateTexture(GfxResourceID* texId, Stream* src, bool setSkinType);
|
||||
|
||||
/* Sets the view distance of the game. */
|
||||
void Game_SetViewDistance(Real32 distance, bool userDist);
|
||||
/* Returns whether the player can pick the given block.*/
|
||||
bool Game_CanPick(BlockID block);
|
||||
|
||||
/* Performs thread sleeping to limit the FPS. */
|
||||
static void Game_LimitFPS(void);
|
||||
|
||||
/* Frees all resources held by the game. */
|
||||
void Game_Free(void);
|
||||
#endif
|
@ -29,6 +29,22 @@ void Lighting_EnvVariableChanged(EnvVar envVar) {
|
||||
}
|
||||
}
|
||||
|
||||
Int32 Lighting_CalcHeightAt(Int32 x, Int32 maxY, Int32 z, Int32 index) {
|
||||
Int32 mapIndex = World_Pack(x, maxY, z);
|
||||
Int32 y;
|
||||
|
||||
for (y = maxY; y >= 0; y--) {
|
||||
BlockID block = World_Blocks[mapIndex];
|
||||
if (Block_BlocksLight[block]) {
|
||||
Int32 offset = (Block_LightOffset[block] >> Face_YMax) & 1;
|
||||
Lighting_heightmap[index] = (Int16)(y - offset);
|
||||
return y - offset;
|
||||
}
|
||||
mapIndex -= World_OneY;
|
||||
}
|
||||
Lighting_heightmap[index] = (Int16)-10;
|
||||
return -10;
|
||||
}
|
||||
|
||||
Int32 Lighting_GetLightHeight(Int32 x, Int32 z) {
|
||||
Int32 index = (z * World_Width) + x;
|
||||
@ -36,7 +52,6 @@ Int32 Lighting_GetLightHeight(Int32 x, Int32 z) {
|
||||
return lightH == Int16_MaxValue ? Lighting_CalcHeightAt(x, World_Height - 1, z, index) : lightH;
|
||||
}
|
||||
|
||||
|
||||
/* Outside colour is same as sunlight colour, so we reuse when possible */
|
||||
bool Lighting_IsLit(Int32 x, Int32 y, Int32 z) {
|
||||
return y > Lighting_GetLightHeight(x, z);
|
||||
@ -196,23 +211,6 @@ void Lighting_OnBlockChanged(Int32 x, Int32 y, Int32 z, BlockID oldBlock, BlockI
|
||||
}
|
||||
|
||||
|
||||
Int32 Lighting_CalcHeightAt(Int32 x, Int32 maxY, Int32 z, Int32 index) {
|
||||
Int32 mapIndex = World_Pack(x, maxY, z);
|
||||
Int32 y;
|
||||
|
||||
for (y = maxY; y >= 0; y--) {
|
||||
BlockID block = World_Blocks[mapIndex];
|
||||
if (Block_BlocksLight[block]) {
|
||||
Int32 offset = (Block_LightOffset[block] >> Face_YMax) & 1;
|
||||
Lighting_heightmap[index] = (Int16)(y - offset);
|
||||
return y - offset;
|
||||
}
|
||||
mapIndex -= World_OneY;
|
||||
}
|
||||
Lighting_heightmap[index] = (Int16)-10;
|
||||
return -10;
|
||||
}
|
||||
|
||||
Int32 Lighting_InitialHeightmapCoverage(Int32 x1, Int32 z1, Int32 xCount, Int32 zCount, Int32* skip) {
|
||||
Int32 elemsLeft = 0, index = 0, curRunCount = 0;
|
||||
Int32 x, z;
|
||||
|
@ -138,6 +138,32 @@ void NotchyGen_CreateHeightmap(void) {
|
||||
}
|
||||
}
|
||||
|
||||
Int32 NotchyGen_CreateStrataFast(void) {
|
||||
/* Make lava layer at bottom */
|
||||
Int32 mapIndex = 0;
|
||||
Int32 x, y, z;
|
||||
|
||||
for (z = 0; z < Gen_Length; z++) {
|
||||
for (x = 0; x < Gen_Width; x++) {
|
||||
Gen_Blocks[mapIndex++] = BlockID_Lava;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invariant: the lowest value dirtThickness can possible be is -14 */
|
||||
Int32 stoneHeight = minHeight - 14;
|
||||
if (stoneHeight <= 0) return 1; /* no layer is fully stone */
|
||||
|
||||
/* We can quickly fill in bottom solid layers */
|
||||
for (y = 1; y <= stoneHeight; y++) {
|
||||
for (z = 0; z < Gen_Length; z++) {
|
||||
for (x = 0; x < Gen_Width; x++) {
|
||||
Gen_Blocks[mapIndex++] = BlockID_Stone;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stoneHeight;
|
||||
}
|
||||
|
||||
void NotchyGen_CreateStrata(void) {
|
||||
OctaveNoise n;
|
||||
OctaveNoise_Init(&n, &rnd, 8);
|
||||
@ -172,32 +198,6 @@ void NotchyGen_CreateStrata(void) {
|
||||
}
|
||||
}
|
||||
|
||||
Int32 NotchyGen_CreateStrataFast(void) {
|
||||
/* Make lava layer at bottom */
|
||||
Int32 mapIndex = 0;
|
||||
Int32 x, y, z;
|
||||
|
||||
for (z = 0; z < Gen_Length; z++) {
|
||||
for (x = 0; x < Gen_Width; x++) {
|
||||
Gen_Blocks[mapIndex++] = BlockID_Lava;
|
||||
}
|
||||
}
|
||||
|
||||
/* Invariant: the lowest value dirtThickness can possible be is -14 */
|
||||
Int32 stoneHeight = minHeight - 14;
|
||||
if (stoneHeight <= 0) return 1; /* no layer is fully stone */
|
||||
|
||||
/* We can quickly fill in bottom solid layers */
|
||||
for (y = 1; y <= stoneHeight; y++) {
|
||||
for (z = 0; z < Gen_Length; z++) {
|
||||
for (x = 0; x < Gen_Width; x++) {
|
||||
Gen_Blocks[mapIndex++] = BlockID_Stone;
|
||||
}
|
||||
}
|
||||
}
|
||||
return stoneHeight;
|
||||
}
|
||||
|
||||
void NotchyGen_CarveCaves(void) {
|
||||
Int32 cavesCount = volume / 8192;
|
||||
String state = String_FromConstant("Carving caves");
|
||||
|
@ -1,30 +1,34 @@
|
||||
#include "Picking.h"
|
||||
#include "ExtMath.h"
|
||||
#include "Game.h"
|
||||
#include "Intersection.h"
|
||||
#include "Player.h"
|
||||
#include "World.h"
|
||||
#include "Funcs.h"
|
||||
|
||||
Real32 PickedPos_dist;
|
||||
void PickedPos_TestAxis(PickedPos* pos, Real32 dAxis, Face fAxis) {
|
||||
dAxis = Math_AbsF(dAxis);
|
||||
if (dAxis >= PickedPos_dist) return;
|
||||
|
||||
PickedPos_dist = dAxis;
|
||||
PickedPos_dist = dAxis;
|
||||
pos->ClosestFace = fAxis;
|
||||
}
|
||||
|
||||
void PickedPos_SetAsValid(PickedPos* pos, Int32 x, Int32 y, Int32 z,
|
||||
Vector3 min, Vector3 max, BlockID block, Vector3 intersect) {
|
||||
pos->Min = min; pos->Max = max;
|
||||
pos->BlockPos = Vector3I_Create3(x, y, z);
|
||||
void PickedPos_SetAsValid(PickedPos* pos, RayTracer* t, Vector3 intersect) {
|
||||
pos->Min = t->Min; pos->Max = t->Max;
|
||||
pos->BlockPos = Vector3I_Create3(t->X, t->Y, t->Z);
|
||||
pos->Valid = true;
|
||||
pos->Block = block;
|
||||
pos->Block = t->Block;
|
||||
pos->Intersect = intersect;
|
||||
|
||||
PickedPos_dist = 1000000000.0f;
|
||||
PickedPos_TestAxis(pos, intersect.X - min.X, Face_XMin);
|
||||
PickedPos_TestAxis(pos, intersect.X - max.X, Face_XMax);
|
||||
PickedPos_TestAxis(pos, intersect.Y - min.Y, Face_YMin);
|
||||
PickedPos_TestAxis(pos, intersect.Y - max.Y, Face_YMax);
|
||||
PickedPos_TestAxis(pos, intersect.Z - min.Z, Face_ZMin);
|
||||
PickedPos_TestAxis(pos, intersect.Z - max.Z, Face_ZMax);
|
||||
PickedPos_dist = MATH_LARGENUM;
|
||||
PickedPos_TestAxis(pos, intersect.X - t->Min.X, Face_XMin);
|
||||
PickedPos_TestAxis(pos, intersect.X - t->Max.X, Face_XMax);
|
||||
PickedPos_TestAxis(pos, intersect.Y - t->Min.Y, Face_YMin);
|
||||
PickedPos_TestAxis(pos, intersect.Y - t->Max.Y, Face_YMax);
|
||||
PickedPos_TestAxis(pos, intersect.Z - t->Min.Z, Face_ZMin);
|
||||
PickedPos_TestAxis(pos, intersect.Z - t->Max.Z, Face_ZMax);
|
||||
|
||||
Vector3I offsets[Face_Count];
|
||||
offsets[Face_XMin] = Vector3I_Create3(-1, 0, 0);
|
||||
@ -42,4 +46,192 @@ void PickedPos_SetAsInvalid(PickedPos* pos) {
|
||||
pos->TranslatedPos = Vector3I_MinusOne;
|
||||
pos->ClosestFace = (Face)Face_Count;
|
||||
pos->Block = BlockID_Air;
|
||||
}
|
||||
|
||||
Real32 RayTracer_Div(Real32 a, Real32 b) {
|
||||
if (Math_AbsF(b) < 0.000001f) return MATH_LARGENUM;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
void RayTracer_SetVectors(RayTracer* t, Vector3 origin, Vector3 dir) {
|
||||
t->Origin = origin; t->Dir = dir;
|
||||
/* Rounds the position's X, Y and Z down to the nearest integer values. */
|
||||
Vector3I start;
|
||||
Vector3I_Floor(&start, &origin);
|
||||
/* The cell in which the ray starts. */
|
||||
t->X = start.X; t->Y = start.Y; t->Z = start.Z;
|
||||
/* Determine which way we go.*/
|
||||
t->step.X = Math_Sign(dir.X); t->step.Y = Math_Sign(dir.Y); t->step.Z = Math_Sign(dir.Z);
|
||||
|
||||
/* Calculate cell boundaries. When the step (i.e. direction sign) is positive,
|
||||
the next boundary is AFTER our current position, meaning that we have to add 1.
|
||||
Otherwise, it is BEFORE our current position, in which case we add nothing. */
|
||||
Vector3I cellBoundary;
|
||||
cellBoundary.X = start.X + (t->step.X > 0 ? 1 : 0);
|
||||
cellBoundary.Y = start.Y + (t->step.Y > 0 ? 1 : 0);
|
||||
cellBoundary.Z = start.Z + (t->step.Z > 0 ? 1 : 0);
|
||||
|
||||
/* NOTE: we want it so if dir.x = 0, tmax.x = positive infinity
|
||||
Determine how far we can travel along the ray before we hit a voxel boundary. */
|
||||
t->tMax.X = RayTracer_Div(cellBoundary.X - origin.X, dir.X); /* Boundary is a plane on the YZ axis. */
|
||||
t->tMax.Y = RayTracer_Div(cellBoundary.Y - origin.Y, dir.Y); /* Boundary is a plane on the XZ axis. */
|
||||
t->tMax.Z = RayTracer_Div(cellBoundary.Z - origin.Z, dir.Z); /* Boundary is a plane on the XY axis. */
|
||||
|
||||
// Determine how far we must travel along the ray before we have crossed a gridcell.
|
||||
t->tDelta.X = RayTracer_Div((Real32)t->step.X, dir.X);
|
||||
t->tDelta.Y = RayTracer_Div((Real32)t->step.Y, dir.Y);
|
||||
t->tDelta.Z = RayTracer_Div((Real32)t->step.Z, dir.Z);
|
||||
}
|
||||
|
||||
void RayTracer_Step(RayTracer* t) {
|
||||
/* For each step, determine which distance to the next voxel boundary is lowest
|
||||
(i.e. which voxel boundary is nearest) and walk that way. */
|
||||
if (t->tMax.X < t->tMax.Y && t->tMax.X < t->tMax.Z) {
|
||||
/* tMax.X is the lowest, an YZ cell boundary plane is nearest. */
|
||||
t->X += t->step.X;
|
||||
t->tMax.X += t->tDelta.X;
|
||||
}
|
||||
else if (t->tMax.Y < t->tMax.Z) {
|
||||
/* tMax.Y is the lowest, an XZ cell boundary plane is nearest. */
|
||||
t->Y += t->step.Y;
|
||||
t->tMax.Y += t->tDelta.Y;
|
||||
}
|
||||
else {
|
||||
/* tMax.Z is the lowest, an XY cell boundary plane is nearest. */
|
||||
t->Z += t->step.Z;
|
||||
t->tMax.Z += t->tDelta.Z;
|
||||
}
|
||||
}
|
||||
|
||||
RayTracer tracer;
|
||||
#define PICKING_BORDER BlockID_Bedrock
|
||||
typedef bool(*IntersectTest)(PickedPos* pos);
|
||||
|
||||
BlockID Picking_GetBlock(Int32 x, Int32 y, Int32 z, Vector3I origin) {
|
||||
bool sides = WorldEnv_SidesBlock != BlockID_Air;
|
||||
Int32 height = WorldEnv_SidesHeight;
|
||||
if (height < 1) height = 1;
|
||||
bool insideMap = World_IsValidPos_3I(origin);
|
||||
|
||||
/* handling of blocks inside the map, above, and on borders */
|
||||
if (x >= 0 && z >= 0 && x < World_Width && z < World_Length) {
|
||||
if (y >= World_Height) return 0;
|
||||
if (sides && y == -1 && insideMap) return PICKING_BORDER;
|
||||
if (sides && y == 0 && origin.Y < 0) return PICKING_BORDER;
|
||||
|
||||
if (sides && x == 0 && y >= 0 && y < height && origin.X < 0) return PICKING_BORDER;
|
||||
if (sides && z == 0 && y >= 0 && y < height && origin.Z < 0) return PICKING_BORDER;
|
||||
if (sides && x == World_MaxX && y >= 0 && y < height && origin.X >= World_Width)
|
||||
return PICKING_BORDER;
|
||||
if (sides && z == World_MaxZ && y >= 0 && y < height && origin.Z >= World_Length)
|
||||
return PICKING_BORDER;
|
||||
if (y >= 0) return World_GetBlock(x, y, z);
|
||||
}
|
||||
|
||||
/* pick blocks on the map boundaries (when inside the map) */
|
||||
if (!sides || !insideMap) return BlockID_Air;
|
||||
if (y == 0 && origin.Y < 0) return PICKING_BORDER;
|
||||
|
||||
bool validX = (x == -1 || x == World_Width) && (z >= 0 && z < World_Length);
|
||||
bool validZ = (z == -1 || z == World_Length) && (x >= 0 && x < World_Width);
|
||||
if (y >= 0 && y < height && (validX || validZ)) return PICKING_BORDER;
|
||||
return BlockID_Air;
|
||||
}
|
||||
|
||||
bool Picking_RayTrace(Vector3 origin, Vector3 dir, Real32 reach, PickedPos* pos, IntersectTest intersect) {
|
||||
RayTracer_SetVectors(&tracer, origin, dir);
|
||||
Real32 reachSq = reach * reach;
|
||||
Vector3I pOrigin;
|
||||
Vector3I_Floor(&pOrigin, &origin);
|
||||
|
||||
Int32 i;
|
||||
Vector3 blockPos;
|
||||
for (i = 0; i < 10000; i++) {
|
||||
Int32 x = tracer.X, y = tracer.Y, z = tracer.Z;
|
||||
blockPos.X = (Real32)x; blockPos.Y = (Real32)y; blockPos.Z = (Real32)z;
|
||||
tracer.Block = Picking_GetBlock(x, y, z, pOrigin);
|
||||
|
||||
Vector3 minPos, maxPos;
|
||||
Vector3_Add(&minPos, &blockPos, &Block_RenderMinBB[tracer.Block]);
|
||||
Vector3_Add(&maxPos, &blockPos, &Block_RenderMaxBB[tracer.Block]);
|
||||
|
||||
Real32 dxMin = Math_AbsF(origin.X - minPos.X), dxMax = Math_AbsF(origin.X - maxPos.X);
|
||||
Real32 dyMin = Math_AbsF(origin.Y - minPos.Y), dyMax = Math_AbsF(origin.Y - maxPos.Y);
|
||||
Real32 dzMin = Math_AbsF(origin.Z - minPos.Z), dzMax = Math_AbsF(origin.Z - maxPos.Z);
|
||||
Real32 dx = min(dxMin, dxMax), dy = min(dyMin, dyMax), dz = min(dzMin, dzMax);
|
||||
if (dx * dx + dy * dy + dz * dz > reachSq) return false;
|
||||
|
||||
tracer.Min = minPos; tracer.Max = maxPos;
|
||||
if (intersect(pos)) return true;
|
||||
RayTracer_Step(&tracer);
|
||||
}
|
||||
ErrorHandler_Fail("Something went wrong, did over 10,000 iterations in Picking_RayTrace()");
|
||||
}
|
||||
|
||||
bool Picking_ClipBlock(PickedPos* pos) {
|
||||
if (!Game_CanPick(tracer.Block)) return false;
|
||||
|
||||
/* This cell falls on the path of the ray. Now perform an additional AABB test,
|
||||
since some blocks do not occupy a whole cell. */
|
||||
Real32 t0, t1;
|
||||
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 scaledDir, intersect;
|
||||
Vector3_Multiply1(&scaledDir, &tracer.Dir, t0); /* scaledDir = dir * t0 */
|
||||
Vector3_Add(&intersect, &tracer.Origin, &scaledDir); /* intersect = origin + scaledDir */
|
||||
/* Only pick the block if the block is precisely within reach distance. */
|
||||
Real32 lenSq = Vector3_LengthSquared(&scaledDir);
|
||||
Real32 reach = LocalPlayer_Instance.ReachDistance;
|
||||
|
||||
if (lenSq <= reach * reach) {
|
||||
PickedPos_SetAsValid(pos, &tracer, intersect);
|
||||
}
|
||||
else {
|
||||
PickedPos_SetAsInvalid(pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Picking_ClipCamera(PickedPos* pos) {
|
||||
if (Block_Draw[tracer.Block] == DrawType_Gas || Block_Collide[tracer.Block] != CollideType_Solid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Real32 t0, t1;
|
||||
if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 intersect;
|
||||
Vector3_Multiply1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */
|
||||
Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */
|
||||
PickedPos_SetAsValid(pos, &tracer, intersect);
|
||||
|
||||
#define PICKING_ADJUST 0.1f
|
||||
switch (pos->ClosestFace) {
|
||||
case Face_XMin: pos->Intersect.X -= PICKING_ADJUST; break;
|
||||
case Face_XMax: pos->Intersect.X += PICKING_ADJUST; break;
|
||||
case Face_YMin: pos->Intersect.Y -= PICKING_ADJUST; break;
|
||||
case Face_YMax: pos->Intersect.Y += PICKING_ADJUST; break;
|
||||
case Face_ZMin: pos->Intersect.Z -= PICKING_ADJUST; break;
|
||||
case Face_ZMax: pos->Intersect.Z += PICKING_ADJUST; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Picking_CalculatePickedBlock(Vector3 origin, Vector3 dir, Real32 reach, PickedPos* pos) {
|
||||
if (!Picking_RayTrace(origin, dir, reach, pos, Picking_ClipBlock)) {
|
||||
PickedPos_SetAsInvalid(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Picking_ClipCameraPos(Vector3 origin, Vector3 dir, Real32 reach, PickedPos* pos) {
|
||||
bool noClip = !Game_CameraClipping || LocalPlayer_Instance.Hacks.Noclip;
|
||||
if (noClip || !Picking_RayTrace(origin, dir, reach, pos, Picking_ClipCamera)) {
|
||||
PickedPos_SetAsInvalid(pos);
|
||||
Vector3_Multiply1(&pos->Intersect, &tracer.Dir, reach); /* intersect = dir * reach */
|
||||
Vector3_Add(&pos->Intersect, &tracer.Origin, &pos->Intersect); /* intersect = origin + dir * reach */
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
#include "Vectors.h"
|
||||
#include "BlockID.h"
|
||||
/* Data for picking/selecting block by the user, and clipping the camera.
|
||||
Copyright 2014 - 2017 ClassicalSharp | Licensed under BSD-3
|
||||
Copyright 2014 - 2017 ClassicalSharp | Licensed under BSD-3
|
||||
*/
|
||||
|
||||
/* Describes the picked/selected block by the user and its position. */
|
||||
@ -28,14 +28,34 @@ typedef struct PickedPos_ {
|
||||
BlockID Block;
|
||||
} PickedPos;
|
||||
|
||||
/* Mark as having a selected block, and calculates the closest face of the selected block's position. */
|
||||
void PickedPos_SetAsValid(PickedPos* pos, Int32 x, Int32 y, Int32 z,
|
||||
Vector3 min, Vector3 max, BlockID block, Vector3 intersect);
|
||||
/* Implements a voxel ray tracer
|
||||
http://www.xnawiki.com/index.php/Voxel_traversal
|
||||
https://web.archive.org/web/20120113051728/http://www.xnawiki.com/index.php?title=Voxel_traversal
|
||||
|
||||
Implementation based on: "A Fast Voxel Traversal Algorithm for Ray Tracing"
|
||||
John Amanatides, Andrew Woo
|
||||
http://www.cse.yorku.ca/~amana/research/grid.pdf
|
||||
http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf
|
||||
*/
|
||||
typedef struct RayTracer_ {
|
||||
Int32 X, Y, Z;
|
||||
Vector3 Origin, Dir;
|
||||
Vector3 Min, Max; /* Block data */
|
||||
BlockID Block; /* Block data */
|
||||
Vector3I step;
|
||||
Vector3 tMax, tDelta;
|
||||
} RayTracer;
|
||||
|
||||
/* Mark as having a selected block, and calculates the closest face of the selected block's position. */
|
||||
void PickedPos_SetAsValid(PickedPos* pos, RayTracer* t, Vector3 intersect);
|
||||
/* Marks as not having a selected block. */
|
||||
void PickedPos_SetAsInvalid(PickedPos* pos);
|
||||
void RayTracer_SetVectors(RayTracer* t, Vector3 origin, Vector3 dir);
|
||||
void RayTracer_Step(RayTracer* t);
|
||||
|
||||
/* Determines the picked block based on the given origin and direction vector.
|
||||
Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
|
||||
or not being able to find a suitable candiate within the given reach distance.*/
|
||||
void Picking_CalculatePickedBlock(Vector3 origin, Vector3 dir, Real32 reach, PickedPos* pos);
|
||||
|
||||
void Picking_ClipCameraPos(Vector3 origin, Vector3 dir, Real32 reach, PickedPos* pos);
|
||||
#endif
|
@ -12,6 +12,15 @@ void Atlas2D_UpdateState(Bitmap bmp) {
|
||||
Block_RecalculateSpriteBB();
|
||||
}
|
||||
|
||||
Int32 Atlas2D_LoadTextureElement_Raw(TextureLoc texLoc, Bitmap* element) {
|
||||
Int32 size = Atlas2D_ElementSize;
|
||||
Int32 x = texLoc % Atlas2D_ElementsPerRow, y = texLoc / Atlas2D_ElementsPerRow;
|
||||
Bitmap_CopyBlock(x * size, y * size, 0, 0,
|
||||
&Atlas2D_Bitmap, element, size);
|
||||
|
||||
return Gfx_CreateTexture(element, true, Gfx_Mipmaps);
|
||||
}
|
||||
|
||||
Int32 Atlas2D_LoadTextureElement(TextureLoc texLoc) {
|
||||
Int32 size = Atlas2D_ElementSize;
|
||||
Bitmap element;
|
||||
@ -34,15 +43,6 @@ Int32 Atlas2D_LoadTextureElement(TextureLoc texLoc) {
|
||||
}
|
||||
}
|
||||
|
||||
Int32 Atlas2D_LoadTextureElement_Raw(TextureLoc texLoc, Bitmap* element) {
|
||||
Int32 size = Atlas2D_ElementSize;
|
||||
Int32 x = texLoc % Atlas2D_ElementsPerRow, y = texLoc / Atlas2D_ElementsPerRow;
|
||||
Bitmap_CopyBlock(x * size, y * size, 0, 0,
|
||||
&Atlas2D_Bitmap, element, size);
|
||||
|
||||
return Gfx_CreateTexture(element, true, Gfx_Mipmaps);
|
||||
}
|
||||
|
||||
void Atlas2D_Free(void) {
|
||||
if (Atlas2D_Bitmap.Scan0 == NULL) return;
|
||||
Platform_MemFree(Atlas2D_Bitmap.Scan0);
|
||||
|
@ -37,17 +37,6 @@ void WeatherRenderer_InitHeightmap(void) {
|
||||
}
|
||||
}
|
||||
|
||||
Real32 WeatherRenderer_RainHeight(Int32 x, Int32 z) {
|
||||
if (x < 0 || z < 0 || x >= World_Width || z >= World_Length) {
|
||||
return (Real32)WorldEnv_EdgeHeight;
|
||||
}
|
||||
Int32 index = (x * World_Length) + z;
|
||||
Int32 height = weather_heightmap[index];
|
||||
|
||||
Int32 y = height == Int16_MaxValue ? WeatherRenderer_CalcHeightAt(x, World_MaxY, z, index) : height;
|
||||
return y == -1 ? 0 : y + Block_MaxBB[World_GetBlock(x, y, z)].Y;
|
||||
}
|
||||
|
||||
Int32 WeatherRenderer_CalcHeightAt(Int32 x, Int32 maxY, Int32 z, Int32 index) {
|
||||
Int32 mapIndex = (maxY * World_Length + z) * World_Width + x;
|
||||
Int32 y = maxY;
|
||||
@ -63,6 +52,17 @@ Int32 WeatherRenderer_CalcHeightAt(Int32 x, Int32 maxY, Int32 z, Int32 index) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Real32 WeatherRenderer_RainHeight(Int32 x, Int32 z) {
|
||||
if (x < 0 || z < 0 || x >= World_Width || z >= World_Length) {
|
||||
return (Real32)WorldEnv_EdgeHeight;
|
||||
}
|
||||
Int32 index = (x * World_Length) + z;
|
||||
Int32 height = weather_heightmap[index];
|
||||
|
||||
Int32 y = height == Int16_MaxValue ? WeatherRenderer_CalcHeightAt(x, World_MaxY, z, index) : height;
|
||||
return y == -1 ? 0 : y + Block_MaxBB[World_GetBlock(x, y, z)].Y;
|
||||
}
|
||||
|
||||
void WeatherRenderer_OnBlockChanged(Int32 x, Int32 y, Int32 z, BlockID oldBlock, BlockID newBlock) {
|
||||
bool didBlock = !(Block_Draw[oldBlock] == DrawType_Gas || Block_Draw[oldBlock] == DrawType_Sprite);
|
||||
bool nowBlock = !(Block_Draw[newBlock] == DrawType_Gas || Block_Draw[newBlock] == DrawType_Sprite);
|
||||
@ -93,6 +93,12 @@ void WeatherRenderer_ContextRecreated(void) {
|
||||
weather_vb = Gfx_CreateDynamicVb(VertexFormat_P3fT2fC4b, weather_verticesCount);
|
||||
}
|
||||
|
||||
Real32 WeatherRenderer_AlphaAt(Real32 x) {
|
||||
/* Wolfram Alpha: fit {0,178},{1,169},{4,147},{9,114},{16,59},{25,9} */
|
||||
Real32 falloff = 0.05f * x * x - 7 * x;
|
||||
return 178 + falloff * WorldEnv_WeatherFade;
|
||||
}
|
||||
|
||||
void WeatherRenderer_Render(Real64 deltaTime) {
|
||||
Weather weather = WorldEnv_Weather;
|
||||
if (weather == Weather_Sunny) return;
|
||||
@ -127,10 +133,12 @@ void WeatherRenderer_Render(Real64 deltaTime) {
|
||||
Real32 height = pos.Y - y;
|
||||
if (height <= 0) continue;
|
||||
|
||||
if (particles && (weather_accumulator >= 0.25 || moved))
|
||||
if (particles && (weather_accumulator >= 0.25 || moved)) {
|
||||
ParticleManager_AddRainParticle(x, y, z);
|
||||
}
|
||||
|
||||
Real32 alpha = WeatherRenderer_AlphaAt(dx * dx + dz * dz);
|
||||
Real32 dist = (Real32)dx * (Real32)dx + (Real32)dz * (Real32)dz;
|
||||
Real32 alpha = WeatherRenderer_AlphaAt(dist);
|
||||
/* Clamp between 0 and 255 */
|
||||
alpha = alpha < 0.0f ? 0.0f : alpha;
|
||||
alpha = alpha > 255.0f ? 255.0f : alpha;
|
||||
@ -180,12 +188,6 @@ void WeatherRenderer_Render(Real64 deltaTime) {
|
||||
Gfx_SetAlphaTest(false);
|
||||
}
|
||||
|
||||
Real32 WeatherRenderer_AlphaAt(Real32 x) {
|
||||
/* Wolfram Alpha: fit {0,178},{1,169},{4,147},{9,114},{16,59},{25,9} */
|
||||
Real32 falloff = 0.05f * x * x - 7 * x;
|
||||
return 178 + falloff * WorldEnv_WeatherFade;
|
||||
}
|
||||
|
||||
void WeatherRenderer_FileChanged(Stream* stream) {
|
||||
String snow = String_FromConstant("snow.png");
|
||||
String rain = String_FromConstant("rain.png");
|
||||
|
Loading…
x
Reference in New Issue
Block a user