4coder/test_data/lots_of_files/handmade_platform.h

609 lines
15 KiB
C

#if !defined(HANDMADE_PLATFORM_H)
/* ========================================================================
$File: $
$Date: $
$Revision: $
$Creator: Casey Muratori $
$Notice: (C) Copyright 2014 by Molly Rocket, Inc. All Rights Reserved. $
======================================================================== */
// TODO(casey): Have the meta-parser ignore its own #define
#define introspect(params)
#define counted_pointer(params)
#include "handmade_config.h"
/*
NOTE(casey):
HANDMADE_INTERNAL:
0 - Build for public release
1 - Build for developer only
HANDMADE_SLOW:
0 - Not slow code allowed!
1 - Slow code welcome.
*/
#ifdef __cplusplus
extern "C" {
#endif
//
// NOTE(casey): Compilers
//
#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_LLVM)
#define COMPILER_LLVM 0
#endif
#if !COMPILER_MSVC && !COMPILER_LLVM
#if _MSC_VER
#undef COMPILER_MSVC
#define COMPILER_MSVC 1
#else
// TODO(casey): Moar compilerz!!!
#undef COMPILER_LLVM
#define COMPILER_LLVM 1
#endif
#endif
#if COMPILER_MSVC
#include <intrin.h>
#elif COMPILER_LLVM
#include <x86intrin.h>
#else
#error SEE/NEON optimizations are not available for this compiler yet!!!!
#endif
//
// NOTE(casey): Types
//
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <float.h>
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef intptr_t intptr;
typedef uintptr_t uintptr;
typedef size_t memory_index;
typedef float real32;
typedef double real64;
typedef int8 s8;
typedef int8 s08;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;
typedef uint8 u8;
typedef uint8 u08;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;
typedef real32 r32;
typedef real64 r64;
#pragma pack(push, 1)
struct bitmap_id
{
u32 Value;
};
struct sound_id
{
u32 Value;
};
struct font_id
{
u32 Value;
};
#pragma pack(pop)
union v2
{
struct
{
real32 x, y;
};
struct
{
real32 u, v;
};
real32 E[2];
};
union v3
{
struct
{
real32 x, y, z;
};
struct
{
real32 u, v, w;
};
struct
{
real32 r, g, b;
};
struct
{
v2 xy;
real32 Ignored0_;
};
struct
{
real32 Ignored1_;
v2 yz;
};
struct
{
v2 uv;
real32 Ignored2_;
};
struct
{
real32 Ignored3_;
v2 vw;
};
real32 E[3];
};
union v4
{
struct
{
union
{
v3 xyz;
struct
{
real32 x, y, z;
};
};
real32 w;
};
struct
{
union
{
v3 rgb;
struct
{
real32 r, g, b;
};
};
real32 a;
};
struct
{
v2 xy;
real32 Ignored0_;
real32 Ignored1_;
};
struct
{
real32 Ignored2_;
v2 yz;
real32 Ignored3_;
};
struct
{
real32 Ignored4_;
real32 Ignored5_;
v2 zw;
};
real32 E[4];
};
introspect(category:"math") struct rectangle2
{
v2 Min;
v2 Max;
};
introspect(category:"math") struct rectangle3
{
v3 Min;
v3 Max;
};
#define Real32Maximum FLT_MAX
#if !defined(internal)
#define internal static
#endif
#define local_persist static
#define global_variable static
#define Pi32 3.14159265359f
#define Tau32 6.28318530717958647692f
#if HANDMADE_SLOW
// TODO(casey): Complete assertion macro - don't worry everyone!
#define Assert(Expression) if(!(Expression)) {*(int *)0 = 0;}
#else
#define Assert(Expression)
#endif
#define InvalidCodePath Assert(!"InvalidCodePath")
#define InvalidDefaultCase default: {InvalidCodePath;} break
#define Kilobytes(Value) ((Value)*1024LL)
#define Megabytes(Value) (Kilobytes(Value)*1024LL)
#define Gigabytes(Value) (Megabytes(Value)*1024LL)
#define Terabytes(Value) (Gigabytes(Value)*1024LL)
#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))
// TODO(casey): swap, min, max ... macros???
#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)
inline uint32
SafeTruncateUInt64(uint64 Value)
{
// TODO(casey): Defines for maximum values
Assert(Value <= 0xFFFFFFFF);
uint32 Result = (uint32)Value;
return(Result);
}
/*
NOTE(casey): Services that the platform layer provides to the game
*/
#if HANDMADE_INTERNAL
/* IMPORTANT(casey):
These are NOT for doing anything in the shipping game - they are
blocking and the write doesn't protect against lost data!
*/
typedef struct debug_read_file_result
{
uint32 ContentsSize;
void *Contents;
} debug_read_file_result;
typedef struct debug_executing_process
{
u64 OSHandle;
} debug_executing_process;
typedef struct debug_process_state
{
b32 StartedSuccessfully;
b32 IsRunning;
s32 ReturnCode;
} debug_process_state;
#define DEBUG_PLATFORM_FREE_FILE_MEMORY(name) void name(void *Memory)
typedef DEBUG_PLATFORM_FREE_FILE_MEMORY(debug_platform_free_file_memory);
#define DEBUG_PLATFORM_READ_ENTIRE_FILE(name) debug_read_file_result name(char *Filename)
typedef DEBUG_PLATFORM_READ_ENTIRE_FILE(debug_platform_read_entire_file);
#define DEBUG_PLATFORM_WRITE_ENTIRE_FILE(name) bool32 name(char *Filename, uint32 MemorySize, void *Memory)
typedef DEBUG_PLATFORM_WRITE_ENTIRE_FILE(debug_platform_write_entire_file);
#define DEBUG_PLATFORM_EXECUTE_SYSTEM_COMMAND(name) debug_executing_process name(char *Path, char *Command, char *CommandLine)
typedef DEBUG_PLATFORM_EXECUTE_SYSTEM_COMMAND(debug_platform_execute_system_command);
// TODO(casey): Do we want a formal release mechanism here?
#define DEBUG_PLATFORM_GET_PROCESS_STATE(name) debug_process_state name(debug_executing_process Process)
typedef DEBUG_PLATFORM_GET_PROCESS_STATE(debug_platform_get_process_state);
// TODO(casey): Actually start using this???
extern struct game_memory *DebugGlobalMemory;
#endif
/*
NOTE(casey): Services that the game provides to the platform layer.
(this may expand in the future - sound on separate thread, etc.)
*/
// FOUR THINGS - timing, controller/keyboard input, bitmap buffer to use, sound buffer to use
// TODO(casey): In the future, rendering _specifically_ will become a three-tiered abstraction!!!
#define BITMAP_BYTES_PER_PIXEL 4
typedef struct game_offscreen_buffer
{
// NOTE(casey): Pixels are always 32-bits wide, Memory Order BB GG RR XX
void *Memory;
int Width;
int Height;
int Pitch;
} game_offscreen_buffer;
typedef struct game_sound_output_buffer
{
int SamplesPerSecond;
int SampleCount;
// IMPORTANT(casey): Samples must be padded to a multiple of 4 samples!
int16 *Samples;
} game_sound_output_buffer;
typedef struct game_button_state
{
int HalfTransitionCount;
bool32 EndedDown;
} game_button_state;
typedef struct game_controller_input
{
bool32 IsConnected;
bool32 IsAnalog;
real32 StickAverageX;
real32 StickAverageY;
union
{
game_button_state Buttons[12];
struct
{
game_button_state MoveUp;
game_button_state MoveDown;
game_button_state MoveLeft;
game_button_state MoveRight;
game_button_state ActionUp;
game_button_state ActionDown;
game_button_state ActionLeft;
game_button_state ActionRight;
game_button_state LeftShoulder;
game_button_state RightShoulder;
game_button_state Back;
game_button_state Start;
// NOTE(casey): All buttons must be added above this line
game_button_state Terminator;
};
};
} game_controller_input;
enum game_input_mouse_button
{
PlatformMouseButton_Left,
PlatformMouseButton_Middle,
PlatformMouseButton_Right,
PlatformMouseButton_Extended0,
PlatformMouseButton_Extended1,
PlatformMouseButton_Count,
};
typedef struct game_input
{
r32 dtForFrame;
game_controller_input Controllers[5];
// NOTE(casey): For debugging only
game_button_state MouseButtons[PlatformMouseButton_Count];
r32 MouseX, MouseY, MouseZ;
b32 ShiftDown, AltDown, ControlDown;
} game_input;
inline game_controller_input *GetController(game_input *Input, int unsigned ControllerIndex)
{
Assert(ControllerIndex < ArrayCount(Input->Controllers));
game_controller_input *Result = &Input->Controllers[ControllerIndex];
return(Result);
}
inline b32 WasPressed(game_button_state State)
{
b32 Result = ((State.HalfTransitionCount > 1) ||
((State.HalfTransitionCount == 1) && (State.EndedDown)));
return(Result);
}
typedef struct platform_file_handle
{
b32 NoErrors;
void *Platform;
} platform_file_handle;
typedef struct platform_file_group
{
u32 FileCount;
void *Platform;
} platform_file_group;
typedef enum platform_file_type
{
PlatformFileType_AssetFile,
PlatformFileType_SavedGameFile,
PlatformFileType_Count,
} platform_file_type;
#define PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(name) platform_file_group name(platform_file_type Type)
typedef PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(platform_get_all_files_of_type_begin);
#define PLATFORM_GET_ALL_FILE_OF_TYPE_END(name) void name(platform_file_group *FileGroup)
typedef PLATFORM_GET_ALL_FILE_OF_TYPE_END(platform_get_all_files_of_type_end);
#define PLATFORM_OPEN_FILE(name) platform_file_handle name(platform_file_group *FileGroup)
typedef PLATFORM_OPEN_FILE(platform_open_next_file);
#define PLATFORM_READ_DATA_FROM_FILE(name) void name(platform_file_handle *Source, u64 Offset, u64 Size, void *Dest)
typedef PLATFORM_READ_DATA_FROM_FILE(platform_read_data_from_file);
#define PLATFORM_FILE_ERROR(name) void name(platform_file_handle *Handle, char *Message)
typedef PLATFORM_FILE_ERROR(platform_file_error);
#define PlatformNoFileErrors(Handle) ((Handle)->NoErrors)
struct platform_work_queue;
#define PLATFORM_WORK_QUEUE_CALLBACK(name) void name(platform_work_queue *Queue, void *Data)
typedef PLATFORM_WORK_QUEUE_CALLBACK(platform_work_queue_callback);
#define PLATFORM_ALLOCATE_MEMORY(name) void *name(memory_index Size)
typedef PLATFORM_ALLOCATE_MEMORY(platform_allocate_memory);
#define PLATFORM_DEALLOCATE_MEMORY(name) void name(void *Memory)
typedef PLATFORM_DEALLOCATE_MEMORY(platform_deallocate_memory);
typedef void platform_add_entry(platform_work_queue *Queue, platform_work_queue_callback *Callback, void *Data);
typedef void platform_complete_all_work(platform_work_queue *Queue);
typedef struct platform_api
{
platform_add_entry *AddEntry;
platform_complete_all_work *CompleteAllWork;
platform_get_all_files_of_type_begin *GetAllFilesOfTypeBegin;
platform_get_all_files_of_type_end *GetAllFilesOfTypeEnd;
platform_open_next_file *OpenNextFile;
platform_read_data_from_file *ReadDataFromFile;
platform_file_error *FileError;
platform_allocate_memory *AllocateMemory;
platform_deallocate_memory *DeallocateMemory;
#if HANDMADE_INTERNAL
debug_platform_free_file_memory *DEBUGFreeFileMemory;
debug_platform_read_entire_file *DEBUGReadEntireFile;
debug_platform_write_entire_file *DEBUGWriteEntireFile;
debug_platform_execute_system_command *DEBUGExecuteSystemCommand;
debug_platform_get_process_state *DEBUGGetProcessState;
#endif debug_table *
} platform_api;
typedef struct game_memory
{
uint64 PermanentStorageSize;
void *PermanentStorage; // NOTE(casey): REQUIRED to be cleared to zero at startup
uint64 TransientStorageSize;
void *TransientStorage; // NOTE(casey): REQUIRED to be cleared to zero at startup
uint64 DebugStorageSize;
void *DebugStorage; // NOTE(casey): REQUIRED to be cleared to zero at startup
platform_work_queue *HighPriorityQueue;
platform_work_queue *LowPriorityQueue;
b32 ExecutableReloaded;
platform_api PlatformAPI;
} game_memory;
#define GAME_UPDATE_AND_RENDER(name) void name(game_memory *Memory, game_input *Input, game_offscreen_buffer *Buffer)
typedef GAME_UPDATE_AND_RENDER(game_update_and_render);
// NOTE(casey): At the moment, this has to be a very fast function, it cannot be
// more than a millisecond or so.
// TODO(casey): Reduce the pressure on this function's performance by measuring it
// or asking about it, etc.
#define GAME_GET_SOUND_SAMPLES(name) void name(game_memory *Memory, game_sound_output_buffer *SoundBuffer)
typedef GAME_GET_SOUND_SAMPLES(game_get_sound_samples);
#if COMPILER_MSVC
#define CompletePreviousReadsBeforeFutureReads _ReadBarrier()
#define CompletePreviousWritesBeforeFutureWrites _WriteBarrier()
inline uint32 AtomicCompareExchangeUInt32(uint32 volatile *Value, uint32 New, uint32 Expected)
{
uint32 Result = _InterlockedCompareExchange((long volatile *)Value, New, Expected);
return(Result);
}
inline u64 AtomicExchangeU64(u64 volatile *Value, u64 New)
{
u64 Result = _InterlockedExchange64((__int64 volatile *)Value, New);
return(Result);
}
inline u64 AtomicAddU64(u64 volatile *Value, u64 Addend)
{
// NOTE(casey): Returns the original value _prior_ to adding
u64 Result = _InterlockedExchangeAdd64((__int64 volatile *)Value, Addend);
return(Result);
}
inline u32 GetThreadID(void)
{
u8 *ThreadLocalStorage = (u8 *)__readgsqword(0x30);
u32 ThreadID = *(u32 *)(ThreadLocalStorage + 0x48);
return(ThreadID);
}
#elif COMPILER_LLVM
// TODO(casey): Does LLVM have real read-specific barriers yet?
#define CompletePreviousReadsBeforeFutureReads asm volatile("" ::: "memory")
#define CompletePreviousWritesBeforeFutureWrites asm volatile("" ::: "memory")
inline uint32 AtomicCompareExchangeUInt32(uint32 volatile *Value, uint32 New, uint32 Expected)
{
uint32 Result = __sync_val_compare_and_swap(Value, Expected, New);
return(Result);
}
inline u64 AtomicExchangeU64(u64 volatile *Value, u64 New)
{
u64 Result = __sync_lock_test_and_set(Value, New);
return(Result);
}
inline u64 AtomicAddU64(u64 volatile *Value, u64 Addend)
{
// NOTE(casey): Returns the original value _prior_ to adding
u64 Result = __sync_fetch_and_add(Value, Addend);
return(Result);
}
inline u32 GetThreadID(void)
{
u32 ThreadID;
#if defined(__APPLE__) && defined(__x86_64__)
asm("mov %%gs:0x00,%0" : "=r"(ThreadID));
#elif defined(__i386__)
asm("mov %%gs:0x08,%0" : "=r"(ThreadID));
#elif defined(__x86_64__)
asm("mov %%fs:0x10,%0" : "=r"(ThreadID));
#else
#error Unsupported architecture
#endif
return(ThreadID);
}
#else
// TODO(casey): Other compilers/platforms??
#endif
#include "handmade_debug_interface.h"
#define HANDMADE_PLATFORM_H
#endif