delete old pp layer
This commit is contained in:
parent
254c6c4126
commit
5bbf007fec
@ -36,14 +36,14 @@ N_Host *N_AcquireHost(u16 listen_port)
|
|||||||
host->num_msg_assembler_lookup_bins = N_NumMsgAssemblerLookupBins;
|
host->num_msg_assembler_lookup_bins = N_NumMsgAssemblerLookupBins;
|
||||||
host->msg_assembler_lookup_bins = PushStructs(host->arena, N_MsgAssemblerLookupBin, host->num_msg_assembler_lookup_bins);
|
host->msg_assembler_lookup_bins = PushStructs(host->arena, N_MsgAssemblerLookupBin, host->num_msg_assembler_lookup_bins);
|
||||||
|
|
||||||
host->sock = P_AcquireSock(listen_port, Mebi(2), Mebi(2));
|
host->sock = PLT_AcquireSock(listen_port, Mebi(2), Mebi(2));
|
||||||
|
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
void N_ReleaseHost(N_Host *host)
|
void N_ReleaseHost(N_Host *host)
|
||||||
{
|
{
|
||||||
P_ReleaseSock(host->sock);
|
PLT_ReleaseSock(host->sock);
|
||||||
|
|
||||||
ReleaseBuddyCtx(host->buddy);
|
ReleaseBuddyCtx(host->buddy);
|
||||||
ReleaseArena(host->rcv_buffer_write->arena);
|
ReleaseArena(host->rcv_buffer_write->arena);
|
||||||
@ -56,18 +56,18 @@ void N_ReleaseHost(N_Host *host)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Channel
|
//~ Channel
|
||||||
|
|
||||||
u64 N_HashFromAddress(P_Address address)
|
u64 N_HashFromAddress(PLT_Address address)
|
||||||
{
|
{
|
||||||
return HashFnv64(Fnv64Basis, StringFromStruct(&address));
|
return HashFnv64(Fnv64Basis, StringFromStruct(&address));
|
||||||
}
|
}
|
||||||
|
|
||||||
N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address)
|
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address)
|
||||||
{
|
{
|
||||||
u64 hash = N_HashFromAddress(address);
|
u64 hash = N_HashFromAddress(address);
|
||||||
N_ChannelLookupBin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins];
|
N_ChannelLookupBin *bin = &host->channel_lookup_bins[hash % host->num_channel_lookup_bins];
|
||||||
for (N_Channel *channel = bin->first; channel; channel = channel->next_address_hash)
|
for (N_Channel *channel = bin->first; channel; channel = channel->next_address_hash)
|
||||||
{
|
{
|
||||||
if (channel->address_hash == hash && P_MatchAddress(channel->address, address))
|
if (channel->address_hash == hash && PLT_MatchAddress(channel->address, address))
|
||||||
{
|
{
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_i
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
N_Channel *N_AcquireChannel(N_Host *host, P_Address address)
|
N_Channel *N_AcquireChannel(N_Host *host, PLT_Address address)
|
||||||
{
|
{
|
||||||
N_ChannelId id = ZI;
|
N_ChannelId id = ZI;
|
||||||
N_Channel *channel;
|
N_Channel *channel;
|
||||||
@ -498,7 +498,7 @@ N_Cmd *N_PushCmd(N_Host *host)
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void N_Connect(N_Host *host, P_Address connect_address)
|
void N_Connect(N_Host *host, PLT_Address connect_address)
|
||||||
{
|
{
|
||||||
N_Channel *channel = N_ChannelFromAddress(host, connect_address);
|
N_Channel *channel = N_ChannelFromAddress(host, connect_address);
|
||||||
if (!channel->valid)
|
if (!channel->valid)
|
||||||
@ -550,11 +550,11 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
|||||||
N_RcvPacket *first_packet = 0;
|
N_RcvPacket *first_packet = 0;
|
||||||
N_RcvPacket *last_packet = 0;
|
N_RcvPacket *last_packet = 0;
|
||||||
{
|
{
|
||||||
P_Sock *sock = host->sock;
|
PLT_Sock *sock = host->sock;
|
||||||
P_SockReadResult result = ZI;
|
PLT_SockReadResult result = ZI;
|
||||||
while ((result = P_ReadSock(scratch.arena, sock)).valid)
|
while ((result = PLT_ReadSock(scratch.arena, sock)).valid)
|
||||||
{
|
{
|
||||||
P_Address address = result.address;
|
PLT_Address address = result.address;
|
||||||
String data = result.data;
|
String data = result.data;
|
||||||
if (data.len > 0)
|
if (data.len > 0)
|
||||||
{
|
{
|
||||||
@ -581,7 +581,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
|||||||
for (N_RcvPacket *packet = first_packet; packet; packet = packet->next)
|
for (N_RcvPacket *packet = first_packet; packet; packet = packet->next)
|
||||||
{
|
{
|
||||||
//struct sock *sock = packet->sock;
|
//struct sock *sock = packet->sock;
|
||||||
P_Address address = packet->address;
|
PLT_Address address = packet->address;
|
||||||
BB_Buff bb = BB_BuffFromString(packet->data);
|
BB_Buff bb = BB_BuffFromString(packet->data);
|
||||||
BB_Reader br = BB_ReaderFromBuff(&bb);
|
BB_Reader br = BB_ReaderFromBuff(&bb);
|
||||||
u32 magic = BB_ReadUBits(&br, 32); // TODO: implicitly encode magic into crc32
|
u32 magic = BB_ReadUBits(&br, 32); // TODO: implicitly encode magic into crc32
|
||||||
@ -634,7 +634,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
|||||||
// A foreign host is trying to connect to us
|
// A foreign host is trying to connect to us
|
||||||
if (!channel->valid)
|
if (!channel->valid)
|
||||||
{
|
{
|
||||||
LogInfoF("Host received conection attempt from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
|
LogInfoF("Host received conection attempt from %F", FmtString(PLT_StringFromAddress(scratch.arena, address)));
|
||||||
// TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect?
|
// TODO: Verify that some per-host uuid isn't present in a rolling window to prevent reconnects right after a disconnect?
|
||||||
channel = N_AcquireChannel(host, address);
|
channel = N_AcquireChannel(host, address);
|
||||||
}
|
}
|
||||||
@ -651,7 +651,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
|||||||
// We successfully connected to a foreign host and they are ready to receive messages
|
// We successfully connected to a foreign host and they are ready to receive messages
|
||||||
if (channel->valid && !channel->connected)
|
if (channel->valid && !channel->connected)
|
||||||
{
|
{
|
||||||
LogInfoF("Host received connection from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
|
LogInfoF("Host received connection from %F", FmtString(PLT_StringFromAddress(scratch.arena, address)));
|
||||||
N_Event *event = N_PushEvent(arena, &events);
|
N_Event *event = N_PushEvent(arena, &events);
|
||||||
event->kind = N_EventKind_ChannelOpened;
|
event->kind = N_EventKind_ChannelOpened;
|
||||||
event->channel_id = channel->id;
|
event->channel_id = channel->id;
|
||||||
@ -667,7 +667,7 @@ N_EventList N_BeginUpdate(Arena *arena, N_Host *host)
|
|||||||
// A foreign host disconnected from us
|
// A foreign host disconnected from us
|
||||||
if (channel->valid)
|
if (channel->valid)
|
||||||
{
|
{
|
||||||
LogInfoF("Host received disconnection from %F", FmtString(P_StringFromAddress(scratch.arena, address)));
|
LogInfoF("Host received disconnection from %F", FmtString(PLT_StringFromAddress(scratch.arena, address)));
|
||||||
N_Event *event = N_PushEvent(arena, &events);
|
N_Event *event = N_PushEvent(arena, &events);
|
||||||
event->kind = N_EventKind_ChannelClosed;
|
event->kind = N_EventKind_ChannelClosed;
|
||||||
event->channel_id = channel->id;
|
event->channel_id = channel->id;
|
||||||
@ -1014,22 +1014,22 @@ void N_EndUpdate(N_Host *host)
|
|||||||
{
|
{
|
||||||
for (u64 i = 0; i < host->num_channels_reserved; ++i)
|
for (u64 i = 0; i < host->num_channels_reserved; ++i)
|
||||||
{
|
{
|
||||||
P_Sock *sock = host->sock;
|
PLT_Sock *sock = host->sock;
|
||||||
N_Channel *channel = &host->channels[i];
|
N_Channel *channel = &host->channels[i];
|
||||||
u64 total_sent = 0;
|
u64 total_sent = 0;
|
||||||
if (channel->valid)
|
if (channel->valid)
|
||||||
{
|
{
|
||||||
P_Address address = channel->address;
|
PLT_Address address = channel->address;
|
||||||
// Send reliable packets to channel
|
// Send reliable packets to channel
|
||||||
for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next)
|
for (N_SndPacket *packet = channel->first_reliable_packet; packet; packet = packet->next)
|
||||||
{
|
{
|
||||||
P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
PLT_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
||||||
total_sent += packet->data_len;
|
total_sent += packet->data_len;
|
||||||
}
|
}
|
||||||
// Send unreliable packets to channel
|
// Send unreliable packets to channel
|
||||||
for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next)
|
for (N_SndPacket *packet = channel->first_unreliable_packet; packet; packet = packet->next)
|
||||||
{
|
{
|
||||||
P_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
PLT_WriteSock(sock, address, STRING(packet->data_len, packet->data));
|
||||||
total_sent += packet->data_len;
|
total_sent += packet->data_len;
|
||||||
}
|
}
|
||||||
// Release unreliable packets
|
// Release unreliable packets
|
||||||
|
|||||||
@ -106,8 +106,8 @@ Struct(N_SndPacket)
|
|||||||
|
|
||||||
Struct(N_RcvPacket)
|
Struct(N_RcvPacket)
|
||||||
{
|
{
|
||||||
P_Sock *sock;
|
PLT_Sock *sock;
|
||||||
P_Address address;
|
PLT_Address address;
|
||||||
String data;
|
String data;
|
||||||
N_RcvPacket *next;
|
N_RcvPacket *next;
|
||||||
};
|
};
|
||||||
@ -131,7 +131,7 @@ Struct(N_Channel)
|
|||||||
|
|
||||||
N_Channel *next_free;
|
N_Channel *next_free;
|
||||||
|
|
||||||
P_Address address;
|
PLT_Address address;
|
||||||
u64 address_hash;
|
u64 address_hash;
|
||||||
N_Channel *next_address_hash;
|
N_Channel *next_address_hash;
|
||||||
N_Channel *prev_address_hash;
|
N_Channel *prev_address_hash;
|
||||||
@ -222,7 +222,7 @@ Struct(N_Host)
|
|||||||
{
|
{
|
||||||
Arena *arena;
|
Arena *arena;
|
||||||
|
|
||||||
P_Sock *sock;
|
PLT_Sock *sock;
|
||||||
|
|
||||||
BuddyCtx *buddy; // For storing msg assembler data
|
BuddyCtx *buddy; // For storing msg assembler data
|
||||||
|
|
||||||
@ -274,11 +274,11 @@ void N_ReleaseHost(N_Host *host);
|
|||||||
#define N_MatchChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
|
#define N_MatchChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
|
||||||
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
|
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
|
||||||
|
|
||||||
u64 N_HashFromAddress(P_Address address);
|
u64 N_HashFromAddress(PLT_Address address);
|
||||||
N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address);
|
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address);
|
||||||
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
|
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
|
||||||
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
|
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
|
||||||
N_Channel *N_AcquireChannel(N_Host *host, P_Address address);
|
N_Channel *N_AcquireChannel(N_Host *host, PLT_Address address);
|
||||||
void N_ReleaseChannel(N_Channel *channel);
|
void N_ReleaseChannel(N_Channel *channel);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -301,7 +301,7 @@ N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
|
|||||||
//~ Host command
|
//~ Host command
|
||||||
|
|
||||||
N_Cmd *N_PushCmd(N_Host *host);
|
N_Cmd *N_PushCmd(N_Host *host);
|
||||||
void N_Connect(N_Host *host, P_Address connect_address);
|
void N_Connect(N_Host *host, PLT_Address connect_address);
|
||||||
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
|
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
|
||||||
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
|
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
|
||||||
|
|
||||||
|
|||||||
@ -1,26 +1,26 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Opaque types
|
//~ Opaque types
|
||||||
|
|
||||||
Struct(P_Watch);
|
Struct(PLT_Watch);
|
||||||
Struct(P_Sock);
|
Struct(PLT_Sock);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ File system types
|
//~ File system types
|
||||||
|
|
||||||
Struct(P_File)
|
Struct(PLT_File)
|
||||||
{
|
{
|
||||||
u64 handle;
|
u64 handle;
|
||||||
b32 valid;
|
b32 valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(P_FileTime)
|
Struct(PLT_FileTime)
|
||||||
{
|
{
|
||||||
DateTime created;
|
DateTime created;
|
||||||
DateTime accessed;
|
DateTime accessed;
|
||||||
DateTime modified;
|
DateTime modified;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(P_FileMap)
|
Struct(PLT_FileMap)
|
||||||
{
|
{
|
||||||
String mapped_memory;
|
String mapped_memory;
|
||||||
u64 handle;
|
u64 handle;
|
||||||
@ -30,16 +30,16 @@ Struct(P_FileMap)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Address types
|
//~ Address types
|
||||||
|
|
||||||
Enum(P_AddressFamily)
|
Enum(PLT_AddressFamily)
|
||||||
{
|
{
|
||||||
P_AddressFamily_Ipv4,
|
PLT_AddressFamily_Ipv4,
|
||||||
P_AddressFamily_Ipv6
|
PLT_AddressFamily_Ipv6
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(P_Address)
|
Struct(PLT_Address)
|
||||||
{
|
{
|
||||||
b32 valid;
|
b32 valid;
|
||||||
P_AddressFamily family;
|
PLT_AddressFamily family;
|
||||||
// NOTE: ipnb & portnb are stored in network byte order
|
// NOTE: ipnb & portnb are stored in network byte order
|
||||||
u8 ipnb[16];
|
u8 ipnb[16];
|
||||||
u16 portnb;
|
u16 portnb;
|
||||||
@ -48,28 +48,28 @@ Struct(P_Address)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Sock types
|
//~ Sock types
|
||||||
|
|
||||||
Struct(P_SockReadResult)
|
Struct(PLT_SockReadResult)
|
||||||
{
|
{
|
||||||
b32 valid; // Since data.len = 0 can be valid
|
b32 valid; // Since data.len = 0 can be valid
|
||||||
P_Address address;
|
PLT_Address address;
|
||||||
String data;
|
String data;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Message box types
|
//~ Message box types
|
||||||
|
|
||||||
Enum(P_MessageBoxKind)
|
Enum(PLT_MessageBoxKind)
|
||||||
{
|
{
|
||||||
P_MessageBoxKind_Ok,
|
PLT_MessageBoxKind_Ok,
|
||||||
P_MessageBoxKind_Warning,
|
PLT_MessageBoxKind_Warning,
|
||||||
P_MessageBoxKind_Error,
|
PLT_MessageBoxKind_Error,
|
||||||
P_MessageBoxKind_Fatal
|
PLT_MessageBoxKind_Fatal
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Bootstrap
|
//~ @hookdecl Bootstrap
|
||||||
|
|
||||||
void P_Bootstrap(void);
|
void PLT_Bootstrap(void);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl File system
|
//~ @hookdecl File system
|
||||||
@ -77,65 +77,65 @@ void P_Bootstrap(void);
|
|||||||
// NOTE: File paths use forward slash '/' as delimiter
|
// NOTE: File paths use forward slash '/' as delimiter
|
||||||
|
|
||||||
//- File system helpers
|
//- File system helpers
|
||||||
String P_GetWritePath(Arena *arena);
|
String PLT_GetWritePath(Arena *arena);
|
||||||
b32 P_IsFile(String path);
|
b32 PLT_IsFile(String path);
|
||||||
b32 P_IsDir(String path);
|
b32 PLT_IsDir(String path);
|
||||||
void P_MkDir(String path);
|
void PLT_MkDir(String path);
|
||||||
|
|
||||||
//- File creation
|
//- File creation
|
||||||
P_File P_OpenFileRead(String path);
|
PLT_File PLT_OpenFileRead(String path);
|
||||||
P_File P_OpenFileReadWait(String path); // Waits until file is not being used by another program
|
PLT_File PLT_OpenFileReadWait(String path); // Waits until file is not being used by another program
|
||||||
P_File P_OpenFileWrite(String path);
|
PLT_File PLT_OpenFileWrite(String path);
|
||||||
P_File P_OpenFileAppend(String path);
|
PLT_File PLT_OpenFileAppend(String path);
|
||||||
void P_CloseFile(P_File file);
|
void PLT_CloseFile(PLT_File file);
|
||||||
|
|
||||||
//- File data manipulation
|
//- File data manipulation
|
||||||
String P_ReadFile(Arena *arena, P_File file);
|
String PLT_ReadFile(Arena *arena, PLT_File file);
|
||||||
void P_WriteFile(P_File file, String data);
|
void PLT_WriteFile(PLT_File file, String data);
|
||||||
|
|
||||||
//- File info
|
//- File info
|
||||||
u64 P_GetFileSize(P_File file);
|
u64 PLT_GetFileSize(PLT_File file);
|
||||||
P_FileTime P_GetFileTime(P_File file);
|
PLT_FileTime PLT_GetFileTime(PLT_File file);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl File map
|
//~ @hookdecl File map
|
||||||
|
|
||||||
P_FileMap P_OpenFileMap(P_File file);
|
PLT_FileMap PLT_OpenFileMap(PLT_File file);
|
||||||
void P_CloseFileMap(P_FileMap map);
|
void PLT_CloseFileMap(PLT_FileMap map);
|
||||||
String P_GetFileMapData(P_FileMap map);
|
String PLT_GetFileMapData(PLT_FileMap map);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Address helpers
|
//~ @hookdecl Address helpers
|
||||||
|
|
||||||
P_Address P_AddressFromString(String str);
|
PLT_Address PLT_AddressFromString(String str);
|
||||||
P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr);
|
PLT_Address PLT_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr);
|
||||||
P_Address P_AddressFromPort(u16 port);
|
PLT_Address PLT_AddressFromPort(u16 port);
|
||||||
String P_StringFromAddress(Arena *arena, P_Address address);
|
String PLT_StringFromAddress(Arena *arena, PLT_Address address);
|
||||||
b32 P_MatchAddress(P_Address a, P_Address b);
|
b32 PLT_MatchAddress(PLT_Address a, PLT_Address b);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Socket
|
//~ @hookdecl Socket
|
||||||
|
|
||||||
P_Sock *P_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size);
|
PLT_Sock *PLT_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size);
|
||||||
void P_ReleaseSock(P_Sock *sock);
|
void PLT_ReleaseSock(PLT_Sock *sock);
|
||||||
P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock);
|
PLT_SockReadResult PLT_ReadSock(Arena *arena, PLT_Sock *sock);
|
||||||
void P_WriteSock(P_Sock *sock, P_Address address, String data);
|
void PLT_WriteSock(PLT_Sock *sock, PLT_Address address, String data);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Utils
|
//~ @hookdecl Utils
|
||||||
|
|
||||||
void P_MessageBox(P_MessageBoxKind kind, String message);
|
void PLT_MessageBox(PLT_MessageBoxKind kind, String message);
|
||||||
void P_SetClipboardText(String str);
|
void PLT_SetClipboardText(String str);
|
||||||
String P_GetClipboardText(Arena *arena);
|
String PLT_GetClipboardText(Arena *arena);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Timer
|
//~ @hookdecl Timer
|
||||||
|
|
||||||
Fence *P_GetTimerFence(void);
|
Fence *PLT_GetTimerFence(void);
|
||||||
i64 P_GetCurrentTimerPeriodNs(void);
|
i64 PLT_GetCurrentTimerPeriodNs(void);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookdecl Sleep
|
//~ @hookdecl Sleep
|
||||||
|
|
||||||
void P_SleepPrecise(i64 sleep_time_ns);
|
void PLT_SleepPrecise(i64 sleep_time_ns);
|
||||||
void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns);
|
void PLT_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
@IncludeC platform.h
|
@IncludeC platform.h
|
||||||
|
|
||||||
@Bootstrap P_Bootstrap
|
@Bootstrap PLT_Bootstrap
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Impl
|
//- Impl
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
P_W32_Ctx P_W32 = Zi;
|
PLT_W32_Ctx PLT_W32 = Zi;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Bootstrap
|
//~ @hookimpl Bootstrap
|
||||||
|
|
||||||
void P_Bootstrap(void)
|
void PLT_Bootstrap(void)
|
||||||
{
|
{
|
||||||
//- Init watches pool
|
//- Init watches pool
|
||||||
P_W32.watches_arena = AcquireArena(Gibi(64));
|
PLT_W32.watches_arena = AcquireArena(Gibi(64));
|
||||||
|
|
||||||
// Init winsock
|
// Init winsock
|
||||||
WSAStartup(MAKEWORD(2, 2), &P_W32.wsa_data);
|
WSAStartup(MAKEWORD(2, 2), &PLT_W32.wsa_data);
|
||||||
P_W32.socks_arena = AcquireArena(Gibi(64));
|
PLT_W32.socks_arena = AcquireArena(Gibi(64));
|
||||||
|
|
||||||
// Init timer
|
// Init timer
|
||||||
DispatchWave(Lit("Win32 timer sync"), 1, P_W32_SyncTimerForever, 0);
|
DispatchWave(Lit("Win32 timer sync"), 1, PLT_W32_SyncTimerForever, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Time
|
//~ Time
|
||||||
|
|
||||||
DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st)
|
DateTime PLT_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st)
|
||||||
{
|
{
|
||||||
return (DateTime)
|
return (DateTime)
|
||||||
{
|
{
|
||||||
@ -37,7 +37,7 @@ DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ File system
|
//~ File system
|
||||||
|
|
||||||
String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src)
|
String PLT_W32_StringFromWin32Path(Arena *arena, wchar_t *src)
|
||||||
{
|
{
|
||||||
String result = Zi;
|
String result = Zi;
|
||||||
result.text = ArenaNext(arena, u8);
|
result.text = ArenaNext(arena, u8);
|
||||||
@ -65,10 +65,10 @@ String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Address
|
//~ Address
|
||||||
|
|
||||||
P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr)
|
PLT_W32_Address PLT_W32_Win32AddressFromPlatformAddress(PLT_Address addr)
|
||||||
{
|
{
|
||||||
P_W32_Address result = Zi;
|
PLT_W32_Address result = Zi;
|
||||||
if (addr.family == P_AddressFamily_Ipv4)
|
if (addr.family == PLT_AddressFamily_Ipv4)
|
||||||
{
|
{
|
||||||
result.family = AF_INET;
|
result.family = AF_INET;
|
||||||
result.size = sizeof(struct sockaddr_in);
|
result.size = sizeof(struct sockaddr_in);
|
||||||
@ -88,7 +88,7 @@ P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If supplied address has ip INADDR_ANY (0), convert ip to localhost
|
// If supplied address has ip INADDR_ANY (0), convert ip to localhost
|
||||||
P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr)
|
PLT_W32_Address PLT_W32_ConvertAnyaddrToLocalhost(PLT_W32_Address addr)
|
||||||
{
|
{
|
||||||
if (addr.family == AF_INET)
|
if (addr.family == AF_INET)
|
||||||
{
|
{
|
||||||
@ -128,19 +128,19 @@ P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr)
|
|||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr)
|
PLT_Address PLT_W32_PlatformAddressFromWin32Address(PLT_W32_Address ws_addr)
|
||||||
{
|
{
|
||||||
P_Address result = Zi;
|
PLT_Address result = Zi;
|
||||||
if (ws_addr.family == AF_INET)
|
if (ws_addr.family == AF_INET)
|
||||||
{
|
{
|
||||||
result.family = P_AddressFamily_Ipv4;
|
result.family = PLT_AddressFamily_Ipv4;
|
||||||
result.portnb = ws_addr.sin.sin_port;
|
result.portnb = ws_addr.sin.sin_port;
|
||||||
CopyBytes(result.ipnb, &ws_addr.sin.sin_addr, 4);
|
CopyBytes(result.ipnb, &ws_addr.sin.sin_addr, 4);
|
||||||
result.valid = 1;
|
result.valid = 1;
|
||||||
}
|
}
|
||||||
else if (ws_addr.family == AF_INET6)
|
else if (ws_addr.family == AF_INET6)
|
||||||
{
|
{
|
||||||
result.family = P_AddressFamily_Ipv6;
|
result.family = PLT_AddressFamily_Ipv6;
|
||||||
result.portnb = ws_addr.sin6.sin6_port;
|
result.portnb = ws_addr.sin6.sin6_port;
|
||||||
CopyBytes(result.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16);
|
CopyBytes(result.ipnb, &ws_addr.sin6.sin6_addr.s6_addr, 16);
|
||||||
result.valid = 1;
|
result.valid = 1;
|
||||||
@ -151,7 +151,7 @@ P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Timer job
|
//~ Timer job
|
||||||
|
|
||||||
void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
void PLT_W32_SyncTimerForever(WaveLaneCtx *lane)
|
||||||
{
|
{
|
||||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
|
||||||
|
|
||||||
@ -163,10 +163,10 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
|
|
||||||
i32 periods_index = 0;
|
i32 periods_index = 0;
|
||||||
i64 periods[P_W32_NumRollingTimerPeriods] = Zi;
|
i64 periods[PLT_W32_NumRollingTimerPeriods] = Zi;
|
||||||
for (i32 i = 0; i < (i32)countof(periods); ++i)
|
for (i32 i = 0; i < (i32)countof(periods); ++i)
|
||||||
{
|
{
|
||||||
periods[i] = P_W32_DefaultTimerPeriodNs;
|
periods[i] = PLT_W32_DefaultTimerPeriodNs;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 last_cycle_ns = 0;
|
i64 last_cycle_ns = 0;
|
||||||
@ -185,7 +185,7 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
|||||||
WaitForSingleObject(timer, INFINITE);
|
WaitForSingleObject(timer, INFINITE);
|
||||||
}
|
}
|
||||||
i64 now_ns = TimeNs();
|
i64 now_ns = TimeNs();
|
||||||
i64 period_ns = last_cycle_ns == 0 ? P_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns;
|
i64 period_ns = last_cycle_ns == 0 ? PLT_W32_DefaultTimerPeriodNs : now_ns - last_cycle_ns;
|
||||||
last_cycle_ns = now_ns;
|
last_cycle_ns = now_ns;
|
||||||
|
|
||||||
// Compute mean period
|
// Compute mean period
|
||||||
@ -201,18 +201,18 @@ void P_W32_SyncTimerForever(WaveLaneCtx *lane)
|
|||||||
periods_sum_ns += (f64)periods[i];
|
periods_sum_ns += (f64)periods[i];
|
||||||
}
|
}
|
||||||
f64 mean_ns = periods_sum_ns / (f64)countof(periods);
|
f64 mean_ns = periods_sum_ns / (f64)countof(periods);
|
||||||
Atomic64Set(&P_W32.average_timer_period_ns.v, RoundF64(mean_ns));
|
Atomic64Set(&PLT_W32.average_timer_period_ns.v, RoundF64(mean_ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update fence
|
// Update fence
|
||||||
SetFence(&P_W32.timer_fence, now_ns);
|
SetFence(&PLT_W32.timer_fence, now_ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl File system
|
//~ @hookimpl File system
|
||||||
|
|
||||||
String P_GetWritePath(Arena *arena)
|
String PLT_GetWritePath(Arena *arena)
|
||||||
{
|
{
|
||||||
u16 *p = 0;
|
u16 *p = 0;
|
||||||
// TODO: cache this?
|
// TODO: cache this?
|
||||||
@ -225,13 +225,13 @@ String P_GetWritePath(Arena *arena)
|
|||||||
String path = Zi;
|
String path = Zi;
|
||||||
if (result == S_OK)
|
if (result == S_OK)
|
||||||
{
|
{
|
||||||
path = P_W32_StringFromWin32Path(arena, p);
|
path = PLT_W32_StringFromWin32Path(arena, p);
|
||||||
}
|
}
|
||||||
CoTaskMemFree(p);
|
CoTaskMemFree(p);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 P_IsFile(String path)
|
b32 PLT_IsFile(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
@ -240,7 +240,7 @@ b32 P_IsFile(String path)
|
|||||||
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 P_IsDir(String path)
|
b32 PLT_IsDir(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
@ -249,7 +249,7 @@ b32 P_IsDir(String path)
|
|||||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_MkDir(String path)
|
void PLT_MkDir(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
@ -292,10 +292,10 @@ void P_MkDir(String path)
|
|||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
P_File P_OpenFileRead(String path)
|
PLT_File PLT_OpenFileRead(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
P_File file = Zi;
|
PLT_File file = Zi;
|
||||||
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
HANDLE handle = CreateFileW(
|
HANDLE handle = CreateFileW(
|
||||||
@ -314,10 +314,10 @@ P_File P_OpenFileRead(String path)
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_File P_OpenFileReadWait(String path)
|
PLT_File PLT_OpenFileReadWait(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
P_File file = Zi;
|
PLT_File file = Zi;
|
||||||
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
i32 delay_ms = 1;
|
i32 delay_ms = 1;
|
||||||
@ -344,10 +344,10 @@ P_File P_OpenFileReadWait(String path)
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_File P_OpenFileWrite(String path)
|
PLT_File PLT_OpenFileWrite(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
P_File file = Zi;
|
PLT_File file = Zi;
|
||||||
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
HANDLE handle = CreateFileW(
|
HANDLE handle = CreateFileW(
|
||||||
@ -366,10 +366,10 @@ P_File P_OpenFileWrite(String path)
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_File P_OpenFileAppend(String path)
|
PLT_File PLT_OpenFileAppend(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
P_File file = Zi;
|
PLT_File file = Zi;
|
||||||
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
HANDLE handle = CreateFileW(
|
HANDLE handle = CreateFileW(
|
||||||
@ -388,7 +388,7 @@ P_File P_OpenFileAppend(String path)
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_CloseFile(P_File file)
|
void PLT_CloseFile(PLT_File file)
|
||||||
{
|
{
|
||||||
if (file.handle)
|
if (file.handle)
|
||||||
{
|
{
|
||||||
@ -396,7 +396,7 @@ void P_CloseFile(P_File file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String P_ReadFile(Arena *arena, P_File file)
|
String PLT_ReadFile(Arena *arena, PLT_File file)
|
||||||
{
|
{
|
||||||
i64 size = 0;
|
i64 size = 0;
|
||||||
GetFileSizeEx((HANDLE)file.handle, (PLARGE_INTEGER)&size);
|
GetFileSizeEx((HANDLE)file.handle, (PLARGE_INTEGER)&size);
|
||||||
@ -419,7 +419,7 @@ String P_ReadFile(Arena *arena, P_File file)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_WriteFile(P_File file, String data)
|
void PLT_WriteFile(PLT_File file, String data)
|
||||||
{
|
{
|
||||||
// TODO: Check what the real data limit is and chunk sequentially based on
|
// TODO: Check what the real data limit is and chunk sequentially based on
|
||||||
// that (rather than failing)
|
// that (rather than failing)
|
||||||
@ -444,14 +444,14 @@ void P_WriteFile(P_File file, String data)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 P_GetFileSize(P_File file)
|
u64 PLT_GetFileSize(PLT_File file)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER li_file_size;
|
LARGE_INTEGER li_file_size;
|
||||||
GetFileSizeEx((HANDLE)file.handle, &li_file_size);
|
GetFileSizeEx((HANDLE)file.handle, &li_file_size);
|
||||||
return (u64)(li_file_size.QuadPart > 0 ? li_file_size.QuadPart : 0);
|
return (u64)(li_file_size.QuadPart > 0 ? li_file_size.QuadPart : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
P_FileTime P_GetFileTime(P_File file)
|
PLT_FileTime PLT_GetFileTime(PLT_File file)
|
||||||
{
|
{
|
||||||
// Get file times
|
// Get file times
|
||||||
FILETIME ft_created;
|
FILETIME ft_created;
|
||||||
@ -473,27 +473,27 @@ P_FileTime P_GetFileTime(P_File file)
|
|||||||
FileTimeToSystemTime(&ft_accessed, &st_accessed);
|
FileTimeToSystemTime(&ft_accessed, &st_accessed);
|
||||||
FileTimeToSystemTime(&ft_modified, &st_modified);
|
FileTimeToSystemTime(&ft_modified, &st_modified);
|
||||||
|
|
||||||
return (P_FileTime)
|
return (PLT_FileTime)
|
||||||
{
|
{
|
||||||
.created = P_W32_DateTimeFromWin32SystemTime(st_created),
|
.created = PLT_W32_DateTimeFromWin32SystemTime(st_created),
|
||||||
.accessed = P_W32_DateTimeFromWin32SystemTime(st_accessed),
|
.accessed = PLT_W32_DateTimeFromWin32SystemTime(st_accessed),
|
||||||
.modified = P_W32_DateTimeFromWin32SystemTime(st_modified)
|
.modified = PLT_W32_DateTimeFromWin32SystemTime(st_modified)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (P_FileTime) { 0 };
|
return (PLT_FileTime) { 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl File map
|
//~ @hookimpl File map
|
||||||
|
|
||||||
P_FileMap P_OpenFileMap(P_File file)
|
PLT_FileMap PLT_OpenFileMap(PLT_File file)
|
||||||
{
|
{
|
||||||
P_FileMap map = Zi;
|
PLT_FileMap map = Zi;
|
||||||
|
|
||||||
u64 size = P_GetFileSize(file);
|
u64 size = PLT_GetFileSize(file);
|
||||||
u8 *base_ptr = 0;
|
u8 *base_ptr = 0;
|
||||||
HANDLE map_handle = 0;
|
HANDLE map_handle = 0;
|
||||||
|
|
||||||
@ -536,7 +536,7 @@ P_FileMap P_OpenFileMap(P_File file)
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_CloseFileMap(P_FileMap map)
|
void PLT_CloseFileMap(PLT_FileMap map)
|
||||||
{
|
{
|
||||||
if (map.mapped_memory.text)
|
if (map.mapped_memory.text)
|
||||||
{
|
{
|
||||||
@ -548,7 +548,7 @@ void P_CloseFileMap(P_FileMap map)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String P_GetFileMapData(P_FileMap map)
|
String PLT_GetFileMapData(PLT_FileMap map)
|
||||||
{
|
{
|
||||||
return map.mapped_memory;
|
return map.mapped_memory;
|
||||||
}
|
}
|
||||||
@ -556,9 +556,9 @@ String P_GetFileMapData(P_FileMap map)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Address helpers
|
//~ @hookimpl Address helpers
|
||||||
|
|
||||||
P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
|
PLT_Address PLT_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
|
||||||
{
|
{
|
||||||
P_Address result = Zi;
|
PLT_Address result = Zi;
|
||||||
|
|
||||||
struct addrinfo hints = Zi;
|
struct addrinfo hints = Zi;
|
||||||
hints.ai_family = AF_UNSPEC;
|
hints.ai_family = AF_UNSPEC;
|
||||||
@ -575,7 +575,7 @@ P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
|
|||||||
{
|
{
|
||||||
struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_result->ai_addr;
|
struct sockaddr_in *sockaddr = (struct sockaddr_in *)ai_result->ai_addr;
|
||||||
result.valid = 1;
|
result.valid = 1;
|
||||||
result.family = P_AddressFamily_Ipv4;
|
result.family = PLT_AddressFamily_Ipv4;
|
||||||
result.portnb = sockaddr->sin_port;
|
result.portnb = sockaddr->sin_port;
|
||||||
StaticAssert(sizeof(sockaddr->sin_addr) == 4);
|
StaticAssert(sizeof(sockaddr->sin_addr) == 4);
|
||||||
CopyBytes(result.ipnb, (void *)&sockaddr->sin_addr, 4);
|
CopyBytes(result.ipnb, (void *)&sockaddr->sin_addr, 4);
|
||||||
@ -586,7 +586,7 @@ P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
|
|||||||
// TODO: Enable ipv6
|
// TODO: Enable ipv6
|
||||||
// struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr;
|
// struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ai_result->ai_addr;
|
||||||
// result.valid = 1;
|
// result.valid = 1;
|
||||||
// result.family = P_AddressFamily_Ipv6;
|
// result.family = PLT_AddressFamily_Ipv6;
|
||||||
// result.portnb = sockaddr->sin6_port;
|
// result.portnb = sockaddr->sin6_port;
|
||||||
// StaticAssert(sizeof(sockaddr->sin6_addr) == 16);
|
// StaticAssert(sizeof(sockaddr->sin6_addr) == 16);
|
||||||
// CopyBytes(result.ipnb, (void *)&sockaddr->sin6_addr, 16);
|
// CopyBytes(result.ipnb, (void *)&sockaddr->sin6_addr, 16);
|
||||||
@ -600,7 +600,7 @@ P_Address P_AddressFromIpPortCstr(char *ip_cstr, char *port_cstr)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_Address P_AddressFromString(String str)
|
PLT_Address PLT_AddressFromString(String str)
|
||||||
{
|
{
|
||||||
// Parse string into ip & port
|
// Parse string into ip & port
|
||||||
u8 ip_buff[1024];
|
u8 ip_buff[1024];
|
||||||
@ -691,11 +691,11 @@ P_Address P_AddressFromString(String str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P_Address result = P_AddressFromIpPortCstr(ip_cstr, port_cstr);
|
PLT_Address result = PLT_AddressFromIpPortCstr(ip_cstr, port_cstr);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
P_Address P_AddressFromPort(u16 port)
|
PLT_Address PLT_AddressFromPort(u16 port)
|
||||||
{
|
{
|
||||||
u8 port_buff[128];
|
u8 port_buff[128];
|
||||||
char *port_cstr = 0;
|
char *port_cstr = 0;
|
||||||
@ -721,16 +721,16 @@ P_Address P_AddressFromPort(u16 port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P_Address result = P_AddressFromIpPortCstr(0, port_cstr);
|
PLT_Address result = PLT_AddressFromIpPortCstr(0, port_cstr);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
String P_StringFromAddress(Arena *arena, P_Address address)
|
String PLT_StringFromAddress(Arena *arena, PLT_Address address)
|
||||||
{
|
{
|
||||||
String result = Zi;
|
String result = Zi;
|
||||||
|
|
||||||
if (address.family == P_AddressFamily_Ipv6)
|
if (address.family == PLT_AddressFamily_Ipv6)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
@ -748,7 +748,7 @@ String P_StringFromAddress(Arena *arena, P_Address address)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
b32 P_MatchAddress(P_Address a, P_Address b)
|
b32 PLT_MatchAddress(PLT_Address a, PLT_Address b)
|
||||||
{
|
{
|
||||||
return MatchStruct(&a, &b);
|
return MatchStruct(&a, &b);
|
||||||
}
|
}
|
||||||
@ -756,26 +756,26 @@ b32 P_MatchAddress(P_Address a, P_Address b)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Socket
|
//~ @hookimpl Socket
|
||||||
|
|
||||||
P_Sock *P_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size)
|
PLT_Sock *PLT_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size)
|
||||||
{
|
{
|
||||||
P_W32_Sock *ws = 0;
|
PLT_W32_Sock *ws = 0;
|
||||||
{
|
{
|
||||||
Lock lock = LockE(&P_W32.socks_mutex);
|
Lock lock = LockE(&PLT_W32.socks_mutex);
|
||||||
if (P_W32.first_free_sock)
|
if (PLT_W32.first_free_sock)
|
||||||
{
|
{
|
||||||
ws = P_W32.first_free_sock;
|
ws = PLT_W32.first_free_sock;
|
||||||
P_W32.first_free_sock = ws->next_free;
|
PLT_W32.first_free_sock = ws->next_free;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ws = PushStructNoZero(P_W32.socks_arena, P_W32_Sock);
|
ws = PushStructNoZero(PLT_W32.socks_arena, PLT_W32_Sock);
|
||||||
}
|
}
|
||||||
Unlock(&lock);
|
Unlock(&lock);
|
||||||
}
|
}
|
||||||
ZeroStruct(ws);
|
ZeroStruct(ws);
|
||||||
|
|
||||||
P_Address addr = P_AddressFromPort(listen_port);
|
PLT_Address addr = PLT_AddressFromPort(listen_port);
|
||||||
P_W32_Address bind_address = P_W32_Win32AddressFromPlatformAddress(addr);
|
PLT_W32_Address bind_address = PLT_W32_Win32AddressFromPlatformAddress(addr);
|
||||||
ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP);
|
ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
{
|
{
|
||||||
i32 sb = sndbuf_size;
|
i32 sb = sndbuf_size;
|
||||||
@ -787,39 +787,39 @@ P_Sock *P_AcquireSock(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size)
|
|||||||
}
|
}
|
||||||
bind(ws->sock, &bind_address.sa, bind_address.size);
|
bind(ws->sock, &bind_address.sa, bind_address.size);
|
||||||
|
|
||||||
return (P_Sock *)ws;
|
return (PLT_Sock *)ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_ReleaseSock(P_Sock *sock)
|
void PLT_ReleaseSock(PLT_Sock *sock)
|
||||||
{
|
{
|
||||||
P_W32_Sock *ws = (P_W32_Sock *)sock;
|
PLT_W32_Sock *ws = (PLT_W32_Sock *)sock;
|
||||||
closesocket(ws->sock);
|
closesocket(ws->sock);
|
||||||
Lock lock = LockE(&P_W32.socks_mutex);
|
Lock lock = LockE(&PLT_W32.socks_mutex);
|
||||||
{
|
{
|
||||||
ws->next_free = P_W32.first_free_sock;
|
ws->next_free = PLT_W32.first_free_sock;
|
||||||
P_W32.first_free_sock = ws;
|
PLT_W32.first_free_sock = ws;
|
||||||
}
|
}
|
||||||
Unlock(&lock);
|
Unlock(&lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
|
PLT_SockReadResult PLT_ReadSock(Arena *arena, PLT_Sock *sock)
|
||||||
{
|
{
|
||||||
P_W32_Sock *ws = (P_W32_Sock *)sock;
|
PLT_W32_Sock *ws = (PLT_W32_Sock *)sock;
|
||||||
|
|
||||||
u64 read_buff_size = Kibi(64);
|
u64 read_buff_size = Kibi(64);
|
||||||
String read_buff = Zi;
|
String read_buff = Zi;
|
||||||
read_buff.len = read_buff_size;
|
read_buff.len = read_buff_size;
|
||||||
read_buff.text = PushStructsNoZero(arena, u8, read_buff_size);
|
read_buff.text = PushStructsNoZero(arena, u8, read_buff_size);
|
||||||
|
|
||||||
P_SockReadResult result = Zi;
|
PLT_SockReadResult result = Zi;
|
||||||
|
|
||||||
P_W32_Address ws_addr = Zi;
|
PLT_W32_Address ws_addr = Zi;
|
||||||
ws_addr.size = sizeof(ws_addr.sas);
|
ws_addr.size = sizeof(ws_addr.sas);
|
||||||
|
|
||||||
i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size);
|
i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size);
|
||||||
ws_addr.family = ws_addr.sin.sin_family;
|
ws_addr.family = ws_addr.sin.sin_family;
|
||||||
|
|
||||||
result.address = P_W32_PlatformAddressFromWin32Address(ws_addr);
|
result.address = PLT_W32_PlatformAddressFromWin32Address(ws_addr);
|
||||||
if (size >= 0)
|
if (size >= 0)
|
||||||
{
|
{
|
||||||
AddGstat(SockBytesReceived, size);
|
AddGstat(SockBytesReceived, size);
|
||||||
@ -845,10 +845,10 @@ P_SockReadResult P_ReadSock(Arena *arena, P_Sock *sock)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_WriteSock(P_Sock *sock, P_Address address, String data)
|
void PLT_WriteSock(PLT_Sock *sock, PLT_Address address, String data)
|
||||||
{
|
{
|
||||||
P_W32_Sock *ws = (P_W32_Sock *)sock;
|
PLT_W32_Sock *ws = (PLT_W32_Sock *)sock;
|
||||||
P_W32_Address ws_addr = P_W32_Win32AddressFromPlatformAddress(address);
|
PLT_W32_Address ws_addr = PLT_W32_Win32AddressFromPlatformAddress(address);
|
||||||
i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size);
|
i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size);
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
@ -867,7 +867,7 @@ void P_WriteSock(P_Sock *sock, P_Address address, String data)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Utils
|
//~ @hookimpl Utils
|
||||||
|
|
||||||
void P_MessageBox(P_MessageBoxKind kind, String message)
|
void PLT_MessageBox(PLT_MessageBoxKind kind, String message)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
|
||||||
@ -877,24 +877,24 @@ void P_MessageBox(P_MessageBoxKind kind, String message)
|
|||||||
|
|
||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case P_MessageBoxKind_Ok:
|
case PLT_MessageBoxKind_Ok:
|
||||||
{
|
{
|
||||||
mbox_type |= MB_ICONINFORMATION;
|
mbox_type |= MB_ICONINFORMATION;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case P_MessageBoxKind_Warning:
|
case PLT_MessageBoxKind_Warning:
|
||||||
{
|
{
|
||||||
title = L"Warning";
|
title = L"Warning";
|
||||||
mbox_type |= MB_ICONWARNING;
|
mbox_type |= MB_ICONWARNING;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case P_MessageBoxKind_Error:
|
case PLT_MessageBoxKind_Error:
|
||||||
{
|
{
|
||||||
title = L"Error";
|
title = L"Error";
|
||||||
mbox_type |= MB_ICONERROR;
|
mbox_type |= MB_ICONERROR;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case P_MessageBoxKind_Fatal:
|
case PLT_MessageBoxKind_Fatal:
|
||||||
{
|
{
|
||||||
title = L"Fatal error";
|
title = L"Fatal error";
|
||||||
mbox_type |= MB_ICONSTOP;
|
mbox_type |= MB_ICONSTOP;
|
||||||
@ -907,7 +907,7 @@ void P_MessageBox(P_MessageBoxKind kind, String message)
|
|||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_SetClipboardText(String str)
|
void PLT_SetClipboardText(String str)
|
||||||
{
|
{
|
||||||
if (OpenClipboard(0))
|
if (OpenClipboard(0))
|
||||||
{
|
{
|
||||||
@ -929,7 +929,7 @@ void P_SetClipboardText(String str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String P_GetClipboardText(Arena *arena)
|
String PLT_GetClipboardText(Arena *arena)
|
||||||
{
|
{
|
||||||
String result = Zi;
|
String result = Zi;
|
||||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(0))
|
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(0))
|
||||||
@ -949,28 +949,28 @@ String P_GetClipboardText(Arena *arena)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Timer
|
//~ @hookimpl Timer
|
||||||
|
|
||||||
Fence *P_GetTimerFence(void)
|
Fence *PLT_GetTimerFence(void)
|
||||||
{
|
{
|
||||||
return &P_W32.timer_fence;
|
return &PLT_W32.timer_fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 P_GetCurrentTimerPeriodNs(void)
|
i64 PLT_GetCurrentTimerPeriodNs(void)
|
||||||
{
|
{
|
||||||
return Atomic64Fetch(&P_W32.average_timer_period_ns.v);
|
return Atomic64Fetch(&PLT_W32.average_timer_period_ns.v);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Sleep
|
//~ @hookimpl Sleep
|
||||||
|
|
||||||
void P_SleepPrecise(i64 sleep_time_ns)
|
void PLT_SleepPrecise(i64 sleep_time_ns)
|
||||||
{
|
{
|
||||||
i64 now_ns = TimeNs();
|
i64 now_ns = TimeNs();
|
||||||
i64 target_ns = now_ns + sleep_time_ns;
|
i64 target_ns = now_ns + sleep_time_ns;
|
||||||
|
|
||||||
// Sleep on timer to conserve power
|
// Sleep on timer to conserve power
|
||||||
{
|
{
|
||||||
Fence *timer_fence = P_GetTimerFence();
|
Fence *timer_fence = PLT_GetTimerFence();
|
||||||
i64 timer_period_ns = P_GetCurrentTimerPeriodNs();
|
i64 timer_period_ns = PLT_GetCurrentTimerPeriodNs();
|
||||||
i64 timer_tolerance_ns = timer_period_ns * 0.5;
|
i64 timer_tolerance_ns = timer_period_ns * 0.5;
|
||||||
i64 target_timer_sleep_ns = target_ns - timer_period_ns - timer_tolerance_ns;
|
i64 target_timer_sleep_ns = target_ns - timer_period_ns - timer_tolerance_ns;
|
||||||
YieldOnFence(timer_fence, target_timer_sleep_ns);
|
YieldOnFence(timer_fence, target_timer_sleep_ns);
|
||||||
@ -985,7 +985,7 @@ void P_SleepPrecise(i64 sleep_time_ns)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns)
|
void PLT_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns)
|
||||||
{
|
{
|
||||||
if (last_frame_time_ns != 0 && target_dt_ns > 0)
|
if (last_frame_time_ns != 0 && target_dt_ns > 0)
|
||||||
{
|
{
|
||||||
@ -994,7 +994,7 @@ void P_SleepFrame(i64 last_frame_time_ns, i64 target_dt_ns)
|
|||||||
i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns;
|
i64 sleep_time_ns = target_dt_ns - last_frame_dt_ns;
|
||||||
if (sleep_time_ns > 0)
|
if (sleep_time_ns > 0)
|
||||||
{
|
{
|
||||||
P_SleepPrecise(sleep_time_ns);
|
PLT_SleepPrecise(sleep_time_ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Watch types
|
//~ Watch types
|
||||||
|
|
||||||
Struct(P_W32_Watch)
|
Struct(PLT_W32_Watch)
|
||||||
{
|
{
|
||||||
HANDLE dir_handle;
|
HANDLE dir_handle;
|
||||||
HANDLE wake_handle;
|
HANDLE wake_handle;
|
||||||
P_W32_Watch *next_free;
|
PLT_W32_Watch *next_free;
|
||||||
u8 results_buff[Kibi(64)];
|
u8 results_buff[Kibi(64)];
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Address types
|
//~ Address types
|
||||||
|
|
||||||
Struct(P_W32_Address)
|
Struct(PLT_W32_Address)
|
||||||
{
|
{
|
||||||
i32 size;
|
i32 size;
|
||||||
i32 family;
|
i32 family;
|
||||||
@ -28,56 +28,56 @@ Struct(P_W32_Address)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Sock types
|
//~ Sock types
|
||||||
|
|
||||||
Struct(P_W32_Sock)
|
Struct(PLT_W32_Sock)
|
||||||
{
|
{
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
P_W32_Sock *next_free;
|
PLT_W32_Sock *next_free;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ State types
|
//~ State types
|
||||||
|
|
||||||
#define P_W32_NumRollingTimerPeriods 500
|
#define PLT_W32_NumRollingTimerPeriods 500
|
||||||
#define P_W32_DefaultTimerPeriodNs 50000000
|
#define PLT_W32_DefaultTimerPeriodNs 50000000
|
||||||
|
|
||||||
Struct(P_W32_Ctx)
|
Struct(PLT_W32_Ctx)
|
||||||
{
|
{
|
||||||
//- Watches pool
|
//- Watches pool
|
||||||
Mutex watches_mutex;
|
Mutex watches_mutex;
|
||||||
Arena *watches_arena;
|
Arena *watches_arena;
|
||||||
P_W32_Watch *watches_first_free;
|
PLT_W32_Watch *watches_first_free;
|
||||||
|
|
||||||
//- Socket pool
|
//- Socket pool
|
||||||
WSADATA wsa_data;
|
WSADATA wsa_data;
|
||||||
Arena *socks_arena;
|
Arena *socks_arena;
|
||||||
Mutex socks_mutex;
|
Mutex socks_mutex;
|
||||||
P_W32_Sock *first_free_sock;
|
PLT_W32_Sock *first_free_sock;
|
||||||
|
|
||||||
//- Timer
|
//- Timer
|
||||||
Fence timer_fence;
|
Fence timer_fence;
|
||||||
Atomic64Padded average_timer_period_ns;
|
Atomic64Padded average_timer_period_ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern P_W32_Ctx P_W32;
|
extern PLT_W32_Ctx PLT_W32;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Time
|
//~ Time
|
||||||
|
|
||||||
DateTime P_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st);
|
DateTime PLT_W32_DateTimeFromWin32SystemTime(SYSTEMTIME st);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ File system
|
//~ File system
|
||||||
|
|
||||||
String P_W32_StringFromWin32Path(Arena *arena, wchar_t *src);
|
String PLT_W32_StringFromWin32Path(Arena *arena, wchar_t *src);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Address
|
//~ Address
|
||||||
|
|
||||||
P_W32_Address P_W32_Win32AddressFromPlatformAddress(P_Address addr);
|
PLT_W32_Address PLT_W32_Win32AddressFromPlatformAddress(PLT_Address addr);
|
||||||
P_W32_Address P_W32_ConvertAnyaddrToLocalhost(P_W32_Address addr);
|
PLT_W32_Address PLT_W32_ConvertAnyaddrToLocalhost(PLT_W32_Address addr);
|
||||||
P_Address P_W32_PlatformAddressFromWin32Address(P_W32_Address ws_addr);
|
PLT_Address PLT_W32_PlatformAddressFromWin32Address(PLT_W32_Address ws_addr);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Timer job
|
//~ Timer job
|
||||||
|
|
||||||
void P_W32_SyncTimerForever(WaveLaneCtx *lane);
|
void PLT_W32_SyncTimerForever(WaveLaneCtx *lane);
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
@Layer pp
|
@Layer pp
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Dependencies
|
//- Resources
|
||||||
|
|
||||||
@Dep pp_sim
|
@EmbedDir P_Resources pp_res
|
||||||
@Dep pp_vis
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Impl
|
||||||
|
|
||||||
|
@DefaultDownstream Any pp_vis
|
||||||
|
@DefaultDownstream Any pp_sim
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Dependencies
|
//- Dependencies
|
||||||
|
|
||||||
|
@Dep pp
|
||||||
@Dep platform
|
@Dep platform
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|||||||
@ -1676,7 +1676,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
if (!shutdown)
|
if (!shutdown)
|
||||||
{
|
{
|
||||||
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||||
P_SleepFrame(frame_begin_ns, step_dt_ns);
|
PLT_SleepFrame(frame_begin_ns, step_dt_ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Dependencies
|
//- Dependencies
|
||||||
|
|
||||||
|
@Dep pp
|
||||||
@Dep gpu
|
@Dep gpu
|
||||||
@Dep glyph_cache
|
@Dep glyph_cache
|
||||||
@Dep platform
|
@Dep platform
|
||||||
@ -13,8 +14,6 @@
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Resources
|
//- Resources
|
||||||
|
|
||||||
@EmbedDir V_Resources pp_vis_res
|
|
||||||
|
|
||||||
@ComputeShader V_ClearCellsCS
|
@ComputeShader V_ClearCellsCS
|
||||||
@ComputeShader V_ClearParticlesCS
|
@ComputeShader V_ClearParticlesCS
|
||||||
@ComputeShader V_BackdropCS
|
@ComputeShader V_BackdropCS
|
||||||
@ -31,10 +30,8 @@
|
|||||||
//- Api
|
//- Api
|
||||||
|
|
||||||
@IncludeC pp_vis_shared.cgh
|
@IncludeC pp_vis_shared.cgh
|
||||||
@IncludeG pp_vis_shared.cgh
|
|
||||||
|
|
||||||
@IncludeC pp_vis_core.h
|
@IncludeC pp_vis_core.h
|
||||||
|
@IncludeG pp_vis_shared.cgh
|
||||||
@IncludeG pp_vis_gpu.gh
|
@IncludeG pp_vis_gpu.gh
|
||||||
|
|
||||||
@Bootstrap V_Bootstrap
|
@Bootstrap V_Bootstrap
|
||||||
@ -43,5 +40,4 @@
|
|||||||
//- Impl
|
//- Impl
|
||||||
|
|
||||||
@IncludeC pp_vis_core.c
|
@IncludeC pp_vis_core.c
|
||||||
|
|
||||||
@IncludeG pp_vis_gpu.g
|
@IncludeG pp_vis_gpu.g
|
||||||
|
|||||||
@ -246,7 +246,7 @@ V_WidgetTheme V_GetWidgetTheme(void)
|
|||||||
{
|
{
|
||||||
V_WidgetTheme theme = Zi;
|
V_WidgetTheme theme = Zi;
|
||||||
|
|
||||||
theme.text_font = GC_FontKeyFromResource(ResourceKeyFromStore(&V_Resources, Lit("font/seguisb.ttf")));
|
theme.text_font = GC_FontKeyFromResource(ResourceKeyFromStore(&P_Resources, Lit("font/seguisb.ttf")));
|
||||||
theme.icon_font = UI_BuiltinIconFont();
|
theme.icon_font = UI_BuiltinIconFont();
|
||||||
|
|
||||||
// theme.font_size = 14;
|
// theme.font_size = 14;
|
||||||
|
|||||||
3092
src/pp_old/pp.c
3092
src/pp_old/pp.c
File diff suppressed because it is too large
Load Diff
336
src/pp_old/pp.h
336
src/pp_old/pp.h
@ -1,336 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Binds
|
|
||||||
|
|
||||||
//- Bind kinds
|
|
||||||
Enum(PP_BindKind)
|
|
||||||
{
|
|
||||||
PP_BindKind_None,
|
|
||||||
|
|
||||||
PP_BindKind_MoveUp,
|
|
||||||
PP_BindKind_MoveDown,
|
|
||||||
PP_BindKind_MoveLeft,
|
|
||||||
PP_BindKind_MoveRight,
|
|
||||||
PP_BindKind_Walk,
|
|
||||||
PP_BindKind_Fire,
|
|
||||||
PP_BindKind_AltFire,
|
|
||||||
|
|
||||||
PP_BindKind_TestTile,
|
|
||||||
PP_BindKind_DebugClear,
|
|
||||||
PP_BindKind_DebugSpawn1,
|
|
||||||
PP_BindKind_DebugSpawn2,
|
|
||||||
PP_BindKind_DebugSpawn3,
|
|
||||||
PP_BindKind_DebugSpawn4,
|
|
||||||
PP_BindKind_DebugWalls,
|
|
||||||
PP_BindKind_DebugFollow,
|
|
||||||
PP_BindKind_DebugDraw,
|
|
||||||
PP_BindKind_DebugConsole,
|
|
||||||
PP_BindKind_DebugCamera,
|
|
||||||
PP_BindKind_DebugLister,
|
|
||||||
PP_BindKind_DebugPause,
|
|
||||||
PP_BindKind_DebugStep,
|
|
||||||
PP_BindKind_DebugDrag,
|
|
||||||
PP_BindKind_DebugDelete,
|
|
||||||
PP_BindKind_DebugTeleport,
|
|
||||||
PP_BindKind_DebugExplode,
|
|
||||||
PP_BindKind_DebugToggleTopmost,
|
|
||||||
PP_BindKind_DebugUi,
|
|
||||||
PP_BindKind_FullscreenMod,
|
|
||||||
PP_BindKind_Fullscreen,
|
|
||||||
PP_BindKind_ZoomIn,
|
|
||||||
PP_BindKind_ZoomOut,
|
|
||||||
PP_BindKind_Pan,
|
|
||||||
|
|
||||||
#if IsRtcEnabled
|
|
||||||
/* Debug */
|
|
||||||
|
|
||||||
PP_BindKind_ResetDebugSteps,
|
|
||||||
PP_BindKind_IncrementDebugSteps,
|
|
||||||
PP_BindKind_DecrementDebugSteps,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PP_BindKind_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
//- Test bindings
|
|
||||||
|
|
||||||
/* TODO: Remove this */
|
|
||||||
Global Readonly PP_BindKind g_binds[Btn_COUNT] = {
|
|
||||||
[Btn_W] = PP_BindKind_MoveUp,
|
|
||||||
[Btn_S] = PP_BindKind_MoveDown,
|
|
||||||
[Btn_A] = PP_BindKind_MoveLeft,
|
|
||||||
[Btn_D] = PP_BindKind_MoveRight,
|
|
||||||
[Btn_M1] = PP_BindKind_Fire,
|
|
||||||
[Btn_M2] = PP_BindKind_AltFire,
|
|
||||||
#if 0
|
|
||||||
[Btn_Alt] = PP_BindKind_Walk,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Testing */
|
|
||||||
[Btn_Z] = PP_BindKind_TestTile,
|
|
||||||
[Btn_M5] = PP_BindKind_DebugDrag,
|
|
||||||
[Btn_M4] = PP_BindKind_DebugDelete,
|
|
||||||
[Btn_F] = PP_BindKind_DebugExplode,
|
|
||||||
[Btn_T] = PP_BindKind_DebugTeleport,
|
|
||||||
[Btn_C] = PP_BindKind_DebugClear,
|
|
||||||
[Btn_1] = PP_BindKind_DebugSpawn1,
|
|
||||||
[Btn_2] = PP_BindKind_DebugSpawn2,
|
|
||||||
[Btn_3] = PP_BindKind_DebugSpawn3,
|
|
||||||
[Btn_4] = PP_BindKind_DebugSpawn4,
|
|
||||||
[Btn_G] = PP_BindKind_DebugWalls,
|
|
||||||
[Btn_N] = PP_BindKind_DebugStep,
|
|
||||||
[Btn_Q] = PP_BindKind_DebugFollow,
|
|
||||||
[Btn_F1] = PP_BindKind_DebugPause,
|
|
||||||
[Btn_F2] = PP_BindKind_DebugCamera,
|
|
||||||
[Btn_F3] = PP_BindKind_DebugDraw,
|
|
||||||
[Btn_Tab] = PP_BindKind_DebugLister,
|
|
||||||
[Btn_F4] = PP_BindKind_DebugToggleTopmost,
|
|
||||||
[Btn_F5] = PP_BindKind_DebugUi,
|
|
||||||
[Btn_GraveAccent] = PP_BindKind_DebugConsole,
|
|
||||||
[Btn_Alt] = PP_BindKind_FullscreenMod,
|
|
||||||
[Btn_Enter] = PP_BindKind_Fullscreen,
|
|
||||||
[Btn_MWheelUp] = PP_BindKind_ZoomIn,
|
|
||||||
[Btn_MWheelDown] = PP_BindKind_ZoomOut,
|
|
||||||
[Btn_M3] = PP_BindKind_Pan,
|
|
||||||
|
|
||||||
#if IsRtcEnabled
|
|
||||||
[Btn_ForwardSlash] = PP_BindKind_ResetDebugSteps,
|
|
||||||
[Btn_Comma] = PP_BindKind_DecrementDebugSteps,
|
|
||||||
[Btn_Period] = PP_BindKind_IncrementDebugSteps
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Stats
|
|
||||||
|
|
||||||
Struct(PP_SecondsStat)
|
|
||||||
{
|
|
||||||
u64 last_second_start;
|
|
||||||
u64 last_second_end;
|
|
||||||
u64 last_second;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Console log
|
|
||||||
|
|
||||||
Struct(PP_ConsoleLog)
|
|
||||||
{
|
|
||||||
String msg;
|
|
||||||
i32 level;
|
|
||||||
i32 color_index;
|
|
||||||
DateTime datetime;
|
|
||||||
PP_ConsoleLog *prev;
|
|
||||||
PP_ConsoleLog *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sim decode queue
|
|
||||||
|
|
||||||
Struct(PP_DecodeQueueNode)
|
|
||||||
{
|
|
||||||
PP_Client *client;
|
|
||||||
u64 tick;
|
|
||||||
u64 base_tick;
|
|
||||||
String tmp_encoded;
|
|
||||||
PP_DecodeQueueNode *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_DecodeQueue)
|
|
||||||
{
|
|
||||||
PP_DecodeQueueNode *first;
|
|
||||||
PP_DecodeQueueNode *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ State types
|
|
||||||
|
|
||||||
Struct(PP_BindState)
|
|
||||||
{
|
|
||||||
b32 is_held; /* Is this bind held down this frame */
|
|
||||||
u32 num_presses; /* How many times was this bind's pressed since last frame */
|
|
||||||
u32 num_repeats; /* How many times was this bind's key repeated since last frame */
|
|
||||||
u32 num_presses_and_repeats; /* Same as `num_presses` but includes key repeats as well */
|
|
||||||
u32 num_releases; /* How many times was this bind released since last frame */
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_SharedUserState)
|
|
||||||
{
|
|
||||||
Atomic32 shutdown;
|
|
||||||
|
|
||||||
Fence shutdown_jobs_fence;
|
|
||||||
u64 shutdown_jobs_count;
|
|
||||||
|
|
||||||
Arena *arena;
|
|
||||||
String connect_address_str;
|
|
||||||
|
|
||||||
PP_ClientStore *user_client_store;
|
|
||||||
PP_Client *user_unblended_client; /* Contains snapshots received from local sim */
|
|
||||||
PP_Client *user_blended_client; /* Contains single snapshot from result of blending local sim snapshots */
|
|
||||||
PP_Snapshot *ss_blended; /* Points to blended snapshot contained in blended client */
|
|
||||||
|
|
||||||
u64 user_tick;
|
|
||||||
u64 window_os_gen;
|
|
||||||
|
|
||||||
//- Usage stats
|
|
||||||
i64 last_second_reset_ns;
|
|
||||||
PP_SecondsStat net_bytes_read;
|
|
||||||
PP_SecondsStat net_bytes_sent;
|
|
||||||
|
|
||||||
//- Renderer gbuffers
|
|
||||||
GPU_Resource *albedo;
|
|
||||||
GPU_Resource *emittance;
|
|
||||||
GPU_Resource *emittance_flood_read;
|
|
||||||
GPU_Resource *emittance_flood_target;
|
|
||||||
GPU_Resource *shade_read;
|
|
||||||
GPU_Resource *shade_target;
|
|
||||||
|
|
||||||
//- Renderer transient buffers
|
|
||||||
GPU_TransientBuffer material_instances_tbuff;
|
|
||||||
GPU_TransientBuffer grids_tbuff;
|
|
||||||
Arena *material_instances_arena;
|
|
||||||
Arena *grids_arena;
|
|
||||||
|
|
||||||
//- Renderer state
|
|
||||||
RandState frame_rand;
|
|
||||||
u64 frame_index;
|
|
||||||
i64 gpu_submit_fence_target;
|
|
||||||
|
|
||||||
//- Bind state
|
|
||||||
PP_BindState bind_states[PP_BindKind_COUNT];
|
|
||||||
|
|
||||||
//- Window -> user
|
|
||||||
Mutex sys_window_events_mutex;
|
|
||||||
Arena *sys_window_events_arena;
|
|
||||||
|
|
||||||
//- User -> sim
|
|
||||||
Mutex user_sim_cmd_mutex;
|
|
||||||
PP_ControlData user_sim_cmd_control;
|
|
||||||
PP_EntKey user_hovered_ent;
|
|
||||||
u64 last_user_sim_cmd_gen;
|
|
||||||
u64 user_sim_cmd_gen;
|
|
||||||
|
|
||||||
Atomic32 user_paused;
|
|
||||||
Atomic32 user_paused_steps;
|
|
||||||
|
|
||||||
//- Sim -> user
|
|
||||||
Mutex local_to_user_client_mutex;
|
|
||||||
PP_ClientStore *local_to_user_client_store;
|
|
||||||
PP_Client *local_to_user_client;
|
|
||||||
i64 local_to_user_client_publish_dt_ns;
|
|
||||||
i64 local_to_user_client_publish_time_ns;
|
|
||||||
|
|
||||||
//- Local sim -> user rolling window of publish time deltas
|
|
||||||
i64 last_local_to_user_snapshot_published_at_ns;
|
|
||||||
i64 average_local_to_user_snapshot_publish_dt_ns;
|
|
||||||
|
|
||||||
i64 local_sim_predicted_time_ns; /* Calculated from <last local sim to user pubilsh time> + <time since last local sim to user publish> */
|
|
||||||
i64 render_time_target_ns; /* Claculated from <local_sim_rpedicted_time_ns> - <render interp delay> */
|
|
||||||
i64 render_time_ns; /* Incremented at a constant rate based on average local to user publish delta, but snaps to render_time_target_ns if it gets too distant */
|
|
||||||
|
|
||||||
u64 local_sim_last_known_tick;
|
|
||||||
i64 local_sim_last_known_time_ns;
|
|
||||||
|
|
||||||
i64 real_dt_ns;
|
|
||||||
i64 real_time_ns;
|
|
||||||
|
|
||||||
//- Window
|
|
||||||
|
|
||||||
String window_restore;
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Persist start
|
|
||||||
StructRegion(AUTO_PERSIST_START);
|
|
||||||
|
|
||||||
//- Debug ui
|
|
||||||
|
|
||||||
b32 ui_debug;
|
|
||||||
|
|
||||||
PP_EntKey debug_following;
|
|
||||||
Vec2 debug_camera_pan_start;
|
|
||||||
b32 debug_camera_panning;
|
|
||||||
b32 debug_camera;
|
|
||||||
|
|
||||||
b32 lister_active;
|
|
||||||
Vec2 lister_pos;
|
|
||||||
|
|
||||||
b32 debug_draw;
|
|
||||||
b32 debug_console;
|
|
||||||
|
|
||||||
//- Per frame
|
|
||||||
|
|
||||||
Vec2I32 screen_size;
|
|
||||||
Vec2 screen_cursor;
|
|
||||||
|
|
||||||
Xform ui_to_screen_xf;
|
|
||||||
Vec2I32 ui_size;
|
|
||||||
Vec2 ui_cursor;
|
|
||||||
|
|
||||||
Xform render_to_ui_xf;
|
|
||||||
Vec2I32 render_size;
|
|
||||||
|
|
||||||
Xform world_to_render_xf;
|
|
||||||
Xform world_to_ui_xf;
|
|
||||||
Vec2 world_cursor;
|
|
||||||
|
|
||||||
Vec2 focus_send;
|
|
||||||
|
|
||||||
StructRegion(AUTO_PERSIST_END);
|
|
||||||
//- Persist end
|
|
||||||
//////////////////////////////
|
|
||||||
|
|
||||||
} extern PP_shared_user_state;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Swap types
|
|
||||||
|
|
||||||
Struct(PP_SwappedUserState)
|
|
||||||
{
|
|
||||||
PP_SharedUserState s;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void PP_StartupUser(void);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Shutdown
|
|
||||||
|
|
||||||
ExitFuncDef(PP_ShutdownUser);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Ui helpers
|
|
||||||
|
|
||||||
void PP_PushGameUiStyle(void);
|
|
||||||
void PP_DrawDebugXform(Xform xf, u32 color_x, u32 color_y);
|
|
||||||
void PP_DrawDebugMovement(PP_Ent *ent);
|
|
||||||
String PP_DebugStringFromEnt(Arena *arena, PP_Ent *ent);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Gpu buffer helpers
|
|
||||||
|
|
||||||
GPU_Resource *PP_AcquireGbuffer(GPU_Format format, Vec2I32 size);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Ent sorting
|
|
||||||
|
|
||||||
MergesortCompareFuncDef(PP_EntSortCmp, arg_a, arg_b, _);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ User update
|
|
||||||
|
|
||||||
void PP_UpdateUser(void);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ User update job
|
|
||||||
|
|
||||||
JobDecl(PP_UpdateUserOrSleep, EmptySig);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ User input cmds
|
|
||||||
|
|
||||||
void PP_GenerateuserInputCmds(PP_Client *user_input_client, u64 tick);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sim update job
|
|
||||||
|
|
||||||
JobDecl(PP_UpdateSim, EmptySig);
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
@Layer pp_old
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Dependencies
|
|
||||||
|
|
||||||
@Dep gpu
|
|
||||||
@Dep sprite
|
|
||||||
@Dep font
|
|
||||||
@Dep collider
|
|
||||||
@Dep net
|
|
||||||
@Dep mixer
|
|
||||||
@Dep rendertest
|
|
||||||
@Dep playback
|
|
||||||
@Dep platform
|
|
||||||
@Dep window
|
|
||||||
@Dep ui
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Resources
|
|
||||||
|
|
||||||
@EmbedDir PP_Resources pp_res
|
|
||||||
|
|
||||||
@VertexShader PP_MaterialVS
|
|
||||||
@PixelShader PP_MaterialPS
|
|
||||||
@ComputeShader PP_FloodCS
|
|
||||||
@ComputeShader PP_ShadeCS
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Api
|
|
||||||
|
|
||||||
@IncludeC pp_sim.h
|
|
||||||
@IncludeC pp_phys.h
|
|
||||||
@IncludeC pp_space.h
|
|
||||||
@IncludeC pp_ent.h
|
|
||||||
@IncludeC pp_step.h
|
|
||||||
@IncludeC pp_widgets.h
|
|
||||||
@IncludeC pp_draw.cgh
|
|
||||||
@IncludeG pp_draw.cgh
|
|
||||||
@IncludeC pp.h
|
|
||||||
|
|
||||||
@Bootstrap PP_StartupSim
|
|
||||||
@Bootstrap PP_StartupUser
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- Impl
|
|
||||||
|
|
||||||
@IncludeC pp_sim.c
|
|
||||||
@IncludeC pp_phys.c
|
|
||||||
@IncludeC pp_space.c
|
|
||||||
@IncludeC pp_ent.c
|
|
||||||
@IncludeC pp_step.c
|
|
||||||
@IncludeC pp_widgets.c
|
|
||||||
@IncludeC pp.c
|
|
||||||
@IncludeG pp_draw.g
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Material types
|
|
||||||
|
|
||||||
Struct(PP_MaterialSig)
|
|
||||||
{
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
Mat4x4 projection; /* 16 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
SamplerStateRid sampler; /* 01 consts */
|
|
||||||
StructuredBufferRid instances; /* 01 consts */
|
|
||||||
StructuredBufferRid grids; /* 01 consts */
|
|
||||||
u32 _pad0; /* 01 consts (padding) */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
};
|
|
||||||
AssertRootConst(PP_MaterialSig, 20);
|
|
||||||
|
|
||||||
Struct(PP_MaterialInstance)
|
|
||||||
{
|
|
||||||
Texture2DRid tex;
|
|
||||||
u32 grid_id;
|
|
||||||
Xform xf;
|
|
||||||
Vec2 tex_uv0;
|
|
||||||
Vec2 tex_uv1;
|
|
||||||
u32 tint_srgb;
|
|
||||||
u32 is_light;
|
|
||||||
Vec3 light_emittance_srgb;
|
|
||||||
};
|
|
||||||
#define PP_DefaultMaterialInstance (PP_MaterialInstance) { \
|
|
||||||
.tex = { U32Max }, \
|
|
||||||
.grid_id = U32Max, \
|
|
||||||
.xf = XformIdentity, \
|
|
||||||
.tex_uv1 = VEC2(1, 1), \
|
|
||||||
.tint_srgb = Color_White, \
|
|
||||||
}
|
|
||||||
|
|
||||||
Struct(PP_MaterialGrid)
|
|
||||||
{
|
|
||||||
f32 line_thickness;
|
|
||||||
f32 line_spacing;
|
|
||||||
Vec2 offset;
|
|
||||||
u32 bg0_srgb;
|
|
||||||
u32 bg1_srgb;
|
|
||||||
u32 line_srgb;
|
|
||||||
u32 x_srgb;
|
|
||||||
u32 y_srgb;
|
|
||||||
};
|
|
||||||
#define PP_DefaultMaterialGrid (PP_MaterialGrid) { \
|
|
||||||
.line_thickness = 1, \
|
|
||||||
.line_spacing = 1, \
|
|
||||||
.bg0_srgb = Color_Black, \
|
|
||||||
.bg0_srgb = Color_White \
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Flood types
|
|
||||||
|
|
||||||
Struct(PP_FloodSig)
|
|
||||||
{
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
i32 step_len; /* 01 consts */
|
|
||||||
Texture2DRid emittance; /* 01 consts */
|
|
||||||
RWTexture2DRid read; /* 01 consts */
|
|
||||||
RWTexture2DRid target; /* 01 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
u32 tex_width; /* 01 consts */
|
|
||||||
u32 tex_height; /* 01 consts */
|
|
||||||
u32 _pad0; /* 01 consts (padding) */
|
|
||||||
u32 _pad1; /* 01 consts (padding) */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
};
|
|
||||||
AssertRootConst(PP_FloodSig, 8);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Shade types
|
|
||||||
|
|
||||||
#define PP_ShadeFlag_None (0 << 0)
|
|
||||||
#define PP_ShadeFlag_DisableEffects (1 << 0)
|
|
||||||
#define PP_ShadeFlag_ToneMap (1 << 1)
|
|
||||||
|
|
||||||
Struct(PP_ShadeSig)
|
|
||||||
{
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
Vec4U32 frame_seed; /* 04 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
u32 flags; /* 01 consts */
|
|
||||||
u32 tex_width; /* 01 consts */
|
|
||||||
u32 tex_height; /* 01 consts */
|
|
||||||
f32 exposure; /* 01 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
Vec2 camera_offset; /* 02 consts */
|
|
||||||
u32 frame_index; /* 01 consts */
|
|
||||||
Texture2DRid albedo; /* 01 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
Texture2DRid emittance; /* 01 consts */
|
|
||||||
Texture2DRid emittance_flood; /* 01 consts */
|
|
||||||
Texture2DRid read; /* 01 consts */
|
|
||||||
RWTexture2DRid target; /* 01 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
Texture3DRid noise; /* 01 consts */
|
|
||||||
u32 noise_tex_width; /* 01 consts */
|
|
||||||
u32 noise_tex_height; /* 01 consts */
|
|
||||||
u32 noise_tex_depth; /* 01 consts */
|
|
||||||
/* ----------------------------------------------------- */
|
|
||||||
};
|
|
||||||
AssertRootConst(PP_ShadeSig, 20);
|
|
||||||
@ -1,304 +0,0 @@
|
|||||||
ConstantBuffer<PP_MaterialSig> PP_mat_sig : register (b0);
|
|
||||||
ConstantBuffer<PP_FloodSig> PP_flood_sig : register (b0);
|
|
||||||
ConstantBuffer<PP_ShadeSig> PP_shade_sig : register (b0);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Material
|
|
||||||
|
|
||||||
Struct(PP_MaterialPS_Input)
|
|
||||||
{
|
|
||||||
Semantic(Vec4, sv_position);
|
|
||||||
Semantic(nointerpolation Texture2DRid, tex);
|
|
||||||
Semantic(nointerpolation u32, grid_id);
|
|
||||||
Semantic(Vec2, tex_uv);
|
|
||||||
Semantic(Vec4, tint_lin);
|
|
||||||
Semantic(Vec4, emittance_lin);
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_MaterialPS_Output)
|
|
||||||
{
|
|
||||||
Semantic(Vec4, sv_target0); /* Albedo */
|
|
||||||
Semantic(Vec4, sv_target1); /* Emittance */
|
|
||||||
};
|
|
||||||
|
|
||||||
//- Vertex shader
|
|
||||||
|
|
||||||
PP_MaterialPS_Input VSDef(PP_MaterialVS, Semantic(u32, sv_instanceid), Semantic(u32, sv_vertexid))
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_MaterialSig> sig = PP_mat_sig;
|
|
||||||
StructuredBuffer<PP_MaterialInstance> instances = UniformResourceFromRid(sig.instances);
|
|
||||||
PP_MaterialInstance instance = instances[sv_instanceid];
|
|
||||||
|
|
||||||
Vec2 mat_uv = RectUvFromVertexId(sv_vertexid);
|
|
||||||
Vec2 mat_uv_centered = mat_uv - 0.5f;
|
|
||||||
Vec2 world_pos = mul(instance.xf, Vec3(mat_uv_centered, 1)).xy;
|
|
||||||
|
|
||||||
PP_MaterialPS_Input result;
|
|
||||||
result.sv_position = mul(sig.projection, Vec4(world_pos, 0, 1));
|
|
||||||
result.tex = instance.tex;
|
|
||||||
result.grid_id = instance.grid_id;
|
|
||||||
result.tex_uv = lerp(instance.tex_uv0, instance.tex_uv1, mat_uv);
|
|
||||||
result.tint_lin = LinearFromSrgbU32(instance.tint_srgb);
|
|
||||||
result.emittance_lin = LinearFromSrgbVec4(Vec4(instance.light_emittance_srgb, instance.is_light));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Pixel shader
|
|
||||||
|
|
||||||
PP_MaterialPS_Output PSDef(PP_MaterialPS, PP_MaterialPS_Input input)
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_MaterialSig> sig = PP_mat_sig;
|
|
||||||
|
|
||||||
PP_MaterialPS_Output result;
|
|
||||||
Vec4 albedo = input.tint_lin;
|
|
||||||
|
|
||||||
/* Texture */
|
|
||||||
if (input.tex < 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
SamplerState sampler = UniformSamplerFromRid(sig.sampler);
|
|
||||||
Texture2D<Vec4> tex = NonUniformResourceFromRid(input.tex);
|
|
||||||
albedo *= tex.Sample(sampler, input.tex_uv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grid */
|
|
||||||
if (input.grid_id < 0xFFFFFFFF)
|
|
||||||
{
|
|
||||||
// StructuredBuffer<PP_MaterialGrid> grids = UniformResourceFromRid(sig.grids);
|
|
||||||
StructuredBuffer<PP_MaterialGrid> grids = ResourceDescriptorHeap[sig.grids];
|
|
||||||
PP_MaterialGrid grid = grids[input.grid_id];
|
|
||||||
Vec2 grid_pos = input.sv_position.xy + grid.offset;
|
|
||||||
f32 half_thickness = grid.line_thickness / 2;
|
|
||||||
f32 spacing = grid.line_spacing;
|
|
||||||
u32 color_srgb = grid.bg0_srgb;
|
|
||||||
Vec2 v = abs(round(grid_pos / spacing) * spacing - grid_pos);
|
|
||||||
f32 dist = min(v.x, v.y);
|
|
||||||
if (grid_pos.y <= half_thickness && grid_pos.y >= -half_thickness)
|
|
||||||
{
|
|
||||||
color_srgb = grid.x_srgb;
|
|
||||||
}
|
|
||||||
else if (grid_pos.x <= half_thickness && grid_pos.x >= -half_thickness)
|
|
||||||
{
|
|
||||||
color_srgb = grid.y_srgb;
|
|
||||||
}
|
|
||||||
else if (dist < half_thickness)
|
|
||||||
{
|
|
||||||
color_srgb = grid.line_srgb;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool checker = 0;
|
|
||||||
u32 cell_x = (u32)(abs(grid_pos.x) / spacing) + (grid_pos.x < 0);
|
|
||||||
u32 cell_y = (u32)(abs(grid_pos.y) / spacing) + (grid_pos.y < 0);
|
|
||||||
if (cell_x % 2 == 0)
|
|
||||||
{
|
|
||||||
checker = cell_y % 2 == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
checker = cell_y % 2 == 1;
|
|
||||||
}
|
|
||||||
if (checker)
|
|
||||||
{
|
|
||||||
color_srgb = grid.bg1_srgb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
albedo = LinearFromSrgbU32(color_srgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4 emittance = input.emittance_lin * albedo.a;
|
|
||||||
|
|
||||||
result.sv_target0 = albedo;
|
|
||||||
result.sv_target1 = emittance;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Flood
|
|
||||||
|
|
||||||
//- Compute shader
|
|
||||||
|
|
||||||
[numthreads(8, 8, 1)]
|
|
||||||
void CSDef(PP_FloodCS, Semantic(Vec3U32, sv_dispatchthreadid))
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_FloodSig> sig = PP_flood_sig;
|
|
||||||
|
|
||||||
Vec2U32 id = sv_dispatchthreadid.xy;
|
|
||||||
Vec2U32 tex_size = Vec2U32(sig.tex_width, sig.tex_height);
|
|
||||||
if (id.x < tex_size.x && id.y < tex_size.y)
|
|
||||||
{
|
|
||||||
Texture2D<Vec4> emittance_tex = UniformResourceFromRid(sig.emittance);
|
|
||||||
RWTexture2D<Vec2U32> read_flood_tex = UniformResourceFromRid(sig.read);
|
|
||||||
RWTexture2D<Vec2U32> target_flood_tex = UniformResourceFromRid(sig.target);
|
|
||||||
i32 step_len = sig.step_len;
|
|
||||||
if (step_len == -1)
|
|
||||||
{
|
|
||||||
/* Seed */
|
|
||||||
Vec4 emittance = emittance_tex[id];
|
|
||||||
Vec2U32 seed = Vec2U32(0xFFFF, 0xFFFF);
|
|
||||||
if (emittance.a > 0)
|
|
||||||
{
|
|
||||||
seed = id;
|
|
||||||
}
|
|
||||||
target_flood_tex[id] = seed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Flood */
|
|
||||||
Vec2I32 read_coords[9] = {
|
|
||||||
(Vec2I32)id + Vec2I32(-step_len, -step_len), /* top left */
|
|
||||||
(Vec2I32)id + Vec2I32(0, -step_len), /* top center */
|
|
||||||
(Vec2I32)id + Vec2I32(+step_len, -step_len), /* top right */
|
|
||||||
(Vec2I32)id + Vec2I32(-step_len, 0), /* center left */
|
|
||||||
(Vec2I32)id + Vec2I32(0, 0), /* center center */
|
|
||||||
(Vec2I32)id + Vec2I32(+step_len, 0), /* center right */
|
|
||||||
(Vec2I32)id + Vec2I32(-step_len, +step_len), /* bottom left */
|
|
||||||
(Vec2I32)id + Vec2I32(0, +step_len), /* bottom center */
|
|
||||||
(Vec2I32)id + Vec2I32(+step_len, +step_len), /* bottom right */
|
|
||||||
};
|
|
||||||
Vec2U32 closest_seed = Vec2U32(0xFFFF, 0xFFFF);
|
|
||||||
u32 closest_seed_len_sq = 0xFFFFFFFF;
|
|
||||||
for (i32 i = 0; i < 9; ++i)
|
|
||||||
{
|
|
||||||
Vec2I32 coord = read_coords[i];
|
|
||||||
if (coord.x >= 0 && coord.x < (i32)tex_size.x && coord.y >= 0 && coord.y < (i32)tex_size.y)
|
|
||||||
{
|
|
||||||
Vec2U32 seed = read_flood_tex[coord];
|
|
||||||
Vec2I32 dist_vec = (Vec2I32)id - (Vec2I32)seed;
|
|
||||||
u32 dist_len_sq = dot(dist_vec, dist_vec);
|
|
||||||
if (dist_len_sq < closest_seed_len_sq)
|
|
||||||
{
|
|
||||||
closest_seed = seed;
|
|
||||||
closest_seed_len_sq = dist_len_sq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
target_flood_tex[id] = closest_seed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Shade
|
|
||||||
|
|
||||||
#define PP_LightSamples 16
|
|
||||||
#define PP_LightMarches 16
|
|
||||||
#define PP_LightEdgeFalloff 100
|
|
||||||
|
|
||||||
//- Lighting
|
|
||||||
|
|
||||||
f32 PP_RandAngleFromPos(Vec2U32 pos, u32 ray_index)
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_ShadeSig> sig = PP_shade_sig;
|
|
||||||
|
|
||||||
Texture3D<u32> noise_tex = UniformResourceFromRid(sig.noise);
|
|
||||||
Vec3I32 noise_coord = Vec3U32(1, 1, 1);
|
|
||||||
noise_coord += Vec3I32(pos.xy, ray_index);
|
|
||||||
// noise_coord.xyz += sig.frame_seed.xyz;
|
|
||||||
noise_coord.xy -= sig.camera_offset;
|
|
||||||
|
|
||||||
u32 noise = noise_tex[noise_coord % Vec3U32(sig.noise_tex_width, sig.noise_tex_height, sig.noise_tex_depth)];
|
|
||||||
return ((f32)noise / (f32)0xFFFF) * Tau;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 PP_LightFromDir(Vec2U32 ray_start, Vec2 ray_dir)
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_ShadeSig> sig = PP_shade_sig;
|
|
||||||
Texture2D<Vec2U32> flood_tex = UniformResourceFromRid(sig.emittance_flood);
|
|
||||||
Texture2D<Vec4> emittance_tex = UniformResourceFromRid(sig.emittance);
|
|
||||||
|
|
||||||
Vec3 result = Vec3(0, 0, 0);
|
|
||||||
Vec2 at_f32 = ray_start;
|
|
||||||
Vec2U32 at_u32 = ray_start;
|
|
||||||
for (u32 i = 0; i < PP_LightMarches; ++i)
|
|
||||||
{
|
|
||||||
Vec2U32 flood = flood_tex[at_u32];
|
|
||||||
Vec2 dist_vec = at_f32 - (Vec2)flood;
|
|
||||||
f32 dist = length(dist_vec);
|
|
||||||
if (dist < 1)
|
|
||||||
{
|
|
||||||
/* Scale light by distance from edge so that offscreen-lights fade in/out rather than popping in */
|
|
||||||
f32 dist_x = min(abs(sig.tex_width - at_f32.x), at_f32.x);
|
|
||||||
f32 dist_y = min(abs(sig.tex_height - at_f32.y), at_f32.y);
|
|
||||||
f32 dist_scale = min(min(dist_x, dist_y) / PP_LightEdgeFalloff, 1);
|
|
||||||
result = emittance_tex[flood].rgb * dist_scale;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
at_f32 += ray_dir * dist;
|
|
||||||
at_u32 = round(at_f32);
|
|
||||||
if (at_u32.x < 0 || at_u32.x >= sig.tex_width || at_u32.y < 0 || at_u32.y >= sig.tex_height)
|
|
||||||
{
|
|
||||||
/* Ray hit edge of screen */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 PP_AccumulatedLightFromPos(Vec2U32 pos)
|
|
||||||
{
|
|
||||||
Vec3 result = 0;
|
|
||||||
for (u32 i = 0; i < PP_LightSamples; ++i)
|
|
||||||
{
|
|
||||||
f32 angle = PP_RandAngleFromPos(pos, i);
|
|
||||||
Vec2 dir = Vec2(cos(angle), sin(angle));
|
|
||||||
Vec3 light_in_dir = PP_LightFromDir(pos, dir);
|
|
||||||
result += light_in_dir;
|
|
||||||
}
|
|
||||||
result /= PP_LightSamples;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Tone mapping
|
|
||||||
|
|
||||||
// ACES approximation by Krzysztof Narkowicz
|
|
||||||
// https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/
|
|
||||||
Vec3 PP_ToneMap(Vec3 v)
|
|
||||||
{
|
|
||||||
return saturate((v * (2.51f * v + 0.03f)) / (v * (2.43f * v + 0.59f) + 0.14f));
|
|
||||||
}
|
|
||||||
|
|
||||||
//- Compute shader
|
|
||||||
|
|
||||||
[numthreads(8, 8, 1)]
|
|
||||||
void CSDef(PP_ShadeCS, Semantic(Vec3U32, sv_dispatchthreadid))
|
|
||||||
{
|
|
||||||
ConstantBuffer<PP_ShadeSig> sig = PP_shade_sig;
|
|
||||||
Vec2U32 id = sv_dispatchthreadid.xy;
|
|
||||||
if (id.x < sig.tex_width && id.y < sig.tex_height)
|
|
||||||
{
|
|
||||||
Texture2D<Vec4> albedo_tex = UniformResourceFromRid(sig.albedo);
|
|
||||||
Texture2D<Vec4> read_tex = UniformResourceFromRid(sig.read);
|
|
||||||
RWTexture2D<Vec4> target_tex = UniformResourceFromRid(sig.target);
|
|
||||||
Vec4 color = Vec4(1, 1, 1, 1);
|
|
||||||
|
|
||||||
/* Apply albedo */
|
|
||||||
color *= albedo_tex[id];
|
|
||||||
|
|
||||||
/* Apply lighting */
|
|
||||||
if (!(sig.flags & PP_ShadeFlag_DisableEffects))
|
|
||||||
{
|
|
||||||
color.rgb *= PP_AccumulatedLightFromPos(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply tone mapping */
|
|
||||||
if (sig.flags & PP_ShadeFlag_ToneMap)
|
|
||||||
{
|
|
||||||
/* TODO: Dynamic exposure based on average scene luminance */
|
|
||||||
color.rgb *= sig.exposure;
|
|
||||||
color.rgb = PP_ToneMap(color.rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply temporal accumulation */
|
|
||||||
f32 hysterisis = 0;
|
|
||||||
// hysterisis = 0.2;
|
|
||||||
// hysterisis = 0.4;
|
|
||||||
// hysterisis = 0.5;
|
|
||||||
// hysterisis = 0.95;
|
|
||||||
color.rgb = lerp(color.rgb, read_tex[id].rgb, hysterisis);
|
|
||||||
target_tex[id] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,795 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acquire
|
|
||||||
|
|
||||||
PP_Ent *PP_AcquireRawEnt(PP_Snapshot *ss, PP_Ent *parent, PP_EntKey key)
|
|
||||||
{
|
|
||||||
Assert(parent->valid);
|
|
||||||
Assert(ss->valid);
|
|
||||||
Assert(ss == parent->ss);
|
|
||||||
PP_Ent *ent;
|
|
||||||
if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved)
|
|
||||||
{
|
|
||||||
/* Reuse from free list */
|
|
||||||
ent = &ss->ents[ss->first_free_ent];
|
|
||||||
ss->first_free_ent = ent->next_free;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Make new */
|
|
||||||
ent = PushStructNoZero(ss->ents_arena, PP_Ent);
|
|
||||||
++ss->num_ents_reserved;
|
|
||||||
}
|
|
||||||
*ent = *PP_NilEnt();
|
|
||||||
ent->ss = ss;
|
|
||||||
ent->valid = 1;
|
|
||||||
ent->owner = ss->client->player_id;
|
|
||||||
ent->_is_xform_dirty = 1;
|
|
||||||
++ss->num_ents_allocated;
|
|
||||||
|
|
||||||
PP_SetEntKey(ent, key);
|
|
||||||
PP_Link(ent, parent);
|
|
||||||
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquires a new entity that will not sync */
|
|
||||||
PP_Ent *PP_AcquireLocalEnt(PP_Ent *parent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = parent->ss;
|
|
||||||
PP_Ent *e = PP_AcquireRawEnt(ss, parent, PP_RandomKey());
|
|
||||||
e->owner = ss->local_player;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_AcquireLocalEntWithKey(PP_Ent *parent, PP_EntKey key)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = parent->ss;
|
|
||||||
PP_Ent *e = PP_AcquireRawEnt(ss, parent, key);
|
|
||||||
e->owner = ss->local_player;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquires a new entity to be synced to clients */
|
|
||||||
PP_Ent *PP_AcquireSyncSrcEnt(PP_Ent *parent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = parent->ss;
|
|
||||||
PP_Ent *e = PP_AcquireRawEnt(ss, parent, PP_RandomKey());
|
|
||||||
PP_EnableProp(e, PP_Prop_SyncSrc);
|
|
||||||
e->owner = ss->local_player;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_AcquireSyncSrcEntWithKey(PP_Ent *parent, PP_EntKey key)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = parent->ss;
|
|
||||||
PP_Ent *e = PP_AcquireRawEnt(ss, parent, key);
|
|
||||||
PP_EnableProp(e, PP_Prop_SyncSrc);
|
|
||||||
e->owner = ss->local_player;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquires a new entity that will sync with incoming net src ents containing key, and coming from the specified owner */
|
|
||||||
PP_Ent *PP_AcquireSyncDstEnt(PP_Ent *parent, PP_EntKey ent_id, PP_EntKey owner_id)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = parent->ss;
|
|
||||||
PP_Ent *e = PP_AcquireRawEnt(ss, parent, ent_id);
|
|
||||||
PP_EnableProp(e, PP_Prop_SyncDst);
|
|
||||||
e->owner = owner_id;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Release
|
|
||||||
|
|
||||||
void PP_ReleaseRawEnt(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
/* Release children */
|
|
||||||
PP_Ent *child = PP_EntFromKey(ss, ent->first);
|
|
||||||
while (child->valid)
|
|
||||||
{
|
|
||||||
PP_Ent *next = PP_EntFromKey(ss, child->next);
|
|
||||||
PP_ReleaseRawEnt(child);
|
|
||||||
child = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release uid */
|
|
||||||
PP_SetEntKey(ent, PP_NilEntKey);
|
|
||||||
|
|
||||||
/* Release */
|
|
||||||
ent->valid = 0;
|
|
||||||
ent->next_free = ss->first_free_ent;
|
|
||||||
ss->first_free_ent = PP_IndexFromEnt(ss, ent);
|
|
||||||
--ss->num_ents_allocated;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_Release(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
PP_Ent *parent = PP_EntFromKey(ss, ent->parent);
|
|
||||||
if (parent->valid)
|
|
||||||
{
|
|
||||||
PP_Unlink(ent);
|
|
||||||
}
|
|
||||||
PP_ReleaseRawEnt(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseAllWithProp(PP_Snapshot *ss, PP_Prop prop)
|
|
||||||
{
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
|
|
||||||
PP_Ent **ents_to_release = PushDry(scratch.arena, PP_Ent *);
|
|
||||||
u64 ents_to_release_count = 0;
|
|
||||||
for (u64 ent_index = 0; ent_index < ss->num_ents_reserved; ++ent_index)
|
|
||||||
{
|
|
||||||
PP_Ent *ent = &ss->ents[ent_index];
|
|
||||||
if (ent->valid && PP_HasProp(ent, prop))
|
|
||||||
{
|
|
||||||
*PushStructNoZero(scratch.arena, PP_Ent *) = ent;
|
|
||||||
++ents_to_release_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release from snapshot
|
|
||||||
//
|
|
||||||
// TODO: Breadth first iteration to only release parent entities (since
|
|
||||||
// child entities will be released along with parent anyway)
|
|
||||||
for (u64 i = 0; i < ents_to_release_count; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *ent = ents_to_release[i];
|
|
||||||
if (ent->valid && !ent->is_root && !PP_HasProp(ent, PP_Prop_Cmd) && !PP_HasProp(ent, PP_Prop_Player))
|
|
||||||
{
|
|
||||||
PP_Release(ent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Activate
|
|
||||||
|
|
||||||
void PP_ActivateEnt(PP_Ent *ent, u64 current_tick)
|
|
||||||
{
|
|
||||||
PP_EnableProp(ent, PP_Prop_Active);
|
|
||||||
ent->activation_tick = current_tick;
|
|
||||||
++ent->continuity_gen;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Ent key
|
|
||||||
|
|
||||||
u32 PP_IndexFromEnt(PP_Snapshot *ss, PP_Ent *ent)
|
|
||||||
{
|
|
||||||
return ent - ss->ents;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_EntFromIndex(PP_Snapshot *ss, u32 index)
|
|
||||||
{
|
|
||||||
if (index > 0 && index < ss->num_ents_reserved)
|
|
||||||
{
|
|
||||||
return &ss->ents[index];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return PP_NilEnt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_EntBin *PP_EntBinFromKey(PP_Snapshot *ss, PP_EntKey key)
|
|
||||||
{
|
|
||||||
return &ss->key_bins[key.uid.lo % ss->num_key_bins];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: This should only really happen during ent allocation (it doesn't make sense for an allocated ent's key to change) */
|
|
||||||
void PP_SetEntKey(PP_Ent *ent, PP_EntKey key)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
PP_EntKey old_id = ent->key;
|
|
||||||
if (!PP_EqEntKey(old_id, key))
|
|
||||||
{
|
|
||||||
/* Release old from lookup */
|
|
||||||
if (!PP_IsNilEntKey(old_id))
|
|
||||||
{
|
|
||||||
PP_EntBin *bin = PP_EntBinFromKey(ss, old_id);
|
|
||||||
u32 prev_index = 0;
|
|
||||||
u32 next_index = 0;
|
|
||||||
u32 search_index = bin->first;
|
|
||||||
PP_Ent *prev = PP_NilEnt();
|
|
||||||
PP_Ent *next = PP_NilEnt();
|
|
||||||
PP_Ent *search = PP_EntFromIndex(ss, search_index);
|
|
||||||
while (search->valid)
|
|
||||||
{
|
|
||||||
next_index = search->next_in_id_bin;
|
|
||||||
next = PP_EntFromIndex(ss, next_index);
|
|
||||||
if (PP_EqEntKey(search->key, old_id))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev_index = search_index;
|
|
||||||
prev = search;
|
|
||||||
search_index = next_index;
|
|
||||||
search = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Old key not in bin, this should be impossible. */
|
|
||||||
Assert(search->valid);
|
|
||||||
|
|
||||||
if (prev->valid)
|
|
||||||
{
|
|
||||||
prev->next_in_id_bin = next_index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = next_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next->valid)
|
|
||||||
{
|
|
||||||
next->prev_in_id_bin = prev_index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->last = prev_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert new key into lookup */
|
|
||||||
if (!PP_IsNilEntKey(key))
|
|
||||||
{
|
|
||||||
if (IsRtcEnabled)
|
|
||||||
{
|
|
||||||
PP_Ent *existing = PP_EntFromKey(ss, key);
|
|
||||||
/* Collision should be extremely unlikely under normal circumstances, there's probably a logic error somewhere. */
|
|
||||||
Assert(!existing->valid);
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_EntBin *bin = PP_EntBinFromKey(ss, key);
|
|
||||||
u32 ent_index = PP_IndexFromEnt(ss, ent);
|
|
||||||
PP_Ent *last = PP_EntFromIndex(ss, bin->last);
|
|
||||||
if (last->valid)
|
|
||||||
{
|
|
||||||
last->next_in_id_bin = ent_index;
|
|
||||||
ent->prev_in_id_bin = bin->last;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = ent_index;
|
|
||||||
ent->prev_in_id_bin = 0;
|
|
||||||
}
|
|
||||||
bin->last = ent_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_EntFromKey(PP_Snapshot *ss, PP_EntKey key)
|
|
||||||
{
|
|
||||||
PP_Ent *result = PP_NilEnt();
|
|
||||||
if (!PP_IsNilEntKey(key) && ss->valid)
|
|
||||||
{
|
|
||||||
PP_EntBin *bin = PP_EntBinFromKey(ss, key);
|
|
||||||
for (PP_Ent *e = PP_EntFromIndex(ss, bin->first); e->valid; e = PP_EntFromIndex(ss, e->next_in_id_bin))
|
|
||||||
{
|
|
||||||
if (PP_EqEntKey(e->key, key))
|
|
||||||
{
|
|
||||||
result = e;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_EntKey PP_RandomKey(void)
|
|
||||||
{
|
|
||||||
PP_EntKey result = ZI;
|
|
||||||
result.uid = UidFromTrueRand();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the deterministic key of the contact constraint ent key that should be produced from e0 & e1 colliding */
|
|
||||||
PP_EntKey PP_ContactConstraintKeyFromContactingKeys(PP_EntKey player_id, PP_EntKey id0, PP_EntKey id1)
|
|
||||||
{
|
|
||||||
PP_EntKey result = ZI;
|
|
||||||
result.uid = PP_ContactBasisUid;
|
|
||||||
result.uid = CombineUid(result.uid, player_id.uid);
|
|
||||||
result.uid = CombineUid(result.uid, id0.uid);
|
|
||||||
result.uid = CombineUid(result.uid, id1.uid);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the deterministic key of the debug contact constraint ent key that should be produced from e0 & e1 colliding */
|
|
||||||
PP_EntKey PP_CollisionDebugKeyFromKeys(PP_EntKey player_id, PP_EntKey id0, PP_EntKey id1)
|
|
||||||
{
|
|
||||||
PP_EntKey result = ZI;
|
|
||||||
result.uid = PP_CollisionDebugBasisUid;
|
|
||||||
result.uid = CombineUid(result.uid, player_id.uid);
|
|
||||||
result.uid = CombineUid(result.uid, id0.uid);
|
|
||||||
result.uid = CombineUid(result.uid, id1.uid);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the deterministic key of the tile chunk that should be produced at chunk pos */
|
|
||||||
PP_EntKey PP_TileChunkKeyFromIndex(Vec2I32 chunk_index)
|
|
||||||
{
|
|
||||||
PP_EntKey result = ZI;
|
|
||||||
result.uid = PP_TileChunkBasisUid;
|
|
||||||
result.uid = CombineUid(result.uid, UID(RandU64FromSeed(chunk_index.x), RandU64FromSeed(chunk_index.y)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Query
|
|
||||||
|
|
||||||
PP_Ent *PP_FirstWithProp(PP_Snapshot *ss, PP_Prop prop)
|
|
||||||
{
|
|
||||||
u64 count = ss->num_ents_reserved;
|
|
||||||
PP_Ent *entities = ss->ents;
|
|
||||||
for (u64 ent_index = 0; ent_index < count; ++ent_index)
|
|
||||||
{
|
|
||||||
PP_Ent *ent = &entities[ent_index];
|
|
||||||
if (ent->valid && PP_HasProp(ent, prop))
|
|
||||||
{
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PP_NilEnt();
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_FirstWithAllProps(PP_Snapshot *ss, PP_PropArray props)
|
|
||||||
{
|
|
||||||
u64 count = ss->num_ents_reserved;
|
|
||||||
PP_Ent *entities = ss->ents;
|
|
||||||
for (u64 ent_index = 0; ent_index < count; ++ent_index)
|
|
||||||
{
|
|
||||||
PP_Ent *ent = &entities[ent_index];
|
|
||||||
if (ent->valid)
|
|
||||||
{
|
|
||||||
b32 all = 1;
|
|
||||||
for (u64 i = 0; i < props.count; ++i)
|
|
||||||
{
|
|
||||||
if (!PP_HasProp(ent, props.props[i]))
|
|
||||||
{
|
|
||||||
all = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (all)
|
|
||||||
{
|
|
||||||
return ent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PP_NilEnt();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tree
|
|
||||||
|
|
||||||
void PP_Link(PP_Ent *ent, PP_Ent *parent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
|
|
||||||
PP_Ent *old_parent = PP_EntFromKey(ss, ent->parent);
|
|
||||||
if (old_parent->valid)
|
|
||||||
{
|
|
||||||
/* Unlink from current parent */
|
|
||||||
PP_Unlink(ent);
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_EntKey ent_id = ent->key;
|
|
||||||
PP_EntKey last_child_id = parent->last;
|
|
||||||
PP_Ent *last_child = PP_EntFromKey(ss, last_child_id);
|
|
||||||
if (last_child->valid)
|
|
||||||
{
|
|
||||||
ent->prev = last_child_id;
|
|
||||||
last_child->next = ent_id;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent->first = ent_id;
|
|
||||||
}
|
|
||||||
parent->last = ent_id;
|
|
||||||
|
|
||||||
if (parent->is_root)
|
|
||||||
{
|
|
||||||
ent->is_top = 1;
|
|
||||||
ent->top = ent_id;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ent->top = parent->top;
|
|
||||||
}
|
|
||||||
|
|
||||||
ent->parent = parent->key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOTE: PP_Ent will be dangling after calling this, should re-link to root ent. */
|
|
||||||
void PP_Unlink(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
|
|
||||||
PP_EntKey parent_id = ent->parent;
|
|
||||||
PP_Ent *parent = PP_EntFromKey(ss, parent_id);
|
|
||||||
PP_Ent *prev = PP_EntFromKey(ss, ent->prev);
|
|
||||||
PP_Ent *next = PP_EntFromKey(ss, ent->next);
|
|
||||||
|
|
||||||
/* Unlink from parent & siblings */
|
|
||||||
if (prev->valid)
|
|
||||||
{
|
|
||||||
prev->next = next->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent->first = next->key;
|
|
||||||
}
|
|
||||||
if (next->valid)
|
|
||||||
{
|
|
||||||
next->prev = prev->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent->last = prev->key;
|
|
||||||
}
|
|
||||||
ent->prev = PP_NilEntKey;
|
|
||||||
ent->next = PP_NilEntKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Xform
|
|
||||||
|
|
||||||
void PP_MarkChildXformsDirty(PP_Snapshot *ss, PP_Ent *ent)
|
|
||||||
{
|
|
||||||
for (PP_Ent *child = PP_EntFromKey(ss, ent->first); child->valid; child = PP_EntFromKey(ss, child->next))
|
|
||||||
{
|
|
||||||
if (child->_is_xform_dirty)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
child->_is_xform_dirty = 1;
|
|
||||||
PP_MarkChildXformsDirty(ss, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Xform PP_XformFromEnt_(PP_Snapshot *ss, PP_Ent *ent)
|
|
||||||
{
|
|
||||||
Xform xf;
|
|
||||||
if (ent->_is_xform_dirty)
|
|
||||||
{
|
|
||||||
if (ent->is_top)
|
|
||||||
{
|
|
||||||
xf = ent->_local_xform;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PP_Ent *parent = PP_EntFromKey(ss, ent->parent);
|
|
||||||
xf = PP_XformFromEnt_(ss, parent);
|
|
||||||
xf = MulXform(xf, ent->_local_xform);
|
|
||||||
ent->_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 0;
|
|
||||||
}
|
|
||||||
ent->_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xf = ent->_xform;
|
|
||||||
}
|
|
||||||
return xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
Xform PP_XformFromEnt(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
Xform xf;
|
|
||||||
if (ent->_is_xform_dirty)
|
|
||||||
{
|
|
||||||
if (ent->is_top)
|
|
||||||
{
|
|
||||||
xf = ent->_local_xform;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
PP_Ent *parent = PP_EntFromKey(ss, ent->parent);
|
|
||||||
xf = PP_XformFromEnt_(ss, parent);
|
|
||||||
xf = MulXform(xf, ent->_local_xform);
|
|
||||||
ent->_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 0;
|
|
||||||
}
|
|
||||||
ent->_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
xf = ent->_xform;
|
|
||||||
}
|
|
||||||
return xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
Xform PP_LocalXformFromEnt(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
return ent->_local_xform;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_SetXform(PP_Ent *ent, Xform xf)
|
|
||||||
{
|
|
||||||
if (!EqXform(xf, ent->_xform))
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = ent->ss;
|
|
||||||
/* Update local xform */
|
|
||||||
if (ent->is_top)
|
|
||||||
{
|
|
||||||
ent->_local_xform = xf;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PP_Ent *parent = PP_EntFromKey(ss, ent->parent);
|
|
||||||
Xform parent_global = PP_XformFromEnt_(ss, parent);
|
|
||||||
ent->_local_xform = MulXform(InvertXform(parent_global), xf);
|
|
||||||
}
|
|
||||||
ent->_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 0;
|
|
||||||
PP_MarkChildXformsDirty(ss, ent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_SetLocalXform(PP_Ent *ent, Xform xf)
|
|
||||||
{
|
|
||||||
if (!EqXform(xf, ent->_local_xform))
|
|
||||||
{
|
|
||||||
ent->_local_xform = xf;
|
|
||||||
ent->_is_xform_dirty = 1;
|
|
||||||
PP_MarkChildXformsDirty(ent->ss, ent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Movement
|
|
||||||
|
|
||||||
void PP_SetLinearVelocity(PP_Ent *ent, Vec2 velocity)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Kinematic) || PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
ent->linear_velocity = ClampVec2Len(velocity, SIM_MAX_LINEAR_VELOCITY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_SetAngularVelocity(PP_Ent *ent, f32 velocity)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Kinematic) || PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
ent->angular_velocity = ClampF32(velocity, -SIM_MAX_ANGULAR_VELOCITY, SIM_MAX_ANGULAR_VELOCITY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ApplyLinearImpulse(PP_Ent *ent, Vec2 impulse, Vec2 point)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
Xform xf = PP_XformFromEnt(ent);
|
|
||||||
Vec2 center = xf.og;
|
|
||||||
f32 scale = AbsF32(DeterminantFromXform(xf));
|
|
||||||
f32 inv_mass = 1.f / (ent->mass_unscaled * scale);
|
|
||||||
f32 inv_inertia = 1.f / (ent->inertia_unscaled * scale);
|
|
||||||
|
|
||||||
Vec2 vcp = SubVec2(point, center);
|
|
||||||
PP_SetLinearVelocity(ent, AddVec2(ent->linear_velocity, MulVec2(impulse, inv_mass)));
|
|
||||||
PP_SetAngularVelocity(ent, WedgeVec2(vcp, impulse) * inv_inertia);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ApplyLinearImpulseToCenter(PP_Ent *ent, Vec2 impulse)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
Xform xf = PP_XformFromEnt(ent);
|
|
||||||
f32 scale = AbsF32(DeterminantFromXform(xf));
|
|
||||||
f32 inv_mass = 1.f / (ent->mass_unscaled * scale);
|
|
||||||
|
|
||||||
PP_SetLinearVelocity(ent, AddVec2(ent->linear_velocity, MulVec2(impulse, inv_mass)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ApplyForceToCenter(PP_Ent *ent, Vec2 force)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
ent->force = AddVec2(ent->force, force);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ApplyAngularImpulse(PP_Ent *ent, f32 impulse)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
Xform xf = PP_XformFromEnt(ent);
|
|
||||||
f32 scale = AbsF32(DeterminantFromXform(xf));
|
|
||||||
f32 inv_inertia = 1.f / (ent->inertia_unscaled * scale);
|
|
||||||
PP_SetAngularVelocity(ent, ent->angular_velocity + impulse * inv_inertia);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ApplyTorque(PP_Ent *ent, f32 torque)
|
|
||||||
{
|
|
||||||
if (PP_HasProp(ent, PP_Prop_Dynamic))
|
|
||||||
{
|
|
||||||
ent->torque += torque;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile
|
|
||||||
|
|
||||||
PP_Ent *PP_TileChunkFromChunkIndex(PP_Snapshot *ss, Vec2I32 chunk_index)
|
|
||||||
{
|
|
||||||
PP_EntKey chunk_id = PP_TileChunkKeyFromIndex(chunk_index);
|
|
||||||
PP_Ent *chunk_ent = PP_EntFromKey(ss, chunk_id);
|
|
||||||
return chunk_ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Ent *PP_TileChunkFromWorldTileIndex(PP_Snapshot *ss, Vec2I32 world_tile_index)
|
|
||||||
{
|
|
||||||
Vec2I32 chunk_index = PP_TileChunkIndexFromWorldTileIndex(world_tile_index);
|
|
||||||
PP_Ent *chunk_ent = PP_TileChunkFromChunkIndex(ss, chunk_index);
|
|
||||||
return chunk_ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_TileKind PP_TileKindFromChunk(PP_Ent *chunk_ent, Vec2I32 local_tile_index)
|
|
||||||
{
|
|
||||||
PP_TileKind result = chunk_ent->tile_chunk_tiles[local_tile_index.x + (local_tile_index.y * SIM_TILES_PER_CHUNK_SQRT)];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Lerp
|
|
||||||
|
|
||||||
void PP_LerpEnt(PP_Ent *e, PP_Ent *e0, PP_Ent *e1, f64 blend)
|
|
||||||
{
|
|
||||||
if (PP_IsValidAndActive(e0) && PP_IsValidAndActive(e1)
|
|
||||||
&& PP_EqEntKey(e0->key, e1->key)
|
|
||||||
&& e0->continuity_gen == e1->continuity_gen)
|
|
||||||
{
|
|
||||||
e->_local_xform = LerpXform(e0->_local_xform, e1->_local_xform, blend);
|
|
||||||
|
|
||||||
if (e->is_top)
|
|
||||||
{
|
|
||||||
/* TODO: Cache parent & child xforms in sim */
|
|
||||||
Xform e0_xf = PP_XformFromEnt(e0);
|
|
||||||
Xform e1_xf = PP_XformFromEnt(e1);
|
|
||||||
PP_SetXform(e, LerpXform(e0_xf, e1_xf, blend));
|
|
||||||
}
|
|
||||||
|
|
||||||
e->control_force = LerpF32(e0->control_force, e1->control_force, blend);
|
|
||||||
e->control_torque = LerpF32(e0->control_torque, e1->control_torque, blend);
|
|
||||||
|
|
||||||
e->linear_velocity = LerpVec2(e0->linear_velocity, e1->linear_velocity, blend);
|
|
||||||
e->angular_velocity = LerpAngleF32(e0->angular_velocity, e1->angular_velocity, blend);
|
|
||||||
|
|
||||||
e->control.move = LerpVec2(e0->control.move, e1->control.move, blend);
|
|
||||||
e->control.focus = LerpVec2(e0->control.focus, e1->control.focus, blend);
|
|
||||||
|
|
||||||
e->sprite_local_xform = LerpXform(e0->sprite_local_xform, e1->sprite_local_xform, blend);
|
|
||||||
e->animation_last_frame_change_time_ns = LerpI64(e0->animation_last_frame_change_time_ns, e1->animation_last_frame_change_time_ns, (f64)blend);
|
|
||||||
e->animation_frame = (u32)RoundF32ToI32(LerpF32(e0->animation_frame, e1->animation_frame, blend));
|
|
||||||
|
|
||||||
e->camera_quad_xform = LerpXform(e0->camera_quad_xform, e1->camera_quad_xform, blend);
|
|
||||||
e->camera_xform_target = LerpXform(e0->camera_xform_target, e1->camera_xform_target, blend);
|
|
||||||
e->shake = LerpF32(e0->shake, e1->shake, blend);
|
|
||||||
|
|
||||||
e->tracer_gradient_start = LerpVec2(e0->tracer_gradient_start, e1->tracer_gradient_start, blend);
|
|
||||||
e->tracer_gradient_end = LerpVec2(e0->tracer_gradient_end, e1->tracer_gradient_end, blend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sync
|
|
||||||
|
|
||||||
/* Walks a local & remote ent tree and allocates any missing net dst ents from remote src ents */
|
|
||||||
void PP_CreateMissingEntsFromSnapshots(PP_Ent *local_parent, PP_Ent *remote, PP_EntKey remote_player)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
if (PP_HasProp(remote, PP_Prop_SyncSrc))
|
|
||||||
{
|
|
||||||
PP_Snapshot *local_ss = local_parent->ss;
|
|
||||||
PP_Snapshot *remote_ss = remote->ss;
|
|
||||||
|
|
||||||
PP_EntKey key = remote->key;
|
|
||||||
PP_Ent *local_ent = PP_EntFromKey(local_ss, key);
|
|
||||||
if (!local_ent->valid)
|
|
||||||
{
|
|
||||||
local_ent = PP_AcquireSyncDstEnt(local_parent, key, remote_player);
|
|
||||||
}
|
|
||||||
for (PP_Ent *remote_child = PP_EntFromKey(remote_ss, remote->first); remote_child->valid; remote_child = PP_EntFromKey(remote_ss, remote_child->next))
|
|
||||||
{
|
|
||||||
PP_CreateMissingEntsFromSnapshots(local_ent, remote_child, remote_player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copies data between two synced entities */
|
|
||||||
void PP_SyncEnt(PP_Ent *local, PP_Ent *remote)
|
|
||||||
{
|
|
||||||
PP_Ent old = *local;
|
|
||||||
CopyStruct(local, remote);
|
|
||||||
|
|
||||||
/* Why would 2 ents w/ different uids ever be synced? */
|
|
||||||
Assert(PP_EqEntKey(local->key, old.key));
|
|
||||||
|
|
||||||
local->ss = old.ss;
|
|
||||||
local->key = old.key;
|
|
||||||
|
|
||||||
/* Keep local tree */
|
|
||||||
local->parent = old.parent;
|
|
||||||
local->prev = old.prev;
|
|
||||||
local->next = old.next;
|
|
||||||
local->first = old.first;
|
|
||||||
local->last = old.last;
|
|
||||||
local->top = old.top;
|
|
||||||
local->owner = old.owner;
|
|
||||||
|
|
||||||
/* Keep indices */
|
|
||||||
local->next_in_id_bin = old.next_in_id_bin;
|
|
||||||
local->prev_in_id_bin = old.prev_in_id_bin;
|
|
||||||
local->next_free = old.next_free;
|
|
||||||
|
|
||||||
PP_DisableProp(local, PP_Prop_SyncSrc);
|
|
||||||
PP_EnableProp(local, PP_Prop_SyncDst);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Encode
|
|
||||||
|
|
||||||
void PP_EncodeEnt(BB_Writer *bw, PP_Ent *e0, PP_Ent *e1)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = e1->ss;
|
|
||||||
/* FIXME: Things like xforms need to be retreived manually rather than memcopied. */
|
|
||||||
|
|
||||||
/* TODO: Granular delta encoding */
|
|
||||||
|
|
||||||
u64 pos = 0;
|
|
||||||
e1->ss = e0->ss;
|
|
||||||
while (pos < sizeof(*e1))
|
|
||||||
{
|
|
||||||
u64 chunk_size = MinU64(pos + 8, sizeof(*e1)) - pos;
|
|
||||||
u8 *chunk0 = (u8 *)e0 + pos;
|
|
||||||
u8 *chunk1 = (u8 *)e1 + pos;
|
|
||||||
if (BB_WriteBit(bw, !EqBytes(chunk0, chunk1, chunk_size)))
|
|
||||||
{
|
|
||||||
u64 bits = 0;
|
|
||||||
CopyBytes(&bits, chunk1, chunk_size);
|
|
||||||
BB_WriteUBits(bw, bits, 64);
|
|
||||||
}
|
|
||||||
pos += 8;
|
|
||||||
}
|
|
||||||
e1->ss = ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Decode
|
|
||||||
|
|
||||||
void PP_DecodeEnt(BB_Reader *br, PP_Ent *e)
|
|
||||||
{
|
|
||||||
PP_Snapshot *old_ss = e->ss;
|
|
||||||
{
|
|
||||||
u64 pos = 0;
|
|
||||||
while (pos < sizeof(*e))
|
|
||||||
{
|
|
||||||
u8 *chunk = (u8 *)e + pos;
|
|
||||||
if (BB_ReadBit(br))
|
|
||||||
{
|
|
||||||
u64 chunk_size = MinU64(pos + 8, sizeof(*e)) - pos;
|
|
||||||
u64 bits = BB_ReadUBits(br, 64);
|
|
||||||
CopyBytes(chunk, &bits, chunk_size);
|
|
||||||
}
|
|
||||||
pos += 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e->ss = old_ss;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,568 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Ent props
|
|
||||||
|
|
||||||
Enum(PP_Prop)
|
|
||||||
{
|
|
||||||
PP_Prop_Active,
|
|
||||||
PP_Prop_Release,
|
|
||||||
|
|
||||||
PP_Prop_SyncSrc, /* This entity is networked to other clients */
|
|
||||||
PP_Prop_SyncDst, /* This entity is not locally created, and will sync with incoming net src ents */
|
|
||||||
|
|
||||||
PP_Prop_Player,
|
|
||||||
PP_Prop_IsMaster,
|
|
||||||
|
|
||||||
PP_Prop_Cmd,
|
|
||||||
|
|
||||||
PP_Prop_TileChunk,
|
|
||||||
PP_Prop_Wall,
|
|
||||||
|
|
||||||
/* Physics collision */
|
|
||||||
PP_Prop_Sensor, /* This entity's collisions generate contacts */
|
|
||||||
PP_Prop_Solid, /* This entity's collisions generate contacts to be solved by the physics system (overrides PP_Prop_Sensor) */
|
|
||||||
PP_Prop_Toi, /* This entity's collisions are processed using TOI (time of impact) for precise collisions */
|
|
||||||
|
|
||||||
/* Physics movement */
|
|
||||||
PP_Prop_Kinematic, /* This entity reacts to velocity */
|
|
||||||
PP_Prop_Dynamic, /* This entity reacts to velocity and forces (overrides PP_Prop_Kinematic) */
|
|
||||||
|
|
||||||
PP_Prop_Controlled,
|
|
||||||
|
|
||||||
PP_Prop_CollisionDebug,
|
|
||||||
PP_Prop_ContactConstraint,
|
|
||||||
PP_Prop_MotorJoint,
|
|
||||||
PP_Prop_MouseJoint,
|
|
||||||
PP_Prop_WeldJoint,
|
|
||||||
|
|
||||||
PP_Prop_Camera,
|
|
||||||
PP_Prop_ActiveCamera,
|
|
||||||
|
|
||||||
PP_Prop_Bullet,
|
|
||||||
PP_Prop_Smg,
|
|
||||||
PP_Prop_Launcher,
|
|
||||||
PP_Prop_Chucker,
|
|
||||||
|
|
||||||
PP_Prop_ChuckerZone,
|
|
||||||
|
|
||||||
PP_Prop_Explosion,
|
|
||||||
|
|
||||||
PP_Prop_Tracer,
|
|
||||||
|
|
||||||
PP_Prop_Quake,
|
|
||||||
|
|
||||||
PP_Prop_Attached,
|
|
||||||
|
|
||||||
/* Test props */
|
|
||||||
|
|
||||||
PP_Prop_Test,
|
|
||||||
PP_Prop_SoundEmitterTest,
|
|
||||||
PP_Prop_LightTest,
|
|
||||||
|
|
||||||
PP_Prop_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Ent
|
|
||||||
|
|
||||||
Struct(PP_Ent)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss;
|
|
||||||
|
|
||||||
//- Metadata
|
|
||||||
|
|
||||||
b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */
|
|
||||||
PP_EntKey key;
|
|
||||||
u64 props[(PP_Prop_COUNT + 63) / 64];
|
|
||||||
u64 continuity_gen;
|
|
||||||
|
|
||||||
/* Is this the root ent */
|
|
||||||
b32 is_root;
|
|
||||||
|
|
||||||
/* Is ent a child of the root ent */
|
|
||||||
b32 is_top;
|
|
||||||
|
|
||||||
/* The key of the top level parent of the ent tree (if ent is top then this point to itself) */
|
|
||||||
PP_EntKey top;
|
|
||||||
|
|
||||||
/* Tree */
|
|
||||||
PP_EntKey parent;
|
|
||||||
PP_EntKey next;
|
|
||||||
PP_EntKey prev;
|
|
||||||
PP_EntKey first;
|
|
||||||
PP_EntKey last;
|
|
||||||
|
|
||||||
/* Lists keyed by index in snapshot ent array */
|
|
||||||
u32 next_in_id_bin;
|
|
||||||
u32 prev_in_id_bin;
|
|
||||||
u32 next_free;
|
|
||||||
|
|
||||||
//- Sync
|
|
||||||
|
|
||||||
/* PP_Prop_SyncSrc */
|
|
||||||
/* PP_Prop_SyncDst */
|
|
||||||
|
|
||||||
/* Key of the player that owns simulation for this entity */
|
|
||||||
PP_EntKey owner;
|
|
||||||
|
|
||||||
/* Key of the player that should predict simulation of this this entity locally */
|
|
||||||
PP_EntKey predictor;
|
|
||||||
|
|
||||||
//- Position
|
|
||||||
|
|
||||||
/* Use xform getters & setters to access. */
|
|
||||||
Xform _local_xform; /* Transform in relation to parent ent (or the world if ent has no parent) */
|
|
||||||
Xform _xform; /* Calculated from ent tree */
|
|
||||||
b32 _is_xform_dirty;
|
|
||||||
|
|
||||||
//- Activation
|
|
||||||
|
|
||||||
/* If 0, the ent will auto activate at start of next tick if not already active. */
|
|
||||||
u64 activation_tick;
|
|
||||||
|
|
||||||
//- Layer
|
|
||||||
|
|
||||||
i32 layer;
|
|
||||||
i32 final_layer; /* Calculated each tick from ent tree */
|
|
||||||
|
|
||||||
//- Cmd
|
|
||||||
|
|
||||||
/* PP_Prop_Cmd */
|
|
||||||
|
|
||||||
PP_CmdKind cmd_kind;
|
|
||||||
PP_EntKey cmd_player;
|
|
||||||
|
|
||||||
/* FIXME: Lerp */
|
|
||||||
|
|
||||||
/* Control cmd */
|
|
||||||
PP_ControlData cmd_control;
|
|
||||||
PP_EntKey cmd_control_hovered_ent;
|
|
||||||
|
|
||||||
/* Chat cmd */
|
|
||||||
//String cmd_chat_msg;
|
|
||||||
|
|
||||||
//- Chat
|
|
||||||
|
|
||||||
/* PP_Prop_Chat */
|
|
||||||
|
|
||||||
PP_EntKey chat_player;
|
|
||||||
//String chat_msg;
|
|
||||||
|
|
||||||
|
|
||||||
//- Tile
|
|
||||||
|
|
||||||
/* PP_Prop_TileChunk */
|
|
||||||
|
|
||||||
/* FIXME: Move out of here */
|
|
||||||
u8 tile_chunk_tiles[SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT];
|
|
||||||
Vec2I32 tile_chunk_index;
|
|
||||||
|
|
||||||
//- Client
|
|
||||||
|
|
||||||
/* PP_Prop_Player */
|
|
||||||
|
|
||||||
/* FIXME: Lerp */
|
|
||||||
|
|
||||||
PP_ClientKey player_client_key; /* The client key on the master sim's machine */
|
|
||||||
|
|
||||||
PP_ControlData player_control;
|
|
||||||
Vec2 player_cursor_pos;
|
|
||||||
|
|
||||||
PP_EntKey player_hovered_ent;
|
|
||||||
PP_EntKey player_control_ent;
|
|
||||||
PP_EntKey player_camera_ent;
|
|
||||||
|
|
||||||
PP_EntKey player_dbg_drag_joint_ent;
|
|
||||||
b32 player_dbg_drag_start;
|
|
||||||
b32 player_dbg_drag_stop;
|
|
||||||
|
|
||||||
/* Client round-trip-time to server */
|
|
||||||
i64 player_last_rtt_ns;
|
|
||||||
f64 player_average_rtt_seconds;
|
|
||||||
|
|
||||||
//- Collider
|
|
||||||
|
|
||||||
Vec2 collision_dir; /* If set, then only collisions coming from this direction will generate contacts (used for walls to prevent ghost collisions) */
|
|
||||||
CLD_Shape local_collider;
|
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
|
||||||
ContactDebugData collision_debug_data;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PP_SpaceEntryKey space_key;
|
|
||||||
|
|
||||||
//- Constraints / joints
|
|
||||||
|
|
||||||
/* PP_Prop_ContactConstraint */
|
|
||||||
PP_ContactConstraint contact_constraint_data;
|
|
||||||
|
|
||||||
/* PP_Prop_MotorJoint */
|
|
||||||
PP_MotorJoint motor_joint_data;
|
|
||||||
|
|
||||||
/* PP_Prop_MouseJoint */
|
|
||||||
PP_MouseJoint mouse_joint_data;
|
|
||||||
|
|
||||||
/* PP_Prop_WeldJoint */
|
|
||||||
PP_WeldJoint weld_joint_data;
|
|
||||||
|
|
||||||
//- Control
|
|
||||||
|
|
||||||
/* PP_Prop_Controlled */
|
|
||||||
|
|
||||||
PP_EntKey controlling_player;
|
|
||||||
|
|
||||||
f32 control_force; /* How much force is applied to achieve desired control movement */
|
|
||||||
f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */
|
|
||||||
|
|
||||||
f32 control_torque; /* How much torque is applied when turning towards desired focus */
|
|
||||||
|
|
||||||
PP_ControlData control;
|
|
||||||
|
|
||||||
PP_EntKey move_joint;
|
|
||||||
PP_EntKey aim_joint;
|
|
||||||
|
|
||||||
//- Physics
|
|
||||||
|
|
||||||
/* PP_Prop_Dynamic */
|
|
||||||
|
|
||||||
//f32 density; /* Density in kg/m^2 */
|
|
||||||
|
|
||||||
f32 friction;
|
|
||||||
|
|
||||||
f32 mass_unscaled; /* Mass of ent in kg before any transformations */
|
|
||||||
f32 inertia_unscaled; /* Inertia of ent in kg*m^2 before any transformations */
|
|
||||||
|
|
||||||
PP_EntKey ground_friction_joint;
|
|
||||||
f32 linear_ground_friction;
|
|
||||||
f32 angular_ground_friction;
|
|
||||||
|
|
||||||
/* Use PP_SetLinearVelocity & PP_SetAngularVelocity to set */
|
|
||||||
Vec2 linear_velocity; /* m/s */
|
|
||||||
f32 angular_velocity; /* rad/s */
|
|
||||||
|
|
||||||
Vec2 force;
|
|
||||||
f32 torque;
|
|
||||||
|
|
||||||
f32 linear_damping;
|
|
||||||
f32 angular_damping;
|
|
||||||
|
|
||||||
//- Sprite
|
|
||||||
|
|
||||||
ResourceKey sprite;
|
|
||||||
SPR_SpanKey sprite_span_key;
|
|
||||||
u32 sprite_tint;
|
|
||||||
Vec3 sprite_emittance;
|
|
||||||
|
|
||||||
SPR_SliceKey sprite_collider_slice_key; /* Collider will sync to bounds of this slice if set */
|
|
||||||
|
|
||||||
Xform sprite_local_xform; /* Sprite transform in relation to ent */
|
|
||||||
|
|
||||||
//- Animation
|
|
||||||
|
|
||||||
/* PP_Prop_Animating */
|
|
||||||
i64 animation_last_frame_change_time_ns;
|
|
||||||
u32 animation_frame;
|
|
||||||
|
|
||||||
//- Attachment
|
|
||||||
|
|
||||||
/* PP_Prop_Attached */
|
|
||||||
/* Slice on the parent ent's sprite to attach to */
|
|
||||||
SPR_SliceKey attach_slice_key;
|
|
||||||
|
|
||||||
//- Equip
|
|
||||||
|
|
||||||
PP_EntKey equipped;
|
|
||||||
|
|
||||||
//- Chucker
|
|
||||||
|
|
||||||
/* PP_Prop_Chucker */
|
|
||||||
|
|
||||||
PP_EntKey chucker_zone;
|
|
||||||
PP_EntKey chucker_joint;
|
|
||||||
|
|
||||||
//- Chucker zone
|
|
||||||
|
|
||||||
/* PP_Prop_ChuckerZone */
|
|
||||||
|
|
||||||
PP_EntKey chucker_zone_ent;
|
|
||||||
u64 chucker_zone_ent_tick;
|
|
||||||
|
|
||||||
//- Triggerable
|
|
||||||
|
|
||||||
i32 num_primary_triggers;
|
|
||||||
i32 num_secondary_triggers;
|
|
||||||
|
|
||||||
f32 primary_fire_delay;
|
|
||||||
f32 secondary_fire_delay;
|
|
||||||
|
|
||||||
i64 last_primary_fire_ns;
|
|
||||||
i64 last_secondary_fire_ns;
|
|
||||||
|
|
||||||
//- Trigger
|
|
||||||
|
|
||||||
/* How many times has this trigger been triggered this tick */
|
|
||||||
i64 triggered_count;
|
|
||||||
|
|
||||||
/* Other triggers to activate when this entity has been triggered */
|
|
||||||
//PP_EntKey trigger_out_left;
|
|
||||||
//PP_EntKey trigger_out_right;
|
|
||||||
|
|
||||||
//- Bullet
|
|
||||||
|
|
||||||
PP_EntKey bullet_src;
|
|
||||||
PP_EntKey bullet_tracer;
|
|
||||||
Vec2 bullet_src_pos;
|
|
||||||
Vec2 bullet_src_dir;
|
|
||||||
f32 bullet_launch_velocity;
|
|
||||||
f32 bullet_knockback;
|
|
||||||
f32 bullet_explosion_strength;
|
|
||||||
f32 bullet_explosion_radius;
|
|
||||||
b32 bullet_has_hit;
|
|
||||||
|
|
||||||
//- Explosion
|
|
||||||
|
|
||||||
f32 explosion_strength;
|
|
||||||
f32 explosion_radius;
|
|
||||||
|
|
||||||
//- Tracer
|
|
||||||
|
|
||||||
/* PP_Prop_Tracer */
|
|
||||||
|
|
||||||
Vec2 tracer_start;
|
|
||||||
Vec2 tracer_start_velocity;
|
|
||||||
f32 tracer_fade_duration; /* Time for tracer to fade from opacity of 1 to 0 */
|
|
||||||
|
|
||||||
/* calculated each frame */
|
|
||||||
Vec2 tracer_gradient_start;
|
|
||||||
Vec2 tracer_gradient_end;
|
|
||||||
|
|
||||||
//- Quake
|
|
||||||
|
|
||||||
/* PP_Prop_Quake */
|
|
||||||
|
|
||||||
f32 quake_intensity;
|
|
||||||
f32 quake_frequency;
|
|
||||||
f32 quake_fade; /* How much intensity to lose per second */
|
|
||||||
|
|
||||||
//- Testing
|
|
||||||
|
|
||||||
/* PP_Prop_Test */
|
|
||||||
b32 test_initialized;
|
|
||||||
Xform test_start_local_xform;
|
|
||||||
Xform test_start_sprite_xform;
|
|
||||||
|
|
||||||
/* PP_Prop_SoundEmitterTest */
|
|
||||||
// String sound_name;
|
|
||||||
// MIX_TrackDesc sound_desc;
|
|
||||||
// MIX_Handle sound_handle;
|
|
||||||
|
|
||||||
//- Camera
|
|
||||||
|
|
||||||
/* PP_Prop_Camera */
|
|
||||||
PP_EntKey camera_follow;
|
|
||||||
Xform camera_quad_xform;
|
|
||||||
f32 camera_lerp; /* Rate at which camera xform approaches target xform */
|
|
||||||
|
|
||||||
u32 camera_lerp_continuity_gen;
|
|
||||||
Xform camera_xform_target; /* Calculated from camera_follow */
|
|
||||||
u32 camera_applied_lerp_continuity_gen_plus_one; /* Calculated */
|
|
||||||
|
|
||||||
f32 shake;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_EntArray)
|
|
||||||
{
|
|
||||||
PP_Ent *ents;
|
|
||||||
u64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_PropArray)
|
|
||||||
{
|
|
||||||
PP_Prop *props;
|
|
||||||
u64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_EntBin)
|
|
||||||
{
|
|
||||||
u32 first;
|
|
||||||
u32 last;
|
|
||||||
};
|
|
||||||
|
|
||||||
Inline PP_Ent *PP_NilEnt(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_Ent **PP_nil_ent;
|
|
||||||
return *PP_nil_ent;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Key types
|
|
||||||
|
|
||||||
#define PP_NilEntKey ((PP_EntKey) { UID(0, 0) })
|
|
||||||
#define PP_RootEntKey ((PP_EntKey) { UID(0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa) })
|
|
||||||
|
|
||||||
/* Key magic number constants (to be used in conjunction with ent ids in deterministic key combinations) */
|
|
||||||
#define PP_TileChunkBasisUid (UID(0x3ce42de071dd226b, 0x9b566f7df30c813a))
|
|
||||||
#define PP_ContactBasisUid (UID(0x6a2a5d2dbecf534f, 0x0a8ca7c372a015af))
|
|
||||||
#define PP_CollisionDebugBasisUid (UID(0x302c01182013bb02, 0x570bd270399d11a5))
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Key helpers
|
|
||||||
|
|
||||||
Inline b32 PP_EqEntKey(PP_EntKey a, PP_EntKey b)
|
|
||||||
{
|
|
||||||
return EqUid(a.uid, b.uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_IsNilEntKey(PP_EntKey key)
|
|
||||||
{
|
|
||||||
return EqUid(key.uid, PP_NilEntKey.uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Property helpers
|
|
||||||
|
|
||||||
Inline void PP_EnableProp(PP_Ent *ent, PP_Prop prop)
|
|
||||||
{
|
|
||||||
u64 index = prop / 64;
|
|
||||||
u64 bit = prop % 64;
|
|
||||||
ent->props[index] |= ((u64)1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline void PP_DisableProp(PP_Ent *ent, PP_Prop prop)
|
|
||||||
{
|
|
||||||
u64 index = prop / 64;
|
|
||||||
u64 bit = prop % 64;
|
|
||||||
ent->props[index] &= ~((u64)1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_HasProp(PP_Ent *ent, PP_Prop prop)
|
|
||||||
{
|
|
||||||
u64 index = prop / 64;
|
|
||||||
u64 bit = prop % 64;
|
|
||||||
return !!(ent->props[index] & ((u64)1 << bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_IsValidAndActive(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
return ent->valid && PP_HasProp(ent, PP_Prop_Active);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_ShouldPredict(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
return PP_EqEntKey(ent->predictor, ent->ss->local_player);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_IsOwner(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
return PP_EqEntKey(ent->owner, ent->ss->local_player);
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_ShouldSimulate(PP_Ent *ent)
|
|
||||||
{
|
|
||||||
b32 result = 0;
|
|
||||||
if (PP_IsValidAndActive(ent))
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
if (PP_HasProp(ent, PP_Prop_SyncDst))
|
|
||||||
{
|
|
||||||
PP_EntKey local_player = ent->ss->local_player;
|
|
||||||
result = PP_EqEntKey(local_player, ent->owner) || PP_EqEntKey(local_player, ent->predictor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acquire operations
|
|
||||||
|
|
||||||
PP_Ent *PP_AcquireRawEnt(PP_Snapshot *ss, PP_Ent *parent, PP_EntKey key);
|
|
||||||
PP_Ent *PP_AcquireLocalEnt(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_AcquireLocalEntWithKey(PP_Ent *parent, PP_EntKey key);
|
|
||||||
PP_Ent *PP_AcquireSyncSrcEnt(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_AcquireSyncSrcEntWithKey(PP_Ent *parent, PP_EntKey key);
|
|
||||||
PP_Ent *PP_AcquireSyncDstEnt(PP_Ent *parent, PP_EntKey ent_id, PP_EntKey owner_id);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Release operations
|
|
||||||
|
|
||||||
void PP_ReleaseRawEnt(PP_Ent *ent);
|
|
||||||
void PP_Release(PP_Ent *ent);
|
|
||||||
void PP_ReleaseAllWithProp(PP_Snapshot *ss, PP_Prop prop);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Activate operations
|
|
||||||
|
|
||||||
void PP_ActivateEnt(PP_Ent *ent, u64 current_tick);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Key operations
|
|
||||||
|
|
||||||
u32 PP_IndexFromEnt(PP_Snapshot *ss, PP_Ent *ent);
|
|
||||||
PP_Ent *PP_EntFromIndex(PP_Snapshot *ss, u32 index);
|
|
||||||
PP_EntBin *PP_EntBinFromKey(PP_Snapshot *ss, PP_EntKey key);
|
|
||||||
void PP_SetEntKey(PP_Ent *ent, PP_EntKey key);
|
|
||||||
PP_Ent *PP_EntFromKey(PP_Snapshot *ss, PP_EntKey key);
|
|
||||||
PP_EntKey PP_RandomKey(void);
|
|
||||||
PP_EntKey PP_ContactConstraintKeyFromContactingKeys(PP_EntKey player_id, PP_EntKey id0, PP_EntKey id1);
|
|
||||||
PP_EntKey PP_CollisionDebugKeyFromKeys(PP_EntKey player_id, PP_EntKey id0, PP_EntKey id1);
|
|
||||||
PP_EntKey PP_TileChunkKeyFromIndex(Vec2I32 chunk_start);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Query operations
|
|
||||||
|
|
||||||
PP_Ent *PP_FirstWithProp(PP_Snapshot *ss, PP_Prop prop);
|
|
||||||
PP_Ent *PP_FirstWithAllProps(PP_Snapshot *ss, PP_PropArray props);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tree operations
|
|
||||||
|
|
||||||
void PP_Link(PP_Ent *parent, PP_Ent *child);
|
|
||||||
void PP_Unlink(PP_Ent *ent);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Xform operations
|
|
||||||
|
|
||||||
void PP_MarkChildXformsDirty(PP_Snapshot *ss, PP_Ent *ent);
|
|
||||||
Xform PP_XformFromEnt_(PP_Snapshot *ss, PP_Ent *ent);
|
|
||||||
Xform PP_XformFromEnt(PP_Ent *ent);
|
|
||||||
Xform PP_LocalXformFromEnt(PP_Ent *ent);
|
|
||||||
void PP_SetXform(PP_Ent *ent, Xform xf);
|
|
||||||
void PP_SetLocalXform(PP_Ent *ent, Xform xf);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Movement operations
|
|
||||||
|
|
||||||
void PP_SetLinearVelocity(PP_Ent *ent, Vec2 velocity);
|
|
||||||
void PP_SetAngularVelocity(PP_Ent *ent, f32 velocity);
|
|
||||||
void PP_ApplyLinearImpulse(PP_Ent *ent, Vec2 impulse, Vec2 world_point);
|
|
||||||
void PP_ApplyLinearImpulseToCenter(PP_Ent *ent, Vec2 impulse);
|
|
||||||
void PP_ApplyForceToCenter(PP_Ent *ent, Vec2 force);
|
|
||||||
void PP_ApplyAngularImpulse(PP_Ent *ent, f32 impulse);
|
|
||||||
void PP_ApplyTorque(PP_Ent *ent, f32 torque);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile operations
|
|
||||||
|
|
||||||
PP_Ent *PP_TileChunkFromChunkIndex(PP_Snapshot *ss, Vec2I32 chunk_index);
|
|
||||||
PP_Ent *PP_TileChunkFromWorldTileIndex(PP_Snapshot *ss, Vec2I32 world_tile_index);
|
|
||||||
PP_TileKind PP_TileKindFromChunk(PP_Ent *chunk_ent, Vec2I32 local_tile_index);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Lerp operations
|
|
||||||
|
|
||||||
void PP_LerpEnt(PP_Ent *e, PP_Ent *e0, PP_Ent *e1, f64 blend);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Sync operations
|
|
||||||
|
|
||||||
void PP_CreateMissingEntsFromSnapshots(PP_Ent *local_parent, PP_Ent *remote, PP_EntKey remote_player);
|
|
||||||
void PP_SyncEnt(PP_Ent *local, PP_Ent *remote);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Encode
|
|
||||||
|
|
||||||
void PP_EncodeEnt(BB_Writer *bw, PP_Ent *e0, PP_Ent *e1);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Decode
|
|
||||||
|
|
||||||
void PP_DecodeEnt(BB_Reader *br, PP_Ent *e);
|
|
||||||
1378
src/pp_old/pp_phys.c
1378
src/pp_old/pp_phys.c
File diff suppressed because it is too large
Load Diff
@ -1,266 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Collision data types
|
|
||||||
|
|
||||||
#define PP_ContactSpringHz 25
|
|
||||||
#define PP_ContactSpringDamp 10
|
|
||||||
|
|
||||||
Struct(PP_CollisionData)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
Vec2 point;
|
|
||||||
Vec2 normal; /* Normal of the collision from e0 to e1 */
|
|
||||||
Vec2 vrel; /* Relative velocity at point of collision */
|
|
||||||
b32 is_start; /* Did this collision just begin */
|
|
||||||
f32 dt; /* How much time elapsed in the step when this event occurred (this will equal the physics timestep unless an early time of impact occurred) */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Callback can return 1 to prevent the physics system from resolving */
|
|
||||||
struct PP_SimStepCtx;
|
|
||||||
#define PP_CollisionCallbackFuncDef(name, arg_collision_data, arg_sim_step_ctx) b32 name(PP_CollisionData *arg_collision_data, struct PP_SimStepCtx *arg_sim_step_ctx)
|
|
||||||
typedef PP_CollisionCallbackFuncDef(PP_CollisionCallbackFunc, collision_data, ctx);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Step ctx
|
|
||||||
|
|
||||||
/* Structure containing data used for a single physics step */
|
|
||||||
Struct(PP_PhysStepCtx)
|
|
||||||
{
|
|
||||||
struct PP_SimStepCtx *sim_step_ctx;
|
|
||||||
PP_CollisionCallbackFunc *collision_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Contact types
|
|
||||||
|
|
||||||
Struct(PP_ContactPoint)
|
|
||||||
{
|
|
||||||
// Contact point relative to the center of each entity.
|
|
||||||
//
|
|
||||||
// NOTE: We use fixed (non-rotated) points relative to the entities
|
|
||||||
// rather than points fully in local space because contact manifolds
|
|
||||||
// shouldn't really be affected by rotation accross substeps
|
|
||||||
// (imagine re-building the manifold of a rotated shape, it would still be
|
|
||||||
// on the same side of the shape that it originally occured on)
|
|
||||||
Vec2 vcp0;
|
|
||||||
Vec2 vcp1;
|
|
||||||
|
|
||||||
u32 id; /* ID generated during clipping */
|
|
||||||
f32 starting_separation; /* How far are original points along normal */
|
|
||||||
f32 normal_impulse; /* Accumulated impulse along normal */
|
|
||||||
f32 tangent_impulse; /* Accumulated impulse along tangent */
|
|
||||||
|
|
||||||
f32 inv_normal_mass;
|
|
||||||
f32 inv_tangent_mass;
|
|
||||||
|
|
||||||
/* Debugging */
|
|
||||||
#if IsDeveloperModeEnabled
|
|
||||||
Vec2 dbg_pt;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_ContactConstraint)
|
|
||||||
{
|
|
||||||
u64 last_phys_iteration; /* To avoid checking collisions for the same constraint twice in one tick */
|
|
||||||
b32 skip_solve;
|
|
||||||
b32 wrong_dir;
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
f32 inv_m0;
|
|
||||||
f32 inv_m1;
|
|
||||||
f32 inv_i0;
|
|
||||||
f32 inv_i1;
|
|
||||||
|
|
||||||
Vec2 normal; /* Normal vector of collision from e0 -> e1 */
|
|
||||||
u64 last_iteration;
|
|
||||||
PP_ContactPoint points[2];
|
|
||||||
u32 num_points;
|
|
||||||
|
|
||||||
f32 friction;
|
|
||||||
|
|
||||||
f32 pushout_velocity;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_ContactDebugData)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
CLD_CollisionData collision_result;
|
|
||||||
|
|
||||||
PP_ContactPoint points[2];
|
|
||||||
u32 num_points;
|
|
||||||
|
|
||||||
Vec2 closest0;
|
|
||||||
Vec2 closest1;
|
|
||||||
|
|
||||||
Xform xf0;
|
|
||||||
Xform xf1;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Motor joint types
|
|
||||||
|
|
||||||
Struct(PP_MotorJointDesc)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
f32 correction_rate;
|
|
||||||
f32 max_force;
|
|
||||||
f32 max_torque;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_MotorJoint)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
f32 correction_rate;
|
|
||||||
f32 max_force;
|
|
||||||
f32 max_torque;
|
|
||||||
|
|
||||||
f32 inv_m0;
|
|
||||||
f32 inv_m1;
|
|
||||||
f32 inv_i0;
|
|
||||||
f32 inv_i1;
|
|
||||||
|
|
||||||
Vec2 linear_impulse;
|
|
||||||
f32 angular_impulse;
|
|
||||||
|
|
||||||
Vec2 point_local_e0;
|
|
||||||
Vec2 point_local_e1;
|
|
||||||
|
|
||||||
Xform linear_mass_xf;
|
|
||||||
f32 angular_mass;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Mouse joint types
|
|
||||||
|
|
||||||
Struct(PP_MouseJointDesc)
|
|
||||||
{
|
|
||||||
PP_EntKey target;
|
|
||||||
Vec2 point_local_start;
|
|
||||||
Vec2 point_end;
|
|
||||||
f32 linear_spring_hz;
|
|
||||||
f32 linear_spring_damp;
|
|
||||||
f32 angular_spring_hz;
|
|
||||||
f32 angular_spring_damp;
|
|
||||||
f32 max_force;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_MouseJoint)
|
|
||||||
{
|
|
||||||
PP_EntKey target;
|
|
||||||
Vec2 point_local_start;
|
|
||||||
Vec2 point_end;
|
|
||||||
f32 linear_spring_hz;
|
|
||||||
f32 linear_spring_damp;
|
|
||||||
f32 angular_spring_hz;
|
|
||||||
f32 angular_spring_damp;
|
|
||||||
f32 max_force;
|
|
||||||
|
|
||||||
f32 inv_m;
|
|
||||||
f32 inv_i;
|
|
||||||
|
|
||||||
Vec2 linear_impulse;
|
|
||||||
f32 angular_impulse;
|
|
||||||
|
|
||||||
Xform linear_mass_xf;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Weld joint types
|
|
||||||
|
|
||||||
Struct(PP_WeldJointDesc)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
|
|
||||||
// The xform that transforms a point in e0's space into the desired e1 space
|
|
||||||
// (IE `xf` * VEC2(0, 0) should evaluate to the local point that e1's origin will lie)
|
|
||||||
Xform xf;
|
|
||||||
|
|
||||||
f32 linear_spring_hz;
|
|
||||||
f32 linear_spring_damp;
|
|
||||||
f32 angular_spring_hz;
|
|
||||||
f32 angular_spring_damp;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_WeldJoint)
|
|
||||||
{
|
|
||||||
PP_EntKey e0;
|
|
||||||
PP_EntKey e1;
|
|
||||||
Xform xf0_to_xf1;
|
|
||||||
|
|
||||||
f32 linear_spring_hz;
|
|
||||||
f32 linear_spring_damp;
|
|
||||||
f32 angular_spring_hz;
|
|
||||||
f32 angular_spring_damp;
|
|
||||||
|
|
||||||
f32 inv_m0;
|
|
||||||
f32 inv_m1;
|
|
||||||
f32 inv_i0;
|
|
||||||
f32 inv_i1;
|
|
||||||
|
|
||||||
Vec2 linear_impulse0;
|
|
||||||
Vec2 linear_impulse1;
|
|
||||||
f32 angular_impulse0;
|
|
||||||
f32 angular_impulse1;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Contact operations
|
|
||||||
|
|
||||||
b32 PP_CanEntsContact(struct PP_Ent *e0, struct PP_Ent *e1);
|
|
||||||
void PP_CreateAndUpdateContacts(PP_PhysStepCtx *ctx, f32 elapsed_dt, u64 phys_iteration);
|
|
||||||
void PP_PrepareContacts(PP_PhysStepCtx *ctx, u64 phys_iteration);
|
|
||||||
void PP_WarmStartContacts(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_SolveContacts(PP_PhysStepCtx *ctx, f32 dt, b32 apply_bias);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Motor joint operations
|
|
||||||
|
|
||||||
PP_MotorJointDesc PP_CreateMotorJointDef(void);
|
|
||||||
PP_MotorJoint PP_MotorJointFromDef(PP_MotorJointDesc def);
|
|
||||||
void PP_PrepareMotorJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_WarmStartMotorJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_SolveMotorJoints(PP_PhysStepCtx *ctx, f32 dt);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Mouse joint operations
|
|
||||||
|
|
||||||
PP_MouseJointDesc PP_CreateMouseJointDef(void);
|
|
||||||
PP_MouseJoint PP_MouseJointFromDef(PP_MouseJointDesc def);
|
|
||||||
void PP_PrepareMouseJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_WarmStartMouseJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_SolveMouseJoints(PP_PhysStepCtx *ctx, f32 dt);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Weld joint operations
|
|
||||||
|
|
||||||
PP_WeldJointDesc PP_CreateWeldJointDef(void);
|
|
||||||
PP_WeldJoint PP_WeldJointFromDef(PP_WeldJointDesc def);
|
|
||||||
void PP_PrepareWeldJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_WarmStartWeldJoints(PP_PhysStepCtx *ctx);
|
|
||||||
void PP_SolveWeldJoints(PP_PhysStepCtx *ctx, f32 dt);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Integration operations
|
|
||||||
|
|
||||||
Xform PP_GetDerivedEntXform(struct PP_Ent *ent, f32 dt);
|
|
||||||
void PP_IntegrateForces(PP_PhysStepCtx *ctx, f32 dt);
|
|
||||||
void PP_IntegrateVelocities(PP_PhysStepCtx *ctx, f32 dt);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Time of impact operations
|
|
||||||
|
|
||||||
f32 PP_DetermineEarliestToi(PP_PhysStepCtx *ctx, f32 step_dt, f32 tolerance, u32 max_iterations);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Spatial operations
|
|
||||||
|
|
||||||
void PP_UpdateAabbs(PP_PhysStepCtx *ctx);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Step
|
|
||||||
|
|
||||||
void PP_StepPhys(PP_PhysStepCtx *ctx, f32 timestep);
|
|
||||||
BIN
src/pp_old/pp_res/font/fixedsys.ttf
(Stored with Git LFS)
BIN
src/pp_old/pp_res/font/fixedsys.ttf
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/font/roboto-med.ttf
(Stored with Git LFS)
BIN
src/pp_old/pp_res/font/roboto-med.ttf
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
BIN
src/pp_old/pp_res/sprite/blood.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/blood.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/box.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/box.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/box_rounded.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/box_rounded.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/bullet.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/bullet.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/crosshair.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/crosshair.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/gun.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/gun.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/tile.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/tile.ase
(Stored with Git LFS)
Binary file not shown.
BIN
src/pp_old/pp_res/sprite/tim.ase
(Stored with Git LFS)
BIN
src/pp_old/pp_res/sprite/tim.ase
(Stored with Git LFS)
Binary file not shown.
@ -1,935 +0,0 @@
|
|||||||
//
|
|
||||||
// Sim hierarchy is as follows:
|
|
||||||
//
|
|
||||||
// PP_Client store -> clients -> snapshots -> ents
|
|
||||||
//
|
|
||||||
// A client store holds clients, which can be retrieved by client key or by a host channel id (if one is assigned).
|
|
||||||
//
|
|
||||||
// A client holds snapshots, which can be retrieved by tick number.
|
|
||||||
// - The snapshots stored in clients & the contents of those snapshots are determined from data transmitted by the client.
|
|
||||||
// - Different kinds of clients will transmit different subsets of snapshot data (e.g. a master client will transmit most ent state, while slave clients may just transmit 1 or more command ents)
|
|
||||||
// - A client will never hold more than one snapshot for the same tick (e.g. a client will never have 2 snapshots at tick 5)
|
|
||||||
//
|
|
||||||
// A snapshot holds the ent tree for a particular tick, in which ents can be retrieved by ent key.
|
|
||||||
// - A tick is the quantized time step that all clients implicitly conform to.
|
|
||||||
//
|
|
||||||
// An ent is the smallest unit of simulation state.
|
|
||||||
// - It is assigned a 128 bit unique identifer generated at allocation time.
|
|
||||||
// - This key is used to refer to other ents in the tree and to sync ents accross clients.
|
|
||||||
// - This key is usually random, but can be deterministic under certain conditions.
|
|
||||||
// - For example, instead of storing a contact constraint lookup table, contact constraints are
|
|
||||||
// retrieved by searching for the ent with the key resulting from combining the ent keys of the
|
|
||||||
// two contacting entities (plus a unique 'basis' ent key used for all contact constraints).
|
|
||||||
// - The ent also implicitly has a 32 bit index, which is just its offset from the start of the entity array in the local snapshot.
|
|
||||||
// - Since index is based on offset which remains stable regardless of snapshot memory location, it
|
|
||||||
// is used when working in contexts where key is irrelevant.
|
|
||||||
//
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
PP_SharedSimCtx PP_shared_sim_ctx = ZI;
|
|
||||||
Readonly PP_ClientStore **PP_nil_client_store = &PP_shared_sim_ctx.nil_client_store;
|
|
||||||
Readonly PP_Client **PP_nil_client = &PP_shared_sim_ctx.nil_client;
|
|
||||||
Readonly PP_Snapshot **PP_nil_snapshot = &PP_shared_sim_ctx.nil_snapshot;
|
|
||||||
Readonly PP_Ent **PP_nil_ent = &PP_shared_sim_ctx.nil_ent;
|
|
||||||
|
|
||||||
void PP_StartupSim(void)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
PP_SharedSimCtx *g = &PP_shared_sim_ctx;
|
|
||||||
g->nil_arena = AcquireArena(Gibi(1));
|
|
||||||
|
|
||||||
/* Nil client store */
|
|
||||||
g->nil_client_store = PushStruct(g->nil_arena, PP_ClientStore);
|
|
||||||
g->nil_client_store->valid = 0;
|
|
||||||
|
|
||||||
/* Nil client */
|
|
||||||
g->nil_client = PushStruct(g->nil_arena, PP_Client);
|
|
||||||
g->nil_client->valid = 0;
|
|
||||||
g->nil_client->store = PP_NilClientStore();
|
|
||||||
|
|
||||||
/* Nil snapshot */
|
|
||||||
g->nil_snapshot = PushStruct(g->nil_arena, PP_Snapshot);
|
|
||||||
g->nil_snapshot->valid = 0;
|
|
||||||
g->nil_snapshot->client = PP_NilClient();
|
|
||||||
|
|
||||||
/* Nil ent */
|
|
||||||
g->nil_ent = PushStruct(g->nil_arena, PP_Ent);
|
|
||||||
g->nil_ent->ss = PP_NilSnapshot();
|
|
||||||
g->nil_ent->valid = 0;
|
|
||||||
g->nil_ent->key = PP_NilEntKey;
|
|
||||||
g->nil_ent->_local_xform = XformIdentity;
|
|
||||||
g->nil_ent->_xform = XformIdentity;
|
|
||||||
g->nil_ent->_is_xform_dirty = 0;
|
|
||||||
g->nil_ent->friction = 0.5f;
|
|
||||||
g->nil_ent->mass_unscaled = 1;
|
|
||||||
g->nil_ent->inertia_unscaled = 1;
|
|
||||||
g->nil_ent->sprite_local_xform = XformIdentity;
|
|
||||||
g->nil_ent->sprite_tint = Color_White;
|
|
||||||
|
|
||||||
/* Lock nil arena */
|
|
||||||
SetArenaReadonly(g->nil_arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acquire client store
|
|
||||||
|
|
||||||
PP_ClientStore *PP_AcquireClientStore(void)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
PP_ClientStore *store;
|
|
||||||
{
|
|
||||||
Arena *arena = AcquireArena(Gibi(64));
|
|
||||||
store = PushStruct(arena, PP_ClientStore);
|
|
||||||
store->arena = arena;
|
|
||||||
}
|
|
||||||
store->valid = 1;
|
|
||||||
store->num_client_lookup_bins = PP_ClientLookupBinsCount;
|
|
||||||
store->client_lookup_bins = PushStructs(store->arena, PP_ClientLookupBin, store->num_client_lookup_bins);
|
|
||||||
store->clients_arena = AcquireArena(Gibi(64));
|
|
||||||
store->clients = PushDry(store->clients_arena, PP_Client);
|
|
||||||
return store;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseClientStore(PP_ClientStore *store)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
for (u64 i = 0; i < store->num_clients_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Client *client = &store->clients[i];
|
|
||||||
if (client->valid)
|
|
||||||
{
|
|
||||||
PP_ReleaseClient(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ReleaseArena(store->clients_arena);
|
|
||||||
ReleaseArena(store->arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acquire client
|
|
||||||
|
|
||||||
PP_Client *PP_AcquireClient(PP_ClientStore *store)
|
|
||||||
{
|
|
||||||
PP_ClientKey key = ZI;
|
|
||||||
PP_Client *client = PP_ClientFromKey(store, store->first_free_client);
|
|
||||||
|
|
||||||
if (client->valid)
|
|
||||||
{
|
|
||||||
store->first_free_client = client->next_free;
|
|
||||||
key = client->key;
|
|
||||||
++key.gen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client = PushStructNoZero(store->clients_arena, PP_Client);
|
|
||||||
key.gen = 1;
|
|
||||||
key.idx = store->num_clients_reserved;
|
|
||||||
++store->num_clients_reserved;
|
|
||||||
}
|
|
||||||
++store->num_clients_allocated;
|
|
||||||
*client = *PP_NilClient();
|
|
||||||
client->store = store;
|
|
||||||
client->valid = 1;
|
|
||||||
client->key = key;
|
|
||||||
|
|
||||||
client->snapshots_arena = AcquireArena(Gibi(8));
|
|
||||||
client->num_snapshot_lookup_bins = PP_TickLookupBinsCount;
|
|
||||||
client->snapshot_lookup_bins = PushStructs(client->snapshots_arena, PP_SnapshotLookupBin, client->num_snapshot_lookup_bins);
|
|
||||||
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseClient(PP_Client *client)
|
|
||||||
{
|
|
||||||
/* Release internal snapshot memory */
|
|
||||||
for (u64 i = 0; i < client->num_snapshot_lookup_bins; ++i)
|
|
||||||
{
|
|
||||||
PP_SnapshotLookupBin *bin = &client->snapshot_lookup_bins[i];
|
|
||||||
PP_Snapshot *ss = bin->first;
|
|
||||||
while (ss)
|
|
||||||
{
|
|
||||||
PP_Snapshot *next = ss->next_in_bin;
|
|
||||||
ReleaseArena(ss->ents_arena);
|
|
||||||
ReleaseArena(ss->arena);
|
|
||||||
ss = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove from channel lookup */
|
|
||||||
PP_SetClientChannelId(client, N_NilChannelId);
|
|
||||||
|
|
||||||
/* Release client */
|
|
||||||
PP_ClientStore *store = client->store;
|
|
||||||
client->valid = 0;
|
|
||||||
client->next_free = store->first_free_client;
|
|
||||||
store->first_free_client = client->key;
|
|
||||||
--store->num_clients_allocated;
|
|
||||||
++client->key.gen;
|
|
||||||
ReleaseArena(client->snapshots_arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client lookup
|
|
||||||
|
|
||||||
u64 PP_ClientChannelHashFromChannelId(N_ChannelId channel_id)
|
|
||||||
{
|
|
||||||
return HashFnv64(Fnv64Basis, StringFromStruct(&channel_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_SetClientChannelId(PP_Client *client, N_ChannelId channel_id)
|
|
||||||
{
|
|
||||||
PP_ClientStore *store = client->store;
|
|
||||||
N_ChannelId old_channel_id = client->channel_id;
|
|
||||||
|
|
||||||
/* Remove old channel id from channel lookup */
|
|
||||||
if (!N_IsChannelIdNil(old_channel_id))
|
|
||||||
{
|
|
||||||
u64 bin_index = client->channel_hash % store->num_client_lookup_bins;
|
|
||||||
PP_ClientLookupBin *bin = &store->client_lookup_bins[bin_index];
|
|
||||||
PP_Client *prev = PP_ClientFromKey(store, client->prev_in_bin);
|
|
||||||
PP_Client *next = PP_ClientFromKey(store, client->next_in_bin);
|
|
||||||
if (prev->valid)
|
|
||||||
{
|
|
||||||
prev->next_in_bin = next->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = next->key;
|
|
||||||
}
|
|
||||||
if (next->valid)
|
|
||||||
{
|
|
||||||
next->prev_in_bin = prev->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->last = prev->key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert into channel lookup */
|
|
||||||
/* TODO: Enforce no duplicates */
|
|
||||||
u64 channel_hash = PP_ClientChannelHashFromChannelId(channel_id);
|
|
||||||
client->channel_id = channel_id;
|
|
||||||
client->channel_hash = channel_hash;
|
|
||||||
if (!N_IsChannelIdNil(channel_id))
|
|
||||||
{
|
|
||||||
u64 bin_index = channel_hash % store->num_client_lookup_bins;
|
|
||||||
PP_ClientLookupBin *bin = &store->client_lookup_bins[bin_index];
|
|
||||||
{
|
|
||||||
PP_Client *prev_in_bin = PP_ClientFromKey(store, bin->last);
|
|
||||||
if (prev_in_bin->valid)
|
|
||||||
{
|
|
||||||
prev_in_bin->next_in_bin = client->key;
|
|
||||||
client->prev_in_bin = prev_in_bin->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = client->key;
|
|
||||||
}
|
|
||||||
bin->last = client->key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Client *PP_ClientFromChannelId(PP_ClientStore *store, N_ChannelId channel_id)
|
|
||||||
{
|
|
||||||
PP_Client *result = PP_NilClient();
|
|
||||||
u64 channel_hash = PP_ClientChannelHashFromChannelId(channel_id);
|
|
||||||
u64 bin_index = channel_hash % store->num_client_lookup_bins;
|
|
||||||
PP_ClientLookupBin *bin = &store->client_lookup_bins[bin_index];
|
|
||||||
for (PP_Client *client = PP_ClientFromKey(store, bin->first); client->valid; client = PP_ClientFromKey(store, client->next_in_bin))
|
|
||||||
{
|
|
||||||
if (client->channel_hash == channel_hash)
|
|
||||||
{
|
|
||||||
result = client;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Client *PP_ClientFromKey(PP_ClientStore *store, PP_ClientKey key)
|
|
||||||
{
|
|
||||||
if (key.gen != 0 && key.idx < store->num_clients_reserved)
|
|
||||||
{
|
|
||||||
PP_Client *client = &store->clients[key.idx];
|
|
||||||
if (client->key.gen == key.gen)
|
|
||||||
{
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PP_NilClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acquire snapshot
|
|
||||||
|
|
||||||
/* Produces a new snapshot at `tick` with data copied from `src` snapshot. */
|
|
||||||
PP_Snapshot *PP_AcquireSnapshot(PP_Client *client, PP_Snapshot *src, u64 tick)
|
|
||||||
{
|
|
||||||
if (tick == 0)
|
|
||||||
{
|
|
||||||
return PP_NilSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Snapshot *ss;
|
|
||||||
{
|
|
||||||
Arena *arena = ZI;
|
|
||||||
Arena *ents_arena = 0;
|
|
||||||
{
|
|
||||||
ss = client->first_free_snapshot;
|
|
||||||
if (ss)
|
|
||||||
{
|
|
||||||
/* Re-use existing snasphot arenas */
|
|
||||||
client->first_free_snapshot = ss->next_free;
|
|
||||||
ents_arena = ss->ents_arena;
|
|
||||||
arena = ss->arena;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Arenas allocated here will be released with client */
|
|
||||||
arena = AcquireArena(Gibi(1));
|
|
||||||
ents_arena = AcquireArena(Gibi(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ResetArena(arena);
|
|
||||||
ss = PushStruct(arena, PP_Snapshot);
|
|
||||||
ss->arena = arena;
|
|
||||||
|
|
||||||
ss->ents_arena = ents_arena;
|
|
||||||
ResetArena(ss->ents_arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss->tick = tick;
|
|
||||||
ss->valid = 1;
|
|
||||||
ss->client = client;
|
|
||||||
++client->num_ticks;
|
|
||||||
|
|
||||||
/* Copy src info */
|
|
||||||
ss->sim_dt_ns = src->sim_dt_ns;
|
|
||||||
ss->sim_time_ns = src->sim_time_ns;
|
|
||||||
ss->continuity_gen = src->continuity_gen;
|
|
||||||
ss->local_player = src->local_player;
|
|
||||||
ss->phys_iteration = src->phys_iteration;
|
|
||||||
|
|
||||||
/* Copy key lookup bins */
|
|
||||||
ss->num_key_bins = src->num_key_bins > 0 ? src->num_key_bins : PP_KeyLookupBinsCount;
|
|
||||||
ss->key_bins = PushStructsNoZero(ss->arena, PP_EntBin, ss->num_key_bins);
|
|
||||||
if (src->num_key_bins > 0)
|
|
||||||
{
|
|
||||||
for (u64 i = 0; i < src->num_key_bins; ++i)
|
|
||||||
{
|
|
||||||
ss->key_bins[i] = src->key_bins[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ZeroBytes(ss->key_bins, sizeof(*ss->key_bins) * ss->num_key_bins);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy entities */
|
|
||||||
ss->first_free_ent = src->first_free_ent;
|
|
||||||
ss->num_ents_allocated = src->num_ents_allocated;
|
|
||||||
ss->num_ents_reserved = src->num_ents_reserved;
|
|
||||||
ss->ents = PushStructsNoZero(ss->ents_arena, PP_Ent, ss->num_ents_reserved);
|
|
||||||
if (ss->num_ents_reserved == 0)
|
|
||||||
{
|
|
||||||
/* Copying from nil snapshot, need to create blank & root entity */
|
|
||||||
|
|
||||||
/* Push blank ent at index 0 (because index 0 is never valid anyway since it maps to nil ent) */
|
|
||||||
{
|
|
||||||
PushStruct(ss->ents_arena, PP_Ent);
|
|
||||||
++ss->num_ents_allocated;
|
|
||||||
++ss->num_ents_reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Push root ent with constant key */
|
|
||||||
{
|
|
||||||
PP_Ent *root = PushStructNoZero(ss->ents_arena, PP_Ent);
|
|
||||||
*root = *PP_NilEnt();
|
|
||||||
root->ss = ss;
|
|
||||||
root->valid = 1;
|
|
||||||
root->is_root = 1;
|
|
||||||
root->mass_unscaled = F32Infinity;
|
|
||||||
root->inertia_unscaled = F32Infinity;
|
|
||||||
PP_SetEntKey(root, PP_RootEntKey);
|
|
||||||
++ss->num_ents_allocated;
|
|
||||||
++ss->num_ents_reserved;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (u64 i = 0; i < ss->num_ents_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *dst_ent = &ss->ents[i];
|
|
||||||
PP_Ent *src_ent = &src->ents[i];
|
|
||||||
*dst_ent = *src_ent;
|
|
||||||
dst_ent->ss = ss;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release duplicate tick if it exists */
|
|
||||||
{
|
|
||||||
PP_Snapshot *existing = PP_SnapshotFromTick(client, tick);
|
|
||||||
if (existing->valid)
|
|
||||||
{
|
|
||||||
PP_ReleaseSnapshot(existing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Linear search to insert snapshot in tick order */
|
|
||||||
{
|
|
||||||
PP_Snapshot *prev = PP_SnapshotFromTick(client, client->last_tick);
|
|
||||||
while (prev->valid)
|
|
||||||
{
|
|
||||||
if (prev->tick < tick)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev = PP_SnapshotFromTick(client, prev->prev_tick);
|
|
||||||
}
|
|
||||||
if (prev->valid)
|
|
||||||
{
|
|
||||||
PP_Snapshot *next = PP_SnapshotFromTick(client, prev->next_tick);
|
|
||||||
if (next->valid)
|
|
||||||
{
|
|
||||||
next->prev_tick = tick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client->last_tick = tick;
|
|
||||||
}
|
|
||||||
ss->next_tick = prev->next_tick;
|
|
||||||
ss->prev_tick = prev->tick;
|
|
||||||
prev->next_tick = ss->tick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PP_Snapshot *first = PP_SnapshotFromTick(client, client->first_tick);
|
|
||||||
if (first->valid)
|
|
||||||
{
|
|
||||||
ss->next_tick = first->tick;
|
|
||||||
first->prev_tick = tick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client->last_tick = tick;
|
|
||||||
}
|
|
||||||
ss->next_tick = client->first_tick;
|
|
||||||
client->first_tick = tick;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert into lookup */
|
|
||||||
{
|
|
||||||
u64 bin_index = tick % client->num_snapshot_lookup_bins;
|
|
||||||
PP_SnapshotLookupBin *bin = &client->snapshot_lookup_bins[bin_index];
|
|
||||||
if (bin->last)
|
|
||||||
{
|
|
||||||
bin->last->next_in_bin = ss;
|
|
||||||
ss->prev_in_bin = bin->last;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = ss;
|
|
||||||
}
|
|
||||||
bin->last = ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseSnapshot(PP_Snapshot *ss)
|
|
||||||
{
|
|
||||||
PP_Client *client = ss->client;
|
|
||||||
|
|
||||||
/* Remove from lookup */
|
|
||||||
{
|
|
||||||
u64 bin_index = ss->tick % client->num_snapshot_lookup_bins;
|
|
||||||
PP_SnapshotLookupBin *bin = &client->snapshot_lookup_bins[bin_index];
|
|
||||||
PP_Snapshot *prev = ss->prev_in_bin;
|
|
||||||
PP_Snapshot *next = ss->next_in_bin;
|
|
||||||
if (prev)
|
|
||||||
{
|
|
||||||
prev->next_in_bin = next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first = next;
|
|
||||||
}
|
|
||||||
if (next)
|
|
||||||
{
|
|
||||||
next->prev_in_bin = prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->last = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove from snapshot list */
|
|
||||||
{
|
|
||||||
PP_Snapshot *prev = PP_SnapshotFromTick(client, ss->prev_tick);
|
|
||||||
PP_Snapshot *next = PP_SnapshotFromTick(client, ss->next_tick);
|
|
||||||
if (prev->valid)
|
|
||||||
{
|
|
||||||
prev->next_tick = next->tick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client->first_tick = next->tick;
|
|
||||||
}
|
|
||||||
if (next->valid)
|
|
||||||
{
|
|
||||||
next->prev_tick = prev->tick;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
client->last_tick = prev->tick;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ss->valid = 0;
|
|
||||||
ss->next_free = client->first_free_snapshot;
|
|
||||||
client->first_free_snapshot = ss;
|
|
||||||
--client->num_ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release all snapshots for client with tick in range [start, end] */
|
|
||||||
void PP_ReleaseSnapshotsInRange(PP_Client *client, u64 start, u64 end)
|
|
||||||
{
|
|
||||||
if (start > end)
|
|
||||||
{
|
|
||||||
u64 swp = start;
|
|
||||||
start = end;
|
|
||||||
end = swp;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Snapshot *ss = PP_SnapshotFromTick(client, client->first_tick);
|
|
||||||
while (ss->valid)
|
|
||||||
{
|
|
||||||
u64 tick = ss->tick;
|
|
||||||
u64 next_tick = ss->next_tick;
|
|
||||||
if (tick >= start)
|
|
||||||
{
|
|
||||||
if (tick <= end)
|
|
||||||
{
|
|
||||||
PP_ReleaseSnapshot(ss);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss = PP_SnapshotFromTick(client, next_tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot lookup
|
|
||||||
|
|
||||||
PP_Snapshot *PP_SnapshotFromTick(PP_Client *client, u64 tick)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = PP_NilSnapshot();
|
|
||||||
if (tick > 0)
|
|
||||||
{
|
|
||||||
u64 bin_index = tick % client->num_snapshot_lookup_bins;
|
|
||||||
PP_SnapshotLookupBin *bin = &client->snapshot_lookup_bins[bin_index];
|
|
||||||
for (PP_Snapshot *search = bin->first; search; search = search->next_in_bin)
|
|
||||||
{
|
|
||||||
if (search->tick == tick)
|
|
||||||
{
|
|
||||||
ss = search;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the snapshot at nearest valid tick <= supplied tick */
|
|
||||||
PP_Snapshot *PP_SnapshotFromClosestTickLte(PP_Client *client, u64 tick)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = PP_SnapshotFromTick(client, tick);
|
|
||||||
if (!ss->valid)
|
|
||||||
{
|
|
||||||
/* Degenerate to linear search */
|
|
||||||
ss = PP_SnapshotFromTick(client, client->last_tick);
|
|
||||||
while (ss->valid)
|
|
||||||
{
|
|
||||||
if (ss->tick <= tick)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ss = PP_SnapshotFromTick(client, ss->prev_tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the snapshot at nearest valid tick >= supplied tick */
|
|
||||||
PP_Snapshot *PP_SnapshotFromClosestTickGte(PP_Client *client, u64 tick)
|
|
||||||
{
|
|
||||||
PP_Snapshot *ss = PP_SnapshotFromTick(client, tick);
|
|
||||||
if (!ss->valid)
|
|
||||||
{
|
|
||||||
/* Degenerate to linear search */
|
|
||||||
ss = PP_SnapshotFromTick(client, client->first_tick);
|
|
||||||
while (ss->valid)
|
|
||||||
{
|
|
||||||
if (ss->tick >= tick)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ss = PP_SnapshotFromTick(client, ss->next_tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile
|
|
||||||
|
|
||||||
Vec2I32 PP_WorldTileIndexFromPos(Vec2 pos)
|
|
||||||
{
|
|
||||||
Vec2I32 result = VEC2I32(pos.x * SIM_TILES_PER_UNIT_SQRT, pos.y * SIM_TILES_PER_UNIT_SQRT);
|
|
||||||
result.x -= pos.x < 0;
|
|
||||||
result.y -= pos.y < 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 PP_PosFromWorldTileIndex(Vec2I32 world_tile_index)
|
|
||||||
{
|
|
||||||
Vec2 result = ZI;
|
|
||||||
f32 tile_size = 1.f / SIM_TILES_PER_UNIT_SQRT;
|
|
||||||
result.x = (f32)world_tile_index.x * tile_size;
|
|
||||||
result.y = (f32)world_tile_index.y * tile_size;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2I32 PP_LocalTileIndexFromWorldTileIndex(Vec2I32 world_tile_index)
|
|
||||||
{
|
|
||||||
Vec2I32 result = world_tile_index;
|
|
||||||
result.x += result.x < 0;
|
|
||||||
result.y += result.y < 0;
|
|
||||||
result.x = result.x % SIM_TILES_PER_CHUNK_SQRT;
|
|
||||||
result.y = result.y % SIM_TILES_PER_CHUNK_SQRT;
|
|
||||||
result.x += (world_tile_index.x < 0) * (SIM_TILES_PER_CHUNK_SQRT - 1);
|
|
||||||
result.y += (world_tile_index.y < 0) * (SIM_TILES_PER_CHUNK_SQRT - 1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2I32 PP_WorldTileIndexFromLocalTileIndex(Vec2I32 tile_chunk_index, Vec2I32 local_tile_index)
|
|
||||||
{
|
|
||||||
Vec2I32 result = ZI;
|
|
||||||
result.x = (tile_chunk_index.x * SIM_TILES_PER_CHUNK_SQRT) + local_tile_index.x;
|
|
||||||
result.y = (tile_chunk_index.y * SIM_TILES_PER_CHUNK_SQRT) + local_tile_index.y;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2I32 PP_TileChunkIndexFromWorldTileIndex(Vec2I32 world_tile_index)
|
|
||||||
{
|
|
||||||
Vec2I32 result = world_tile_index;
|
|
||||||
result.x += result.x < 0;
|
|
||||||
result.y += result.y < 0;
|
|
||||||
result.x = result.x / SIM_TILES_PER_CHUNK_SQRT;
|
|
||||||
result.y = result.y / SIM_TILES_PER_CHUNK_SQRT;
|
|
||||||
result.x -= world_tile_index.x < 0;
|
|
||||||
result.y -= world_tile_index.y < 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_SetSnapshotTile(PP_Snapshot *ss, Vec2I32 world_tile_index, PP_TileKind tile_kind)
|
|
||||||
{
|
|
||||||
Vec2I32 chunk_index = PP_TileChunkIndexFromWorldTileIndex(world_tile_index);
|
|
||||||
|
|
||||||
PP_EntKey chunk_id = PP_TileChunkKeyFromIndex(chunk_index);
|
|
||||||
PP_Ent *chunk_ent = PP_EntFromKey(ss, chunk_id);
|
|
||||||
if (!chunk_ent->valid)
|
|
||||||
{
|
|
||||||
PP_Ent *root = PP_EntFromKey(ss, PP_RootEntKey);
|
|
||||||
chunk_ent = PP_AcquireSyncSrcEntWithKey(root, chunk_id);
|
|
||||||
PP_EnableProp(chunk_ent, PP_Prop_TileChunk);
|
|
||||||
chunk_ent->tile_chunk_index = chunk_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2I32 local_index = PP_LocalTileIndexFromWorldTileIndex(world_tile_index);
|
|
||||||
chunk_ent->tile_chunk_tiles[local_index.x + (local_index.y * SIM_TILES_PER_CHUNK_SQRT)] = tile_kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot lerp
|
|
||||||
|
|
||||||
PP_Snapshot *PP_AcquireSnapshotFromLerp(PP_Client *client, PP_Snapshot *ss0, PP_Snapshot *ss1, f64 blend)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
|
|
||||||
/* New snapshot will be allocated with same tick as ss0 or ss1, so the result should go into a different client */
|
|
||||||
Assert(ss0->client != client && ss1->client != client);
|
|
||||||
|
|
||||||
PP_Snapshot *ss;
|
|
||||||
b32 should_blend = 1;
|
|
||||||
if (ss0->continuity_gen == ss1->continuity_gen && 0 < blend && blend < 1)
|
|
||||||
{
|
|
||||||
ss = PP_AcquireSnapshot(client, ss0, ss0->tick);
|
|
||||||
}
|
|
||||||
else if (RoundF64ToI64(blend) <= 0)
|
|
||||||
{
|
|
||||||
ss = PP_AcquireSnapshot(client, ss0, ss0->tick);
|
|
||||||
should_blend = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ss = PP_AcquireSnapshot(client, ss1, ss1->tick);
|
|
||||||
should_blend = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ss0->valid || !ss1->valid)
|
|
||||||
{
|
|
||||||
// New snapshot allocation caused one of the src snapshots original to release.
|
|
||||||
// ss0 & ss1 should be from a separate client than the allocating one.
|
|
||||||
Assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_blend)
|
|
||||||
{
|
|
||||||
/* Blend time */
|
|
||||||
ss->sim_dt_ns = LerpI64(ss0->sim_dt_ns, ss1->sim_dt_ns, blend);
|
|
||||||
ss->sim_time_ns = LerpI64(ss0->sim_time_ns, ss1->sim_time_ns, blend);
|
|
||||||
|
|
||||||
/* Blend entities */
|
|
||||||
{
|
|
||||||
__profn("Lerp snapshot entities");
|
|
||||||
u64 num_entities = MinU64(ss0->num_ents_reserved, ss1->num_ents_reserved);
|
|
||||||
for (u64 i = 0; i < num_entities; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *e = &ss->ents[i];
|
|
||||||
PP_Ent *e0 = &ss0->ents[i];
|
|
||||||
PP_Ent *e1 = &ss1->ents[i];
|
|
||||||
PP_LerpEnt(e, e0, e1, blend);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot sync
|
|
||||||
|
|
||||||
/* Syncs entity data between snapshots */
|
|
||||||
void PP_SyncSnapshotEnts(PP_Snapshot *local_ss, PP_Snapshot *remote_ss, PP_EntKey remote_player, u32 sync_flags)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
|
|
||||||
// FIXME: Don't trust non-master clients:
|
|
||||||
// - Only sync cmd ents
|
|
||||||
// - Determine new UUids for newly created ents
|
|
||||||
|
|
||||||
PP_Ent *local_root = PP_EntFromKey(local_ss, PP_RootEntKey);
|
|
||||||
PP_Ent *remote_root = PP_EntFromKey(remote_ss, PP_RootEntKey);
|
|
||||||
|
|
||||||
/* Create new ents from remote */
|
|
||||||
for (PP_Ent *remote_top = PP_EntFromKey(remote_ss, remote_root->first); remote_top->valid; remote_top = PP_EntFromKey(remote_ss, remote_top->next))
|
|
||||||
{
|
|
||||||
PP_CreateMissingEntsFromSnapshots(local_root, remote_top, remote_player);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sync ents with remote, skipping index 0 (nil) & index 1 (root) */
|
|
||||||
for (u64 i = 2; i < local_ss->num_ents_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *local_ent = &local_ss->ents[i];
|
|
||||||
if (local_ent->valid && PP_HasProp(local_ent, PP_Prop_SyncDst))
|
|
||||||
{
|
|
||||||
b32 should_sync = PP_EqEntKey(local_ent->owner, remote_player) || PP_IsNilEntKey(remote_player);
|
|
||||||
if ((sync_flags & PP_SyncFlag_NoSyncPredictables) && PP_EqEntKey(local_ent->predictor, local_ss->local_player))
|
|
||||||
{
|
|
||||||
should_sync = 0;
|
|
||||||
}
|
|
||||||
if (should_sync)
|
|
||||||
{
|
|
||||||
PP_Ent *remote_ent = PP_EntFromKey(remote_ss, local_ent->key);
|
|
||||||
if (remote_ent->valid)
|
|
||||||
{
|
|
||||||
/* Copy all ent data from remote */
|
|
||||||
PP_SyncEnt(local_ent, remote_ent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Remote ent is no longer valid / networked, release it */
|
|
||||||
PP_EnableProp(local_ent, PP_Prop_Release);
|
|
||||||
PP_DisableProp(local_ent, PP_Prop_SyncDst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PP_ReleaseAllWithProp(local_ss, PP_Prop_Release);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot encode
|
|
||||||
|
|
||||||
void PP_EncodeSnapshot(BB_Writer *bw, PP_Client *receiver, PP_Snapshot *ss0, PP_Snapshot *ss1)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
|
|
||||||
BB_WriteDebugMarker(bw, Lit("SNAPSHOT START"));
|
|
||||||
|
|
||||||
BB_WriteIV(bw, ss1->sim_dt_ns);
|
|
||||||
BB_WriteIV(bw, ss1->sim_time_ns);
|
|
||||||
|
|
||||||
BB_WriteUV(bw, ss1->continuity_gen);
|
|
||||||
BB_WriteUV(bw, ss1->phys_iteration);
|
|
||||||
|
|
||||||
BB_WriteUid(bw, receiver->player_id.uid);
|
|
||||||
|
|
||||||
/* Key bins */
|
|
||||||
/* TODO: Don't encode these */
|
|
||||||
BB_WriteDebugMarker(bw, Lit("SNAPSHOT BINS"));
|
|
||||||
for (u64 i = 0; i < ss1->num_key_bins; ++i)
|
|
||||||
{
|
|
||||||
u32 old_first = 0;
|
|
||||||
u32 old_last = 0;
|
|
||||||
if (i < ss0->num_key_bins)
|
|
||||||
{
|
|
||||||
PP_EntBin *old_bin = &ss0->key_bins[i];
|
|
||||||
old_first = old_bin->first;
|
|
||||||
old_last = old_bin->last;
|
|
||||||
}
|
|
||||||
PP_EntBin *bin = &ss1->key_bins[i];
|
|
||||||
b32 first_diff = bin->first != old_first;
|
|
||||||
b32 last_diff = bin->last != old_last;
|
|
||||||
if (first_diff || last_diff)
|
|
||||||
{
|
|
||||||
BB_WriteBit(bw, 1);
|
|
||||||
BB_WriteUV(bw, i);
|
|
||||||
if (BB_WriteBit(bw, first_diff))
|
|
||||||
{
|
|
||||||
BB_WriteUV(bw, bin->first);
|
|
||||||
}
|
|
||||||
if (BB_WriteBit(bw, last_diff))
|
|
||||||
{
|
|
||||||
BB_WriteUV(bw, bin->last);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BB_WriteBit(bw, 0);
|
|
||||||
|
|
||||||
/* Ents */
|
|
||||||
BB_WriteDebugMarker(bw, Lit("SNAPSHOT NUM ENTS"));
|
|
||||||
if (BB_WriteBit(bw, ss1->num_ents_allocated != ss0->num_ents_allocated))
|
|
||||||
{
|
|
||||||
BB_WriteUV(bw, ss1->num_ents_allocated);
|
|
||||||
}
|
|
||||||
if (BB_WriteBit(bw, ss1->num_ents_reserved != ss0->num_ents_reserved))
|
|
||||||
{
|
|
||||||
BB_WriteUV(bw, ss1->num_ents_reserved);
|
|
||||||
}
|
|
||||||
|
|
||||||
BB_WriteDebugMarker(bw, Lit("SNAPSHOT ENTS"));
|
|
||||||
BB_WriteDebugMarker(bw, StringFromStruct(&ss1->num_ents_reserved));
|
|
||||||
|
|
||||||
for (u64 i = 1; i < ss1->num_ents_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *e0 = PP_NilEnt();
|
|
||||||
if (i < ss0->num_ents_reserved)
|
|
||||||
{
|
|
||||||
e0 = &ss0->ents[i];
|
|
||||||
}
|
|
||||||
PP_Ent *e1 = &ss1->ents[i];
|
|
||||||
PP_EncodeEnt(bw, e0, e1);
|
|
||||||
}
|
|
||||||
|
|
||||||
BB_WriteDebugMarker(bw, Lit("SNAPSHOT END"));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot decode
|
|
||||||
|
|
||||||
void PP_DecodeSnapshot(BB_Reader *br, PP_Snapshot *ss)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
|
|
||||||
BB_ReadDebugMarker(br, Lit("SNAPSHOT START"));
|
|
||||||
|
|
||||||
ss->sim_dt_ns = BB_ReadIV(br);
|
|
||||||
ss->sim_time_ns = BB_ReadIV(br);
|
|
||||||
|
|
||||||
ss->continuity_gen = BB_ReadUV(br);
|
|
||||||
ss->phys_iteration = BB_ReadUV(br);
|
|
||||||
|
|
||||||
ss->local_player = (PP_EntKey){ .uid = BB_ReadUid(br) };
|
|
||||||
|
|
||||||
/* Key bins */
|
|
||||||
/* TODO: Don't decode these, determine them implicitly from decoded ents */
|
|
||||||
BB_ReadDebugMarker(br, Lit("SNAPSHOT BINS"));
|
|
||||||
{
|
|
||||||
b32 bin_changed = BB_ReadBit(br);
|
|
||||||
while (bin_changed)
|
|
||||||
{
|
|
||||||
u32 bin_index = BB_ReadUV(br);
|
|
||||||
if (bin_index < ss->num_key_bins)
|
|
||||||
{
|
|
||||||
PP_EntBin *bin = &ss->key_bins[bin_index];
|
|
||||||
if (BB_ReadBit(br))
|
|
||||||
{
|
|
||||||
bin->first = BB_ReadUV(br);
|
|
||||||
}
|
|
||||||
if (BB_ReadBit(br))
|
|
||||||
{
|
|
||||||
bin->last = BB_ReadUV(br);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Invalid bin index */
|
|
||||||
Assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bin_changed = BB_ReadBit(br);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ents */
|
|
||||||
BB_ReadDebugMarker(br, Lit("SNAPSHOT NUM ENTS"));
|
|
||||||
if (BB_ReadBit(br))
|
|
||||||
{
|
|
||||||
ss->num_ents_allocated = BB_ReadUV(br);
|
|
||||||
}
|
|
||||||
b32 num_ents_reserved_changed = BB_ReadBit(br);
|
|
||||||
if (num_ents_reserved_changed)
|
|
||||||
{
|
|
||||||
u64 old_num_ents_reserved = ss->num_ents_reserved;
|
|
||||||
ss->num_ents_reserved = BB_ReadUV(br);
|
|
||||||
i64 reserve_diff = (i64)ss->num_ents_reserved - (i64)old_num_ents_reserved;
|
|
||||||
if (reserve_diff > 0)
|
|
||||||
{
|
|
||||||
PushStructsNoZero(ss->ents_arena, PP_Ent, reserve_diff);
|
|
||||||
for (u64 i = old_num_ents_reserved; i < ss->num_ents_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *e = &ss->ents[i];
|
|
||||||
*e = *PP_NilEnt();
|
|
||||||
e->ss = ss;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (reserve_diff < 0)
|
|
||||||
{
|
|
||||||
/* TODO: Handle this */
|
|
||||||
/* NOTE: Should be impossible for snasphot reserve count to decrease at the moment */
|
|
||||||
Assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BB_ReadDebugMarker(br, Lit("SNAPSHOT ENTS"));
|
|
||||||
BB_ReadDebugMarker(br, StringFromStruct(&ss->num_ents_reserved));
|
|
||||||
for (u64 i = 1; i < ss->num_ents_reserved; ++i)
|
|
||||||
{
|
|
||||||
PP_Ent *e = &ss->ents[i];
|
|
||||||
e->ss = ss;
|
|
||||||
PP_DecodeEnt(br, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
BB_ReadDebugMarker(br, Lit("SNAPSHOT END"));
|
|
||||||
}
|
|
||||||
@ -1,322 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Key types
|
|
||||||
|
|
||||||
Struct(PP_EntKey)
|
|
||||||
{
|
|
||||||
Uid uid;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_ClientKey)
|
|
||||||
{
|
|
||||||
u32 idx;
|
|
||||||
u32 gen;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PP_NilClientKey ((PP_ClientKey) { .gen = 0, .idx = 0 })
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client store types
|
|
||||||
|
|
||||||
Struct(PP_ClientLookupBin)
|
|
||||||
{
|
|
||||||
PP_ClientKey first;
|
|
||||||
PP_ClientKey last;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_ClientStore)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
Arena *arena;
|
|
||||||
|
|
||||||
/* Client lookup */
|
|
||||||
PP_ClientLookupBin *client_lookup_bins;
|
|
||||||
u64 num_client_lookup_bins;
|
|
||||||
|
|
||||||
/* Clients */
|
|
||||||
Arena *clients_arena;
|
|
||||||
struct PP_Client *clients;
|
|
||||||
PP_ClientKey first_free_client;
|
|
||||||
u64 num_clients_allocated;
|
|
||||||
u64 num_clients_reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
Inline PP_ClientStore *PP_NilClientStore(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_ClientStore **PP_nil_client_store;
|
|
||||||
return *PP_nil_client_store;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client types
|
|
||||||
|
|
||||||
Struct(PP_SnapshotLookupBin)
|
|
||||||
{
|
|
||||||
struct PP_Snapshot *first;
|
|
||||||
struct PP_Snapshot *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_Client)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
PP_ClientKey key;
|
|
||||||
PP_ClientStore *store;
|
|
||||||
|
|
||||||
Arena *snapshots_arena;
|
|
||||||
|
|
||||||
/* Round trip time of the client (if networked) */
|
|
||||||
i64 last_rtt_ns;
|
|
||||||
|
|
||||||
N_ChannelId channel_id;
|
|
||||||
u64 channel_hash;
|
|
||||||
|
|
||||||
PP_ClientKey next_free;
|
|
||||||
PP_ClientKey next_in_bin;
|
|
||||||
PP_ClientKey prev_in_bin;
|
|
||||||
|
|
||||||
/* The client's player entity key in the master sim (if relevant) */
|
|
||||||
PP_EntKey player_id;
|
|
||||||
|
|
||||||
/* This is the highest confirmed tick of ours that we know this client has received */
|
|
||||||
u64 ack;
|
|
||||||
|
|
||||||
// This is the highest confirmed ack of ours that we know this client has received (this
|
|
||||||
// can be used to determine which client ticks will no longer be delta encoded from and
|
|
||||||
// therefore can be released)
|
|
||||||
u64 double_ack;
|
|
||||||
|
|
||||||
/* This is the highest tick of their's that we have received */
|
|
||||||
u64 highest_received_tick;
|
|
||||||
|
|
||||||
/* Snapshots sorted by tick (low to high) */
|
|
||||||
u64 first_tick;
|
|
||||||
u64 last_tick;
|
|
||||||
u64 num_ticks;
|
|
||||||
struct PP_Snapshot *first_free_snapshot;
|
|
||||||
|
|
||||||
/* Tick -> snapshot lookup */
|
|
||||||
u64 num_snapshot_lookup_bins;
|
|
||||||
PP_SnapshotLookupBin *snapshot_lookup_bins;
|
|
||||||
};
|
|
||||||
|
|
||||||
Inline PP_Client *PP_NilClient(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_Client **PP_nil_client;
|
|
||||||
return *PP_nil_client;
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline b32 PP_EqClientKey(PP_ClientKey a, PP_ClientKey b)
|
|
||||||
{
|
|
||||||
return a.gen == b.gen && a.idx == b.idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Layer types
|
|
||||||
|
|
||||||
/* Absolute layers */
|
|
||||||
#define PP_Layer_FloorDecals (-300)
|
|
||||||
#define PP_Layer_Bullets (-200)
|
|
||||||
#define PP_Layer_Tracers (-100)
|
|
||||||
#define PP_Layer_Shoulders (0)
|
|
||||||
#define PP_Layer_Walls (100)
|
|
||||||
|
|
||||||
/* Relative layers */
|
|
||||||
#define PP_Layer_DefaultRelative (0)
|
|
||||||
#define PP_Layer_RelativeWeapon (1)
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Control types
|
|
||||||
|
|
||||||
Enum(PP_ControlFlag)
|
|
||||||
{
|
|
||||||
PP_ControlFlag_Fire = 1 << 0,
|
|
||||||
PP_ControlFlag_AltFire = 1 << 1,
|
|
||||||
|
|
||||||
/* Testing */
|
|
||||||
PP_ControlFlag_Drag = 1 << 2,
|
|
||||||
PP_ControlFlag_Delete = 1 << 3,
|
|
||||||
PP_ControlFlag_ClearAll = 1 << 4,
|
|
||||||
PP_ControlFlag_SpawnTest1 = 1 << 5,
|
|
||||||
PP_ControlFlag_SpawnTest2 = 1 << 6,
|
|
||||||
PP_ControlFlag_SpawnTest3 = 1 << 7,
|
|
||||||
PP_ControlFlag_SpawnTest4 = 1 << 8,
|
|
||||||
PP_ControlFlag_TestWalls = 1 << 9,
|
|
||||||
PP_ControlFlag_TestTiles = 1 << 10,
|
|
||||||
PP_ControlFlag_TestExplode = 1 << 11,
|
|
||||||
PP_ControlFlag_TestTeleport = 1 << 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_ControlData)
|
|
||||||
{
|
|
||||||
Vec2 move; /* Movement direction vector (speed of 0 -> 1) */
|
|
||||||
Vec2 focus; /* Focus direction vector (where does the controller want to look) */
|
|
||||||
Vec2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */
|
|
||||||
PP_ControlFlag flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
Enum(PP_CmdKind)
|
|
||||||
{
|
|
||||||
PP_CmdKind_Invalid,
|
|
||||||
|
|
||||||
PP_CmdKind_Control,
|
|
||||||
PP_CmdKind_Chat
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile types
|
|
||||||
|
|
||||||
Enum(PP_TileKind)
|
|
||||||
{
|
|
||||||
PP_TileKind_None,
|
|
||||||
PP_TileKind_Wall,
|
|
||||||
|
|
||||||
PP_TileKind_COUNT
|
|
||||||
};
|
|
||||||
StaticAssert(PP_TileKind_COUNT < 256); /* Tile kind must fit in 8 bits */
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot types
|
|
||||||
|
|
||||||
Enum(PP_SyncFlag)
|
|
||||||
{
|
|
||||||
PP_SyncFlag_NoSyncPredictables = 1 << 0
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_Snapshot)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
u64 tick;
|
|
||||||
PP_Client *client;
|
|
||||||
PP_Snapshot *next_free;
|
|
||||||
PP_Snapshot *next_in_bin;
|
|
||||||
PP_Snapshot *prev_in_bin;
|
|
||||||
u64 prev_tick;
|
|
||||||
u64 next_tick;
|
|
||||||
|
|
||||||
Arena *arena;
|
|
||||||
|
|
||||||
/* Sim time (guaranteed to increase by sim_dt_ns each step) */
|
|
||||||
i64 sim_dt_ns;
|
|
||||||
i64 sim_time_ns;
|
|
||||||
|
|
||||||
/* If != previous tick's continuity then don't lerp */
|
|
||||||
u64 continuity_gen;
|
|
||||||
|
|
||||||
/* The last physics iteration (used for tracking contact lifetime) */
|
|
||||||
u64 phys_iteration;
|
|
||||||
|
|
||||||
/* The key of the receiver's player in the snapshot */
|
|
||||||
PP_EntKey local_player;
|
|
||||||
|
|
||||||
/* Key lookup */
|
|
||||||
struct PP_EntBin *key_bins;
|
|
||||||
u64 num_key_bins;
|
|
||||||
|
|
||||||
/* Ents */
|
|
||||||
Arena *ents_arena;
|
|
||||||
struct PP_Ent *ents;
|
|
||||||
u32 first_free_ent;
|
|
||||||
u32 num_ents_allocated;
|
|
||||||
u32 num_ents_reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
Inline PP_Snapshot *PP_NilSnapshot(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_Snapshot **PP_nil_snapshot;
|
|
||||||
return *PP_nil_snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ State types
|
|
||||||
|
|
||||||
#define PP_ClientLookupBinsCount 127
|
|
||||||
#define PP_TickLookupBinsCount 127
|
|
||||||
#define PP_KeyLookupBinsCount 4096
|
|
||||||
|
|
||||||
Struct(PP_SharedSimCtx)
|
|
||||||
{
|
|
||||||
Arena *nil_arena;
|
|
||||||
PP_ClientStore *nil_client_store;
|
|
||||||
PP_Client *nil_client;
|
|
||||||
PP_Snapshot *nil_snapshot;
|
|
||||||
struct PP_Ent *nil_ent;
|
|
||||||
} extern PP_shared_sim_ctx;
|
|
||||||
|
|
||||||
/* Accessed via `PP_NilClientStore()` */
|
|
||||||
extern Readonly PP_ClientStore **PP_nil_client_store;
|
|
||||||
|
|
||||||
/* Accessed via `PP_NilClient()` */
|
|
||||||
extern Readonly PP_Client **PP_nil_client;
|
|
||||||
|
|
||||||
/* Accessed via `NilSnapshot()` */
|
|
||||||
extern Readonly PP_Snapshot **PP_nil_snapshot;
|
|
||||||
extern Readonly struct PP_Ent **PP_nil_ent;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Startup
|
|
||||||
|
|
||||||
void PP_StartupSim(void);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client store acquire operations
|
|
||||||
|
|
||||||
PP_ClientStore *PP_AcquireClientStore(void);
|
|
||||||
void PP_ReleaseClientStore(PP_ClientStore *store);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client acquire operations
|
|
||||||
|
|
||||||
PP_Client *PP_AcquireClient(PP_ClientStore *store);
|
|
||||||
void PP_ReleaseClient(PP_Client *client);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Client lookup operations
|
|
||||||
|
|
||||||
u64 PP_ClientChannelHashFromChannelId(N_ChannelId channel_id);
|
|
||||||
void PP_SetClientChannelId(PP_Client *client, N_ChannelId channel_id);
|
|
||||||
PP_Client *PP_ClientFromChannelId(PP_ClientStore *store, N_ChannelId channel_id);
|
|
||||||
PP_Client *PP_ClientFromKey(PP_ClientStore *store, PP_ClientKey key);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot acquire operations
|
|
||||||
|
|
||||||
PP_Snapshot *PP_AcquireSnapshot(PP_Client *client, PP_Snapshot *src, u64 tick);
|
|
||||||
void PP_ReleaseSnapshot(PP_Snapshot *ss);
|
|
||||||
void PP_ReleaseSnapshotsInRange(PP_Client *client, u64 start, u64 end);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot lookup operations
|
|
||||||
|
|
||||||
PP_Snapshot *PP_SnapshotFromTick(PP_Client *client, u64 tick);
|
|
||||||
PP_Snapshot *PP_SnapshotFromClosestTickLte(PP_Client *client, u64 tick);
|
|
||||||
PP_Snapshot *PP_SnapshotFromClosestTickGte(PP_Client *client, u64 tick);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile operations
|
|
||||||
|
|
||||||
Vec2I32 PP_WorldTileIndexFromPos(Vec2 pos);
|
|
||||||
Vec2 PP_PosFromWorldTileIndex(Vec2I32 world_tile_index);
|
|
||||||
Vec2I32 PP_LocalTileIndexFromWorldTileIndex(Vec2I32 world_tile_index);
|
|
||||||
Vec2I32 PP_WorldTileIndexFromLocalTileIndex(Vec2I32 tile_chunk_index, Vec2I32 local_tile_index);
|
|
||||||
Vec2I32 PP_TileChunkIndexFromWorldTileIndex(Vec2I32 world_tile_index);
|
|
||||||
void PP_SetSnapshotTile(PP_Snapshot *ss, Vec2I32 world_tile_index, PP_TileKind tile_kind);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot lerp operations
|
|
||||||
|
|
||||||
PP_Snapshot *PP_AcquireSnapshotFromLerp(PP_Client *client, PP_Snapshot *ss0, PP_Snapshot *ss1, f64 blend);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot sync operations
|
|
||||||
|
|
||||||
void PP_SyncSnapshotEnts(PP_Snapshot *local_ss, PP_Snapshot *remote_ss, PP_EntKey remote_player, u32 sync_flags);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot encode operations
|
|
||||||
|
|
||||||
void PP_EncodeSnapshot(BB_Writer *bw, PP_Client *receiver, PP_Snapshot *ss0, PP_Snapshot *ss1);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Snapshot decode operations
|
|
||||||
|
|
||||||
void PP_DecodeSnapshot(BB_Reader *br, PP_Snapshot *ss);
|
|
||||||
@ -1,493 +0,0 @@
|
|||||||
/* FIXME: Default space entry & cell pointers to nil */
|
|
||||||
|
|
||||||
Readonly PP_SpaceEntry PP_nil_space_entry = ZI;
|
|
||||||
Readonly PP_SpaceCell PP_nil_space_cell = ZI;
|
|
||||||
Readonly PP_Space PP_nil_space = ZI;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Space
|
|
||||||
|
|
||||||
// NOTE:
|
|
||||||
// The number of bins determines how often tiles will collide in the spatial hash.
|
|
||||||
// For example, at `num_bins_sqrt` = 256 (65536 bins), tiles <1, 1>, <1, 257>, and <257, 257> will collide. */
|
|
||||||
PP_Space *PP_AcquireSpace(f32 cell_size, u32 num_bins_sqrt)
|
|
||||||
{
|
|
||||||
PP_Space *space;
|
|
||||||
{
|
|
||||||
Arena *arena = AcquireArena(Gibi(64));
|
|
||||||
space = PushStruct(arena, PP_Space);
|
|
||||||
space->entry_arena = arena;
|
|
||||||
}
|
|
||||||
|
|
||||||
space->valid = 1;
|
|
||||||
space->entries = PushDry(space->entry_arena, PP_SpaceEntry);
|
|
||||||
|
|
||||||
space->cell_arena = AcquireArena(Gibi(64));
|
|
||||||
space->cell_size = cell_size;
|
|
||||||
space->num_bins = num_bins_sqrt * num_bins_sqrt;
|
|
||||||
space->num_bins_sqrt = num_bins_sqrt;
|
|
||||||
space->bins = PushStructs(space->cell_arena, PP_SpaceCellBin, space->num_bins);
|
|
||||||
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseSpace(PP_Space *space)
|
|
||||||
{
|
|
||||||
ReleaseArena(space->cell_arena);
|
|
||||||
ReleaseArena(space->entry_arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ResetSpace(PP_Space *space)
|
|
||||||
{
|
|
||||||
PopTo(space->entry_arena, (u64)space->entries - (u64)ArenaBase(space->entry_arena));
|
|
||||||
ResetArena(space->cell_arena);
|
|
||||||
space->bins = PushStructs(space->cell_arena, PP_SpaceCellBin, space->num_bins);
|
|
||||||
space->num_entries_reserved = 0;
|
|
||||||
space->first_free_cell = 0;
|
|
||||||
space->first_free_cell_node = 0;
|
|
||||||
space->first_free_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Space *PP_SpaceFromEntry(PP_SpaceEntry *entry)
|
|
||||||
{
|
|
||||||
if (entry->valid)
|
|
||||||
{
|
|
||||||
u64 first_entry_addr = (u64)(entry - entry->key.idx);
|
|
||||||
PP_Space *space = (PP_Space *)(first_entry_addr - PP_SpaceEntriesOffset);
|
|
||||||
Assert(space->entries == (PP_SpaceEntry *)first_entry_addr);
|
|
||||||
return space;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return PP_NilSpace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Cell
|
|
||||||
|
|
||||||
Vec2I32 PP_SpaceCellCoordsFromWorldCoords(f32 cell_size, Vec2 world_pos)
|
|
||||||
{
|
|
||||||
f32 x = world_pos.x;
|
|
||||||
f32 y = world_pos.y;
|
|
||||||
x = (x + ((x >= 0) - (x < 0)) * cell_size) / cell_size;
|
|
||||||
y = (y + ((y >= 0) - (y < 0)) * cell_size) / cell_size;
|
|
||||||
return VEC2I32((i32)x, (i32)y);
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 PP_SpaceBinIndexFromCellCoords(PP_Space *space, Vec2I32 cell_pos)
|
|
||||||
{
|
|
||||||
i32 num_bins_sqrt = space->num_bins_sqrt;
|
|
||||||
|
|
||||||
/* Cell pos of 0 is not valid and will be converted to -1 */
|
|
||||||
Assert(cell_pos.x != 0 && cell_pos.y != 0);
|
|
||||||
|
|
||||||
i32 index_x = cell_pos.x;
|
|
||||||
i32 index_y = cell_pos.y;
|
|
||||||
/* Offset cell index by -1 since cell pos of 0 is invalid */
|
|
||||||
index_x -= (index_x >= 0);
|
|
||||||
index_y -= (index_y >= 0);
|
|
||||||
/* Un-mirror coords to prevent collisions between cells near the axes. (e.g. <3, 1> & <3, -1> should not collide) */
|
|
||||||
index_x += (index_x < 0) * (num_bins_sqrt * ((index_x / -num_bins_sqrt) + 1));
|
|
||||||
index_y += (index_y < 0) * (num_bins_sqrt * ((index_y / -num_bins_sqrt) + 1));
|
|
||||||
|
|
||||||
i32 bin_index = (index_x % num_bins_sqrt) + (index_y % num_bins_sqrt) * num_bins_sqrt;
|
|
||||||
Assert(bin_index >= 0 && bin_index < (i32)space->num_bins);
|
|
||||||
|
|
||||||
return bin_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_SpaceCell *PP_SpaceCellFromCellPos(PP_Space *space, Vec2I32 cell_pos)
|
|
||||||
{
|
|
||||||
i32 bin_index = PP_SpaceBinIndexFromCellCoords(space, cell_pos);
|
|
||||||
PP_SpaceCellBin *bin = &space->bins[bin_index];
|
|
||||||
PP_SpaceCell *result = PP_NilSpaceCell();
|
|
||||||
for (PP_SpaceCell *n = bin->first_cell; n; n = n->next_in_bin)
|
|
||||||
{
|
|
||||||
if (EqVec2I32(n->pos, cell_pos))
|
|
||||||
{
|
|
||||||
result = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_AcquireSpaceCellNode(Vec2I32 cell_pos, PP_SpaceEntry *entry)
|
|
||||||
{
|
|
||||||
PP_Space *space = PP_SpaceFromEntry(entry);
|
|
||||||
i32 bin_index = PP_SpaceBinIndexFromCellCoords(space, cell_pos);
|
|
||||||
PP_SpaceCellBin *bin = &space->bins[bin_index];
|
|
||||||
|
|
||||||
/* Find existing cell */
|
|
||||||
PP_SpaceCell *cell = 0;
|
|
||||||
for (PP_SpaceCell *n = bin->first_cell; n; n = n->next_in_bin)
|
|
||||||
{
|
|
||||||
if (EqVec2I32(n->pos, cell_pos))
|
|
||||||
{
|
|
||||||
cell = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquire new cell if necessary */
|
|
||||||
if (!cell)
|
|
||||||
{
|
|
||||||
if (space->first_free_cell)
|
|
||||||
{
|
|
||||||
cell = space->first_free_cell;
|
|
||||||
space->first_free_cell = cell->next_free;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell = PushStructNoZero(space->cell_arena, PP_SpaceCell);
|
|
||||||
}
|
|
||||||
ZeroStruct(cell);
|
|
||||||
if (bin->last_cell)
|
|
||||||
{
|
|
||||||
bin->last_cell->next_in_bin = cell;
|
|
||||||
cell->prev_in_bin = bin->last_cell;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first_cell = cell;
|
|
||||||
}
|
|
||||||
bin->last_cell = cell;
|
|
||||||
cell->pos = cell_pos;
|
|
||||||
cell->bin = bin;
|
|
||||||
cell->valid = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Acquire node */
|
|
||||||
PP_SpaceCellNode *node;
|
|
||||||
{
|
|
||||||
if (space->first_free_cell_node)
|
|
||||||
{
|
|
||||||
node = space->first_free_cell_node;
|
|
||||||
space->first_free_cell_node = node->next_free;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = PushStructNoZero(space->cell_arena, PP_SpaceCellNode);
|
|
||||||
}
|
|
||||||
ZeroStruct(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert into cell list */
|
|
||||||
node->cell = cell;
|
|
||||||
if (cell->last_node)
|
|
||||||
{
|
|
||||||
cell->last_node->next_in_cell = node;
|
|
||||||
node->prev_in_cell = cell->last_node;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell->first_node = node;
|
|
||||||
}
|
|
||||||
cell->last_node = node;
|
|
||||||
|
|
||||||
/* Insert into entry list */
|
|
||||||
node->entry = entry;
|
|
||||||
if (entry->last_node)
|
|
||||||
{
|
|
||||||
entry->last_node->next_in_entry = node;
|
|
||||||
node->prev_in_entry = entry->last_node;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->first_node = node;
|
|
||||||
}
|
|
||||||
entry->last_node = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseSpaceCellNode(PP_SpaceCellNode *n)
|
|
||||||
{
|
|
||||||
PP_SpaceCell *cell = n->cell;
|
|
||||||
PP_SpaceEntry *entry = n->entry;
|
|
||||||
PP_Space *space = PP_SpaceFromEntry(entry);
|
|
||||||
PP_SpaceCellBin *bin = cell->bin;
|
|
||||||
|
|
||||||
/* Remove from entry list */
|
|
||||||
{
|
|
||||||
PP_SpaceCellNode *prev = n->prev_in_entry;
|
|
||||||
PP_SpaceCellNode *next = n->next_in_entry;
|
|
||||||
if (prev)
|
|
||||||
{
|
|
||||||
prev->next_in_entry = next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->first_node = next;
|
|
||||||
}
|
|
||||||
if (next)
|
|
||||||
{
|
|
||||||
next->prev_in_entry = prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry->last_node = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove from cell list */
|
|
||||||
{
|
|
||||||
PP_SpaceCellNode *prev = n->prev_in_cell;
|
|
||||||
PP_SpaceCellNode *next = n->next_in_cell;
|
|
||||||
if (prev)
|
|
||||||
{
|
|
||||||
prev->next_in_cell = next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell->first_node = next;
|
|
||||||
}
|
|
||||||
if (next)
|
|
||||||
{
|
|
||||||
next->prev_in_cell = prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell->last_node = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If cell is now empty, release it */
|
|
||||||
if (!cell->first_node && !cell->last_node)
|
|
||||||
{
|
|
||||||
/* Remove from bin */
|
|
||||||
PP_SpaceCell *prev = cell->prev_in_bin;
|
|
||||||
PP_SpaceCell *next = cell->next_in_bin;
|
|
||||||
if (prev)
|
|
||||||
{
|
|
||||||
prev->next_in_bin = next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->first_cell = next;
|
|
||||||
}
|
|
||||||
if (next)
|
|
||||||
{
|
|
||||||
next->prev_in_bin = prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bin->last_cell = prev;
|
|
||||||
}
|
|
||||||
cell->valid = 0;
|
|
||||||
|
|
||||||
/* Insert cell into free list */
|
|
||||||
cell->next_free = space->first_free_cell;
|
|
||||||
space->first_free_cell = cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert node into free list */
|
|
||||||
n->next_free = space->first_free_cell_node;
|
|
||||||
space->first_free_cell_node = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Entry
|
|
||||||
|
|
||||||
PP_SpaceEntry *PP_SpaceEntryFromKey(PP_Space *space, PP_SpaceEntryKey key)
|
|
||||||
{
|
|
||||||
PP_SpaceEntry *entry = PP_NilSpaceEntry();
|
|
||||||
|
|
||||||
if (key.gen > 0 && key.idx < space->num_entries_reserved)
|
|
||||||
{
|
|
||||||
PP_SpaceEntry *tmp = &space->entries[key.idx];
|
|
||||||
if (tmp->key.gen == key.gen)
|
|
||||||
{
|
|
||||||
entry = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_SpaceEntry *PP_AcquireSpaceEntry(PP_Space *space, PP_EntKey ent)
|
|
||||||
{
|
|
||||||
PP_SpaceEntry *entry = 0;
|
|
||||||
PP_SpaceEntryKey key = ZI;
|
|
||||||
if (space->first_free_entry)
|
|
||||||
{
|
|
||||||
entry = space->first_free_entry;
|
|
||||||
space->first_free_entry = entry->next_free;
|
|
||||||
key = entry->key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry = PushStructNoZero(space->entry_arena, PP_SpaceEntry);
|
|
||||||
key.idx = space->num_entries_reserved;
|
|
||||||
key.gen = 1;
|
|
||||||
++space->num_entries_reserved;
|
|
||||||
}
|
|
||||||
ZeroStruct(entry);
|
|
||||||
entry->valid = 1;
|
|
||||||
entry->key = key;
|
|
||||||
entry->ent = ent;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_ReleaseSpaceEntry(PP_SpaceEntry *entry)
|
|
||||||
{
|
|
||||||
/* Release nodes */
|
|
||||||
PP_SpaceCellNode *n = entry->first_node;
|
|
||||||
while (n)
|
|
||||||
{
|
|
||||||
PP_SpaceCellNode *next = n->next_in_entry;
|
|
||||||
/* TODO: More efficient batch release that doesn't care about maintaining entry list */
|
|
||||||
PP_ReleaseSpaceCellNode(n);
|
|
||||||
n = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_Space *space = PP_SpaceFromEntry(entry);
|
|
||||||
entry->next_free = space->first_free_entry;
|
|
||||||
entry->valid = 0;
|
|
||||||
++entry->key.gen;
|
|
||||||
space->first_free_entry = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PP_UpdateSpaceEntryAabb(PP_SpaceEntry *entry, Aabb new_aabb)
|
|
||||||
{
|
|
||||||
PP_Space *space = PP_SpaceFromEntry(entry);
|
|
||||||
f32 cell_size = space->cell_size;
|
|
||||||
|
|
||||||
Vec2I32 old_cell_p0 = VEC2I32(0, 0);
|
|
||||||
Vec2I32 old_cell_p1 = VEC2I32(0, 0);
|
|
||||||
if (entry->first_node)
|
|
||||||
{
|
|
||||||
Aabb old_aabb = entry->aabb;
|
|
||||||
old_cell_p0 = PP_SpaceCellCoordsFromWorldCoords(cell_size, old_aabb.p0);
|
|
||||||
old_cell_p1 = PP_SpaceCellCoordsFromWorldCoords(cell_size, old_aabb.p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2I32 new_cell_p0 = PP_SpaceCellCoordsFromWorldCoords(cell_size, new_aabb.p0);
|
|
||||||
Vec2I32 new_cell_p1 = PP_SpaceCellCoordsFromWorldCoords(cell_size, new_aabb.p1);
|
|
||||||
|
|
||||||
/* Release outdated nodes */
|
|
||||||
PP_SpaceCellNode *n = entry->first_node;
|
|
||||||
while (n)
|
|
||||||
{
|
|
||||||
PP_SpaceCell *cell = n->cell;
|
|
||||||
Vec2I32 cell_pos = cell->pos;
|
|
||||||
if (cell_pos.x < new_cell_p0.x || cell_pos.x > new_cell_p1.x || cell_pos.y < new_cell_p0.y || cell_pos.y > new_cell_p1.y)
|
|
||||||
{
|
|
||||||
/* Cell is outside of new AABB */
|
|
||||||
PP_SpaceCellNode *next = n->next_in_entry;
|
|
||||||
PP_ReleaseSpaceCellNode(n);
|
|
||||||
n = next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = n->next_in_entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert new nodes */
|
|
||||||
for (i32 y = new_cell_p0.y; y <= new_cell_p1.y; ++y)
|
|
||||||
{
|
|
||||||
for (i32 x = new_cell_p0.x; x <= new_cell_p1.x; ++x)
|
|
||||||
{
|
|
||||||
if (x != 0 && y != 0 && (x < old_cell_p0.x || x > old_cell_p1.x || y < old_cell_p0.y || y > old_cell_p1.y))
|
|
||||||
{
|
|
||||||
/* Cell is outside of old AABB */
|
|
||||||
PP_AcquireSpaceCellNode(VEC2I32(x, y), entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->aabb = new_aabb;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Iter
|
|
||||||
|
|
||||||
PP_SpaceIter PP_BeginSpaceIterAabb(PP_Space *space, Aabb aabb)
|
|
||||||
{
|
|
||||||
PP_SpaceIter iter = ZI;
|
|
||||||
f32 cell_size = space->cell_size;
|
|
||||||
|
|
||||||
iter.space = space;
|
|
||||||
iter.cell_start = PP_SpaceCellCoordsFromWorldCoords(cell_size, aabb.p0);
|
|
||||||
iter.cell_end = PP_SpaceCellCoordsFromWorldCoords(cell_size, aabb.p1);
|
|
||||||
if (iter.cell_start.x > iter.cell_end.x || iter.cell_start.y > iter.cell_end.y)
|
|
||||||
{
|
|
||||||
/* Swap cell_start & cell_end */
|
|
||||||
Vec2I32 tmp = iter.cell_start;
|
|
||||||
iter.cell_start = iter.cell_end;
|
|
||||||
iter.cell_end = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter.aabb = aabb;
|
|
||||||
iter.cell_cur = iter.cell_start;
|
|
||||||
iter.cell_cur.x -= 1;
|
|
||||||
iter.cell_cur.y -= 1;
|
|
||||||
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
PP_SpaceEntry *PP_NextSpaceIterAabb(PP_SpaceIter *iter)
|
|
||||||
{
|
|
||||||
PP_Space *space = iter->space;
|
|
||||||
Aabb iter_aabb = iter->aabb;
|
|
||||||
Vec2I32 cell_start = iter->cell_start;
|
|
||||||
Vec2I32 cell_end = iter->cell_end;
|
|
||||||
Vec2I32 cell_cur = iter->cell_cur;
|
|
||||||
i32 span = cell_end.x - cell_start.x;
|
|
||||||
|
|
||||||
PP_SpaceCellNode *next_node = 0;
|
|
||||||
if (cell_cur.x >= cell_start.x && cell_cur.x <= cell_end.x && cell_cur.y >= cell_start.y && cell_cur.y <= cell_end.y)
|
|
||||||
{
|
|
||||||
/* Started */
|
|
||||||
Assert(iter->prev != 0);
|
|
||||||
next_node = iter->prev->next_in_cell;
|
|
||||||
}
|
|
||||||
else if (cell_cur.x > cell_end.x || cell_cur.y > cell_end.y)
|
|
||||||
{
|
|
||||||
/* Ended */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
if (next_node)
|
|
||||||
{
|
|
||||||
PP_SpaceEntry *entry = next_node->entry;
|
|
||||||
Aabb entry_aabb = entry->aabb;
|
|
||||||
if (CLD_TestAabb(entry_aabb, iter_aabb))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
next_node = next_node->next_in_cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Reached end of cell, find next cell */
|
|
||||||
b32 nextx = (cell_cur.x + 1) <= cell_end.x;
|
|
||||||
b32 nexty = (nextx == 0) && ((cell_cur.y + 1) <= cell_end.y);
|
|
||||||
if (nextx || nexty)
|
|
||||||
{
|
|
||||||
cell_cur.x += nextx - (span * nexty);
|
|
||||||
cell_cur.y += nexty;
|
|
||||||
cell_cur.x += (cell_cur.x == 0);
|
|
||||||
cell_cur.y += (cell_cur.y == 0);
|
|
||||||
PP_SpaceCell *cell = PP_SpaceCellFromCellPos(space, cell_cur);
|
|
||||||
next_node = cell->first_node;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Reached end of iter */
|
|
||||||
cell_cur.x += 1;
|
|
||||||
cell_cur.y += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iter->prev = next_node;
|
|
||||||
iter->cell_cur = cell_cur;
|
|
||||||
|
|
||||||
return next_node ? next_node->entry : 0;
|
|
||||||
}
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Space entry types
|
|
||||||
|
|
||||||
Struct(PP_SpaceEntryKey)
|
|
||||||
{
|
|
||||||
u64 idx;
|
|
||||||
u64 gen;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_SpaceEntry)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
PP_SpaceEntryKey key;
|
|
||||||
|
|
||||||
struct PP_SpaceCellNode *first_node;
|
|
||||||
struct PP_SpaceCellNode *last_node;
|
|
||||||
|
|
||||||
Aabb aabb;
|
|
||||||
PP_EntKey ent;
|
|
||||||
|
|
||||||
PP_SpaceEntry *next_free;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Space cell types
|
|
||||||
|
|
||||||
// Links a cell to a entry.
|
|
||||||
// Acts as both a node in the list of entries contained by the cell, and a node in the list of cells containing the entry. */
|
|
||||||
Struct(PP_SpaceCellNode)
|
|
||||||
{
|
|
||||||
PP_SpaceEntry *entry;
|
|
||||||
struct PP_SpaceCell *cell;
|
|
||||||
|
|
||||||
/* For list of all entries contained by cell */
|
|
||||||
PP_SpaceCellNode *prev_in_cell;
|
|
||||||
PP_SpaceCellNode *next_in_cell;
|
|
||||||
|
|
||||||
/* For list of all cells containing entry */
|
|
||||||
PP_SpaceCellNode *prev_in_entry;
|
|
||||||
PP_SpaceCellNode *next_in_entry;
|
|
||||||
|
|
||||||
PP_SpaceCellNode *next_free;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_SpaceCell)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
Vec2I32 pos;
|
|
||||||
|
|
||||||
PP_SpaceCellNode *first_node;
|
|
||||||
PP_SpaceCellNode *last_node;
|
|
||||||
|
|
||||||
struct PP_SpaceCellBin *bin;
|
|
||||||
PP_SpaceCell *prev_in_bin;
|
|
||||||
PP_SpaceCell *next_in_bin;
|
|
||||||
|
|
||||||
PP_SpaceCell *next_free;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_SpaceCellBin)
|
|
||||||
{
|
|
||||||
PP_SpaceCell *first_cell;
|
|
||||||
PP_SpaceCell *last_cell;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Space types
|
|
||||||
|
|
||||||
Struct(PP_Space)
|
|
||||||
{
|
|
||||||
b32 valid;
|
|
||||||
f32 cell_size;
|
|
||||||
|
|
||||||
Arena *cell_arena;
|
|
||||||
PP_SpaceCellBin *bins;
|
|
||||||
i32 num_bins;
|
|
||||||
i32 num_bins_sqrt;
|
|
||||||
PP_SpaceCell *first_free_cell;
|
|
||||||
PP_SpaceCellNode *first_free_cell_node;
|
|
||||||
|
|
||||||
Arena *entry_arena;
|
|
||||||
u64 num_entries_reserved;
|
|
||||||
PP_SpaceEntry *entries;
|
|
||||||
PP_SpaceEntry *first_free_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(PP_SpaceIter)
|
|
||||||
{
|
|
||||||
Aabb aabb;
|
|
||||||
PP_Space *space;
|
|
||||||
Vec2I32 cell_start;
|
|
||||||
Vec2I32 cell_end;
|
|
||||||
Vec2I32 cell_cur;
|
|
||||||
PP_SpaceCellNode *prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Nil types
|
|
||||||
|
|
||||||
/* Offset in bytes from start of space struct to start of entry array (assume adjacently allocated) */
|
|
||||||
#define PP_SpaceEntriesOffset (sizeof(PP_Space) + (sizeof(PP_Space) % alignof(PP_SpaceEntry)))
|
|
||||||
|
|
||||||
/* Accessed via NilEnt() */
|
|
||||||
extern Readonly PP_SpaceEntry PP_nil_space_entry;
|
|
||||||
extern Readonly PP_SpaceCell PP_nil_space_cell;
|
|
||||||
extern Readonly PP_Space PP_nil_space;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Nil helpers
|
|
||||||
|
|
||||||
Inline PP_SpaceEntry *PP_NilSpaceEntry(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_SpaceEntry PP_nil_space_entry;
|
|
||||||
return &PP_nil_space_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline PP_SpaceCell *PP_NilSpaceCell(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_SpaceCell PP_nil_space_cell;
|
|
||||||
return &PP_nil_space_cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline PP_Space *PP_NilSpace(void)
|
|
||||||
{
|
|
||||||
extern Readonly PP_Space PP_nil_space;
|
|
||||||
return &PP_nil_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Space
|
|
||||||
|
|
||||||
PP_Space *PP_AcquireSpace(f32 cell_size, u32 num_bins_sqrt);
|
|
||||||
void PP_ReleaseSpace(PP_Space *space);
|
|
||||||
void PP_ResetSpace(PP_Space *space);
|
|
||||||
PP_Space *PP_SpaceFromEntry(PP_SpaceEntry *entry);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Cell
|
|
||||||
|
|
||||||
Vec2I32 PP_SpaceCellCoordsFromWorldCoords(f32 cell_size, Vec2 world_pos);
|
|
||||||
i32 PP_SpaceBinIndexFromCellCoords(PP_Space *space, Vec2I32 cell_pos);
|
|
||||||
PP_SpaceCell *PP_SpaceCellFromCellPos(PP_Space *space, Vec2I32 cell_pos);
|
|
||||||
void PP_AcquireSpaceCellNode(Vec2I32 cell_pos, PP_SpaceEntry *entry);
|
|
||||||
void PP_ReleaseSpaceCellNode(PP_SpaceCellNode *n);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Entry
|
|
||||||
|
|
||||||
PP_SpaceEntry *PP_SpaceEntryFromKey(PP_Space *space, PP_SpaceEntryKey key);
|
|
||||||
PP_SpaceEntry *PP_AcquireSpaceEntry(PP_Space *space, PP_EntKey ent);
|
|
||||||
void PP_ReleaseSpaceEntry(PP_SpaceEntry *entry);
|
|
||||||
void PP_UpdateSpaceEntryAabb(PP_SpaceEntry *entry, Aabb new_aabb);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Iter
|
|
||||||
|
|
||||||
PP_SpaceIter PP_BeginSpaceIterAabb(PP_Space *space, Aabb aabb);
|
|
||||||
PP_SpaceEntry *PP_NextSpaceIterAabb(PP_SpaceIter *iter);
|
|
||||||
#define PP_EndSpaceIter(i)
|
|
||||||
2035
src/pp_old/pp_step.c
2035
src/pp_old/pp_step.c
File diff suppressed because it is too large
Load Diff
@ -1,68 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Acceleration structure types
|
|
||||||
|
|
||||||
/* Structure used to accelerate up entity lookup (rebuilt every step) */
|
|
||||||
/* TODO: Remove this and do something better. Just a hack to de-couple old sim ctx from step. */
|
|
||||||
|
|
||||||
Struct(PP_Accel)
|
|
||||||
{
|
|
||||||
PP_Space *space;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Step ctx
|
|
||||||
|
|
||||||
Struct(PP_SimStepCtx)
|
|
||||||
{
|
|
||||||
b32 is_master;
|
|
||||||
PP_Accel *accel;
|
|
||||||
RandState rand; /* TODO: Replace with per-sim rand for deterministic rng */
|
|
||||||
|
|
||||||
PP_Snapshot *world; /* The world to simulate */
|
|
||||||
i64 sim_dt_ns; /* How much sim time should progress */
|
|
||||||
|
|
||||||
PP_Client *user_input_client; /* The client that contains input from the user thread */
|
|
||||||
PP_Client *master_client; /* The master client to read snapshots from (nil if world is master) */
|
|
||||||
PP_Client *publish_client; /* The publish client to write syncable state to (nil if skipping publish) */
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Accel operations
|
|
||||||
|
|
||||||
PP_Accel PP_AcquireAccel(void);
|
|
||||||
void PP_ReleaseAccel(PP_Accel *accel);
|
|
||||||
void PP_ResetAccel(PP_Snapshot *ss, PP_Accel *accel);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Spawn test operations
|
|
||||||
|
|
||||||
PP_Ent *PP_SpawnTestSmg(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_SpawnTestLauncher(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_SpawnTestChucker(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_SpawnTestEmployee(PP_Ent *parent);
|
|
||||||
PP_Ent *PP_SpawnTestCamera(PP_Ent *parent, PP_Ent *follow);
|
|
||||||
PP_Ent *PP_SpawnTestExplosion(PP_Ent *parent, Vec2 pos, f32 strength, f32 radius);
|
|
||||||
void PP_TeleportTest(PP_Ent *ent, Vec2 pos);
|
|
||||||
void PP_SpawnTestEnts1(PP_Ent *parent, Vec2 pos);
|
|
||||||
void PP_SpawnTestEnts2(PP_Ent *parent, Vec2 pos);
|
|
||||||
void PP_SpawnTestEnts3(PP_Ent *parent, Vec2 pos);
|
|
||||||
void PP_SpawnTestEnts4(PP_Ent *parent, Vec2 pos);
|
|
||||||
void PP_SpawnTestTile(PP_Snapshot *world, Vec2 world_pos);
|
|
||||||
void PP_ClearLevelTest(PP_SimStepCtx *ctx);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Tile test operations
|
|
||||||
|
|
||||||
MergesortCompareFuncDef(PP_SortTileXCmp, arg_a, arg_b, _);
|
|
||||||
MergesortCompareFuncDef(PP_SortTileYCmp, arg_a, arg_b, _);
|
|
||||||
void PP_GenerateTestWalls(PP_Snapshot *world);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Collision response
|
|
||||||
|
|
||||||
PP_CollisionCallbackFuncDef(PP_OnEntCollision, data, step_ctx);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Step
|
|
||||||
|
|
||||||
void PP_StepSim(PP_SimStepCtx *ctx);
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Console
|
|
||||||
|
|
||||||
UI_Box *PP_BuildDebugConsole(b32 minimized)
|
|
||||||
{
|
|
||||||
/* TODO: Remove this whole thing */
|
|
||||||
__prof;
|
|
||||||
PP_SharedUserState *g = &PP_shared_user_state;
|
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
|
|
||||||
// i32 console_level = minimized ? LogLevel_Success : LogLevel_Debug;
|
|
||||||
i32 console_level = LogLevel_Debug;
|
|
||||||
|
|
||||||
u32 colors[LogLevel_COUNT][2] = ZI;
|
|
||||||
SetBytes(colors, 0xFF, sizeof(colors));
|
|
||||||
/* Debug colors */
|
|
||||||
colors[LogLevel_Debug][0] = Rgb32F(0.4, 0.1, 0.4);
|
|
||||||
colors[LogLevel_Debug][1] = Rgb32F(0.5, 0.2, 0.5);
|
|
||||||
/* Info colors */
|
|
||||||
colors[LogLevel_Info][0] = Rgb32F(0.4, 0.4, 0.4);
|
|
||||||
colors[LogLevel_Info][1] = Rgb32F(0.5, 0.5, 0.5);
|
|
||||||
/* Success colors */
|
|
||||||
colors[LogLevel_Success][0] = Rgb32F(0.1, 0.3, 0.1);
|
|
||||||
colors[LogLevel_Success][1] = Rgb32F(0.2, 0.4, 0.2);
|
|
||||||
/* Warning colors */
|
|
||||||
colors[LogLevel_Warning][0] = Rgb32F(0.4, 0.4, 0.1);
|
|
||||||
colors[LogLevel_Warning][1] = Rgb32F(0.5, 0.5, 0.2);
|
|
||||||
/* Error colors */
|
|
||||||
colors[LogLevel_Error][0] = Rgb32F(0.4, 0.1, 0.1);
|
|
||||||
colors[LogLevel_Error][1] = Rgb32F(0.5, 0.2, 0.2);
|
|
||||||
|
|
||||||
i64 max_time_ns = I64Max;
|
|
||||||
i64 fade_time_ns = max_time_ns;
|
|
||||||
if (minimized)
|
|
||||||
{
|
|
||||||
max_time_ns = NsFromSeconds(10);
|
|
||||||
fade_time_ns = max_time_ns;
|
|
||||||
}
|
|
||||||
f32 fade_curve = 0.5;
|
|
||||||
|
|
||||||
i64 now_ns = TimeNs();
|
|
||||||
UI_Box *console_box = 0;
|
|
||||||
{
|
|
||||||
UI_SetNext(Border, 0);
|
|
||||||
if (minimized)
|
|
||||||
{
|
|
||||||
UI_SetNext(BackgroundColor, 0);
|
|
||||||
UI_SetNext(Width, UI_PIX(500, 0));
|
|
||||||
UI_SetNext(Height, UI_FIT(1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UI_SetNext(BackgroundColor, Rgba32F(1, 1, 1, 0.02));
|
|
||||||
UI_SetNext(Width, UI_FILL(1, 0));
|
|
||||||
UI_SetNext(Height, UI_FIT(1));
|
|
||||||
}
|
|
||||||
console_box = UI_BuildColumn(UI_KeyF("Console box"));
|
|
||||||
UI_PushCP(console_box);
|
|
||||||
{
|
|
||||||
/* Gather display logs */
|
|
||||||
u64 max = 20;
|
|
||||||
u64 display_count = 0;
|
|
||||||
LogEvent *display_logs = PushStructs(scratch.arena, LogEvent, max);
|
|
||||||
{
|
|
||||||
b32 done = 0;
|
|
||||||
if (minimized)
|
|
||||||
{
|
|
||||||
max = 5;
|
|
||||||
}
|
|
||||||
LogEventsArray logs = GetLogEvents();
|
|
||||||
for (u64 i = logs.count; i-- > 0 && display_count < max && !done;)
|
|
||||||
{
|
|
||||||
LogEvent ev = logs.logs[i];
|
|
||||||
if (ev.time_ns > (now_ns - max_time_ns))
|
|
||||||
{
|
|
||||||
if (ev.level <= console_level)
|
|
||||||
{
|
|
||||||
display_logs[display_count] = ev;
|
|
||||||
++display_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Display logs in reverse */
|
|
||||||
for (u64 i = display_count; i-- > 0;)
|
|
||||||
{
|
|
||||||
LogEvent log = display_logs[i];
|
|
||||||
f32 opacity = 0.75;
|
|
||||||
f32 lin = 1.0 - ClampF64((f64)(now_ns - log.time_ns) / (f64)fade_time_ns, 0, 1);
|
|
||||||
opacity *= PowF32(lin, fade_curve);
|
|
||||||
String text = log.msg;
|
|
||||||
if (!minimized)
|
|
||||||
{
|
|
||||||
DateTime datetime = log.datetime;
|
|
||||||
text = StringF(
|
|
||||||
scratch.arena,
|
|
||||||
"[%F:%F:%F.%F] %F",
|
|
||||||
FmtUintZ(datetime.hour, 2),
|
|
||||||
FmtUintZ(datetime.minute, 2),
|
|
||||||
FmtUintZ(datetime.second, 2),
|
|
||||||
FmtUintZ(datetime.milliseconds, 3),
|
|
||||||
FmtString(text)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
UI_PushCP(0);
|
|
||||||
{
|
|
||||||
UI_Push(Tint, Alpha32F(0xFFFFFFFF, opacity));
|
|
||||||
{
|
|
||||||
u32 color = colors[log.level][log.level_id % 2];
|
|
||||||
UI_Push(BackgroundColor, color);
|
|
||||||
UI_Push(Width, UI_FILL(1, 0));
|
|
||||||
UI_Push(Height, UI_FNT(1.5, 1));
|
|
||||||
UI_Push(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1));
|
|
||||||
UI_Push(Rounding, UI_RPIX(0));
|
|
||||||
UI_Push(Border, 1);
|
|
||||||
UI_Push(ChildAlignment, UI_Alignment_Left);
|
|
||||||
UI_PushCP(UI_BuildRow(UI_NilKey));
|
|
||||||
{
|
|
||||||
// UI_SetNext(Height, UI_PIX(100, 0));
|
|
||||||
UI_BuildSpacer(UI_PIX(10, 0));
|
|
||||||
UI_Push(BackgroundColor, 0);
|
|
||||||
UI_Push(Border, 0);
|
|
||||||
UI_Push(Text, text);
|
|
||||||
UI_Push(Width, UI_FILL(1, 0));
|
|
||||||
UI_Push(Height, UI_FIT(1));
|
|
||||||
UI_Push(Flags, UI_BoxFlag_DrawText);
|
|
||||||
UI_BuildBox(UI_NilKey);
|
|
||||||
}
|
|
||||||
UI_PopCP();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UI_PopCP();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UI_PopCP();
|
|
||||||
}
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
return console_box;
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
////////////////////////////////////////////////////////////
|
|
||||||
//~ Console
|
|
||||||
|
|
||||||
UI_Box *PP_BuildDebugConsole(b32 minimized);
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Serialize
|
//~ Serialize
|
||||||
|
|
||||||
String SETTINGS_StringFromWindowSettings(Arena *arena, const P_WindowSettings *settings)
|
String SETTINGS_StringFromWindowSettings(Arena *arena, const PLT_WindowSettings *settings)
|
||||||
{
|
{
|
||||||
String minimized = settings->flags & P_WindowSettingsFlag_Minimized ? Lit("true") : Lit("false");
|
String minimized = settings->flags & PLT_WindowSettingsFlag_Minimized ? Lit("true") : Lit("false");
|
||||||
String maximized = settings->flags & P_WindowSettingsFlag_Maximized ? Lit("true") : Lit("false");
|
String maximized = settings->flags & PLT_WindowSettingsFlag_Maximized ? Lit("true") : Lit("false");
|
||||||
String fullscreen = settings->flags & P_WindowSettingsFlag_Fullscreen ? Lit("true") : Lit("false");
|
String fullscreen = settings->flags & PLT_WindowSettingsFlag_Fullscreen ? Lit("true") : Lit("false");
|
||||||
i32 x = settings->floating_x;
|
i32 x = settings->floating_x;
|
||||||
i32 y = settings->floating_y;
|
i32 y = settings->floating_y;
|
||||||
i32 width = settings->floating_width;
|
i32 width = settings->floating_width;
|
||||||
@ -43,14 +43,14 @@ String SETTINGS_StringFromWindowSettings(Arena *arena, const P_WindowSettings *s
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Deserialize
|
//~ Deserialize
|
||||||
|
|
||||||
P_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out)
|
PLT_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratch(arena);
|
TempArena scratch = BeginScratch(arena);
|
||||||
|
|
||||||
String error = ZI;
|
String error = ZI;
|
||||||
JSON_Error json_error = ZI;
|
JSON_Error json_error = ZI;
|
||||||
|
|
||||||
P_WindowSettings *settings = PushStruct(arena, P_WindowSettings);
|
PLT_WindowSettings *settings = PushStruct(arena, PLT_WindowSettings);
|
||||||
JSON_Result parse_result = JSON_BlobFromString(scratch.arena, src);
|
JSON_Result parse_result = JSON_BlobFromString(scratch.arena, src);
|
||||||
|
|
||||||
if (parse_result.errors.count > 0)
|
if (parse_result.errors.count > 0)
|
||||||
@ -92,7 +92,7 @@ P_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, St
|
|||||||
}
|
}
|
||||||
if (child->value.boolean)
|
if (child->value.boolean)
|
||||||
{
|
{
|
||||||
settings->flags |= P_WindowSettingsFlag_Maximized;
|
settings->flags |= PLT_WindowSettingsFlag_Maximized;
|
||||||
}
|
}
|
||||||
found_maximized = 1;
|
found_maximized = 1;
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ P_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, St
|
|||||||
}
|
}
|
||||||
if (child->value.boolean)
|
if (child->value.boolean)
|
||||||
{
|
{
|
||||||
settings->flags |= P_WindowSettingsFlag_Fullscreen;
|
settings->flags |= PLT_WindowSettingsFlag_Fullscreen;
|
||||||
}
|
}
|
||||||
found_fullscreen = 1;
|
found_fullscreen = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
String SETTINGS_StringFromWindowSettings(Arena *arena, const P_WindowSettings *settings);
|
String SETTINGS_StringFromWindowSettings(Arena *arena, const PLT_WindowSettings *settings);
|
||||||
P_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out);
|
PLT_WindowSettings *SETTINGS_WindowSettingsFromString(Arena *arena, String src, String *error_out);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user