Port Picking to C.

This commit is contained in:
UnknownShadow200 2017-09-12 16:22:18 +10:00
parent fb18b2fe6f
commit fccc7dad12
13 changed files with 335 additions and 135 deletions

View File

@ -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;

View File

@ -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" />

View File

@ -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>

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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");

View File

@ -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 */
}
}

View File

@ -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

View File

@ -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);

View File

@ -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");