mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 01:55:19 -04:00
Refactor physics some more, also fix bug with terrain atlas sometimes causing crash. More work on occlusion, still broken.
This commit is contained in:
parent
2674cabfaa
commit
f99a01cba9
@ -19,7 +19,7 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<BaseAddress>4194304</BaseAddress>
|
||||
<RegisterForComInterop>False</RegisterForComInterop>
|
||||
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
|
||||
@ -108,6 +108,7 @@
|
||||
<Compile Include="Entities\Particles\Particle.cs" />
|
||||
<Compile Include="Entities\Particles\ParticleManager.cs" />
|
||||
<Compile Include="Entities\Particles\TerrainParticle.cs" />
|
||||
<Compile Include="Entities\PhysicsEntity.cs" />
|
||||
<Compile Include="Entities\Player.cs" />
|
||||
<Compile Include="Entities\Player.Rendering.cs" />
|
||||
<Compile Include="Game\ChatLog.cs" />
|
||||
@ -159,12 +160,12 @@
|
||||
<Compile Include="Commands\CommandManager.cs" />
|
||||
<Compile Include="Commands\CommandReader.cs" />
|
||||
<Compile Include="Physics\BoundingBox.cs" />
|
||||
<Compile Include="Physics\Entity.Physics.cs" />
|
||||
<Compile Include="Physics\IntersectionUtils.cs" />
|
||||
<Compile Include="Physics\Picking.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Rendering\EnvRenderer.cs" />
|
||||
<Compile Include="Rendering\MapRenderer.Occlusion.cs" />
|
||||
<Compile Include="Rendering\MapRenderer.Rendering.cs" />
|
||||
<Compile Include="Rendering\MinimalEnvRenderer.cs" />
|
||||
<Compile Include="Rendering\FrustumCulling.cs" />
|
||||
|
@ -4,7 +4,7 @@ using OpenTK;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
public abstract partial class Entity {
|
||||
public abstract class Entity {
|
||||
|
||||
public Entity( Game game ) {
|
||||
map = game.Map;
|
||||
@ -19,6 +19,8 @@ namespace ClassicalSharp {
|
||||
public Vector3 Velocity;
|
||||
public float YawDegrees, PitchDegrees;
|
||||
protected float StepSize;
|
||||
protected Map map;
|
||||
protected BlockInfo info;
|
||||
|
||||
public float YawRadians {
|
||||
get { return YawDegrees * Utils.Deg2Rad; }
|
||||
@ -87,5 +89,7 @@ namespace ClassicalSharp {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public const float Adjustment = 0.001f;
|
||||
}
|
||||
}
|
@ -143,7 +143,7 @@ namespace ClassicalSharp {
|
||||
const float liquidGrav = 0.02f, ropeGrav = 0.034f, normalGrav = 0.08f;
|
||||
|
||||
void PhysicsTick( float xMoving, float zMoving ) {
|
||||
float multiply = flying ? ( speeding ? 90 : 15 ) : ( speeding ? 10 : 1 );
|
||||
float multiply = flying ? (speeding ? 90 : 15) : (speeding ? 10 : 1);
|
||||
float modifier = LowestSpeedModifier();
|
||||
multiply *= modifier;
|
||||
|
||||
@ -155,7 +155,7 @@ namespace ClassicalSharp {
|
||||
Move( xMoving, zMoving, 0.02f * 1.7f, ropeDrag, ropeGrav, 1 );
|
||||
} else {
|
||||
float factor = !flying && onGround ? 0.1f : 0.02f;
|
||||
float yMul = modifier * Math.Max( 1, multiply / 5f );
|
||||
float yMul = multiply == 1 ? 1 : multiply / 5f;
|
||||
float gravity = useLiquidGravity ? liquidGrav : normalGrav;
|
||||
Move( xMoving, zMoving, factor * multiply, normalDrag, gravity, yMul );
|
||||
|
||||
|
@ -4,12 +4,11 @@ using OpenTK;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
public partial class Entity {
|
||||
public abstract class PhysicsEntity : Entity {
|
||||
|
||||
public PhysicsEntity( Game game ) : base( game ) {
|
||||
}
|
||||
protected bool onGround, collideX, collideY, collideZ;
|
||||
protected Map map;
|
||||
protected BlockInfo info;
|
||||
public const float Adjustment = 0.001f;
|
||||
|
||||
protected byte GetPhysicsBlockId( int x, int y, int z ) {
|
||||
if( x < 0 || x >= map.Width || z < 0 || z >= map.Length || y < 0 ) return (byte)Block.Bedrock;
|
||||
@ -45,6 +44,7 @@ namespace ClassicalSharp {
|
||||
return x.tSquared.CompareTo( y.tSquared );
|
||||
}
|
||||
}
|
||||
|
||||
static StateComparer comparer = new StateComparer();
|
||||
protected void MoveAndWallSlide() {
|
||||
if( Velocity == Vector3.Zero )
|
||||
@ -77,7 +77,7 @@ namespace ClassicalSharp {
|
||||
Vector3I min = Vector3I.Floor( entityExtentBB.Min );
|
||||
Vector3I max = Vector3I.Floor( entityExtentBB.Max );
|
||||
|
||||
int elements = ( max.X + 1 - min.X ) * ( max.Y + 1 - min.Y ) * ( max.Z + 1 - min.Z );
|
||||
int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z);
|
||||
if( elements > stateCache.Length ) {
|
||||
stateCache = new State[elements];
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenTK;
|
||||
using ClassicalSharp.Network;
|
||||
using ClassicalSharp.Model;
|
||||
using ClassicalSharp.Renderers;
|
||||
using OpenTK;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
public abstract partial class Player : Entity {
|
||||
public abstract partial class Player : PhysicsEntity {
|
||||
|
||||
/// <summary> Gets the position of the player's eye in the world. </summary>
|
||||
public Vector3 EyePosition {
|
||||
@ -36,9 +34,8 @@ namespace ClassicalSharp {
|
||||
}
|
||||
|
||||
Block GetBlock( Vector3 coords ) {
|
||||
Vector3I blockCoords = Vector3I.Floor( coords );
|
||||
return map.IsValidPos( blockCoords ) ?
|
||||
(Block)map.GetBlock( blockCoords ) : Block.Air;
|
||||
Vector3I p = Vector3I.Floor( coords );
|
||||
return (Block)map.SafeGetBlock( p.X, p.Y, p.Z );
|
||||
}
|
||||
|
||||
public abstract void Tick( double delta );
|
||||
|
@ -246,6 +246,7 @@ namespace ClassicalSharp.GraphicsAPI {
|
||||
LoadIdentityMatrix();
|
||||
AlphaBlending = true;
|
||||
if( setFog ) Fog = false;
|
||||
//OpenTK.Graphics.OpenGL.GL.PolygonMode( 0x0408, 0x1B02 );
|
||||
}
|
||||
|
||||
protected virtual void LoadOrthoMatrix( float width, float height ) {
|
||||
@ -262,6 +263,7 @@ namespace ClassicalSharp.GraphicsAPI {
|
||||
DepthTest = true;
|
||||
AlphaBlending = false;
|
||||
if( setFog ) Fog = true;
|
||||
//OpenTK.Graphics.OpenGL.GL.PolygonMode( 0x0408, 0x1B01 );
|
||||
}
|
||||
|
||||
internal unsafe int MakeDefaultIb() {
|
||||
|
195
ClassicalSharp/Rendering/MapRenderer.Occlusion.cs
Normal file
195
ClassicalSharp/Rendering/MapRenderer.Occlusion.cs
Normal file
@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using ClassicalSharp.GraphicsAPI;
|
||||
using OpenTK;
|
||||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
public partial class MapRenderer : IDisposable {
|
||||
|
||||
void SimpleOcclusionCulling() { // TODO: broken
|
||||
Vector3 p = game.LocalPlayer.EyePosition;
|
||||
Vector3I chunkLoc = Vector3I.Floor( p );
|
||||
Utils.Clamp( ref chunkLoc.X, 0, game.Map.Width - 1 );
|
||||
Utils.Clamp( ref chunkLoc.Y, 0, game.Map.Height - 1 );
|
||||
Utils.Clamp( ref chunkLoc.Z, 0, game.Map.Length- 1 );
|
||||
|
||||
int cx = chunkLoc.X >> 4;
|
||||
int cy = chunkLoc.Y >> 4;
|
||||
int cz = chunkLoc.Z >> 4;
|
||||
|
||||
ChunkInfo chunkIn = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
byte chunkInFlags = chunkIn.OcclusionFlags;
|
||||
chunkIn.OcclusionFlags = 0;
|
||||
|
||||
ChunkQueue queue = new ChunkQueue( chunksX * chunksY * chunksZ );
|
||||
for( int i = 0; i < chunks.Length; i++ ) {
|
||||
chunks[i].Visited = false;
|
||||
chunks[i].Occluded = false;
|
||||
chunks[i].VisibilityFlags = 0;
|
||||
}
|
||||
|
||||
chunkIn.Visited = true;
|
||||
QueueChunk( cx - 1, cy, cz, queue );
|
||||
QueueChunk( cx + 1, cy, cz, queue );
|
||||
QueueChunk( cx, cy - 1, cz, queue );
|
||||
QueueChunk( cx, cy + 1, cz, queue );
|
||||
QueueChunk( cx, cy, cz - 1, queue );
|
||||
QueueChunk( cx, cy, cz + 1, queue );
|
||||
|
||||
ProcessQueue( chunkIn, queue );
|
||||
chunkIn.OcclusionFlags = chunkInFlags;
|
||||
}
|
||||
|
||||
void ProcessQueue( ChunkInfo src, ChunkQueue queue ) {
|
||||
Vector3I p = new Vector3I( src.CentreX, src.CentreY, src.CentreZ );
|
||||
while( queue.Size > 0 ) {
|
||||
ChunkInfo chunk = queue.Dequeue();
|
||||
chunk.VisibilityFlags = chunk.OcclusionFlags;
|
||||
int x1 = chunk.CentreX - 8, x2 = chunk.CentreX + 8;
|
||||
int y1 = chunk.CentreY - 8, y2 = chunk.CentreY + 8;
|
||||
int z1 = chunk.CentreZ - 8, z2 = chunk.CentreZ + 8;
|
||||
int cx = chunk.CentreX >> 4;
|
||||
int cy = chunk.CentreY >> 4;
|
||||
int cz = chunk.CentreZ >> 4;
|
||||
|
||||
int xOffset, yOffset, zOffset;
|
||||
int dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
int dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
int dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
int distX, distY, distZ;
|
||||
|
||||
// X axis collisions
|
||||
int dxLeft = Math.Abs( x1 - p.X ), dxRight = Math.Abs( x2 - p.X );
|
||||
if( dxLeft < dxRight ) {
|
||||
distX = dxLeft * dxLeft + dy * dy + dz * dz; xOffset = -1;
|
||||
} else {
|
||||
distX = dxRight * dxRight + dy * dy + dz * dz; xOffset = 1;
|
||||
}
|
||||
|
||||
// Z axis collisions
|
||||
int dxFront = Math.Abs( z1 - p.Z ), dxBack = Math.Abs( z2 - p.Z );
|
||||
if( dxFront < dxBack ) {
|
||||
distZ = dx * dx + dy * dy + dxFront * dxFront; zOffset = -1;
|
||||
} else {
|
||||
distZ = dx * dx + dy * dy + dxBack * dxBack; zOffset = 1;
|
||||
}
|
||||
|
||||
// Y axis collisions
|
||||
int dxBottom = Math.Abs( y1 - p.Y ), dxTop = Math.Abs( y2 - p.Y );
|
||||
if( dxBottom < dxTop ) {
|
||||
distY = dx * dx + dxBottom * dxBottom + dz * dz; yOffset = -1;
|
||||
} else {
|
||||
distY = dx * dx + dxTop * dxTop + dz * dz; yOffset = 1;
|
||||
}
|
||||
|
||||
int distMin = Math.Min( distX, Math.Min( distY, distZ ) );
|
||||
bool occlude = true;
|
||||
byte flags = 0;
|
||||
if( distMin == distX )
|
||||
OccludeX( cx, cy, cz, xOffset, ref occlude, ref flags );
|
||||
if( distMin == distZ )
|
||||
OccludeZ( cx, cy, cz, zOffset, ref occlude, ref flags );
|
||||
if( distMin == distY )
|
||||
OccludeY( cx, cy, cz, yOffset, ref occlude, ref flags );
|
||||
|
||||
if( occlude )
|
||||
chunk.Occluded = true;
|
||||
chunk.VisibilityFlags = (byte)( flags | chunk.OcclusionFlags );
|
||||
QueueChunk( cx - 1, cy, cz, queue );
|
||||
QueueChunk( cx + 1, cy, cz, queue );
|
||||
QueueChunk( cx, cy, cz - 1, queue );
|
||||
QueueChunk( cx, cy, cz + 1, queue );
|
||||
QueueChunk( cx, cy - 1, cz, queue );
|
||||
QueueChunk( cx, cy + 1, cz, queue );
|
||||
}
|
||||
Console.WriteLine( "======================" );
|
||||
}
|
||||
|
||||
void OccludeX( int cx, int cy, int cz, int xOffset, ref bool occlude, ref byte flags ) {
|
||||
cx += xOffset;
|
||||
if( cx >= 0 && cx < chunksX ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 1) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void OccludeZ( int cx, int cy, int cz, int zOffset, ref bool occlude, ref byte flags ) {
|
||||
cz += zOffset;
|
||||
if( cz >= 0 && cz < chunksZ ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 2) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void OccludeY( int cx, int cy, int cz, int yOffset, ref bool occlude, ref byte flags ) {
|
||||
cy += yOffset;
|
||||
if( cy >= 0 && cy< chunksY ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 4) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 4;
|
||||
}
|
||||
}
|
||||
|
||||
static float DistToRecSquared( Vector3 p, int x1, int y1, int z1, int x2, int y2, int z2 ) {
|
||||
float dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
float dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
float dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
void QueueChunk( int cx, int cy, int cz, ChunkQueue queue ) {
|
||||
if( cx >= 0 && cy >= 0 && cz >= 0 && cx < chunksX && cy < chunksY && cz < chunksZ ) {
|
||||
ChunkInfo info = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( !info.Visited )
|
||||
queue.Enqueue( info );
|
||||
info.Visited = true;
|
||||
}
|
||||
}
|
||||
|
||||
class ChunkQueue {
|
||||
ChunkInfo[] array;
|
||||
int head, tail;
|
||||
public int Size;
|
||||
|
||||
public ChunkQueue( int capacity ) {
|
||||
array = new ChunkInfo[capacity];
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
Array.Clear( array, 0, Size );
|
||||
head = 0;
|
||||
tail = 0;
|
||||
Size = 0;
|
||||
}
|
||||
|
||||
public void Enqueue( ChunkInfo item ) {
|
||||
if( Size == array.Length )
|
||||
throw new InvalidOperationException( "Queue limit reached" );
|
||||
|
||||
array[tail] = item;
|
||||
tail = (tail + 1) % array.Length;
|
||||
Size++;
|
||||
}
|
||||
|
||||
public ChunkInfo Dequeue() {
|
||||
if( Size == 0 )
|
||||
throw new InvalidOperationException( "No elements left in queue" );
|
||||
|
||||
ChunkInfo item = array[head];
|
||||
array[head] = null;
|
||||
head = (head + 1) % array.Length;
|
||||
Size--;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace ClassicalSharp {
|
||||
void RenderNormalBatch( int batch ) {
|
||||
for( int i = 0; i < chunks.Length; i++ ) {
|
||||
ChunkInfo info = chunks[i];
|
||||
if( info.NormalParts == null || !info.Visible ) continue;
|
||||
if( info.NormalParts == null || !info.Visible || info.Occluded ) continue;
|
||||
|
||||
ChunkPartInfo part = info.NormalParts[batch];
|
||||
if( part.IndicesCount == 0 ) continue;
|
||||
@ -33,7 +33,7 @@ namespace ClassicalSharp {
|
||||
void RenderTranslucentBatch( int batch ) {
|
||||
for( int i = 0; i < chunks.Length; i++ ) {
|
||||
ChunkInfo info = chunks[i];
|
||||
if( info.TranslucentParts == null || !info.Visible ) continue;
|
||||
if( info.TranslucentParts == null || !info.Visible || info.Occluded ) continue;
|
||||
ChunkPartInfo part = info.TranslucentParts[batch];
|
||||
|
||||
if( part.IndicesCount == 0 ) continue;
|
||||
@ -45,7 +45,7 @@ namespace ClassicalSharp {
|
||||
void RenderTranslucentBatchDepthPass( int batch ) {
|
||||
for( int i = 0; i < chunks.Length; i++ ) {
|
||||
ChunkInfo info = chunks[i];
|
||||
if( info.TranslucentParts == null || !info.Visible ) continue;
|
||||
if( info.TranslucentParts == null || !info.Visible || info.Occluded ) continue;
|
||||
|
||||
ChunkPartInfo part = info.TranslucentParts[batch];
|
||||
if( part.IndicesCount == 0 ) continue;
|
||||
|
@ -11,8 +11,8 @@ namespace ClassicalSharp {
|
||||
class ChunkInfo {
|
||||
|
||||
public ushort CentreX, CentreY, CentreZ;
|
||||
public bool Visible = true;
|
||||
public bool Empty = false;
|
||||
public bool Visible = true, Occluded = false;
|
||||
public bool Visited = false, Empty = false;
|
||||
public bool DrawLeft, DrawRight, DrawFront, DrawBack, DrawBottom, DrawTop;
|
||||
public byte OcclusionFlags, VisibilityFlags;
|
||||
|
||||
@ -216,7 +216,6 @@ namespace ClassicalSharp {
|
||||
if( chunks == null ) return;
|
||||
UpdateSortOrder();
|
||||
UpdateChunks( deltaTime );
|
||||
//SimpleOcclusionCulling();
|
||||
|
||||
RenderNormal();
|
||||
game.MapEnvRenderer.Render( deltaTime );
|
||||
@ -255,6 +254,7 @@ namespace ClassicalSharp {
|
||||
info.DrawBottom = !(dY1 <= 0 && dY2 <= 0);
|
||||
info.DrawTop = !(dY1 >= 0 && dY2 >= 0);
|
||||
}
|
||||
//SimpleOcclusionCulling();
|
||||
}
|
||||
|
||||
int chunksTarget = 4;
|
||||
@ -332,141 +332,5 @@ namespace ClassicalSharp {
|
||||
api.AlphaBlending = false;
|
||||
api.Texturing = false;
|
||||
}
|
||||
|
||||
void SimpleOcclusionCulling() { // TODO: broken
|
||||
Vector3 p = game.LocalPlayer.EyePosition;
|
||||
Vector3I chunkLoc = Vector3I.Floor( p );
|
||||
ChunkInfo chunkIn = null;
|
||||
byte chunkInFlags = 0;
|
||||
// We have to pretend that the chunk the player is in does no occlusion
|
||||
// (because for example, only X15 may be filled while X0 is air)
|
||||
if( game.Map.IsValidPos( chunkLoc ) ) {
|
||||
int cx = chunkLoc.X >> 4;
|
||||
int cy = chunkLoc.Y >> 4;
|
||||
int cz = chunkLoc.Z >> 4;
|
||||
chunkIn = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
chunkInFlags = chunkIn.OcclusionFlags;
|
||||
chunkIn.OcclusionFlags = 0;
|
||||
}
|
||||
|
||||
for( int i = 0; i < chunks.Length; i++ ) {
|
||||
ChunkInfo chunk = chunks[i];
|
||||
chunk.VisibilityFlags = chunk.OcclusionFlags;
|
||||
int x1 = chunk.CentreX - 8, x2 = chunk.CentreX + 8;
|
||||
int y1 = chunk.CentreY - 8, y2 = chunk.CentreY + 8;
|
||||
int z1 = chunk.CentreZ - 8, z2 = chunk.CentreZ + 8;
|
||||
int xOffset = 0, yOffset = 0, zOffset = 0;
|
||||
float dx = 0, dy = 0, dz = 0;
|
||||
float distX, distY, distZ;
|
||||
|
||||
// TODO: two axes with same distance
|
||||
|
||||
// X axis collisions
|
||||
dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
|
||||
float dxLeft = Math.Max( x1 - p.X, Math.Max( 0, p.X - x1 ) );
|
||||
float dxRight = Math.Max( x2 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
if( dxLeft < dxRight ) {
|
||||
xOffset = -1;
|
||||
distX = dxLeft * dxLeft + dy * dy + dz * dz;
|
||||
} else {
|
||||
xOffset = 1;
|
||||
distX = dxRight * dxRight + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
// Z axis collisions
|
||||
dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
|
||||
float dxFront = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z1 ) );
|
||||
float dxBack = Math.Max( z2 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
if( dxFront < dxBack ) {
|
||||
zOffset = -1;
|
||||
distZ = dx * dx + dy * dy + dxFront * dxFront;
|
||||
} else {
|
||||
zOffset = 1;
|
||||
distZ = dx * dx + dy * dy + dxBack * dxBack;
|
||||
}
|
||||
|
||||
// Y axis collisions
|
||||
dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
|
||||
float dxBottom = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y1 ) );
|
||||
float dxTop = Math.Max( y2 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
if( dxBottom < dxTop ) {
|
||||
yOffset = -1;
|
||||
distY = dx * dx + dxBottom * dxBottom + dz * dz;
|
||||
} else {
|
||||
yOffset = 1;
|
||||
distY = dx * dx + dxTop * dxTop + dz * dz;
|
||||
}
|
||||
|
||||
int cx = chunk.CentreX >> 4;
|
||||
int cy = chunk.CentreY >> 4;
|
||||
int cz = chunk.CentreZ >> 4;
|
||||
float distMin = Math.Min( distX, Math.Min( distY, distZ ) );
|
||||
|
||||
bool occlude = true;
|
||||
byte flags = 0;
|
||||
if( Math.Abs( distMin - distX ) < 0.00001f )
|
||||
OccludeX( cx, cy, cz, xOffset, ref occlude, ref flags );
|
||||
if( Math.Abs( distMin - distZ ) < 0.00001f )
|
||||
OccludeZ( cx, cy, cz, zOffset, ref occlude, ref flags );
|
||||
if( Math.Abs( distMin - distY ) < 0.00001f )
|
||||
OccludeY( cx, cy, cz, yOffset, ref occlude, ref flags );
|
||||
|
||||
if( occlude ) {
|
||||
chunk.Visible = false;
|
||||
chunk.VisibilityFlags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
if( chunkIn != null ) {
|
||||
chunkIn.Visible = true;
|
||||
chunkIn.OcclusionFlags = chunkInFlags;
|
||||
}
|
||||
}
|
||||
|
||||
void OccludeX( int cx, int cy, int cz, int xOffset, ref bool occlude, ref byte flags ) {
|
||||
cx += xOffset;
|
||||
if( cx >= 0 && cx < chunksX ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 0x1) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
void OccludeZ( int cx, int cy, int cz, int zOffset, ref bool occlude, ref byte flags ) {
|
||||
cz += zOffset;
|
||||
if( cz >= 0 && cz < chunksZ ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 0x2) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
void OccludeY( int cx, int cy, int cz, int yOffset, ref bool occlude, ref byte flags ) {
|
||||
cy += yOffset;
|
||||
if( cy >= 0 && cy< chunksY ) {
|
||||
ChunkInfo neighbour = unsortedChunks[cx + chunksX * (cy + cz * chunksY)];
|
||||
if( (neighbour.VisibilityFlags & 0x4) == 0 )
|
||||
occlude = false;
|
||||
else
|
||||
flags |= 0x4;
|
||||
}
|
||||
}
|
||||
|
||||
static float DistToRecSquared( Vector3 p, int x1, int y1, int z1, int x2, int y2, int z2 ) {
|
||||
float dx = Math.Max( x1 - p.X, Math.Max( 0, p.X - x2 ) );
|
||||
float dy = Math.Max( y1 - p.Y, Math.Max( 0, p.Y - y2 ) );
|
||||
float dz = Math.Max( z1 - p.Z, Math.Max( 0, p.Z - z2 ) );
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ namespace ClassicalSharp {
|
||||
/// <summary> Represents a 2D packed texture atlas that has been converted into an array of 1D atlases. </summary>
|
||||
public sealed class TerrainAtlas1D : IDisposable {
|
||||
|
||||
int usedElementsPerAtlas1D;
|
||||
int elementsPerAtlas1D;
|
||||
internal int elementsPerBitmap;
|
||||
public float invElementSize;
|
||||
public int[] TexIds;
|
||||
@ -18,38 +18,39 @@ namespace ClassicalSharp {
|
||||
}
|
||||
|
||||
public TextureRec GetTexRec( int texId, int uCount, out int index ) {
|
||||
index = texId / usedElementsPerAtlas1D;
|
||||
int y = texId % usedElementsPerAtlas1D;
|
||||
index = texId / elementsPerAtlas1D;
|
||||
int y = texId % elementsPerAtlas1D;
|
||||
return new TextureRec( 0, y * invElementSize, uCount, invElementSize );
|
||||
}
|
||||
|
||||
public int Get1DIndex( int texId ) {
|
||||
return texId / usedElementsPerAtlas1D;
|
||||
return texId / elementsPerAtlas1D;
|
||||
}
|
||||
|
||||
public int Get1DRowId( int texId ) {
|
||||
return texId % usedElementsPerAtlas1D;
|
||||
return texId % elementsPerAtlas1D;
|
||||
}
|
||||
|
||||
public void UpdateState( TerrainAtlas2D atlas2D ) {
|
||||
int maxVerSize = Math.Min( 4096, graphics.MaxTextureDimensions );
|
||||
int verElements = maxVerSize / atlas2D.elementSize;
|
||||
int elemPerFullAtlas = maxVerSize / atlas2D.elementSize;
|
||||
int totalElements = TerrainAtlas2D.RowsCount * TerrainAtlas2D.ElementsPerRow;
|
||||
int elemSize = atlas2D.elementSize;
|
||||
|
||||
int atlasesCount = Utils.CeilDiv( totalElements, verElements );
|
||||
usedElementsPerAtlas1D = Math.Min( verElements, totalElements );
|
||||
int atlas1DHeight = Utils.NextPowerOf2( usedElementsPerAtlas1D * atlas2D.elementSize );
|
||||
int atlasesCount = Utils.CeilDiv( totalElements, elemPerFullAtlas );
|
||||
elementsPerAtlas1D = Math.Min( elemPerFullAtlas, totalElements );
|
||||
int atlas1DHeight = Utils.NextPowerOf2( elementsPerAtlas1D * elemSize );
|
||||
|
||||
int index = 0;
|
||||
TexIds = new int[atlasesCount];
|
||||
Utils.LogDebug( "Loaded new atlas: {0} bmps, {1} per bmp", atlasesCount, usedElementsPerAtlas1D );
|
||||
Utils.LogDebug( "Loaded new atlas: {0} bmps, {1} per bmp", atlasesCount, elementsPerAtlas1D );
|
||||
|
||||
using( FastBitmap atlas = new FastBitmap( atlas2D.AtlasBitmap, true ) ) {
|
||||
for( int i = 0; i < TexIds.Length; i++ ) {
|
||||
Bitmap atlas1d = new Bitmap( atlas2D.elementSize, atlas1DHeight );
|
||||
using( FastBitmap dst = new FastBitmap( atlas1d, true ) ) {
|
||||
for( int y_1D = 0; y_1D < usedElementsPerAtlas1D; y_1D++ ) {
|
||||
for( int y_1D = 0; y_1D < elementsPerAtlas1D; y_1D++ ) {
|
||||
if( index >= 256 ) break;
|
||||
int x = index & 0x0F;
|
||||
int y = index >> 4;
|
||||
FastBitmap.MovePortion( x * elemSize, y * elemSize, 0, y_1D * elemSize, atlas, dst, elemSize );
|
||||
|
@ -71,7 +71,7 @@ namespace ClassicalSharp {
|
||||
|
||||
/// <summary> Returns a pointer to the start of the y'th scanline. </summary>
|
||||
public int* GetRowPtr( int y ) {
|
||||
return (int*)( scan0Byte + ( y * Stride ) );
|
||||
return (int*)(scan0Byte + (y * Stride));
|
||||
}
|
||||
|
||||
public static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, FastBitmap dst, int size ) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user