diff options
-rwxr-xr-x | build/handmade.so | bin | 0 -> 64192 bytes | |||
-rwxr-xr-x | build/linux_handmade | bin | 0 -> 94120 bytes | |||
-rwxr-xr-x | code/build.sh | 15 | ||||
-rw-r--r-- | code/handmade.cpp | 523 | ||||
-rw-r--r-- | code/handmade.h | 57 | ||||
-rw-r--r-- | code/handmade_graph.cpp | 1 | ||||
-rw-r--r-- | code/handmade_intrinsics.h | 103 | ||||
-rw-r--r-- | code/handmade_math.h | 134 | ||||
-rw-r--r-- | code/handmade_platform.h | 243 | ||||
-rw-r--r-- | code/handmade_random.h | 523 | ||||
-rw-r--r-- | code/linux_handmade.cpp | 1236 | ||||
-rw-r--r-- | code/linux_handmade.h | 91 | ||||
-rwxr-xr-x | data/structured_art.bmp | bin | 0 -> 9670 bytes | |||
-rw-r--r-- | project.4coder | 41 |
14 files changed, 2967 insertions, 0 deletions
diff --git a/build/handmade.so b/build/handmade.so Binary files differnew file mode 100755 index 0000000..78623f9 --- /dev/null +++ b/build/handmade.so diff --git a/build/linux_handmade b/build/linux_handmade Binary files differnew file mode 100755 index 0000000..f251388 --- /dev/null +++ b/build/linux_handmade diff --git a/code/build.sh b/code/build.sh new file mode 100755 index 0000000..9be3b65 --- /dev/null +++ b/code/build.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +ThisDir="$(dirname "$(readlink -f "$0")")" +cd "$ThisDir" + +mkdir ../build > /dev/null 2>&1 + +CompilerFlags="-ggdb -DHANDMADE_INTERNAL -DHANDMADE_SLOW" +WarningFlags="-Wall -Wextra -Wno-unused-but-set-variable -Wno-unused-variable -Wno-write-strings -Wno-unused-parameter -Wno-unused-function" + +printf 'handmade.cpp\n' +g++ $CompilerFlags $WarningFlags -shared -o ../build/handmade.so handmade.cpp + +printf 'linux_handmade.cpp\n' +g++ $CompilerFlags $WarningFlags -o ../build/linux_handmade linux_handmade.cpp -lasound -lm -lX11 -lXfixes diff --git a/code/handmade.cpp b/code/handmade.cpp new file mode 100644 index 0000000..efd16b0 --- /dev/null +++ b/code/handmade.cpp @@ -0,0 +1,523 @@ +#include "handmade.h" +#include "handmade_random.h" +#include "handmade_graph.cpp" + +internal s16 +GetSineSound(u32 SampleRate) +{ + s16 Result = 0; + + s16 ToneVolume = (1 << 15) * 0.01; + r32 ToneHz = 440; + s32 WavePeriod = 0; + local_persist r32 tSine = 0; + WavePeriod = SampleRate/ToneHz; + r32 SineValue = Sin(tSine); + tSine += 2.0f*Pi32*1.0f/(r32)WavePeriod; + if(tSine > 2*Pi32) + { + tSine -= 2*Pi32; + } + + Result = (s16)(SineValue * ToneVolume); + + return Result; +} + +internal void +GameOutputSound(game_state *GameState, game_sound_output_buffer *SoundBuffer) +{ + s16 SampleValue = 0; + + s16 *SampleOut = SoundBuffer->Samples; + for(int SampleIndex = 0; + SampleIndex < SoundBuffer->SampleCount; + ++SampleIndex) + { + +#if 0 + SampleValue = GetSineSound(SoundBuffer->SamplesPerSecond); +#endif + + *SampleOut++ = SampleValue; + *SampleOut++ = SampleValue; + } +} + +internal void +RenderWeirdGradient(game_offscreen_buffer *Buffer, int BlueOffset, int GreenOffset) +{ + // TODO(casey): Let's see what the optimizer does + + u8 *Row = (u8 *)Buffer->Memory; + for(int Y = 0; + Y < Buffer->Height; + ++Y) + { + u32 *Pixel = (u32 *)Row; + for(int X = 0; + X < Buffer->Width; + ++X) + { + u8 Blue = (u8)(X + BlueOffset); + u8 Green = (u8)(Y + GreenOffset); + + *Pixel++ = (Green | Blue); + } + + Row += Buffer->Pitch; + } +} + +internal void +DrawRectangle(game_offscreen_buffer *Buffer, + v2 vMin, v2 vMax, + r32 R, r32 G, r32 B) +{ + int MinX = RoundReal32ToInt32(vMin.X); + int MaxX = RoundReal32ToInt32(vMax.X); + int MinY = RoundReal32ToInt32(vMin.Y); + int MaxY = RoundReal32ToInt32(vMax.Y); + + if(MinX < 0) + { + MinX = 0; + } + + if(MinY < 0) + { + MinY = 0; + } + + if(MaxX > Buffer->Width) + { + MaxX = Buffer->Width; + } + + if(MaxY > Buffer->Height) + { + MaxY = Buffer->Height; + } + + u32 Color = + (RoundReal32ToUInt32(R * 255.0f) << 2*8) | + (RoundReal32ToUInt32(G * 255.0f) << 1*8) | + (RoundReal32ToUInt32(B * 255.0f) << 0*8); + + u8 *Row = ((u8 *)(Buffer->Memory) + + MinX*Buffer->BytesPerPixel + + MinY*Buffer->Pitch); + + for(int Y = MinY; + Y < MaxY; + Y++) + { + u32 *Pixel = (u32 *)Row; + + for(int X = MinX; + X < MaxX; + X++) + { + *Pixel++ = Color; + } + + Row += Buffer->Pitch; + } + +} + +internal void +DrawBitmap(game_offscreen_buffer *Buffer, loaded_bitmap Bitmap, + r32 RealX, r32 RealY, + s32 AlignX = 0, s32 AlignY = 0) +{ + RealX -= AlignX; + RealY -= AlignY; + + s32 MinX = RoundReal32ToInt32(RealX); + s32 MinY = RoundReal32ToInt32(RealY); + s32 MaxX = RoundReal32ToInt32(RealX + (r32)Bitmap.Width); + s32 MaxY = RoundReal32ToInt32(RealY + (r32)Bitmap.Height); + + s32 SourceOffsetX = 0; + if(MinX < 0) + { + SourceOffsetX = -MinX; + MinX = 0; + } + + s32 SourceOffsetY = 0; + if(MinY < 0) + { + SourceOffsetY = -MinY; + MinY = 0; + } + + if(MaxX > Buffer->Width) + { + MaxX = Buffer->Width; + } + + if(MaxY > Buffer->Height) + { + MaxY = Buffer->Height; + } + + // TODO(casey): Source row needs to be changed based on clipping. + + u32 *SourceRow = ((u32 *)Bitmap.Pixels + Bitmap.Width*(Bitmap.Height - 1)); + SourceRow += -(Bitmap.Width*SourceOffsetY) + SourceOffsetX; + u8 *DestRow = ((u8 *)Buffer->Memory + + MinX*Buffer->BytesPerPixel + + MinY*Buffer->Pitch); + for(s32 Y = MinY; + Y < MaxY; + Y++) + { + u32 *Dest = (u32 *)DestRow; + u32 *Source = (u32 *)SourceRow; + for(s32 X = MinX; + X < MaxX; + X++) + { + + // simple alpha rendering + r32 A = (r32)((*Source >> 24) & 0xFF)/255.0f; + r32 SR = (r32)((*Source >> 16) & 0xFF); + r32 SG = (r32)((*Source >> 8) & 0xFF); + r32 SB = (r32)((*Source >> 0) & 0xFF); + + r32 DR = (r32)((*Dest >> 16) & 0xFF); + r32 DG = (r32)((*Dest >> 8) & 0xFF); + r32 DB = (r32)((*Dest >> 0) & 0xFF); + + r32 R = ((1-A)*DR + A*SR); + r32 G = ((1-A)*DG + A*SG); + r32 B = ((1-A)*DB + A*SB); + + u32 C = (((u32)(R + 0.5f) << 16) | + ((u32)(G + 0.5f) << 8) | + ((u32)(B + 0.5f) << 0)); + *Dest = C; + + Dest++; + Source++; + } + + DestRow += Buffer->Pitch; + SourceRow -= Bitmap.Width; + } + +} + +internal inline +void MemCpy(char *Dest, char *Source, size_t Count) +{ + while(Count--) *Dest++ = *Source++; +} + +#pragma pack(push, 1) +struct bitmap_header +{ + u16 FileType; + u32 FileSize; + u16 Reserved1; + u16 Reserved2; + u32 BitmapOffset; + u32 Size; + s32 Width; + s32 Height; + u16 Planes; + u16 BitsPerPixel; + u32 Compression; + u32 PicSize; + u32 HorizontalResolution; + u32 VerticalResolution; + u32 Colors; + u32 ColorsImportant; + + u32 RedMask; + u32 GreenMask; + u32 BlueMask; + u32 AlphaMask; +}; +#pragma pack(pop) + +internal loaded_bitmap +DEBUGLoadBMP(thread_context *Thread, debug_platform_read_entire_file *DEBUGPlatformReadEntireFile, + char *FileName) +{ + loaded_bitmap Result = {}; + debug_read_file_result File = DEBUGPlatformReadEntireFile(Thread, FileName); + + if(File.ContentsSize) + { + bitmap_header *Header = (bitmap_header *)File.Contents; + + u32 *Pixels = (u32 *)((u8 *)File.Contents + Header->BitmapOffset); + + // NOTE(casey): If you are using this generically for some reason, please remember that + // BMP files CAN GO IN EITHER DIRECTION and the height will be negative for top-down. + // (Also, there can be compression, etc..., etc...) + + // NOTE(casey): Byte order in memory is determined by the header itself, so we have to read + // out the masks and convert the pixels ourselves. + s32 RedMask = Header->RedMask; + s32 BlueMask = Header->BlueMask; + s32 GreenMask = Header->GreenMask; + s32 AlphaMask = ~(RedMask | GreenMask | BlueMask); + + bit_scan_result RedShift = FindLeastSignificantSetBit(RedMask); + bit_scan_result GreenShift = FindLeastSignificantSetBit(GreenMask); + bit_scan_result BlueShift = FindLeastSignificantSetBit(BlueMask); + bit_scan_result AlphaShift = FindLeastSignificantSetBit(AlphaMask); + Assert(AlphaShift.Found); + Assert(RedShift.Found); + Assert(GreenShift.Found); + Assert(BlueShift.Found); + Assert(Header->Compression == 3); + + u32 *SourceDest = Pixels; + for(s32 Y = 0; + Y < Header->Height; + Y++) + { + for(s32 X = 0; + X < Header->Width; + X++) + { + u32 C = *SourceDest; + u32 ConvertedColor = ((((C >> AlphaShift.Index) & 0xFF) << 24) | + (((C >> RedShift.Index) & 0xFF) << 16) | + (((C >> GreenShift.Index) & 0xFF) << 8) | + (((C >> BlueShift.Index) & 0xFF) << 0)); + *SourceDest++ = ConvertedColor; + } + } + + Result.Pixels = Pixels; + Result.Width = Header->Width; + Result.Height = Header->Height; + } + + return Result; +} + +internal void +DrawVerticalAxis(game_offscreen_buffer *Buffer, + u32 ViewHeight, u32 PointsToPixels, v2 Pad, v2 PointPad, v2 PointCenterOffset, + r32 PointX) +{ + PointX += PointCenterOffset.X; + + for(u32 Y = 0; + Y < ViewHeight; + Y++) + { + u32 X = PointX*PointsToPixels + PointPad.X; + + v2 LineMin = {(r32)X, (r32)Y + Pad.Y}; + v2 LineMax = LineMin + v2{1, 1}; + + DrawRectangle(Buffer, + LineMin, LineMax, + 0.0f, 0.0f, 1.0f); + + } +} + +internal void +DrawHorizontalAxis(game_offscreen_buffer *Buffer, + u32 ViewWidth, u32 PointsToPixels, v2 Pad, v2 PointPad, v2 PointCenterOffset, + r32 PointY) +{ + PointY += PointCenterOffset.Y; + + for(u32 X = 0; + X < ViewWidth; + X++) + { + u32 Y = PointY*PointsToPixels + PointPad.Y; + + v2 LineMin = {(r32)X + Pad.X, (r32)Y}; + v2 LineMax = LineMin + v2{1, 1}; + + DrawRectangle(Buffer, + LineMin, LineMax, + 1.0f, 1.0f, 0.0f); + } + +} + +internal void +DrawPoint(game_offscreen_buffer *Buffer, + v2 TopLeft, v2 BottomRight, + u32 PointsToPixels, v2 Pad, v2 PointPad, v2 PointCenterOffset, + v2 Point, v2 PointSize = {1, 1}) +{ + Point.Y *= -1; + Point += PointCenterOffset; + v2 PointMin = Point*PointsToPixels + PointPad; + v2 PointMax = PointMin + v2{1, 1}; + PointMin += -PointSize; + PointMax += PointSize; + + b32 IsOutOfView = ((PointMin.X < TopLeft.X) || + (PointMin.Y < TopLeft.Y) || + (PointMax.X > BottomRight.X) || + (PointMax.Y > BottomRight.Y)); + if(!IsOutOfView) + { + DrawRectangle(Buffer, PointMin, PointMax, + 1.0f, 0.0f, 1.0f); + } + +} + +extern "C" GAME_UPDATE_AND_RENDER(GameUpdateAndRender) +{ + Assert((&Input->Controllers[0].Terminator - &Input->Controllers[0].Buttons[0]) == + (ArrayCount(Input->Controllers[0].Buttons))); + Assert(sizeof(game_state) <= Memory->PermanentStorageSize); + + game_state *GameState = (game_state *)Memory->PermanentStorage; + if(!Memory->IsInitialized) + { + Memory->IsInitialized = true; + GameState->Slope = 1.0f; + GameState->Step = 0.5f; + } + + u32 PointsToPixels = 20; + v2 ViewSizePixels = V2((r32)(0.56f*Buffer->Width), + (r32)(1.00f*Buffer->Height)); + // NOTE(luca): This is truncated so that when it is scaled back to pixels we can use the "lost" pixels for centering. On top of that we make sure that it is an even number so both axises pass through {0, 0}. + + v2 ViewSizePoints = V2(((r32)(((u32)ViewSizePixels.X / PointsToPixels) & (0xFFFFFFFF - 1))), + ((r32)(((u32)ViewSizePixels.Y / PointsToPixels) & (0xFFFFFFFF - 1)))); + + v2 ScreenCenter = 0.5f*ViewSizePixels; + + // NOTE(luca): This value is used to interpret points as being centered. + v2 PointCenterOffset = 0.5f*ViewSizePoints; + + // NOTE(luca): Make it so that we can only draw in a restricted area, this is useful so we can change the scale in both dimensions. + + v2 BufferSize = {(r32)Buffer->Width, (r32)Buffer->Height}; + v2 Pad = (BufferSize - ViewSizePixels)/2.0f; + + // NOTE(luca): We need to add padding to center points in the restricted area + v2 PointPad = Pad + 0.5f*(ViewSizePixels - (r32)PointsToPixels*ViewSizePoints); + v2 TopLeft = Pad; + v2 BottomRight = Pad + ViewSizePixels; + + for(u32 ControllerIndex = 0; + ControllerIndex < ArrayCount(Input->Controllers); + ControllerIndex++) + { + game_controller_input *Controller = GetController(Input, ControllerIndex); + if(Controller->IsConnected) + { + + if(Controller->IsAnalog) + { + + } + else + { + + r32 SlopeStep = 2.0f*Input->dtForFrame; + if(Controller->MoveUp.EndedDown) + { + GameState->Slope += SlopeStep; + } + + if(Controller->MoveDown.EndedDown) + { + GameState->Slope -= SlopeStep; + } + + if(Controller->MoveRight.EndedDown) + { + GameState->Step -= 0.02f; + + } + + if(Controller->MoveLeft.EndedDown) + { + GameState->Step += 0.02f; + } + if(GameState->Step <= 0) + { + GameState->Step = 0.001; + } + + if(Controller->ActionUp.EndedDown) + { + GameState->Step = 0.5f; + GameState->Slope = 1.0f; + } + }; + } + } + + + //-Rendering + + DrawRectangle(Buffer, TopLeft, BottomRight, 0.1f, 0.1f, 0.1f); + DrawHorizontalAxis(Buffer, ViewSizePixels.X, PointsToPixels, Pad, PointPad, PointCenterOffset, 0); + DrawVerticalAxis(Buffer, ViewSizePixels.Y, PointsToPixels, Pad, PointPad, PointCenterOffset, 0); + + // X Points + for(r32 Col = 0; + Col <= ViewSizePoints.X; + Col++) + { + v2 LineMin = {Col, PointCenterOffset.Y - 0.5f}; + v2 LineMax = {Col, PointCenterOffset.Y + 0.5f}; + + DrawRectangle(Buffer, + PointPad + LineMin*PointsToPixels, + PointPad + LineMax*PointsToPixels + v2{1, 1}, + 1.0f, 1.0f, 1.0f); + } + + // Y Points + for(r32 Row = 0; + Row <= ViewSizePoints.Y; + Row++) + { + v2 LineMin = v2{PointCenterOffset.X - 0.5f, Row}; + v2 LineMax = v2{PointCenterOffset.X + 0.5f, Row}; + DrawRectangle(Buffer, + PointPad + LineMin*PointsToPixels , + PointPad + LineMax*PointsToPixels + v2{1, 1}, + 1.0f, 1.0f, 1.0f); + } + + + // Plot some points + + r32 B = 0.0f; + r32 Step = GameState->Step; + r32 Slope = GameState->Slope; + + for(r32 X = -(PointCenterOffset.X + 1); + X < (PointCenterOffset.X + 1); + X += Step) + { + r32 Y = X * Slope + B; + DrawPoint(Buffer, + TopLeft, BottomRight, + PointsToPixels, Pad, PointPad, PointCenterOffset, + V2(X, Y), {.5, .5}); + } + +} + + +extern "C" GAME_GET_SOUND_SAMPLES(GameGetSoundSamples) +{ + game_state *GameState = (game_state *)Memory->PermanentStorage; + GameOutputSound(GameState, SoundBuffer); +}
\ No newline at end of file diff --git a/code/handmade.h b/code/handmade.h new file mode 100644 index 0000000..b807644 --- /dev/null +++ b/code/handmade.h @@ -0,0 +1,57 @@ +#if !defined(HANDMADE_H) +/* ======================================================================== + $File: $ + $Date: $ + $Revision: $ + $Creator: Casey Muratori $ + $Notice: (C) Copyright 2014 by Molly Rocket, Inc. All Rights Reserved. $ + ======================================================================== */ + +#include "handmade_platform.h" +#include "handmade_math.h" + +struct memory_arena +{ + memory_index Size; + u8 *Base; + memory_index Used; +}; + +void +InitializeArena(memory_arena *Arena, memory_index Size, void *Base) +{ + Arena->Size = Size; + Arena->Base = (u8 *)Base; + Arena->Used = 0; +} + +#define PushStruct(Arena, type) ((type *)PushSize((Arena), (sizeof(type)))) +#define PushArray(Arena, Count, type) (type *)PushSize((Arena), (sizeof(type))*(Count)) +void * +PushSize(memory_arena *Arena, memory_index Size) +{ + Assert((Arena->Used + Size) < Arena->Size); + + void *Result = Arena->Base + Arena->Used; + Arena->Used += Size; + + return Result; +} + +#include "handmade_intrinsics.h" + +struct loaded_bitmap +{ + int Width; + int Height; + u32 *Pixels; +}; + +struct game_state +{ + r32 Slope; + r32 Step; +}; + +#define HANDMADE_H +#endif diff --git a/code/handmade_graph.cpp b/code/handmade_graph.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/code/handmade_graph.cpp @@ -0,0 +1 @@ + diff --git a/code/handmade_intrinsics.h b/code/handmade_intrinsics.h new file mode 100644 index 0000000..2a3a69e --- /dev/null +++ b/code/handmade_intrinsics.h @@ -0,0 +1,103 @@ +/* date = May 13th 2025 1:41 pm */ + +#ifndef HANDMADE_INTRINSICS_H +#define HANDMADE_INTRINSICS_H + +// +// TODO(casey): Remove math.h +// +#include <math.h> + +inline s32 +RoundReal32ToInt32(r32 Real32) +{ + s32 Result = (s32)(roundf(Real32)); + return Result; +} + +inline u32 +RoundReal32ToUInt32(r32 Real32) +{ + u32 Result = (u32)(roundf(Real32)); + return Result; +} + +inline u32 +TruncateReal32ToUInt32(r32 Real32) +{ + u32 Result = (u32)Real32; + return Result; +} + +inline s32 +TruncateReal32ToInt32(r32 Real32) +{ + s32 Result = (s32)Real32; + return Result; +} + +inline s32 +FloorReal32ToInt32(r32 Real32) +{ + s32 Result = (s32)floorf(Real32); + return Result; +} + +inline r32 +Sin(r32 Angle) +{ + r32 Result = sinf(Angle); + return Result; +} + +inline r32 +Cos(r32 Angle) +{ + r32 Result = cosf(Angle); + return Result; +} + +inline r32 +Atan2(r32 Y, r32 X) +{ + r32 Result = atan2f(Y, X); + return Result; +} + +struct bit_scan_result +{ + b32 Found; + u32 Index; +}; + +internal inline bit_scan_result +FindLeastSignificantSetBit(u32 Value) +{ + bit_scan_result Result = {}; + +#if 0 +#elif COMPILER_GNU + Result.Index = __builtin_ffs(Value); + if(Result.Index) + { + Result.Found = true; + Result.Index--; + } +#else + for(u32 Test = 0; + Test < 32; + Test++) + { + if(Value & (1 << Test)) + { + Result.Index = Test; + Result.Found = true; + break; + } + } +#endif + + return Result; +} + +#endif //HANDMADE_INTRINSICS_H diff --git a/code/handmade_math.h b/code/handmade_math.h new file mode 100644 index 0000000..98b2328 --- /dev/null +++ b/code/handmade_math.h @@ -0,0 +1,134 @@ +/* date = June 10th 2025 1:05 pm */ + +#ifndef HANDMADE_MATH_H +#define HANDMADE_MATH_H + + +union v2 +{ + struct + { + r32 X, Y; + }; + r32 E[2]; +}; + +inline v2 +V2(r32 X, r32 Y) +{ + v2 Result; + + Result.X = X; + Result.Y = Y; + + return(Result); +} + +inline v2 +operator-(v2 A) +{ + v2 Result; + + Result.X = -A.X; + Result.Y = -A.Y; + + return Result; +} + +inline v2 +operator+(v2 A, v2 B) +{ + v2 Result; + + Result.X = A.X + B.X; + Result.Y = A.Y + B.Y; + + return Result; +} + +inline v2 +operator+(v2 A, r32 B) +{ + v2 Result; + + Result.X = A.X + B; + Result.Y = A.Y + B; + + return Result; +} + +inline v2 +operator-(v2 A, v2 B) +{ + v2 Result; + + Result.X = A.X - B.X; + Result.Y = A.Y - B.Y; + + return Result; +} + +inline v2 +operator*(r32 A, v2 B) +{ + v2 Result; + + Result.X = A*B.X; + Result.Y = A*B.Y; + + return Result; +} + +inline v2 +operator*(v2 A, r32 B) +{ + return B*A; +} + +inline v2 +operator/(v2 A, r32 B) +{ + v2 Result; + + Result.X = A.X/B; + Result.Y = A.Y/B; + + return Result; +} + +inline v2 & +operator*=(v2 &A, r32 B) +{ + A = B * A; + return A; +} + +inline v2 & +operator+=(v2 &A, v2 B) +{ + A = A + B; + return A; +} + +inline +r32 Square(r32 A) +{ + r32 Result = A*A; + return Result; +} + +inline +r32 Inner(v2 A, v2 B) +{ + r32 Result = A.X*B.X + A.Y*B.Y; + return Result; +} + +inline +r32 LengthSq(v2 A) +{ + r32 Result = Inner(A, A); + return Result; +} + +#endif //HANDMADE_MATH_H diff --git a/code/handmade_platform.h b/code/handmade_platform.h new file mode 100644 index 0000000..8831767 --- /dev/null +++ b/code/handmade_platform.h @@ -0,0 +1,243 @@ +/* date = May 12th 2025 10:53 am */ + +#ifndef HANDMADE_PLATFORM_H +#define HANDMADE_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* + 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. + */ + +#include <stdint.h> +#include <stddef.h> + +#if !defined(COMPILER_MSVC) +#define COMPILER_MSVC 0 +#endif + +#if !defined(COMPILER_LLVM) +#define COMPILER_LLVM 0 +#endif + +#if !defined(COMPILER_GNU) +#define COMPILER_GNU 0 +#endif + +#if !COMPILER_MSVC && !COMPILER_LLVM && !COMPILER_GNU +#if _MSC_VER +#undef COMPILER_MSVC +#define COMPILER_MSVC 1 +#elif __GNUC__ +#undef COMPILER_GNU +#define COMPILER_GNU 1 +#else + // TODO(casey): More compilerz!!! +#endif +#endif + +#define internal static +#define local_persist static +#define global_variable static + +#define Pi32 3.14159265359f + +#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 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??? + + + typedef int8_t s8; + typedef int16_t s16; + typedef int32_t s32; + typedef int64_t s64; + typedef s32 b32; + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef size_t memory_index; + + typedef float r32; + typedef double r64; + + + typedef struct thread_context + { + int Placeholder; + } thread_context; + + /* + 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 + { + u32 ContentsSize; + void *Contents; + } debug_read_file_result; + +#define DEBUG_PLATFORM_FREE_FILE_MEMORY(name) void name(thread_context *Thread, void *Memory, u64 MemorySize) + typedef DEBUG_PLATFORM_FREE_FILE_MEMORY(debug_platform_free_file_memory); + +#define DEBUG_PLATFORM_READ_ENTIRE_FILE(name) debug_read_file_result name(thread_context *Thread, char *FileName) + typedef DEBUG_PLATFORM_READ_ENTIRE_FILE(debug_platform_read_entire_file); + +#define DEBUG_PLATFORM_WRITE_ENTIRE_FILE(name) b32 name(thread_context *Thread, char *FileName, u32 MemorySize, void *Memory) + typedef DEBUG_PLATFORM_WRITE_ENTIRE_FILE(debug_platform_write_entire_file); + +#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!!! + typedef struct game_offscreen_buffer + { + // NOTE(casey): Pixels are alwasy 32-bits wide, Memory Order BB GG RR XX + void *Memory; + int Width; + int Height; + int Pitch; + int BytesPerPixel; + } game_offscreen_buffer; + + typedef struct game_sound_output_buffer + { + int SamplesPerSecond; + int SampleCount; + s16 *Samples; + } game_sound_output_buffer; + + typedef struct game_button_state + { + int HalfTransitionCount; + b32 EndedDown; + } game_button_state; + + typedef struct game_controller_input + { + b32 IsConnected; + b32 IsAnalog; + r32 StickAverageX; + r32 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; + + typedef struct game_input + { + game_button_state MouseButtons[5]; + s32 MouseX, MouseY, MouseZ; + + r32 dtForFrame; + + game_controller_input Controllers[5]; + } game_input; + + typedef struct game_memory + { + b32 IsInitialized; + + memory_index PermanentStorageSize; + void *PermanentStorage; // NOTE(casey): REQUIRED to be cleared to zero at startup + + memory_index TransientStorageSize; + void *TransientStorage; // NOTE(casey): REQUIRED to be cleared to zero at startup + +#if HANDMADE_INTERNAL + debug_platform_free_file_memory *DEBUGPlatformFreeFileMemory; + debug_platform_read_entire_file *DEBUGPlatformReadEntireFile; + debug_platform_write_entire_file *DEBUGPlatformWriteEntireFile; +#endif + } game_memory; + +#define GAME_UPDATE_AND_RENDER(name) void name(thread_context *Thread, 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(thread_context *Thread, game_memory *Memory, game_sound_output_buffer *SoundBuffer) + typedef GAME_GET_SOUND_SAMPLES(game_get_sound_samples); + + inline u32 + SafeTruncateUInt64(u64 Value) + { + // TODO(casey): Defines for maximum values + Assert(Value <= 0xFFFFFFFF); + u32 Result = (u32)Value; + return(Result); + } + + 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); + } + +#endif //HANDMADE_PLATFORM_H + +#ifdef __cplusplus +} +#endif diff --git a/code/handmade_random.h b/code/handmade_random.h new file mode 100644 index 0000000..62c0296 --- /dev/null +++ b/code/handmade_random.h @@ -0,0 +1,523 @@ +/* date = May 25th 2025 3:52 pm */ + +#ifndef HANDMADE_RANDOM_H +#define HANDMADE_RANDOM_H + +// TODO(casey): Random number generator +global_variable u32 RandomNumberTable[] = +{ + 0x40b08f4, 0x250d26d, 0x010b25a, 0x0e2419d, 0x57cbef9, 0x295bc4c, 0x1c48458, 0x50c39bd, + 0x1a1949a, 0x59c49ec, 0x3c57981, 0x48462f9, 0x257a42d, 0x5a471eb, 0x54bf6d4, 0x018afe4, + 0x3ca046b, 0x27262d4, 0x04b9810, 0x09e11de, 0x40db785, 0x5c7407b, 0x493c53c, 0x48226cc, + 0x4eff2a7, 0x4bfe8c4, 0x228634b, 0x0f5b587, 0x13c16a7, 0x2283955, 0x340d47d, 0x22aabf1, + 0x053be91, 0x5abc5dc, 0x152ca59, 0x5f1b97e, 0x03f0447, 0x21dc620, 0x2c711de, 0x4b6ffaf, + 0x289b46d, 0x1b72886, 0x0abdc79, 0x2bd96f0, 0x2e52aaf, 0x47361f3, 0x0ca29d0, 0x131b6c6, + 0x0d6e9ce, 0x577ba83, 0x2662024, 0x4677998, 0x5674410, 0x10f32a6, 0x5259b4f, 0x5a4d30b, + 0x01560ae, 0x5f19462, 0x5026716, 0x5244b36, 0x3e4025c, 0x34bec6d, 0x449cb4d, 0x32cce4d, + 0x22a4053, 0x20e587e, 0x33ee288, 0x3e455c5, 0x3dadd96, 0x15239b9, 0x58f90e0, 0x5513d37, + 0x040b09a, 0x0adeb62, 0x58643f8, 0x4d42b24, 0x3a0008c, 0x3f2293f, 0x104c744, 0x1e94406, + 0x44e1491, 0x18358be, 0x4d3b8b9, 0x039401d, 0x4a2c84b, 0x3a13394, 0x0cc2dcf, 0x408e31f, + 0x1a507cc, 0x0de0d0f, 0x15ee9c2, 0x5716ca8, 0x1d88635, 0x06eb181, 0x231c9d9, 0x0713eab, + 0x1efe9ff, 0x51782df, 0x3c06e54, 0x41c1432, 0x0682e69, 0x3de044c, 0x0021fbf, 0x39b7fbc, + 0x3d325a4, 0x1201826, 0x03df8f2, 0x377ba82, 0x3a05c4c, 0x26b5ae3, 0x0bd6d9d, 0x5eaec5e, + 0x4ac4bc3, 0x0edd917, 0x16cb305, 0x0d1a1c9, 0x2ac9368, 0x5113168, 0x33598c3, 0x3b4b932, + 0x518fa82, 0x45b03c4, 0x224be63, 0x0072e2a, 0x32b4541, 0x57f988e, 0x4ad0aab, 0x222e31f, + 0x2c4fea2, 0x1062c78, 0x0d8afae, 0x1fb7ff6, 0x461759e, 0x00bc51e, 0x4720780, 0x5f3b12f, + 0x5a25bf6, 0x135f6d9, 0x221fb91, 0x0f25295, 0x391b372, 0x32e0f68, 0x5aecfe7, 0x4e25df8, + 0x16b0f0f, 0x5bdbc3d, 0x50d6de4, 0x0caae07, 0x4ea73ba, 0x48f8291, 0x10de215, 0x220e926, + 0x499b1f4, 0x5b0fce8, 0x09713a2, 0x19f5c1b, 0x5748547, 0x5d7a699, 0x026d257, 0x1f69124, + 0x3696026, 0x198b3f1, 0x2b82fde, 0x3d70eeb, 0x3d709e0, 0x198b587, 0x385d162, 0x5008e72, + 0x2c3d373, 0x5db2bfd, 0x1db0ffd, 0x24c1a9d, 0x30c0e89, 0x1eb7270, 0x16cbf26, 0x125cc53, + 0x49f02f2, 0x4c4707d, 0x1d71042, 0x27a3dfc, 0x2ff42a4, 0x345ccbc, 0x57ac497, 0x3e7b150, + 0x59a2b24, 0x2c8baaf, 0x5443cf1, 0x0baef65, 0x0a413ad, 0x08bd94f, 0x5923fc1, 0x0c67e35, + 0x3c41149, 0x10f09ce, 0x434b3d8, 0x2a312e8, 0x4a58a3c, 0x07856df, 0x5c45bce, 0x24bde22, + 0x23e81d3, 0x02ce712, 0x073d662, 0x218d9bd, 0x230d282, 0x2bd1063, 0x3d76c56, 0x3094548, + 0x427dea6, 0x3358922, 0x11c6f4e, 0x1e33217, 0x120e1b4, 0x1fb3d5b, 0x119c694, 0x23fa06c, + 0x1bb946e, 0x48d2e37, 0x021ce1d, 0x5e45f8c, 0x21484ee, 0x256b6a8, 0x198c310, 0x3fe623b, + 0x4ae86c7, 0x034d665, 0x2bd75b6, 0x1f20624, 0x2f4f28c, 0x24b393e, 0x012df4f, 0x431e229, + 0x5749f69, 0x0dd6110, 0x366cc63, 0x0e30277, 0x117357b, 0x1c69b7b, 0x3d2a3fc, 0x39f45e7, + 0x3e11545, 0x2cb33a6, 0x3771a96, 0x2db1fb9, 0x5f54a13, 0x0392bc0, 0x179fcf5, 0x5cc61fc, + 0x36ca6c4, 0x1fd7263, 0x458f6c6, 0x1fa7c6b, 0x1480b5b, 0x4325bed, 0x4ecd826, 0x0e0ab1a, + 0x1198d10, 0x5536bd2, 0x1d43b70, 0x15ff966, 0x5399da2, 0x3fb9597, 0x0e91408, 0x279c0da, + 0x4937035, 0x588107e, 0x25d9272, 0x29fb0aa, 0x3eb2dc8, 0x45d6ed3, 0x3480c55, 0x4de3744, + 0x58a64e9, 0x11004f3, 0x3bfa62f, 0x26cbc6c, 0x1a81ed7, 0x0e6a678, 0x0e03af4, 0x4fe424c, + 0x58be92d, 0x252b4ba, 0x5d71e7c, 0x2152743, 0x1d1b0b4, 0x3955736, 0x46fd376, 0x10502e1, + 0x4ffcd6f, 0x4b5bcff, 0x02a07bf, 0x4cd871a, 0x38e818a, 0x516b47c, 0x47fbbfb, 0x4218910, + 0x06e046f, 0x4087672, 0x135a86e, 0x205dea2, 0x57cbf9c, 0x4fc85ad, 0x2870c37, 0x46e2fdf, + 0x299997e, 0x5a94e1c, 0x2dd6515, 0x15f21cb, 0x253ddbb, 0x4eebcc8, 0x19cb5c0, 0x3aef6d7, + 0x5c1b922, 0x1056618, 0x298be87, 0x555bb80, 0x23d6fb8, 0x12a7f6a, 0x12e3ef7, 0x5950e52, + 0x3cdfd9d, 0x4f4c152, 0x561c991, 0x04246aa, 0x064a8d0, 0x21a4a14, 0x25bd748, 0x182ee1f, + 0x2b303f8, 0x166224d, 0x44e755d, 0x32dec58, 0x5c3f8b3, 0x23c1485, 0x336ed9a, 0x0c5a136, + 0x51a8d1b, 0x5e06a4a, 0x0490486, 0x1421917, 0x2156c80, 0x228f44a, 0x0155cea, 0x56c1308, + 0x3eb72c8, 0x33f3895, 0x20e2510, 0x0dd048f, 0x3083ee5, 0x1c8af01, 0x0fd2e7c, 0x59581af, + 0x5b5516c, 0x0e6a55c, 0x2fb1270, 0x01a413b, 0x18e940a, 0x0c9f6da, 0x54bbfd5, 0x085fa3a, + 0x5f4eadf, 0x2d8e931, 0x034673e, 0x59cb836, 0x42a8249, 0x24782cd, 0x25f3855, 0x43bd757, + 0x2aef111, 0x1e04542, 0x4e8477c, 0x09761be, 0x511f445, 0x02f27be, 0x142c2e3, 0x44468f9, + 0x33be9e4, 0x2287917, 0x51426ea, 0x5d5c98f, 0x1ac7ba6, 0x06017dc, 0x4cafdfa, 0x22370f2, + 0x3735adb, 0x39c0427, 0x3c7a1ea, 0x0f3295c, 0x084e600, 0x51ef3ff, 0x3235272, 0x4532267, + 0x2b6b434, 0x0be7681, 0x396805b, 0x0f4b61a, 0x0b5834a, 0x53077e7, 0x00a63c8, 0x2cfebf9, + 0x42b3b29, 0x3722747, 0x55efd75, 0x1a418eb, 0x4f00df5, 0x5cd80a5, 0x2dbbe19, 0x3d8ddc5, + 0x1f156ad, 0x3ffca57, 0x23050ba, 0x086639e, 0x44b76e9, 0x301c9af, 0x43132e7, 0x38d345a, + 0x369e508, 0x4420c12, 0x103a0e1, 0x4f35f1b, 0x27f95a1, 0x1caba81, 0x3daed2e, 0x1169738, + 0x0d58e16, 0x58f7208, 0x3f3dbff, 0x27cb14c, 0x39d66de, 0x30e1000, 0x336348d, 0x167ebd6, + 0x42ec90b, 0x1194ec1, 0x086a1ae, 0x1804ffe, 0x0468cab, 0x1655e6e, 0x3331de1, 0x0151436, + 0x155383f, 0x0173c0f, 0x26221b1, 0x18071a2, 0x0098c24, 0x349dedb, 0x3839724, 0x0765302, + 0x5f337cd, 0x5f0d473, 0x2615915, 0x5f0a08a, 0x38dbdc9, 0x378e983, 0x05ced0c, 0x2405c41, + 0x0da7a43, 0x0a74465, 0x4c50588, 0x46fa244, 0x393f638, 0x2c2ee51, 0x058a72a, 0x12c5f85, + 0x22eb458, 0x03be332, 0x38e6a87, 0x43e6f10, 0x1a91270, 0x4729f5e, 0x5f4ede5, 0x41bb125, + 0x55d2fd7, 0x190bbbb, 0x4320523, 0x1138b90, 0x160d3c6, 0x0b0388a, 0x040cd12, 0x2d83d3c, + 0x3a04672, 0x3a60b37, 0x07536aa, 0x4200fd1, 0x5504270, 0x3a5f1f8, 0x35dcb07, 0x398e1d8, + 0x0c56427, 0x44e08df, 0x15a9c0b, 0x141c1bd, 0x100890b, 0x44cff84, 0x315077b, 0x04b5946, + 0x052e643, 0x29d2121, 0x3947108, 0x222b58e, 0x1cf63e3, 0x0dc4ccf, 0x4d5b7f0, 0x0458765, + 0x5645664, 0x3bb05fb, 0x3f1521f, 0x4628c23, 0x4c58a7d, 0x2df819f, 0x2f358db, 0x2487bc9, + 0x30046bf, 0x4ff453e, 0x062546a, 0x314e785, 0x3ada109, 0x18ad40b, 0x508f50f, 0x2a61a95, + 0x0aab796, 0x0e2b9d7, 0x26ab413, 0x06c02c7, 0x5ae676e, 0x2c5db29, 0x5f301ba, 0x30a1bc0, + 0x373da02, 0x4969272, 0x24feff9, 0x3700ae9, 0x26fea38, 0x1bff77e, 0x10ada25, 0x2877713, + 0x0d487c8, 0x25ba30f, 0x20f697d, 0x4d03f09, 0x23c9e2d, 0x4635a9a, 0x5c628c3, 0x2102252, + 0x1886045, 0x180ab3c, 0x3f8293a, 0x4b9e404, 0x15fcea2, 0x35efddb, 0x082b7e8, 0x43f8c6b, + 0x3599754, 0x5919b55, 0x2c096df, 0x4ce4297, 0x35fe42b, 0x338a11f, 0x4b2d3e8, 0x05e9244, + 0x04a8296, 0x5674a57, 0x143b73c, 0x1479daa, 0x04c6c20, 0x3bf3164, 0x57f7241, 0x49b01cb, + 0x3508aac, 0x09caa3c, 0x34613fa, 0x3153d71, 0x5b23999, 0x294545e, 0x5eeb9ea, 0x3b74418, + 0x33e2031, 0x4167ce3, 0x3279308, 0x58ae7f7, 0x0d44322, 0x51ed3bf, 0x4364a84, 0x06e6f8b, + 0x107a819, 0x09869de, 0x5050281, 0x31deeda, 0x3101c0e, 0x3469dd8, 0x0a9f5d1, 0x0681f39, + 0x5389164, 0x427b85e, 0x3d8b38e, 0x06c1462, 0x39f9f94, 0x1d03eed, 0x171a5dd, 0x452abbf, + 0x5e9cb95, 0x200d298, 0x04f48a3, 0x54e147d, 0x2499bc4, 0x519ce9a, 0x554ff50, 0x0c40315, + 0x0391f80, 0x54bbb74, 0x4c650fb, 0x28e4727, 0x29627ba, 0x21d5695, 0x24d5940, 0x340bfcf, + 0x301876e, 0x2bfae91, 0x28af691, 0x41519a2, 0x1ff8699, 0x5f2a5cd, 0x0ec1285, 0x5287719, + 0x48721c4, 0x543280d, 0x04e830f, 0x3d6ea4b, 0x3f296e1, 0x3e53bc9, 0x0133c38, 0x5d60dc5, + 0x31a66bf, 0x41cbc48, 0x308668e, 0x28a2812, 0x0231dab, 0x0ed6707, 0x55280dd, 0x1fe00d3, + 0x51bd734, 0x0dca815, 0x279a93b, 0x17ca34e, 0x3645c73, 0x4d50065, 0x3d0ce60, 0x479962c, + 0x4863763, 0x17e9560, 0x55eb9d5, 0x55d976e, 0x57bed16, 0x0cdfe53, 0x0afb95c, 0x00cb315, + 0x0b484fa, 0x0e3b805, 0x073f12b, 0x39e9ceb, 0x284448a, 0x2583928, 0x1b0f78a, 0x4747cd2, + 0x02010be, 0x077e35d, 0x33d01dc, 0x02102f6, 0x152eccd, 0x007db07, 0x4702e53, 0x11669b5, + 0x2b97932, 0x5b2ae45, 0x4828530, 0x35f702c, 0x05cbb16, 0x4a9a2ef, 0x0fbe06c, 0x55e656f, + 0x13d95d1, 0x58c2c96, 0x181056a, 0x1948066, 0x15b4e14, 0x40afd13, 0x53afd25, 0x04a1fff, + 0x233be6d, 0x41e35c5, 0x1a07f4b, 0x04a852e, 0x17ef18f, 0x4099ba5, 0x1451f93, 0x47a6be2, + 0x3a18d90, 0x301d2cb, 0x1aa2355, 0x4a3b3a9, 0x1e8c5fb, 0x1e8a2a1, 0x5481c69, 0x2b1b6c0, + 0x0cc9fa5, 0x3d25e2c, 0x1276d4d, 0x1b93d2f, 0x4050939, 0x5a35720, 0x1089d10, 0x4c021a3, + 0x1596518, 0x5096287, 0x3579dce, 0x41cd6b2, 0x4288ab6, 0x23f0342, 0x5a292e4, 0x371b5dd, + 0x39ccccc, 0x412a377, 0x046a1f8, 0x5476284, 0x509871a, 0x5700b16, 0x11d0130, 0x085305f, + 0x4bc56ca, 0x39554f1, 0x43003c9, 0x46d2576, 0x0fca9f1, 0x0a3eb11, 0x5d0bbb1, 0x1c398ba, + 0x2364d47, 0x15cddd4, 0x4b9dc62, 0x030ef93, 0x236bf6d, 0x4e4f91c, 0x2cda26d, 0x53335c3, + 0x21b6dc3, 0x2d4fa61, 0x565a0e1, 0x0793bc4, 0x5ce6a44, 0x15a368e, 0x2cd95fd, 0x12f26ed, + 0x2fa3114, 0x3432731, 0x42a250e, 0x107ebcf, 0x014d4bd, 0x1537682, 0x4163ae8, 0x3abfa29, + 0x2316422, 0x0ac57fb, 0x47324cc, 0x2ba47d4, 0x120f741, 0x04cdfa2, 0x2d6bc4d, 0x49c5c8c, + 0x40094de, 0x32e69f7, 0x278dad5, 0x4ed74f4, 0x041ac47, 0x4469acf, 0x24611ac, 0x12fb048, + 0x1d77b71, 0x1a744eb, 0x51588e7, 0x27d309a, 0x465a738, 0x0c96689, 0x16a13c4, 0x367e2a2, + 0x1f5b15a, 0x4e342e6, 0x3a855e6, 0x23bbcc0, 0x51493c8, 0x428a8ba, 0x250d021, 0x14ac336, + 0x14089c7, 0x3443c20, 0x2cc18f6, 0x00d1285, 0x3ea4e72, 0x3b4c82d, 0x14f96d5, 0x3b58eb5, + 0x067351a, 0x17d96bf, 0x22ba681, 0x238c812, 0x3c060d0, 0x12b5a4d, 0x4fd09bf, 0x38fdd7a, + 0x32f95da, 0x09e7e33, 0x5a79fb8, 0x2f3e1ac, 0x13f452f, 0x5888b8a, 0x44a0b49, 0x0e887ba, + 0x185badd, 0x2c94386, 0x40be881, 0x2066c96, 0x50801e8, 0x4f81dc5, 0x2a6fbc8, 0x1833be3, + 0x06845eb, 0x0dcf6f4, 0x52e468e, 0x06bd826, 0x3744d94, 0x3803a02, 0x4c4e28f, 0x32f34e9, + 0x5816c64, 0x40fe2c8, 0x4a91740, 0x3589f11, 0x27c60b8, 0x46e24e2, 0x52b6513, 0x0ae09e9, + 0x4f326d3, 0x032243a, 0x4fe64cc, 0x38aaa7c, 0x2d8d778, 0x07e21cf, 0x283139e, 0x2d3b4cd, + 0x232115e, 0x115723d, 0x1290eae, 0x4069443, 0x4d641c2, 0x21ec7f2, 0x594f92b, 0x3c25356, + 0x0c0d24e, 0x3651f33, 0x5f3812c, 0x49055d3, 0x2d2b214, 0x3ff8176, 0x1d87c71, 0x09902a2, + 0x09b8d6d, 0x45c9b5b, 0x5976d7f, 0x042070d, 0x31e665c, 0x5795df3, 0x24664d9, 0x452868f, + 0x3219bc0, 0x42558dc, 0x33a2db0, 0x1141af0, 0x574ad93, 0x1d49628, 0x5e51bc7, 0x5c9e5da, + 0x52d791c, 0x01f7162, 0x3e630e6, 0x442578a, 0x551cad4, 0x0998dcd, 0x4ec2e4d, 0x00612f7, + 0x4a95eaa, 0x0972cfa, 0x370fd95, 0x4c03559, 0x4a3f9ab, 0x3d10c6a, 0x2397318, 0x0290d97, + 0x5a4364c, 0x4154089, 0x03ed511, 0x03f0db4, 0x5c1e40f, 0x274e249, 0x5405348, 0x5d2d000, + 0x22480e9, 0x3f2c727, 0x1f89ec1, 0x2a25a34, 0x3654db5, 0x4449665, 0x49af161, 0x0bb6ec5, + 0x42d14f5, 0x25ce02b, 0x0f19d70, 0x0bb9bcf, 0x4d271f1, 0x24e4919, 0x41ed6a1, 0x5399a77, + 0x1a448de, 0x0f8ad5b, 0x04ceab6, 0x259c130, 0x1398979, 0x093d829, 0x0eb9476, 0x585a3ac, + 0x45e2bf0, 0x46682a3, 0x32f1c2a, 0x2517cb3, 0x5c9fb70, 0x5a7f1f5, 0x1531fb2, 0x4cdaf01, + 0x217ae86, 0x32e4944, 0x2580a77, 0x11e4187, 0x0eb2129, 0x03c801e, 0x4599841, 0x5cb5336, + 0x506bdbd, 0x172e116, 0x11f4b49, 0x46e8f0d, 0x0125277, 0x5e84222, 0x59eafd3, 0x5ba6536, + 0x5cb623f, 0x252ca81, 0x33a55ff, 0x22449a1, 0x4c9cb8f, 0x3577105, 0x29ed11a, 0x110b4aa, + 0x5b8fe98, 0x1890ef4, 0x29d70ee, 0x0ddb0e4, 0x190225b, 0x4e6d8bd, 0x488b631, 0x2a589b7, + 0x38fe15c, 0x185899d, 0x5defd7b, 0x0fb9cd9, 0x31cdd72, 0x0aa22ec, 0x5612572, 0x3d663c9, + 0x5607677, 0x22ff381, 0x155ab1a, 0x0f3efd9, 0x0d9f6c4, 0x4432c64, 0x1129e9a, 0x3fcd2a3, + 0x4b12c2b, 0x316ae66, 0x48006bb, 0x1f55790, 0x00bb39c, 0x404a03f, 0x53db67b, 0x4fddace, + 0x4080b33, 0x358229a, 0x34f34d2, 0x28f18b0, 0x495e2ba, 0x5a6f5e7, 0x4f90982, 0x3290ed3, + 0x2bccaad, 0x4f75afd, 0x3268858, 0x22fd06c, 0x42ef393, 0x45f2fd4, 0x4f13c02, 0x06c9f98, + 0x4b4939c, 0x53f4934, 0x492b82b, 0x2b5c977, 0x5b00d6c, 0x093bdf3, 0x0496185, 0x2533f26, + 0x06e79c7, 0x410a732, 0x504a16c, 0x41e00df, 0x0e9a7ec, 0x15a3c92, 0x5483893, 0x4f0a88d, + 0x02ea38b, 0x409f620, 0x3ab296d, 0x3862766, 0x513229c, 0x20d5be3, 0x15458b3, 0x5097723, + 0x04c3013, 0x218cc33, 0x229f9d1, 0x31068a1, 0x007ddbe, 0x3fc4522, 0x217f795, 0x4946f2a, + 0x2cdb137, 0x5eba4bb, 0x5e5d5f8, 0x3a770e3, 0x2152c02, 0x155a2a7, 0x3a63b8c, 0x3d10ea1, + 0x5beece1, 0x07460d8, 0x0d28753, 0x3b3495b, 0x19eac89, 0x4c3fbce, 0x5c0c09a, 0x03edf94, + 0x31c53f1, 0x386fef8, 0x23a7d43, 0x1842275, 0x454a481, 0x220ee9d, 0x2bf08c5, 0x52d37db, + 0x322c2bb, 0x4530119, 0x419f045, 0x5bb7b01, 0x53a6a40, 0x26227b0, 0x5484c53, 0x38aca8b, + 0x4402c6f, 0x47e69ca, 0x44b3a82, 0x36523bf, 0x3382046, 0x5696a3c, 0x541ac5e, 0x4501230, + 0x04d41c7, 0x1a1b410, 0x4bc3239, 0x5f3af79, 0x0234f03, 0x44209cb, 0x4edb7d9, 0x100983a, + 0x567dea9, 0x353946e, 0x4380554, 0x0377efb, 0x2a11ff2, 0x4acab05, 0x4628947, 0x2e0d317, + 0x26b06e4, 0x36765fb, 0x0a72372, 0x23a76c8, 0x334b0cc, 0x4bd8f4b, 0x424c1fe, 0x1c74592, + 0x024f5d5, 0x39393e3, 0x461de5e, 0x262f9ce, 0x0e6832c, 0x0f0f4e8, 0x2b3985e, 0x07089f9, + 0x4e74f13, 0x0df24b9, 0x05405e1, 0x021fcc5, 0x0ed3abf, 0x31a39bf, 0x3221866, 0x3a5ac42, + 0x31c83f9, 0x2dde389, 0x0c0edd7, 0x3570d50, 0x0b396b9, 0x1f6a575, 0x0e52ffe, 0x22c9182, + 0x3fdf825, 0x02d9a05, 0x5cdad84, 0x3227ea6, 0x5c6799c, 0x388f7ad, 0x4809613, 0x3ad2150, + 0x14d6c63, 0x4eb3010, 0x2023d27, 0x3fdf4b3, 0x2a90078, 0x0e4241b, 0x54db401, 0x0a6fc94, + 0x0568369, 0x27a5d66, 0x4859254, 0x3dc7800, 0x02cf58a, 0x04ff1a0, 0x06efded, 0x5a9a6de, + 0x383c1d6, 0x3079378, 0x5a55888, 0x3f34fb2, 0x0b85690, 0x3038635, 0x3f7a91f, 0x475fcda, + 0x30f3fb8, 0x3591494, 0x2cb50d7, 0x2fa17fc, 0x3266adf, 0x369693d, 0x0d25952, 0x1935d8b, + 0x1b7de60, 0x282ed20, 0x3cb67ba, 0x276f361, 0x2b78576, 0x5a1a4ad, 0x128b397, 0x31636c6, + 0x3ca673c, 0x5a36e8b, 0x06df139, 0x0110e05, 0x50d9b2b, 0x495cf4d, 0x1a46a12, 0x050e043, + 0x0cf64a2, 0x59e5f79, 0x5ad67c7, 0x452a3c8, 0x22d25bd, 0x077ef0f, 0x4b0f021, 0x24002c2, + 0x5cefc57, 0x4a4b013, 0x1b56b42, 0x281afb9, 0x36d7971, 0x36c9243, 0x3dd030c, 0x00358c2, + 0x182ed92, 0x208b866, 0x156d298, 0x187ac0d, 0x2c49d5d, 0x197c3e1, 0x26aaed4, 0x4b4ea3c, + 0x0996dd0, 0x01f7d0e, 0x18b795a, 0x119c9b3, 0x0e302d6, 0x34093ab, 0x20b0f12, 0x0738cbb, + 0x40486f9, 0x4067d25, 0x54bdb53, 0x5ef40ac, 0x37944f0, 0x165b4bd, 0x323cd16, 0x5be6714, + 0x29c4fe4, 0x44b9192, 0x4cd5b1c, 0x44e3f71, 0x513468a, 0x22512ac, 0x4a537b2, 0x257f648, + 0x164f064, 0x48537ee, 0x4d4e6f9, 0x08ec8b7, 0x05716c8, 0x40f16fb, 0x2393efd, 0x07c5b13, + 0x1ecba80, 0x3186212, 0x549f31e, 0x2577267, 0x24ecee4, 0x17bc47f, 0x565d921, 0x0ec5e3a, + 0x325190b, 0x1cff370, 0x0087d63, 0x4b112cf, 0x398b2ed, 0x4c6c9b3, 0x47a081f, 0x3a0f020, + 0x422e039, 0x2c6ffb8, 0x2ea3ce1, 0x31d9f8e, 0x18c2d2d, 0x528635d, 0x4642d43, 0x529b8fb, + 0x2c51be8, 0x19f6917, 0x548747d, 0x25d9b01, 0x5bced0a, 0x381d2ed, 0x597a938, 0x303afc8, + 0x3b0c6c3, 0x39dde60, 0x5ef2774, 0x1515d13, 0x40f5a2c, 0x302e374, 0x3dca124, 0x1d3a933, + 0x22f82db, 0x364d702, 0x00a56d7, 0x3d5b2bd, 0x3b31c05, 0x467f987, 0x183b271, 0x000e7bc, + 0x16ad34a, 0x4f1611d, 0x01edb68, 0x50ea6aa, 0x08b8afa, 0x0f519d3, 0x426d88a, 0x4a6190d, + 0x2a5d6ab, 0x4b4e1b1, 0x0fb567d, 0x4ac21f7, 0x3c40421, 0x1e56261, 0x086807e, 0x0be3c92, + 0x2e69388, 0x5e00be3, 0x14932d8, 0x4c3cc01, 0x206d72b, 0x2f8ed84, 0x2067762, 0x3a0d075, + 0x0c1bb77, 0x599ae23, 0x265db2c, 0x370be56, 0x20a6bb4, 0x5d83e59, 0x455d07f, 0x36a0b75, + 0x36e4101, 0x442d8ae, 0x0bc2096, 0x5c53091, 0x21a479a, 0x41fa4c5, 0x063a3d8, 0x3579710, + 0x279c53d, 0x28b322e, 0x42e08fa, 0x1699087, 0x3a1436f, 0x1f3fbea, 0x0f0d854, 0x090c967, + 0x4124fba, 0x2670548, 0x05e63bb, 0x55791cb, 0x015dc52, 0x51d6fa9, 0x0c37f40, 0x1c699d2, + 0x41007cf, 0x02b5b99, 0x5443dee, 0x3a75a0c, 0x35e4910, 0x5e418ca, 0x45246a5, 0x43964b9, + 0x44626aa, 0x3a5649f, 0x1673b57, 0x4c030a3, 0x3ee2397, 0x32212d3, 0x440a386, 0x563b8c8, + 0x0c5b0af, 0x59fe821, 0x5c3ceb1, 0x10b3cd2, 0x0f23794, 0x3f1401f, 0x2e2bc83, 0x547b48b, + 0x4f08495, 0x559e152, 0x551e2f7, 0x0a95575, 0x193dc31, 0x1aff3a8, 0x1622561, 0x11c3eca, + 0x2475a37, 0x101a0b3, 0x212ff3a, 0x5c0f0f7, 0x5555728, 0x56cc758, 0x3d976e3, 0x07cc720, + 0x54abcab, 0x00f3699, 0x1a4ecb7, 0x47e5d98, 0x58a60c7, 0x17ceb42, 0x3ba31a6, 0x5594a5d, + 0x5297b5f, 0x3755760, 0x08bb052, 0x50a94d5, 0x54728da, 0x4527661, 0x0b80181, 0x0b73184, + 0x1f40d4b, 0x0e99785, 0x3c7baae, 0x189f847, 0x40b05c5, 0x0d6232a, 0x0e01be7, 0x1b5eff7, + 0x0f4d27e, 0x35ff7bc, 0x07db6ce, 0x293f46d, 0x0d59a24, 0x24bff19, 0x445827c, 0x4762260, + 0x3504123, 0x5bbc4a8, 0x5561747, 0x1caa3d2, 0x1672e7f, 0x2157f6d, 0x2fdecf2, 0x2c87a33, + 0x37a8e8e, 0x49ee8ed, 0x2644159, 0x1db8996, 0x1bedbf6, 0x5a4d259, 0x1cfcc1e, 0x2621328, + 0x0d169d3, 0x2d59b54, 0x2380389, 0x47b504b, 0x05c9abc, 0x043a826, 0x4e6cdcf, 0x58a39ec, + 0x446e66c, 0x0b2fcb9, 0x55770bb, 0x5b0790b, 0x5b37d02, 0x5db3168, 0x114989a, 0x1734938, + 0x18af4a8, 0x5248e17, 0x033491f, 0x2104ebc, 0x37c1341, 0x409b84e, 0x02df916, 0x1269066, + 0x5ed7b3e, 0x4b67ecb, 0x529ecca, 0x174b124, 0x16251c6, 0x4e869d4, 0x2f3aec1, 0x3560742, + 0x38fbb7f, 0x5d8e368, 0x2df5cac, 0x2c5def5, 0x0765eed, 0x3f51556, 0x2801bb9, 0x338c35a, + 0x40a98e9, 0x411069a, 0x03f604f, 0x19ae8f6, 0x2b22a9d, 0x5b9eb91, 0x3bac070, 0x5d949bd, + 0x4a42279, 0x2c3b7cf, 0x22c1ea7, 0x5ae81ac, 0x5b907b2, 0x2172898, 0x42d3e08, 0x4a24187, + 0x3f0fa94, 0x1a213dd, 0x4bf22a1, 0x08a168b, 0x08bbc28, 0x09a7717, 0x47ab152, 0x30d6a18, + 0x053855a, 0x1baeceb, 0x2c19559, 0x1987b50, 0x25d0d58, 0x534a93b, 0x5a313a4, 0x4bd9b63, + 0x2dcda6e, 0x0617a68, 0x19f589c, 0x0d2fc3c, 0x28a08f3, 0x28fa180, 0x4864ff2, 0x3709602, + 0x497f0fc, 0x292351b, 0x2342358, 0x4eefefe, 0x4f02560, 0x1da306e, 0x2442784, 0x054590d, + 0x442abad, 0x1d3256c, 0x1f91d3d, 0x193c481, 0x0ef8261, 0x0bf4d13, 0x26f62e5, 0x5cbcd1f, + 0x4896521, 0x0819238, 0x56bc4dc, 0x33d0274, 0x3ca7bef, 0x1fff1bc, 0x254b6a6, 0x1b033ac, + 0x3504933, 0x2a5b788, 0x2c18dcc, 0x0b3426b, 0x18aab6d, 0x04e29fc, 0x01e2826, 0x52746c3, + 0x1e9bd95, 0x423e941, 0x21b36b8, 0x426844f, 0x0a9f571, 0x059ccce, 0x2c48a54, 0x218536f, + 0x15d8a37, 0x2fecff3, 0x51d8c64, 0x46c8c95, 0x2d0803d, 0x09ad749, 0x4d86207, 0x0b3db2b, + 0x49c484c, 0x3be76a9, 0x5bbc5d7, 0x1b8dde1, 0x0c9cd7f, 0x2648954, 0x1f5abb8, 0x5a44d5d, + 0x5c80db4, 0x3500ef8, 0x5a3e8f3, 0x5504dff, 0x2d2557e, 0x3a5556c, 0x50cfe1c, 0x26ae3b6, + 0x12ef82e, 0x10bb2c9, 0x3538602, 0x242f809, 0x0ea4b5d, 0x0eff9ee, 0x04282d3, 0x0c9be20, + 0x31264d9, 0x24bd07e, 0x20e16ff, 0x4762b27, 0x0e13f39, 0x5c00f4b, 0x5bdaec9, 0x04e6f8c, + 0x18c26e8, 0x127b9b2, 0x3a14434, 0x3a0934f, 0x007e4b2, 0x2c35ab1, 0x53b3862, 0x3da5287, + 0x2e40a09, 0x1056af4, 0x189693b, 0x5877cfd, 0x3fd0244, 0x18af3f4, 0x0caad60, 0x1a2c6d0, + 0x16da39a, 0x03bf257, 0x43ab16b, 0x418f0cf, 0x3ea6739, 0x288e761, 0x3a5da78, 0x5482b6c, + 0x0f918f6, 0x20b1308, 0x1a2a591, 0x3633ab1, 0x17f67b9, 0x557d5ea, 0x4b49bfa, 0x3b3d094, + 0x3d99b36, 0x2547280, 0x069d6f1, 0x292f7a1, 0x4d5955d, 0x0a32997, 0x20a5474, 0x0cf2798, + 0x1e8d8a9, 0x17f17e2, 0x0d28129, 0x1ce033f, 0x4aaab98, 0x4bb630a, 0x10b3a75, 0x273db75, + 0x4da54a7, 0x1074818, 0x1f5b363, 0x30d1ce2, 0x03bd97a, 0x5a2ef27, 0x18c3f13, 0x188c037, + 0x12cc960, 0x5c71ce5, 0x127dfa6, 0x4662581, 0x3ae1d46, 0x2a4bd5d, 0x2fc7fd9, 0x24fc9d0, + 0x512bd0d, 0x511072d, 0x488eb0b, 0x4d6c627, 0x0e29340, 0x1c22408, 0x1b8038d, 0x4025779, + 0x125ed99, 0x5f312ff, 0x0813754, 0x2d856de, 0x2d80a10, 0x04c1a26, 0x5c3adc2, 0x45d91ad, + 0x4f76cf8, 0x4bb7dce, 0x418d3f4, 0x1621cfc, 0x1ca4e30, 0x279e98a, 0x022d081, 0x29fb58a, + 0x0b5c166, 0x1c9f49e, 0x253544e, 0x56fbee7, 0x03c01fb, 0x3261a34, 0x1740383, 0x185945f, + 0x3cabe75, 0x502796d, 0x16fa5a9, 0x5b69f73, 0x222ffc1, 0x25182d8, 0x50071a8, 0x58f36da, + 0x28a158f, 0x3a3eefe, 0x05e78bc, 0x0946d00, 0x515dd0b, 0x1c5cd53, 0x4141e88, 0x5f5d27c, + 0x10ff790, 0x57fa831, 0x04e981d, 0x51422cd, 0x0c6605a, 0x5e7c829, 0x4084cdd, 0x182c027, + 0x2922a38, 0x540f44e, 0x416d98f, 0x482e25e, 0x0fae0f7, 0x2f6d700, 0x16ea7e6, 0x3d3b62f, + 0x35afcc4, 0x02c254e, 0x5d3879c, 0x188a8aa, 0x5a6947e, 0x4c7e01f, 0x4bd9445, 0x284d4f6, + 0x5c33205, 0x54e99ba, 0x50b397d, 0x12b4cb8, 0x190848d, 0x302ed86, 0x3bff082, 0x30d7bc4, + 0x416aaa6, 0x0a3b2b8, 0x1e116cd, 0x43b9a05, 0x05965d2, 0x2401d72, 0x1590c38, 0x410fc5c, + 0x543f750, 0x1d15bdd, 0x0453198, 0x0051098, 0x1b17759, 0x4eea31b, 0x37abcee, 0x48cfb51, + 0x50c88c6, 0x0e73761, 0x1e50898, 0x24bc9f3, 0x5044dcc, 0x25e5c76, 0x07fbba4, 0x27cd83d, + 0x1f47114, 0x0da74a8, 0x43cc767, 0x37614e3, 0x135239f, 0x0737fb6, 0x1904917, 0x14aa79a, + 0x14934a7, 0x165b99c, 0x1973fb2, 0x02669eb, 0x35918f8, 0x44fe55b, 0x024c422, 0x1563dd3, + 0x00eee9d, 0x10d7c44, 0x0a9bef4, 0x3fcdafe, 0x591bc91, 0x3693261, 0x57daa5d, 0x0237399, + 0x23235b0, 0x3ca2035, 0x2129b53, 0x50b2a60, 0x52d22b3, 0x0c073fe, 0x0bdacee, 0x1d5f8e5, + 0x58ae588, 0x1fef7ef, 0x37a37f1, 0x5f543c2, 0x208df57, 0x0cd79ad, 0x1e52838, 0x1dc4f31, + 0x5b3f1dc, 0x3d16e15, 0x1d817d6, 0x399fb31, 0x0e8f894, 0x3509b60, 0x3d9a3ad, 0x1578865, + 0x22e825c, 0x4d0f309, 0x070d79e, 0x450e0f4, 0x37b0dd0, 0x3449fc8, 0x171a3d7, 0x20a0fa4, + 0x5542364, 0x403129f, 0x5d76d87, 0x451345d, 0x305dba9, 0x0a6ae12, 0x40d7877, 0x22f4542, + 0x2b5dfc3, 0x0d1c51f, 0x5636304, 0x192da06, 0x1340eee, 0x0a8fe8b, 0x005dc7f, 0x140442d, + 0x255bd6c, 0x27eaf06, 0x07b7803, 0x0c79d01, 0x241e2c9, 0x0a3a238, 0x307aacf, 0x0aa4ae8, + 0x2e68ad0, 0x43281c9, 0x2c07cc0, 0x40bfead, 0x0a38e0d, 0x46a77bd, 0x2bc5629, 0x2b804d2, + 0x0a061f5, 0x0292ccc, 0x21e2af7, 0x0dc71e2, 0x45a5a87, 0x5270299, 0x31dd493, 0x322ef72, + 0x4210798, 0x064aea9, 0x42d93d9, 0x1edd5ce, 0x098e31d, 0x0360cfc, 0x279e014, 0x5aa3aab, + 0x3fc0b5e, 0x4e76dba, 0x2726cc1, 0x08e117b, 0x54dad63, 0x3e3aa8c, 0x15bf2c2, 0x41fc63c, + 0x5252faa, 0x381f26b, 0x0824870, 0x585f815, 0x11c504c, 0x13c7c39, 0x27ef3c8, 0x50b4f12, + 0x2072486, 0x0d651be, 0x184599b, 0x2086d11, 0x18e296c, 0x2182c0c, 0x0db302d, 0x01318ab, + 0x335e5b4, 0x588176b, 0x1dd33a6, 0x39021be, 0x49031d3, 0x16940f5, 0x33cd9cb, 0x2bbb046, + 0x4bf939e, 0x07800b7, 0x52169ac, 0x546ccb0, 0x5aa06d7, 0x48e2c59, 0x0c73269, 0x201b823, + 0x3e4343d, 0x3e26e90, 0x1b961b3, 0x2518776, 0x054866a, 0x53eb8bd, 0x1316e1b, 0x163edb7, + 0x0cb1781, 0x2451d89, 0x163e870, 0x1ec45e1, 0x5d2119f, 0x3618660, 0x23670cc, 0x3cb2dcf, + 0x03177c8, 0x08a04a7, 0x03596a4, 0x24bd865, 0x59c133a, 0x1b34056, 0x170c67b, 0x1b1ece5, + 0x15bd3ae, 0x2d92fc8, 0x4f42f7a, 0x5f37aa4, 0x5f1eb5a, 0x4911ae8, 0x4bb9a14, 0x165e9c5, + 0x0d6986d, 0x4d067bd, 0x07353a3, 0x412b293, 0x18d604b, 0x236e1ca, 0x1b94f9c, 0x4344d53, + 0x07fce8d, 0x3200e61, 0x42ef27a, 0x21322db, 0x2d25a95, 0x29eb41d, 0x2cb5263, 0x2c92932, + 0x330219e, 0x55a58e1, 0x04be406, 0x13049d2, 0x5c38d2a, 0x4936470, 0x500b842, 0x15e8cf3, + 0x31d667b, 0x1d0d619, 0x09c7d81, 0x4ce6299, 0x50731e0, 0x0eed83e, 0x3b483d5, 0x3d1222e, + 0x4c11c6a, 0x4b7f977, 0x598b92e, 0x4725da0, 0x297e28d, 0x193e38b, 0x38b4014, 0x57dce4b, + 0x54852f6, 0x52ab75a, 0x0a69e74, 0x3c8b2fd, 0x0b6bb0e, 0x40e5fad, 0x1f3f23a, 0x46e014c, + 0x467975e, 0x578966d, 0x5851f49, 0x3dbf6ac, 0x5aa2c1e, 0x2fb7f15, 0x5e47806, 0x5a430a0, + 0x08077ea, 0x21bdbd5, 0x30f7ad5, 0x317e4e1, 0x2c21940, 0x51a23d0, 0x0762701, 0x3058ae8, + 0x5c9f51d, 0x1d6432f, 0x5df4629, 0x407a538, 0x512d733, 0x4932a57, 0x5027472, 0x3806fe9, + 0x140d3a1, 0x1327536, 0x44eb239, 0x0b4dd19, 0x0bdebd4, 0x1fc5852, 0x06eaaad, 0x344d159, + 0x5acf803, 0x076ae3a, 0x49ecdd5, 0x25349d4, 0x2991506, 0x209923b, 0x0eacc04, 0x0ae0389, + 0x3a136ec, 0x3273565, 0x0b23ae4, 0x230f777, 0x5e745d1, 0x2cdddfc, 0x461cebc, 0x11397a4, + 0x50caf35, 0x00c217e, 0x2c15a0d, 0x528a3f3, 0x3beeec6, 0x0574ce7, 0x4e13c54, 0x08567b9, + 0x19b1026, 0x094f834, 0x4949ce9, 0x257af64, 0x1917298, 0x2c7e077, 0x0fc0adc, 0x5b9d4ff, + 0x5d49d96, 0x4bbab94, 0x341f3f2, 0x0a42fed, 0x00935f3, 0x49dbe68, 0x07509a1, 0x4847b12, + 0x04df450, 0x09d99c7, 0x4e20a11, 0x31df11f, 0x13826bf, 0x3500a11, 0x2b4ec53, 0x4c21db7, + 0x47f77c7, 0x360efa2, 0x10dea45, 0x361c0d3, 0x1622908, 0x4be66e2, 0x48c09c2, 0x2dc1223, + 0x0f5bb33, 0x39a7a4b, 0x559b47b, 0x50bb13c, 0x194db2b, 0x1083783, 0x34b9745, 0x3e7266f, + 0x3f8f999, 0x536a10e, 0x31db868, 0x45dc2b5, 0x587d672, 0x27111a5, 0x4287bda, 0x42d10d5, + 0x0872cd8, 0x506bb72, 0x5641995, 0x059e8b1, 0x586fb8b, 0x02bc847, 0x3347025, 0x090bc0f, + 0x5ebd587, 0x0432727, 0x3009cce, 0x4004044, 0x2415228, 0x4ca38bc, 0x0e56675, 0x225cf94, + 0x3eb039c, 0x3f93d64, 0x3a9dc3f, 0x1766e2f, 0x50bcd79, 0x203860c, 0x31b8b30, 0x1bf880b, + 0x5071a4b, 0x1b78561, 0x2a5ca39, 0x30279fb, 0x0d2c507, 0x27090dc, 0x280de21, 0x5d281c9, + 0x0f8ab92, 0x2c4337f, 0x0d400e2, 0x1094a44, 0x2af7f54, 0x39f02b5, 0x41bd12d, 0x34870b9, + 0x14776b1, 0x2ec956b, 0x06e38cd, 0x4b31c0b, 0x2e9301c, 0x368c1e0, 0x1dc12fe, 0x1d10a02, + 0x2371140, 0x0815726, 0x2cc04c9, 0x303eb46, 0x4f45626, 0x219728d, 0x3705496, 0x0e4413d, + 0x06fb06d, 0x4a6b437, 0x48b677e, 0x292feb2, 0x15f2333, 0x4d71cae, 0x350cc72, 0x4e61350, + 0x44e6da1, 0x27b0fc7, 0x13d5fc5, 0x5bc5e47, 0x3de9105, 0x035a17c, 0x10c64f7, 0x265285d, + 0x4ca10c1, 0x0ca0aaf, 0x3c88830, 0x01bb8cf, 0x01967fd, 0x11be1d5, 0x2caed8e, 0x440ac15, + 0x3747aa5, 0x5cf61b1, 0x1878819, 0x5eaabc3, 0x4a02438, 0x046e6f9, 0x29f165a, 0x18e32d4, + 0x09357e9, 0x1fdbc0e, 0x58a89f0, 0x4adf2fe, 0x3181d08, 0x57cb400, 0x095eb6b, 0x0a1a717, + 0x35f7427, 0x041e2d5, 0x206abd7, 0x1644838, 0x21cab37, 0x0f463bb, 0x4d9b766, 0x31122a9, + 0x222dd11, 0x53965a1, 0x54fb506, 0x3f8d379, 0x48c571d, 0x0c02405, 0x2e89dac, 0x4ca0253, + 0x3421375, 0x3fe67b2, 0x40906cd, 0x40c9a36, 0x1f2d45d, 0x352eceb, 0x0bb966e, 0x395dafa, + 0x57daf23, 0x44fda3d, 0x5478e73, 0x19e2425, 0x2f1f6bc, 0x41375a1, 0x12a15c3, 0x02216ea, + 0x2bf3d78, 0x5054bf7, 0x5946a78, 0x382330d, 0x0b4d93c, 0x1658f41, 0x2d79f97, 0x3473d39, + 0x03c5afe, 0x502a6b3, 0x237d179, 0x3d04f49, 0x1c6ba24, 0x256da9c, 0x1fcc97f, 0x0819b17, + 0x2f2237a, 0x5e4b0cc, 0x5f2bb55, 0x5d66b35, 0x5977740, 0x454a859, 0x006b0c8, 0x035afe0, + 0x5de03d0, 0x5e7cc89, 0x3e8a8ae, 0x1d371cd, 0x19fb5cb, 0x01ee248, 0x0c4ec88, 0x5b8de2e, + 0x0bc1155, 0x3fa0e14, 0x1ba980e, 0x30eff3f, 0x4e09a44, 0x21a065e, 0x5dd2610, 0x26a19fd, + 0x41c6ed3, 0x0a2051f, 0x488e5c4, 0x1f2b9f8, 0x233045a, 0x3737355, 0x0c14828, 0x180b6f3, + 0x5eab34c, 0x30c6c2a, 0x041613a, 0x178daed, 0x4bdd77a, 0x1784391, 0x101c30b, 0x36d8692, + 0x42f3105, 0x1208229, 0x363372c, 0x2832d1f, 0x3584340, 0x56b8e70, 0x313f511, 0x329ec15, + 0x065f9df, 0x2884d9f, 0x22775b4, 0x43713ad, 0x161e966, 0x30cd083, 0x20533ca, 0x336021a, + 0x239bde8, 0x0a8ac2b, 0x5d797ff, 0x2a6119f, 0x124bce0, 0x43ab0fb, 0x22038d8, 0x0088c1e, + 0x283fd86, 0x060bc06, 0x5829675, 0x5a80765, 0x362dd84, 0x26259e9, 0x3b6170e, 0x03b5faa, + 0x4c796ce, 0x3132719, 0x3893a26, 0x5b2dc35, 0x0b9170e, 0x2c7b1ec, 0x326e150, 0x4e6a436, + 0x0f82805, 0x5cc5401, 0x4cdca08, 0x14142b1, 0x3a1160c, 0x1ba1089, 0x49e7154, 0x1472a2c, + 0x160a2fa, 0x2a4e359, 0x3983bb1, 0x413bc59, 0x33115bc, 0x542c6ec, 0x5c95f6f, 0x4ac49ad, + 0x5c8adb4, 0x24cbfc2, 0x4d7f529, 0x44ebcce, 0x116e87e, 0x4997e56, 0x15d189a, 0x03405d6, + 0x5e400d9, 0x43157b0, 0x515b017, 0x3bebe6c, 0x214ed49, 0x3bff11d, 0x1ef7fa1, 0x1506ab2, + 0x0c38f01, 0x15a10f4, 0x3f8b831, 0x4230340, 0x0627c89, 0x3aab3c8, 0x28609c2, 0x5d585a2, + 0x43401dd, 0x134cd26, 0x3d66788, 0x42a136b, 0x237c077, 0x17c5ad4, 0x5243d67, 0x2848a1a, + 0x59bec1c, 0x261d217, 0x46c3802, 0x468521d, 0x4c67d89, 0x3c08c83, 0x01f6299, 0x5f2dd0e, + 0x5800817, 0x2a11028, 0x17bbd6d, 0x2f01557, 0x313e89e, 0x2c68c40, 0x1161cc8, 0x2003757, + 0x3682fb8, 0x182bbe5, 0x5c9e6a3, 0x41c221c, 0x1733a72, 0x2d5fbda, 0x5dca95f, 0x226c107, + 0x03e237a, 0x1d17f2f, 0x421ade1, 0x4e2f2f1, 0x1995694, 0x309ac78, 0x006f5e4, 0x0744fbf, + 0x04352cf, 0x0093cb4, 0x307b15d, 0x02fa686, 0x14f073d, 0x5ac03f7, 0x2213ce3, 0x060c604, + 0x5e74d1b, 0x1f12c5e, 0x4933315, 0x0335c1a, 0x18400e8, 0x46c48ac, 0x4693f25, 0x49d171c, + 0x3b93c97, 0x2d6f214, 0x5054eaf, 0x2ca623d, 0x27f3795, 0x4351790, 0x2ef2b2e, 0x389b08e, + 0x5dd6b3f, 0x1174526, 0x0493418, 0x50bb599, 0x2bc3afe, 0x5b6566d, 0x32d5079, 0x536b094, + 0x03d2491, 0x4a6b0d2, 0x0c444b8, 0x137084d, 0x46b67e0, 0x590ab72, 0x32e4a91, 0x52f6903, + 0x0118d8e, 0x4415af1, 0x3782410, 0x5df4a91, 0x491eac5, 0x090439c, 0x1a794a1, 0x449fe54, + 0x4aecae1, 0x063c150, 0x1190564, 0x2884b75, 0x0080e61, 0x25eb90a, 0x4a09522, 0x1ddf80d, + 0x01e6681, 0x501a862, 0x3298909, 0x1e1a3c2, 0x3a41007, 0x4e7ba8f, 0x2a48f9a, 0x4efb715, + 0x2e807bc, 0x3c29d45, 0x1d48b1f, 0x15e463b, 0x0c7f07b, 0x52f8e8a, 0x42ab9f4, 0x499c305, + 0x1569fcc, 0x252963f, 0x12dbc06, 0x5e9c007, 0x4cb9e09, 0x2078f9c, 0x574a2c9, 0x50ae9b1, + 0x3dbfb59, 0x3093f8d, 0x4c0d3c8, 0x38f5950, 0x2ad2bb2, 0x46ad239, 0x4461cae, 0x2b74e33, + 0x3e6de52, 0x2684e31, 0x4b4d9a5, 0x5af6a1b, 0x3cf1cc7, 0x11b9fb8, 0x020e2a1, 0x5ebe430, + 0x0a463ee, 0x4a95181, 0x3cb4017, 0x13585ad, 0x2c2a70f, 0x1a479da, 0x44c72de, 0x46ea387, + 0x5551bbb, 0x135c3e7, 0x0548504, 0x4afaf06, 0x4ab8907, 0x32979b5, 0x49da110, 0x264e37f, + 0x3aeed69, 0x2421da2, 0x3ff5a60, 0x4153248, 0x18747a0, 0x301de15, 0x2d321c4, 0x04c386e, + 0x5832d6a, 0x5e5582a, 0x17436be, 0x0048b42, 0x4249dd9, 0x51d061b, 0x3b17e72, 0x4cd6ae1, + 0x26143c3, 0x3230645, 0x143f6d4, 0x293cf11, 0x437b4ce, 0x339f6b8, 0x4634a89, 0x5ec0c75, + 0x129e992, 0x02e1106, 0x4634e06, 0x4813aec, 0x2712d84, 0x1c9fe66, 0x1363214, 0x0752ac1, + 0x4eba581, 0x515e952, 0x482d0f3, 0x08c480f, 0x4a3bb5a, 0x21d4569, 0x1af49c0, 0x3882aec, + 0x03e7eb5, 0x11618fc, 0x3d39868, 0x1fa2b4e, 0x0eb296d, 0x0b2ae80, 0x12e0658, 0x3bb168a, + 0x2b7a334, 0x5795fef, 0x486bdd0, 0x078215d, 0x50f0942, 0x21c1eb6, 0x567fac9, 0x556abc7, + 0x38bd41c, 0x03a4e6f, 0x3fef019, 0x0a9dfdb, 0x0f1c831, 0x5248ff1, 0x23f54e5, 0x2c220c3, + 0x31c3f04, 0x41e43f3, 0x2acb165, 0x5dcbf97, 0x5a0da9a, 0x4cf70e0, 0x239fdf9, 0x54ed47e, + 0x39ee4c2, 0x1cf1185, 0x00db037, 0x50e89de, 0x066da42, 0x5eb984b, 0x3ade1c6, 0x2c9f25f, + 0x0e30776, 0x47f4e48, 0x2899f2a, 0x471c299, 0x004a01e, 0x4abbb34, 0x1e838ae, 0x04c5d4f, + 0x41198a5, 0x18ef330, 0x1cb105d, 0x200c6e9, 0x59858b7, 0x515dae3, 0x3f8c5e4, 0x208c379, + 0x3496910, 0x519d0ab, 0x57db524, 0x4c6ffc1, 0x4bda881, 0x0cb3219, 0x1e993e4, 0x42a7e44, + 0x5e20325, 0x2561649, 0x08649fd, 0x06ddd1a, 0x2258e0c, 0x3ffbdeb, 0x5efaf6d, 0x1a6eb3c, + 0x4344093, 0x4ee4c8d, 0x3c02176, 0x1eac715, 0x17b10b5, 0x43354cb, 0x1a1296b, 0x22c344d, + 0x3aab0f7, 0x0f41a3b, 0x3bbd605, 0x13fa8e2, 0x56f614e, 0x522f248, 0x01ba92c, 0x0e1e367, + 0x373499b, 0x0f4c7d1, 0x1eb2356, 0x4be7a23, 0x3ad8e49, 0x101be04, 0x46a374a, 0x496cf51, + 0x15bef64, 0x54de588, 0x5c8e5e0, 0x3a55595, 0x25ff3ac, 0x122e9cd, 0x4391df5, 0x4cf23a9, + 0x0bac729, 0x5324dd1, 0x5a30a68, 0x13e4950, 0x246dc6d, 0x03b7024, 0x34a845c, 0x2f7bcc6, + 0x052adcc, 0x34c74ab, 0x43a7eaf, 0x3e12011, 0x5afece3, 0x1827127, 0x4fc2824, 0x36b6019, + 0x126412e, 0x571eb9f, 0x2e3bcd3, 0x5829e92, 0x5b19aaf, 0x027a8df, 0x5f52a83, 0x502e720, + 0x4d89c28, 0x49884e0, 0x4d21b02, 0x2928b2d, 0x2440031, 0x43e43b7, 0x10ecaf4, 0x0d3dae9, + 0x1a8fc3b, 0x031bf8c, 0x4b899aa, 0x48c714d, 0x41056d5, 0x250a2ef, 0x380304a, 0x14e6d99, + 0x48a6031, 0x0a28aa5, 0x1fb8ea0, 0x36243a2, 0x26a03c0, 0x5b11bee, 0x2ff068c, 0x24008bd, + 0x03ab1f2, 0x1f6be04, 0x0139f64, 0x3b73aef, 0x22666b9, 0x193349b, 0x0dc08be, 0x1325d82, + 0x305728a, 0x5356755, 0x1d44d6d, 0x4731bc7, 0x0fe5c29, 0x4062e2a, 0x03f358b, 0x46c4b19, + 0x3552ad7, 0x16a5689, 0x28bd405, 0x2f207be, 0x19dcc9b, 0x3e948a5, 0x365bfb0, 0x47c760f, + 0x1bdb9c5, 0x4586546, 0x381da9b, 0x5441a40, 0x24f1374, 0x362f6c9, 0x1c7b72a, 0x0d67af6, + 0x108e313, 0x4b0875d, 0x26579bd, 0x3fc8115, 0x02783b9, 0x5c26318, 0x164ee1b, 0x2113935, + 0x593f177, 0x3437711, 0x0b823fa, 0x0e6fe66, 0x2113a7e, 0x00d37e2, 0x28bb589, 0x09b5c22, + 0x3f97138, 0x09e8ef6, 0x187ab96, 0x3d4e14b, 0x3907261, 0x1d19c0b, 0x4cae1c7, 0x0faf7b1, + 0x56ded8d, 0x00ab4e1, 0x182b204, 0x154cdaf, 0x2c30e53, 0x0ba06d2, 0x3db7f06, 0x37e777c, + 0x4243ec3, 0x21ab200, 0x24f33db, 0x5720e79, 0x00c6e2a, 0x22dcaba, 0x06b9994, 0x2cba83d, + 0x3486d55, 0x23b0a3c, 0x23a4e9b, 0x40e67df, 0x2678063, 0x54c920b, 0x473cc3b, 0x48dae0d, + 0x3e85306, 0x5555f88, 0x424d712, 0x08a9efb, 0x4e6b15d, 0x0ab244a, 0x1e5ac00, 0x3f712fa, + 0x49476c9, 0x2f9b430, 0x4f059fe, 0x01fe1bd, 0x3057394, 0x4c091e5, 0x3093547, 0x2ff4046, + 0x424c884, 0x59ddc82, 0x31b1fba, 0x0411f54, 0x0bb8315, 0x1b5b8e5, 0x060abd4, 0x48ef072, + 0x12f79c7, 0x0b4f172, 0x58812fd, 0x0d306c5, 0x581a7db, 0x2f00e4c, 0x455f6e5, 0x3fa852a, + 0x438895b, 0x4376efc, 0x5dfd21d, 0x57b4515, 0x582cb64, 0x5ddfd0b, 0x4d901c7, 0x38c7f9a, + 0x32bedd5, 0x5735a1d, 0x36abd7d, 0x12cc99b, 0x3368c91, 0x1f4253b, 0x1187fb2, 0x3a82727, + 0x4e809b1, 0x0b5d7e0, 0x2addd22, 0x497e2bd, 0x24e8e69, 0x20ed11b, 0x587841c, 0x491b885, + 0x191eeda, 0x2b0b157, 0x17a9db8, 0x2898d96, 0x5890993, 0x0b69199, 0x4e4be7c, 0x5eca2ad, + 0x58c2f3a, 0x4d4af8f, 0x2c79bb4, 0x02492d7, 0x3848fde, 0x121dd52, 0x2500c39, 0x39d6d26, + 0x0161333, 0x339b2e5, 0x1bb4fa9, 0x099c585, 0x0146f0d, 0x267b215, 0x59646a8, 0x0dd98ce, + 0x148d268, 0x35ed2fa, 0x162cb85, 0x4945db7, 0x0d87012, 0x253af5b, 0x548bacc, 0x4b7215a, + 0x50595df, 0x3153b0c, 0x126a4db, 0x288a395, 0x268a874, 0x12e5084, 0x3e44bb4, 0x435508a, + 0x055f995, 0x1648bd5, 0x52ea978, 0x16ac23c, 0x36fefec, 0x2326b34, 0x0426d05, 0x0f9a67a, + 0x2154920, 0x500fc7a, 0x36e4e46, 0x08d89c9, 0x58abc4a, 0x5726bbb, 0x252a438, 0x48e3829, + 0x38c9b50, 0x052959c, 0x0b475e5, 0x278fb9b, 0x04660fe, 0x5e158ff, 0x11ad5de, 0x356e090, + 0x3adf18e, 0x0a15742, 0x5076265, 0x3a16502, 0x0dd6710, 0x01a17e2, 0x19aee39, 0x0f3960f, + 0x4ac7054, 0x415adc9, 0x51b0709, 0x4642043, 0x4e8f3ab, 0x100da14, 0x0865311, 0x34d412a, + 0x5eb8865, 0x15858bf, 0x4501c42, 0x47d8e25, 0x1f083d9, 0x483862f, 0x3e67ba1, 0x59266f6, + 0x3096def, 0x3a95e99, 0x27817ae, 0x299d878, 0x3f6f049, 0x3cdec14, 0x32e9881, 0x2827352, + 0x4fd7743, 0x31d49ec, 0x5e75240, 0x5a6f219, 0x501fe0f, 0x38bb22e, 0x0fa86c7, 0x595fdc8, + 0x1689b22, 0x2a63762, 0x4cd84c8, 0x0a55e9b, 0x0f92a3c, 0x0d46d14, 0x4676363, 0x016dba5, + 0x2095106, 0x5b8449b, 0x05a7847, 0x415fd77, 0x070a1c7, 0x4832930, 0x3ae746f, 0x1c48220, + 0x1fdb785, 0x3693d61, 0x38d42ec, 0x3ebbe13, 0x3e0eba7, 0x3c31ed1, 0x546b79c, 0x15ce2fe, + 0x411de5f, 0x10b9ebd, 0x4c701c9, 0x2394c59, 0x0a72c80, 0x17a8bac, 0x328cfec, 0x44f6fd6, + 0x4470ace, 0x1d635d8, 0x5847fdc, 0x524b683, 0x3a237e4, 0x28e2eb2, 0x3e41bf0, 0x3da4ed1, + 0x38df4c0, 0x287168d, 0x33e18c7, 0x4e8ecaf, 0x10afd98, 0x27d01a0, 0x2f51dfa, 0x067e672, + 0x2e75f0d, 0x3d9eec1, 0x21bb888, 0x2d91594, 0x21d8265, 0x3ba86f3, 0x265b30a, 0x0065d2d, + 0x3d616d9, 0x0fd404e, 0x008213d, 0x20fedef, 0x1ef454e, 0x5ad5081, 0x52a6256, 0x2748787, + 0x347d4e0, 0x1b03300, 0x25c7375, 0x5da2064, 0x5e18d20, 0x371c72e, 0x40c66a4, 0x35b3f61, + 0x36d6e0b, 0x0085923, 0x11882a9, 0x1a35180, 0x4fcb63a, 0x5818145, 0x5ab0ee2, 0x29ad9bf, + 0x5a24c27, 0x14ed603, 0x0ecc889, 0x514fa85, 0x468273b, 0x1f5b376, 0x589dcdd, 0x4f7bbb9, + 0x38f62f9, 0x4527e35, 0x41e1127, 0x29dc31c, 0x54dd2b6, 0x59d9f6f, 0x157520e, 0x3793ac2, + 0x0750eb1, 0x25af7be, 0x314b3a4, 0x0ceb121, 0x4afc0de, 0x5c1ff4e, 0x1d192da, 0x204b672, + 0x4207303, 0x0f6926d, 0x47cdd67, 0x4628181, 0x567b00e, 0x17cb06c, 0x46e4280, 0x28e5888, + 0x0251fb3, 0x07f13d0, 0x1a2c1a3, 0x02578c1, 0x09d4a8c, 0x4514ae4, 0x46707d2, 0x0ba1617, + 0x459fd8c, 0x324461b, 0x4b1eb31, 0x5487b02, 0x15e7138, 0x4405ad1, 0x06ecc3a, 0x1848563, + 0x46372b1, 0x23f8978, 0x33141bd, 0x0b529d7, 0x2b0eeec, 0x1e7de1d, 0x4f176d0, 0x3d83ea5, + 0x0438956, 0x41074ca, 0x08e674f, 0x20b5283, 0x2208c56, 0x509edce, 0x03f1fe1, 0x15e02be, + 0x22f048e, 0x1635033, 0x28db620, 0x260d187, 0x580f915, 0x3c599f6, 0x198cb56, 0x3e56588, + 0x1fd376d, 0x3d89a44, 0x3e5bd32, 0x2083dc0, 0x086bcb3, 0x05544ac, 0x4a5ffb3, 0x1f2e316, + 0x2454fba, 0x0b43a5f, 0x4c88a0b, 0x3572929, 0x27b8b63, 0x1e496c0, 0x1b5ea34, 0x148b265, + 0x4c45123, 0x1a235c2, 0x35064f2, 0x3f80b54, 0x0aef8ef, 0x47b8a3e, 0x45de7ed, 0x1fc243b, + 0x1bd8d96, 0x58ba796, 0x57cf9ba, 0x222f2fa, 0x2e8303c, 0x149f21a, 0x444efbb, 0x4adf939, + 0x33a6f97, 0x0861e09, 0x3aed44e, 0x183cfcd, 0x34371e8, 0x4bbc657, 0x5dc6dbe, 0x2efc70b, + 0x550afb4, 0x5a061db, 0x2a319c1, 0x4fea894, 0x3db2687, 0x4362f36, 0x36c3996, 0x5775b40, + 0x573a550, 0x45b5305, 0x43a3436, 0x5625bf0, 0x14e1104, 0x59010cf, 0x1d81a05, 0x1d3fc56, + 0x25a8eeb, 0x37e01ef, 0x2f0123a, 0x17e85eb, 0x1fc293d, 0x2b4910a, 0x307bc7a, 0x14d0a69, + 0x31d39e9, 0x1b67c67, 0x21f0804, 0x4c02e45, 0x3cdc594, 0x00f9984, 0x5ade279, 0x3dca4b1, + 0x2f7cd93, 0x1108102, 0x2ee3776, 0x4f0cd9b, 0x308f79b, 0x15adf95, 0x2c944c3, 0x441c955, + 0x523c133, 0x33dabc5, 0x3166c49, 0x153d7fc, 0x043a528, 0x2827c47, 0x0316b73, 0x4094ceb, + 0x1e3e72a, 0x4488479, 0x529dabe, 0x0108ac9, 0x521fad4, 0x2ab1465, 0x592a237, 0x355ef43, + 0x53e2855, 0x434470f, 0x50535c9, 0x085a52e, 0x3310a48, 0x5286e73, 0x0cbfaed, 0x1c7605f, + 0x0ab46af, 0x1bf4323, 0x0e1b19f, 0x543ec0a, 0x0efafa4, 0x3e282d1, 0x45a3df7, 0x0de7887, + 0x5727149, 0x14ddc6e, 0x2d9357a, 0x188ad16, 0x0cb703b, 0x2e52285, 0x1e9f403, 0x2a967f1, + 0x26685c6, 0x0d3854c, 0x1b54a5f, 0x23eb3bf, 0x4dc6723, 0x3d1bc39, 0x4159e97, 0x3c6d4e5, + 0x464f25a, 0x3da03c2, 0x2cc16b8, 0x4879337, 0x01ecc85, 0x287edcd, 0x2b7c36c, 0x169a7f4, + 0x0a7fdc3, 0x2632163, 0x1f037ec, 0x2a38703, 0x0a8cb33, 0x55fb838, 0x4118c39, 0x5d7be76, + 0x2abcdd7, 0x0b8f660, 0x51e4922, 0x30cf4f3, 0x23796f8, 0x5a20206, 0x4ccf6c5, 0x03dbc1f, + 0x08135e2, 0x29fc975, 0x40fbd7d, 0x5eb25cc, 0x1c61aad, 0x267d3fb, 0x0d7b4c3, 0x3e02712, + 0x2257ede, 0x061b564, 0x0cd6093, 0x306b7e5, 0x02ff7ae, 0x330698f, 0x3a6ddc5, 0x234a4ce, + 0x3d770a4, 0x3a1035f, 0x5b6c738, 0x18ff11c, 0x1855aa8, 0x25e9604, 0x24fcf2b, 0x15e797b, + 0x05d08cc, 0x595b8b7, 0x24fbe23, 0x4953093, 0x020b995, 0x56a3e13, 0x3e44824, 0x3d8b856, + 0x0088183, 0x00137f2, 0x206eaa5, 0x5c6c443, 0x1ce930c, 0x52b9af0, 0x35cf161, 0x22dcbc0, + 0x12551e2, 0x27c4ed1, 0x502c053, 0x30ba1ea, 0x1f0cfc8, 0x0ade342, 0x1e809c4, 0x2c16cd4, + 0x01a16d6, 0x5134dc7, 0x365f631, 0x49663f6, 0x5a1f534, 0x445631a, 0x401dcaa, 0x05e1fdf, + 0x0e1cd13, 0x19bc6ad, 0x1bb3a67, 0x0b69d07, 0x25504ef, 0x255ce54, 0x524528f, 0x1b2830b, + 0x55aff20, 0x371c983, 0x3e5afea, 0x539a4a4, 0x53ca3c3, 0x20972aa, 0x125f078, 0x5827943, + 0x3c36a0a, 0x53e99fa, 0x3aad984, 0x061ce17, 0x16854d2, 0x26a6271, 0x0d62703, 0x033bd36, + 0x458a391, 0x5771431, 0x0b79aa6, 0x2138864, 0x5b95d65, 0x05856f6, 0x49e1466, 0x4827581, + 0x3618bc3, 0x29c476b, 0x51ee30e, 0x1b083de, 0x4009844, 0x26c8a8f, 0x0c797ca, 0x1dcf718, + 0x1e03b18, 0x4587e26, 0x2ca13a8, 0x5d35f1e, 0x4b30d73, 0x56962db, 0x12caac0, 0x116ec83, + 0x5b27ef7, 0x4beb901, 0x0b0b2de, 0x3cd901b, 0x19c65e8, 0x49b0ae2, 0x505d01e, 0x124df03, + 0x0e25ff4, 0x2b6d404, 0x5c6cdce, 0x4378b96, 0x207b94f, 0x4c27e51, 0x110a570, 0x4a40b76, + 0x51c5256, 0x40a315e, 0x0f976d2, 0x36d709a, 0x5bf59ab, 0x0212573, 0x0256866, 0x47512f4, + 0x5456ac4, 0x3897f74, 0x0ca43b3, 0x16dea74, 0x35ea0cb, 0x3661bcc, 0x5e9a40b, 0x1ef26f8, + 0x559c344, 0x1b8febd, 0x427e49d, 0x4c66d7f, 0x12a98a6, 0x2d6a870, 0x2431dbd, 0x41004a3, + 0x0e23bed, 0x024b3a8, 0x444f48a, 0x437d720, 0x02baa10, 0x4c2b783, 0x48ea0f7, 0x227d439, + 0x0621084, 0x0aee308, 0x1ae97a3, 0x28c9518, 0x5d0d5c7, 0x54926e8, 0x4ac901c, 0x37b1047, + 0x538c2aa, 0x4683d0b, 0x04605cc, 0x172775e, 0x2ded039, 0x40727a3, 0x287c320, 0x18bb9ae, + 0x3f6417e, 0x1e055cf, 0x0192b69, 0x3cdc0a2, 0x5dae3d4, 0x2d29b61, 0x46c938b, 0x2abe054, + 0x2f8a9e1, 0x5ea887a, 0x328f3e5, 0x2321633, 0x46d83e0, 0x340548a, 0x00d1e3b, 0x4958684, + 0x57e672f, 0x54d7339, 0x09a8657, 0x4695a46, 0x1c9413e, 0x50a6a29, 0x525907c, 0x53b2ac6, + 0x34e71a5, 0x20a0b2d, 0x527907a, 0x183d3bd, 0x4073f63, 0x0720a4b, 0x2c136c1, 0x2995c6d, + 0x1983eed, 0x24b8991, 0x3e99841, 0x34f936a, 0x4fdacc8, 0x5703481, 0x308cdf4, 0x05970b7, + 0x048e445, 0x11e7696, 0x57782fc, 0x1dfa9d5, 0x4b11fe0, 0x39571dc, 0x45b39ea, 0x395e54f, + 0x2156793, 0x1db35dc, 0x0f0c42d, 0x5d80f25, 0x0e8d5e6, 0x04ea51c, 0x359854e, 0x05137c4, + 0x291d1ca, 0x4428117, 0x0e5eac1, 0x5dc7ccd, 0x19d5b30, 0x388f5a0, 0x18ac461, 0x30dcdfa, + 0x4ff81f8, 0x304cbef, 0x2030d70, 0x5a1ecf4, 0x5322a97, 0x1fa8c51, 0x0f23a48, 0x1d00e0f, + 0x2c8164f, 0x218a3db, 0x12af397, 0x35b8e2d, 0x5171385, 0x4f760ad, 0x3ea4b70, 0x13d03d8, + 0x537821b, 0x326c437, 0x3261acc, 0x2d46169, 0x15ffcd8, 0x57da404, 0x3890abd, 0x1c37f56, + 0x0b5f501, 0x4d2aed8, 0x25bd90f, 0x2c8c374, 0x111eb3a, 0x40ff3c2, 0x4de340b, 0x296364f, + 0x4d1b855, 0x19ff471, 0x24082cd, 0x4025ce6, 0x0ea9fab, 0x509ac5b, 0x15d3fa4, 0x36bbfbd, + 0x4ac85ad, 0x5a5cedf, 0x1020e20, 0x58f9071, 0x4d034b0, 0x333f9de, 0x30b54fd, 0x5a0176a, + 0x465947b, 0x4e116de, 0x06a276a, 0x5d510e3, 0x32a4a06, 0x5bacd21, 0x4d4a403, 0x02d07b3, + 0x24d3f52, 0x1b07c22, 0x528f034, 0x5ad7848, 0x5a9f97a, 0x5641fa8, 0x3fe32da, 0x1dcd5fa, + 0x4ed0b7f, 0x1c6d056, 0x482b44f, 0x2969433, 0x55c41e0, 0x291bf43, 0x47e309a, 0x38dc816, + 0x1416c58, 0x2d622fc, 0x3ec5d7a, 0x52afe0a, 0x26e9481, 0x551acb7, 0x38c05f6, 0x2d9276e, + 0x04eacde, 0x33d5fa4, 0x29a47f9, 0x233432f, 0x46a81a3, 0x44a3665, 0x327ba24, 0x0e8342f, + 0x42ff42e, 0x4d09768, 0x1538472, 0x12670fa, 0x52df07f, 0x259ab5c, 0x2740731, 0x216d8b8, + 0x2bfb56b, 0x0147e66, 0x3d417e2, 0x460847a, 0x493892d, 0x3525e21, 0x456b259, 0x06cd366, + 0x4b43ea3, 0x0efd4b9, 0x3edba39, 0x15fe640, 0x5a28437, 0x2518256, 0x57540a3, 0x3d4c899, + 0x5a563fe, 0x2768e38, 0x25c4cb7, 0x2a5e588, 0x0fed8e2, 0x083e6fa, 0x3a52799, 0x3787539, + 0x3898ca0, 0x4ef2a91, 0x42464f2, 0x3196c28, 0x172ed53, 0x5b3ff4b, 0x3e8d236, 0x50d2d57, + 0x081d29d, 0x3c9779e, 0x2879e0c, 0x0ec128c, 0x388d328, 0x487b8b7, 0x274fbf6, 0x0cc9a8b, + 0x4aae646, 0x366279f, 0x4a42c11, 0x2d5e946, 0x25ecfa4, 0x378ac19, 0x168efa0, 0x2ce0bfd, + 0x2a8780c, 0x58afbda, 0x3943c1c, 0x2724574, 0x122c376, 0x5c1ab52, 0x11a2e77, 0x50c4d52, + 0x3385243, 0x586051b, 0x47261e7, 0x554e19d, 0x4c65bf5, 0x3001ae3, 0x3b31b73, 0x32500ae, + 0x4304d03, 0x0a22b6b, 0x1d70fd6, 0x4ab181b, 0x231f9d5, 0x46f877c, 0x31343fa, 0x538e0d6, + 0x330ec82, 0x3ceed30, 0x0956707, 0x49019a3, 0x55cd1ae, 0x3a0361e, 0x40d9ebb, 0x1cac32b, + 0x3be11eb, 0x34a420b, 0x2570256, 0x0d84afc, 0x06ecd81, 0x4f26160, 0x326b9c9, 0x10821ed, + 0x5282774, 0x3c78ecd, 0x0498110, 0x23958c2, 0x33e2753, 0x1261346, 0x29f6e90, 0x315ae66, + 0x2a07fc8, 0x4c4f089, 0x3d19cc5, 0x31f92f9, 0x440c6de, 0x1f27e85, 0x59a304d, 0x14aa689, + 0x0f23824, 0x4a2a23f, 0x2d0601b, 0x30ba52a, 0x4927192, 0x00b3915, 0x10d7486, 0x15d216c, + 0x03dda7a, 0x4dc8c20, 0x4da9f00, 0x2117e24, 0x558c0cc, 0x58117b8, 0x43eca20, 0x553d0af, + 0x16741bc, 0x1e60276, 0x3b2ff43, 0x273096d, 0x4934aca, 0x18e9ad3, 0x15cf83e, 0x195b627, + 0x4847c69, 0x5b49c49, 0x27d812e, 0x043b6b7, 0x2a46387, 0x55f0098, 0x0353bcc, 0x2d0de38, + 0x29ec39d, 0x4763cb6, 0x52b5241, 0x3b0d944, 0x27b229a, 0x168ad32, 0x466bf49, 0x3b8fcf1, + 0x17fc250, 0x0b03fdd, 0x30850a3, 0x05bb286, 0x0a6e2da, 0x0398b01, 0x221d110, 0x02c79ba, + 0x11b044f, 0x1545631, 0x530c341, 0x5dcb7b5, 0x3394942, 0x5b77119, 0x4e7084e, 0x5b801b3, + 0x36118f6, 0x17071bc, 0x07cbd40, 0x42fc53f, 0x08cd0b7, 0x4e1cfa0, 0x12ec1e1, 0x3015c85, + 0x2c7de50, 0x00f4d03, 0x128da75, 0x587704e, 0x16fedec, 0x093b36e, 0x5d9a07b, 0x4839429, + 0x0361826, 0x52ea158, 0x40255cd, 0x4f76348, 0x45de566, 0x48e2c51, 0x0064139, 0x5309d4d, + 0x35d6002, 0x44b7e63, 0x1acad14, 0x06ebd6d, 0x54e5f19, 0x2bc4bba, 0x35d6786, 0x49f735f, + 0x3a67551, 0x2f3dfb6, 0x05d44a1, 0x50fe526, 0x294c76e, 0x222b45b, 0x28c841b, 0x045268a, + 0x4e5ad43, 0x54ffc69, 0x219fdb7, 0x3e04c0d, 0x4d83db5, 0x081921b, 0x35878d2, 0x3329e6b, + 0x098295a, 0x0866016, 0x3e8a941, 0x1250c38, 0x1b5cde1, 0x59360c8, 0x21a5d85, 0x11f9c5f, + 0x15e3aa5, 0x49a6b1b, 0x4260739, 0x186a7d3, 0x51983a3, 0x17e7ff6, 0x07df71b, 0x093f52d, + 0x40f8ab4, 0x0fb318e, 0x2e5cbae, 0x5ac9f99, 0x200d1ac, 0x3e21d2a, 0x2202dbd, 0x4da67c7, + 0x2d7ae58, 0x3c93738, 0x403d5c3, 0x0ac3699, 0x5c8fd81, 0x1646d0f, 0x5f1f6bc, 0x256216a, + 0x4dc806d, 0x51a7d70, 0x4e7dd6e, 0x128b05e, 0x071724a, 0x3119b1b, 0x3a6fc0a, 0x07a1083, + 0x0d1024c, 0x3c56757, 0x342c083, 0x0017899, 0x59f172c, 0x1d74f5e, 0x45f8aa2, 0x4744052, + 0x0166f7c, 0x2f6c1c3, 0x4eae530, 0x57ffedf, 0x00ce5ec, 0x5b888d1, 0x12e66cb, 0x569baaa, + 0x46ea80c, 0x04d99d1, 0x5009617, 0x185de50, 0x2640b09, 0x4f89089, 0x4192255, 0x2b23b41, + 0x237b145, 0x47a377b, 0x0ad4901, 0x32d801d, 0x24e008d, 0x070cbb3, 0x09f7b55, 0x238ec31, + 0x2fa361b, 0x2833b0c, 0x3e00d62, 0x2dad01d, 0x1723989, 0x0ded4bf, 0x4934d43, 0x05ae7d3, + 0x56d8cbb, 0x47c3497, 0x27750c8, 0x009b45e, 0x284f2cf, 0x21867b5, 0x0eac841, 0x3543157, + 0x271560a, 0x20f123f, 0x3ba23ee, 0x58b0047, 0x38f68c9, 0x4d5db24, 0x092af5e, 0x4c15129, + 0x3f671c9, 0x4057dd2, 0x5dde9d9, 0x4e6e66e, 0x5f1978d, 0x19cbc09, 0x494e739, 0x57e54c0, + 0x224cf59, 0x22b7ca3, 0x23c0f39, 0x5750b32, 0x035b331, 0x5db41a9, 0x5c4a784, 0x3777d86, + 0x1ba2bfb, 0x22755b1, 0x27edc81, 0x31a29c6, 0x2ffacd6, 0x51734e3, 0x1999d44, 0x50e2193, + 0x3391493, 0x18f814b, 0x0683542, 0x25fc7b6, 0x48d5b31, 0x455c229, 0x2d5ceb7, 0x1b4c9be, + 0x239962e, 0x45a87f5, 0x36454eb, 0x37d31bd, 0x3e498e7, 0x4d75de6, 0x4a79100, 0x14338c5, + 0x284d55c, 0x1eb5be7, 0x3c68206, 0x2556629, 0x397a65a, 0x18ca4c8, 0x060c0f8, 0x446e66e, + 0x5d21fee, 0x3d5e055, 0x5079b8b, 0x0b88ee5, 0x2b68486, 0x50a7f20, 0x1b3a90e, 0x05d2c3d, + 0x4819c75, 0x4d64ad5, 0x09f9cc3, 0x3045dbe, 0x3ab4aee, 0x06c513a, 0x5a58422, 0x3f31cfe, + 0x2e60203, 0x406fd82, 0x1334b97, 0x1c81db1, 0x1202a5a, 0x39ba93e, 0x3e899b1, 0x5f58eb9, + 0x1952df1, 0x473a497, 0x47a87ae, 0x2452ae7, 0x0e81114, 0x44392dc, 0x502e357, 0x1e5ad2a, + 0x0081636, 0x1999402, 0x029b1ca, 0x5007c7b, 0x2751e59, 0x30cbd1b, 0x108cfca, 0x2f39609, + 0x1ea328f, 0x0fa840f, 0x42c3dba, 0x3d2c44a, 0x5a544c5, 0x5cb7504, 0x414c358, 0x1054b69, + 0x40b21d0, 0x485f2b7, 0x1202a8a, 0x003c004, 0x2b6598a, 0x0175c56, 0x411513c, 0x394453f, + 0x11cc0f8, 0x2badb3f, 0x524632b, 0x1717497, 0x21e79bf, 0x3648387, 0x20cf1a1, 0x4425693, + 0x1889cc3, 0x4cfcf42, 0x23e708b, 0x39eacd7, 0x0268682, 0x30fb9ba, 0x5dc45a1, 0x58b1b75, + 0x04e896a, 0x4c8b92f, 0x38e0208, 0x3df41e0, 0x0a97fdc, 0x1a719e0, 0x2ca1d99, 0x062c71a, + 0x0e3d4aa, 0x1fe5af4, 0x06bf441, 0x0c78267, 0x0425444, 0x1ff85c1, 0x3b49717, 0x269895b, + 0x0d845e2, 0x0f73789, 0x4e29cfc, 0x59df6b4, 0x402b9f4, 0x0da38dc, 0x03a1d23, 0x4921801, + 0x1d3dedd, 0x3b946b9, 0x5ccd907, 0x278cc66, 0x428c643, 0x4376283, 0x1d115ac, 0x33f5f25, + 0x3c44ac0, 0x59d6e54, 0x1557963, 0x27d3d85, 0x51625c1, 0x55e1843, 0x3b5b163, 0x0b00a35, + 0x2e414f6, 0x560051e, 0x24679d5, 0x57c650c, 0x1fc9933, 0x3bd37be, 0x23d4a94, 0x3d069b5, + 0x52ca23b, 0x3283409, 0x21ad173, 0x395f20e, 0x0f74ea4, 0x2d85d11, 0x420b7ee, 0x489402f, + 0x5ad2d63, 0x253f082, 0x4fb654e, 0x4ff1def, 0x24ef4e3, 0x386e491, 0x1cad437, 0x2cbeff2, + 0x5350173, 0x13295b1, 0x0499824, 0x320e59b, 0x30dca1f, 0x417c927, 0x5847c0b, 0x39aff79, + 0x40ced4d, 0x1eebd31, 0x3ccf91d, 0x05e7f9c, 0x4174c73, 0x1cc279f, 0x3580a53, 0x01cd2b4, + 0x10eb1ed, 0x423e5e1, 0x4309400, 0x016f6f6, 0x11b26a7, 0x216dedf, 0x33a3233, 0x506ca34, + 0x58efb2d, 0x3171694, 0x3fbd876, 0x452b332, 0x06a79c9, 0x4171e89, 0x20fa4a1, 0x037db91, + 0x5a35abb, 0x147e3f1, 0x2d4f374, 0x234e568, 0x19a4af1, 0x4ffcf2b, 0x3a408ad, 0x442d3e5 +}; + +#endif //HANDMADE_RANDOM_H diff --git a/code/linux_handmade.cpp b/code/linux_handmade.cpp new file mode 100644 index 0000000..2832ea6 --- /dev/null +++ b/code/linux_handmade.cpp @@ -0,0 +1,1236 @@ +#include <stdio.h> +#include <time.h> +#include <x86intrin.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> + +#include <signal.h> +#include <linux/limits.h> +#include <linux/input.h> +#include <alsa/asoundlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysymdef.h> +#include <X11/extensions/Xrandr.h> + +#include "handmade_platform.h" +#include "linux_handmade.h" + +#define true 1 +#define false 0 + +#define MAX_PLAYER_COUNT 4 + +#ifdef Assert +#undef Assert +#define Assert(Expression) \ +if(!(Expression)) \ +{ \ +raise(SIGTRAP); \ +} +#endif + +// NOTE(luca): Bits are layed out over multiple bytes. This macro checks which byte the bit will be set in. +#define IsEvdevBitSet(Bit, Array) (Array[(Bit) / 8] & (1 << ((Bit) % 8))) +#define BytesNeededForBits(Bits) ((Bits + 7) / 8) + +global_variable b32 GlobalRunning; +global_variable b32 GlobalPaused; + +void MemCpy(char *Dest, char *Source, size_t Count) +{ + while(Count--) *Dest++ = *Source++; + +} + +void MemSet(char *Dest, char Value, size_t Count) +{ + while(Count--) *Dest++ = Value; +} + +int StrLen(char *String) +{ + size_t Result = 0; + + while(*String++) Result++; + + return Result; +} + +void CatStrings(size_t SourceACount, char *SourceA, + size_t SourceBCount, char *SourceB, + size_t DestCount, char *Dest) +{ + for(size_t Index = 0; + Index < SourceACount; + Index++) + { + *Dest++ = *SourceA++; + } + + for(size_t Index = 0; + Index < SourceBCount; + Index++) + { + *Dest++ = *SourceB++; + } +} + +struct linux_init_alsa_result +{ + snd_pcm_t *PCMHandle; + snd_pcm_hw_params_t *PCMParams; +}; + +internal linux_init_alsa_result LinuxInitALSA() +{ + linux_init_alsa_result Result = {}; + + int PCMResult = 0; + if((PCMResult = snd_pcm_open(&Result.PCMHandle, "default", + SND_PCM_STREAM_PLAYBACK, 0)) == 0) + { + snd_pcm_hw_params_alloca(&Result.PCMParams); + snd_pcm_hw_params_any(Result.PCMHandle, Result.PCMParams); + u32 ChannelCount = 2; + u32 SampleRate = 48000; + + if((PCMResult = snd_pcm_hw_params_set_access(Result.PCMHandle, Result.PCMParams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + { + // TODO(luca): Logging + // snd_strerror(pcm) + } + if((PCMResult = snd_pcm_hw_params_set_format(Result.PCMHandle, Result.PCMParams, SND_PCM_FORMAT_S16_LE)) < 0) + { + // TODO(luca): Logging + } + if((PCMResult = snd_pcm_hw_params_set_channels(Result.PCMHandle, Result.PCMParams, ChannelCount)) < 0) + { + // TODO(luca): Logging + } + if((PCMResult = snd_pcm_hw_params_set_rate_near(Result.PCMHandle, Result.PCMParams, &SampleRate, 0)) < 0) + { + // TODO(luca): Logging + } + if((PCMResult = snd_pcm_nonblock(Result.PCMHandle, 1)) < 0) + { + // TODO(luca): Logging + } + if((PCMResult = snd_pcm_reset(Result.PCMHandle)) < 0) + { + // TODO(luca): Logging + } + if((PCMResult = snd_pcm_hw_params(Result.PCMHandle, Result.PCMParams)) < 0) + { + // TODO(luca): Logging + } + + } + else + { + // TODO(luca): Logging + } + + return Result; +} + +internal void LinuxGetAxisInfo(linux_gamepad *GamePad, linux_gamepad_axes_enum Axis, int AbsAxis) +{ + input_absinfo AxesInfo = {}; + if(ioctl(GamePad->File, EVIOCGABS(AbsAxis), &AxesInfo) != -1) + { + GamePad->Axes[Axis].Minimum = AxesInfo.minimum; + GamePad->Axes[Axis].Maximum = AxesInfo.maximum; + GamePad->Axes[Axis].Fuzz = AxesInfo.fuzz; + GamePad->Axes[Axis].Flat = AxesInfo.flat; + } +} + +internal void LinuxOpenGamePad(char *FilePath, linux_gamepad *GamePad) +{ + GamePad->File = open(FilePath, O_RDWR|O_NONBLOCK); + + if(GamePad->File != -1) + { + int Version = 0; + int IsCompatible = true; + + // TODO(luca): Check versions + ioctl(GamePad->File, EVIOCGVERSION, &Version); + ioctl(GamePad->File, EVIOCGNAME(sizeof(GamePad->Name)), GamePad->Name); + + char SupportedEventBits[BytesNeededForBits(EV_MAX)] = {}; + if(ioctl(GamePad->File, EVIOCGBIT(0, sizeof(SupportedEventBits)), SupportedEventBits) != -1) + { + if(!IsEvdevBitSet(EV_ABS, SupportedEventBits)) + { + // TODO(luca): Logging + IsCompatible = false; + } + if(!IsEvdevBitSet(EV_KEY, SupportedEventBits)) + { + // TODO(luca): Logging + IsCompatible = false; + } + } + + char SupportedKeyBits[BytesNeededForBits(KEY_MAX)] = {}; + if(ioctl(GamePad->File, EVIOCGBIT(EV_KEY , sizeof(SupportedKeyBits)), SupportedKeyBits) != -1) + { + if(!IsEvdevBitSet(BTN_GAMEPAD, SupportedKeyBits)) + { + // TODO(luca): Logging + IsCompatible = false; + } + } + + GamePad->SupportsRumble = IsEvdevBitSet(EV_FF, SupportedEventBits); + + if(IsCompatible) + { + // NOTE(luca): Map evdev axes to my enum. + LinuxGetAxisInfo(GamePad, LSTICKX, ABS_X); + LinuxGetAxisInfo(GamePad, LSTICKY, ABS_Y); + LinuxGetAxisInfo(GamePad, RSTICKX, ABS_RX); + LinuxGetAxisInfo(GamePad, RSTICKY, ABS_RY); + LinuxGetAxisInfo(GamePad, LSHOULDER, ABS_Z); + LinuxGetAxisInfo(GamePad, RSHOULDER, ABS_RZ); + LinuxGetAxisInfo(GamePad, DPADX, ABS_HAT0X); + LinuxGetAxisInfo(GamePad, DPADY, ABS_HAT0Y); + + MemCpy(GamePad->FilePath, FilePath, StrLen(FilePath)); + } + else + { + close(GamePad->File); + *GamePad = {}; + GamePad->File = -1; + } + } +} + +// TODO(luca): Make this work in the case of multiple displays. +internal r32 LinuxGetMonitorRefreshRate(Display *DisplayHandle, Window RootWindow) +{ + r32 Result = 0; + + void *LibraryHandle = dlopen("libXrandr.so.2", RTLD_NOW); + + if(LibraryHandle) + { + typedef XRRScreenResources *xrr_get_screen_resources(Display *Display, Window Window); + typedef XRRCrtcInfo *xrr_get_crtc_info(Display* Display, XRRScreenResources *Resources, RRCrtc Crtc); + + xrr_get_screen_resources *XRRGetScreenResources = (xrr_get_screen_resources *)dlsym(LibraryHandle, "XRRGetScreenResources"); + xrr_get_crtc_info *XRRGetCrtcInfo = (xrr_get_crtc_info *)dlsym(LibraryHandle, "XRRGetCrtcInfo"); + + XRRScreenResources *ScreenResources = XRRGetScreenResources(DisplayHandle, RootWindow); + + RRMode ActiveModeID = 0; + for(int CRTCIndex = 0; + CRTCIndex< ScreenResources->ncrtc; + CRTCIndex++) + { + XRRCrtcInfo *CRTCInfo = XRRGetCrtcInfo(DisplayHandle, ScreenResources, ScreenResources->crtcs[CRTCIndex]); + if(CRTCInfo->mode) + { + ActiveModeID = CRTCInfo->mode; + } + } + + r32 ActiveRate = 0; + for(int ModeIndex = 0; + ModeIndex < ScreenResources->nmode; + ModeIndex++) + { + XRRModeInfo ModeInfo = ScreenResources->modes[ModeIndex]; + if(ModeInfo.id == ActiveModeID) + { + Assert(ActiveRate == 0); + Result = (r32)ModeInfo.dotClock / ((r32)ModeInfo.hTotal * (r32)ModeInfo.vTotal); + } + } + + dlclose(LibraryHandle); + } + + return Result; +} + +internal void LinuxBuildFileNameFromExecutable(char *Dest, linux_state *State, char *FileName) +{ + char *Path = State->ExecutablePath; + + size_t LastSlash = 0; + for(char *Scan = Path; + *Scan; + Scan++) + { + if(*Scan == '/') + { + LastSlash = Scan - Path; + } + } + + for(size_t Index = 0; + Index < LastSlash + 1; + Index++) + { + *Dest++ = *Path++; + } + + while(*FileName) + *Dest++ = *FileName++; +} + +GAME_UPDATE_AND_RENDER(LinuxGameUpdateAndRenderStub) {} +GAME_GET_SOUND_SAMPLES(LinuxGameGetSoundSamplesStub) {} + +internal linux_game_code LinuxLoadGameCode(char *LibraryPath) +{ + linux_game_code Result = {}; + + Result.LibraryHandle = dlopen(LibraryPath, RTLD_NOW); + if(Result.LibraryHandle) + { + Result.UpdateAndRender = (game_update_and_render *)dlsym(Result.LibraryHandle, "GameUpdateAndRender"); + Result.GetSoundSamples = (game_get_sound_samples *)dlsym(Result.LibraryHandle, "GameGetSoundSamples"); + } + else + { + Result.UpdateAndRender = (game_update_and_render *)LinuxGameUpdateAndRenderStub; + Result.GetSoundSamples = (game_get_sound_samples *)LinuxGameGetSoundSamplesStub; + } + + return Result; +} + +internal void LinuxUnloadGameCode(linux_game_code *Game) +{ + if(Game->LibraryHandle) + { + dlclose(Game->LibraryHandle); + } +} + +internal void LinuxProcessKeyPress(game_button_state *ButtonState, b32 IsDown) +{ + if(ButtonState->EndedDown != IsDown) + { + ButtonState->EndedDown = IsDown; + ButtonState->HalfTransitionCount++; + } +} + +internal void LinuxBeginRecordingInput(linux_state *State, int SlotIndex) +{ + char Temp[64]; + sprintf(Temp, "loop_edit_%d.hmi", SlotIndex); + char FileName[PATH_MAX] = {}; + LinuxBuildFileNameFromExecutable(FileName, State, Temp); + + int File = open(FileName, O_WRONLY|O_CREAT|O_TRUNC|O_APPEND, 0600); + if(State->InputRecordingFile != -1) + { + int BytesWritten = write(File, State->GameMemoryBlock, State->TotalSize); + if(BytesWritten != -1 && + BytesWritten == (int)State->TotalSize) + { + State->InputRecordingFile = File; + State->InputRecordingIndex = SlotIndex; + } + else + { + // TODO(luca): Logging + } + } + else + { + // TODO(luca): Logging + } + +} + +internal void LinuxEndRecordingInput(linux_state *State, int SlotIndex) +{ + Assert(State->InputRecordingIndex); + Assert(State->InputRecordingFile != -1); + + State->InputRecordingIndex = 0; + + if(close(State->InputRecordingFile) == -1) + { + State->InputRecordingFile = -1; + } + else + { + // TODO(luca): Logging + } + +} + +internal void LinuxBeginInputPlayBack(linux_state *State, int SlotIndex) +{ + char Temp[64]; + sprintf(Temp, "loop_edit_%d.hmi", SlotIndex); + char FileName[PATH_MAX] = {}; + LinuxBuildFileNameFromExecutable(FileName, State, Temp); + + int File = open(FileName, O_RDONLY, 0400); + if(File != -1) + { + State->InputPlayingFile = File; + + int BytesRead = read(State->InputPlayingFile, State->GameMemoryBlock, State->TotalSize); + if(BytesRead != -1) + { + State->InputPlayingIndex = SlotIndex; + } + else + { + // TODO(luca): Logging + } + } + else + { + // TODO(luca): Logging + } + +} + +internal void LinuxEndInputPlayBack(linux_state *State) +{ + Assert(State->InputPlayingIndex); + Assert(State->InputPlayingFile != -1); + + if(close(State->InputPlayingFile) != -1) + { + State->InputPlayingFile = -1; + } + else + { + // TODO(luca): Logging + } + + State->InputPlayingIndex = 0; + +} + +internal void LinuxRecordInput(linux_state *State, game_input *Input) +{ + int BytesWritten = write(State->InputRecordingFile, Input, sizeof(*Input)); + if(BytesWritten != -1 && + BytesWritten == (int)sizeof(*Input)) + { + } + else + { + // TODO: Logging + } + +} + +internal void LinuxPlayBackInput(linux_state *State, game_input *Input) +{ + int BytesRead = read(State->InputPlayingFile, Input, sizeof(*Input)); + if(BytesRead != -1) + { + if(BytesRead == 0) + { + int PlayingIndex = State->InputPlayingIndex; + LinuxEndInputPlayBack(State); + LinuxBeginInputPlayBack(State, PlayingIndex); + read(State->InputPlayingFile, Input, sizeof(*Input)); + } + } + +} + +internal void LinuxHideCursor(Display *DisplayHandle, Window WindowHandle) +{ + XColor black = {}; + char NoData[8] = {}; + + Pixmap BitmapNoData = XCreateBitmapFromData(DisplayHandle, WindowHandle, NoData, 8, 8); + Cursor InvisibleCursor = XCreatePixmapCursor(DisplayHandle, BitmapNoData, BitmapNoData, + &black, &black, 0, 0); + XDefineCursor(DisplayHandle, WindowHandle, InvisibleCursor); + XFreeCursor(DisplayHandle, InvisibleCursor); + XFreePixmap(DisplayHandle, BitmapNoData); +} + +internal void LinuxShowCursor(Display *DisplayHandle, Window WindowHandle) +{ + XUndefineCursor(DisplayHandle, WindowHandle); +} + +internal void LinuxProcessPendingMessages(Display *DisplayHandle, Window WindowHandle, + Atom WM_DELETE_WINDOW, linux_state *State, game_controller_input *KeyboardController) +{ + XEvent WindowEvent = {}; + while(XPending(DisplayHandle) > 0) + { + XNextEvent(DisplayHandle, &WindowEvent); + switch (WindowEvent.type) + { + case KeyPress: + case KeyRelease: + { + KeySym Symbol = XLookupKeysym(&WindowEvent.xkey, 0); + b32 IsDown = (WindowEvent.type == KeyPress); + + if(0) {} + else if(Symbol == XK_w) + { + LinuxProcessKeyPress(&KeyboardController->MoveUp, IsDown); + } + else if(Symbol == XK_a) + { + LinuxProcessKeyPress(&KeyboardController->MoveLeft, IsDown); + } + else if(Symbol == XK_r) + { + LinuxProcessKeyPress(&KeyboardController->MoveDown, IsDown); + } + else if(Symbol == XK_s) + { + LinuxProcessKeyPress(&KeyboardController->MoveRight, IsDown); + } + else if(Symbol == XK_Up) + { + LinuxProcessKeyPress(&KeyboardController->ActionUp, IsDown); + } + else if(Symbol == XK_Left) + { + LinuxProcessKeyPress(&KeyboardController->ActionLeft, IsDown); + } + else if(Symbol == XK_Down) + { + LinuxProcessKeyPress(&KeyboardController->ActionDown, IsDown); + } + else if(Symbol == XK_Right) + { + LinuxProcessKeyPress(&KeyboardController->ActionRight, IsDown); + } + else if(Symbol == XK_p) + { + if(IsDown) + { + GlobalPaused = !GlobalPaused; + } + } + else if(Symbol == XK_l) + { + if(IsDown) + { + if(State->InputPlayingIndex == 0) + { + if(State->InputRecordingIndex == 0) + { + LinuxBeginRecordingInput(State, 1); + } + else + { + LinuxEndRecordingInput(State, 1); + LinuxBeginInputPlayBack(State, 1); + } + } + else + { + // TODO(luca): Reset buttons so they aren't held? + for(u32 ButtonIndex = 0; + ButtonIndex < ArrayCount(KeyboardController->Buttons); + ButtonIndex++) + { + KeyboardController->Buttons[ButtonIndex] = {}; + } + LinuxEndInputPlayBack(State); + } + } + } + else if(Symbol == XK_Escape || + Symbol == XK_q) + { + GlobalRunning = false; + } + + } break; + case DestroyNotify: + { + XDestroyWindowEvent *Event = (XDestroyWindowEvent *)&WindowEvent; + if(Event->window == WindowHandle) + { + GlobalRunning = false; + } + } break; + + case ClientMessage: + { + XClientMessageEvent *Event = (XClientMessageEvent *)&WindowEvent; + if((Atom)Event->data.l[0] == WM_DELETE_WINDOW) + { + XDestroyWindow(DisplayHandle, WindowHandle); + GlobalRunning = false; + } + } break; + + case EnterNotify: + { + //LinuxHideCursor(DisplayHandle, WindowHandle); + } break; + + case LeaveNotify: + { + //LinuxShowCursor(DisplayHandle, WindowHandle); + } break; + + } + + } + +} + +internal void LinuxSetSizeHint(Display *DisplayHandle, Window WindowHandle, + int MinWidth, int MinHeight, + int MaxWidth, int MaxHeight) +{ + XSizeHints Hints = {}; + if(MinWidth > 0 && MinHeight > 0) Hints.flags |= PMinSize; + if(MaxWidth > 0 && MaxHeight > 0) Hints.flags |= PMaxSize; + + Hints.min_width = MinWidth; + Hints.min_height = MinHeight; + Hints.max_width = MaxWidth; + Hints.max_height = MaxHeight; + + XSetWMNormalHints(DisplayHandle, WindowHandle, &Hints); +} + +DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile) +{ + debug_read_file_result Result = {}; + + int File = open(FileName, O_RDONLY); + if(File != -1) + { + struct stat FileStats = {}; + fstat(File, &FileStats); + Result.ContentsSize = FileStats.st_size; + Result.Contents = mmap(0, FileStats.st_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, File, 0); + + close(File); + } + + return Result; +} + +DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory) +{ + munmap(Memory, MemorySize); +} + +DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteEntireFile) +{ + b32 Result = false; + + int FD = open(FileName, O_CREAT|O_WRONLY|O_TRUNC, 00600); + if(FD != -1) + { + if(write(FD, Memory, MemorySize) != MemorySize) + { + Result = true; + } + + close(FD); + } + + return Result; +} + +internal struct timespec LinuxGetLastWriteTime(char *FilePath) +{ + struct timespec Result = {}; + + struct stat LibraryFileStats = {}; + if(!stat(FilePath, &LibraryFileStats)) + { + Result = LibraryFileStats.st_mtim; + } + + return Result; +} + +internal struct timespec LinuxGetWallClock() +{ + struct timespec Counter = {}; + clock_gettime(CLOCK_MONOTONIC, &Counter); + return Counter; +} + +internal s64 LinuxGetNSecondsElapsed(struct timespec Start, struct timespec End) +{ + s64 Result = 0; + Result = ((s64)End.tv_sec*1000000000 + (s64)End.tv_nsec) - ((s64)Start.tv_sec*1000000000 + (s64)Start.tv_nsec); + return Result; +} + +internal r32 LinuxGetSecondsElapsed(struct timespec Start, struct timespec End) +{ + r32 Result = 0; + Result = LinuxGetNSecondsElapsed(Start, End)/1000.0f/1000.0f/1000.0f; + + return Result; +} + +internal r32 LinuxNormalizeAxisValue(s32 Value, linux_gamepad_axis Axis) +{ + r32 Result = 0; + if(Value) + { + // ((value - min / max) - 0.5) * 2 + r32 Normalized = ((r32)((r32)(Value - Axis.Minimum) / (r32)(Axis.Maximum - Axis.Minimum)) - 0.5f)*2; + Result = Normalized; + } + Assert(Result <= 1.0f && Result >= -1.0f); + + return Result; +} + +void LinuxDebugVerticalLine(game_offscreen_buffer *Buffer, int X, int Y, u32 Color) +{ + int Height = 32; + + if(X <= Buffer->Width && X >= 0 && + Y <= Buffer->Height - Height && Y <= 0) + { + u8 *Row = (u8 *)Buffer->Memory + Y*Buffer->Pitch + X*Buffer->BytesPerPixel; + while(Height--) + { + *(u32 *)Row = Color; + Row += Buffer->Pitch; + } + } +} + +int main(int ArgC, char *Args[]) +{ + Display *DisplayHandle = XOpenDisplay(0); + + if(DisplayHandle) + { + Window RootWindow = XDefaultRootWindow(DisplayHandle); + int Screen = XDefaultScreen(DisplayHandle); + int Width = 1920/2; + int Height = 1080/2; + int ScreenBitDepth = 24; + XVisualInfo WindowVisualInfo = {}; + if(XMatchVisualInfo(DisplayHandle, Screen, ScreenBitDepth, TrueColor, &WindowVisualInfo)) + { + XSetWindowAttributes WindowAttributes = {}; + WindowAttributes.bit_gravity = StaticGravity; + WindowAttributes.background_pixel = 0xFF00FF; + WindowAttributes.colormap = XCreateColormap(DisplayHandle, RootWindow, WindowVisualInfo.visual, AllocNone); + WindowAttributes.event_mask = (StructureNotifyMask | + KeyPressMask | KeyReleaseMask | + EnterWindowMask | LeaveWindowMask); + u64 WindowAttributeMask = CWBitGravity | CWBackPixel | CWColormap | CWEventMask; + + Window WindowHandle = XCreateWindow(DisplayHandle, RootWindow, + 1920 - Width - 10, 1080 - Height - 10, + Width, Height, + 0, + WindowVisualInfo.depth, InputOutput, + WindowVisualInfo.visual, WindowAttributeMask, &WindowAttributes); + if(WindowHandle) + { + XStoreName(DisplayHandle, WindowHandle, "Handmade Window"); + LinuxSetSizeHint(DisplayHandle, WindowHandle, Width, Height, Width, Height); + + Atom WM_DELETE_WINDOW = XInternAtom(DisplayHandle, "WM_DELETE_WINDOW", False); + if(!XSetWMProtocols(DisplayHandle, WindowHandle, &WM_DELETE_WINDOW, 1)) + { + // TODO(luca): Logging + } + + XClassHint ClassHint = {}; + ClassHint.res_name = "Handmade Window"; + ClassHint.res_class = "Handmade Window"; + XSetClassHint(DisplayHandle, WindowHandle, &ClassHint); + + int BitsPerPixel = 32; + int BytesPerPixel = BitsPerPixel/8; + int WindowBufferSize = Width*Height*BytesPerPixel; + char *WindowBuffer = (char *)malloc(WindowBufferSize); + + XImage *WindowImage = XCreateImage(DisplayHandle, WindowVisualInfo.visual, WindowVisualInfo.depth, ZPixmap, 0, WindowBuffer, Width, Height, BitsPerPixel, 0); + GC DefaultGC = DefaultGC(DisplayHandle, Screen); + + + linux_state LinuxState = {}; + MemCpy(LinuxState.ExecutablePath, Args[0], strlen(Args[0])); + + char LibraryFullPath[PATH_MAX] = {}; + char LibraryName[] = "handmade.so"; + LinuxBuildFileNameFromExecutable(LibraryFullPath, &LinuxState, LibraryName); + linux_game_code Game = LinuxLoadGameCode(LibraryFullPath); + Game.LibraryLastWriteTime = LinuxGetLastWriteTime(LibraryFullPath); + + game_memory GameMemory = {}; + + GameMemory.PermanentStorageSize = Megabytes(64); + GameMemory.TransientStorageSize = Gigabytes(1); + GameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile; + GameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory; + GameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile; + +#if HANDMADE_INTERNAL + void *BaseAddress = (void *)Terabytes(2); +#else + void *BaseAddress = 0; +#endif + + // TODO(casey): TransientStorage needs to be broken into game transient and cache transient + LinuxState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; + LinuxState.GameMemoryBlock = mmap(BaseAddress, LinuxState.TotalSize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); + GameMemory.PermanentStorage = LinuxState.GameMemoryBlock; + GameMemory.TransientStorage = (u8 *)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize; + + game_input Input[2] = {}; + game_input *NewInput = &Input[0]; + game_input *OldInput = &Input[1]; + + linux_gamepad GamePads[MAX_PLAYER_COUNT] = {}; + for(int GamePadIndex = 0; + GamePadIndex < MAX_PLAYER_COUNT; + GamePadIndex++) + { + GamePads[GamePadIndex].File = -1; + } + + char EventDirectoryName[] = "/dev/input/"; + DIR *EventDirectory = opendir(EventDirectoryName); + struct dirent *Entry = 0; + int GamePadIndex = 0; + while((Entry = readdir(EventDirectory))) + { + if(!strncmp(Entry->d_name, "event", sizeof("event") - 1)) + { + char FilePath[PATH_MAX] = {}; + CatStrings(sizeof(EventDirectoryName) - 1, EventDirectoryName, + StrLen(Entry->d_name), Entry->d_name, + sizeof(FilePath) - 1, FilePath); + if(GamePadIndex < MAX_PLAYER_COUNT) + { + linux_gamepad *GamePadAt = &GamePads[GamePadIndex]; + LinuxOpenGamePad(FilePath, GamePadAt); + if(GamePadAt->File != -1) + { +#if 0 + for(int AxesIndex = 0; + AxesIndex < AXES_COUNT; + AxesIndex++) + { + linux_gamepad_axis Axis = GamePadAt->Axes[AxesIndex]; + printf("min: %d, max: %d, fuzz: %d, flat: %d\n", Axis.Minimum, Axis.Maximum, Axis.Fuzz, Axis.Flat); + } +#endif + GamePadIndex++; + } + } + else + { + // TODO(luca): Logging + } + } + } + + game_offscreen_buffer OffscreenBuffer = {}; + OffscreenBuffer.Memory = WindowBuffer; + OffscreenBuffer.Width = Width; + OffscreenBuffer.Height = Height; + OffscreenBuffer.BytesPerPixel = BytesPerPixel; + OffscreenBuffer.Pitch = Width*BytesPerPixel; + + int LastFramesWritten = 0; + unsigned int SampleRate, ChannelCount, PeriodTime, SampleCount; + snd_pcm_status_t *PCMStatus = 0; + snd_pcm_t* PCMHandle = 0; + snd_pcm_hw_params_t *PCMParams = 0; + snd_pcm_uframes_t PeriodSize = 0; + snd_pcm_uframes_t PCMBufferSize = 0; + + linux_init_alsa_result ALSAInit = LinuxInitALSA(); + PCMHandle = ALSAInit.PCMHandle; + PCMParams = ALSAInit.PCMParams; + snd_pcm_hw_params_get_channels(PCMParams, &ChannelCount); + snd_pcm_hw_params_get_rate(PCMParams, &SampleRate, 0); + snd_pcm_hw_params_get_period_size(PCMParams, &PeriodSize, 0); + snd_pcm_hw_params_get_period_time(PCMParams, &PeriodTime, NULL); + snd_pcm_hw_params_get_buffer_size(PCMParams, &PCMBufferSize); + snd_pcm_status_malloc(&PCMStatus); + +#if 0 + { + Assert(0); + u32 Value, Result; + snd_pcm_uframes_t Frames; + Result = snd_pcm_hw_params_get_buffer_time_min(PCMParams, &Value, 0); + Result = snd_pcm_hw_params_get_buffer_size_min(PCMParams, &Frames); + Frames = PCMBufferSize/2; + Result = snd_pcm_hw_params_set_period_size_near(PCMHandle, PCMParams, &Frames, 0); + Result = snd_pcm_hw_params_get_period_size(PCMParams, &PeriodSize, 0); + } +#endif + + + char AudioSamples[PCMBufferSize]; + u64 Periods = 2; + u32 BytesPerSample = (sizeof(s16)*ChannelCount); + +#if 1 + r32 GameUpdateHz = 30; +#else + r32 GameUpdateHz = LinuxGetMonitorRefreshRate(DisplayHandle, RootWindow); +#endif + + thread_context ThreadContext = {}; + + XMapWindow(DisplayHandle, WindowHandle); + XFlush(DisplayHandle); + + struct timespec LastCounter = LinuxGetWallClock(); + struct timespec FlipWallClock = LinuxGetWallClock(); + r32 TargetSecondsPerFrame = 1.0f / GameUpdateHz; + + GlobalRunning = true; + + u64 LastCycleCount = __rdtsc(); + while(GlobalRunning) + { + NewInput->dtForFrame = TargetSecondsPerFrame; + +#if HANDMADE_INTERNAL + // NOTE(luca): Because gcc will first create an empty file and then write into it we skip trying to reload when the file is empty. + struct stat FileStats = {}; + stat(LibraryFullPath, &FileStats); + if(FileStats.st_size) + { + s64 SecondsElapsed = LinuxGetNSecondsElapsed(Game.LibraryLastWriteTime, FileStats.st_mtim) / 1000/1000; + if(SecondsElapsed > 0) + { + LinuxUnloadGameCode(&Game); + Game = LinuxLoadGameCode(LibraryFullPath); + Game.LibraryLastWriteTime = FileStats.st_mtim; + } + } +#endif + + game_controller_input *OldKeyboardController = GetController(OldInput, 0); + game_controller_input *NewKeyboardController = GetController(NewInput, 0); + NewKeyboardController->IsConnected = true; + + LinuxProcessPendingMessages(DisplayHandle, WindowHandle, WM_DELETE_WINDOW, &LinuxState, NewKeyboardController); + + // TODO(luca): Use buttonpress/release events instead so we query this less frequently. + s32 MouseX = 0, MouseY = 0, MouseZ = 0; // TODO(luca): Support mousewheel? + u32 MouseMask = 0; + u64 Ignored; + if(XQueryPointer(DisplayHandle, WindowHandle, + &Ignored, &Ignored, (int *)&Ignored, (int *)&Ignored, + &MouseX, &MouseY, &MouseMask)) + { + if(MouseX <= OffscreenBuffer.Width && + MouseX >= 0 && + MouseY <= OffscreenBuffer.Height && + MouseY >= 0) + { + NewInput->MouseY = MouseY; + NewInput->MouseX = MouseX; + NewInput->MouseButtons[0].EndedDown = ((MouseMask & Button1Mask) > 0); + NewInput->MouseButtons[1].EndedDown = ((MouseMask & Button2Mask) > 0); + NewInput->MouseButtons[2].EndedDown = ((MouseMask & Button3Mask) > 0); + } + } + + for(int GamePadIndex = 0; + GamePadIndex < MAX_PLAYER_COUNT; + GamePadIndex++) + { + linux_gamepad *GamePadAt = &GamePads[GamePadIndex]; + + if(GamePadAt->File != -1) + { + game_controller_input *OldController = GetController(OldInput, 0); + game_controller_input *NewController = GetController(NewInput, 0); + + // TODO(luca): Cross frame values!!! + struct input_event InputEvents[64] = {}; + int BytesRead = 0; + + BytesRead = read(GamePadAt->File, InputEvents, sizeof(InputEvents)); + if(BytesRead != -1) + { + for(u32 EventIndex = 0; + EventIndex < ArrayCount(InputEvents); + EventIndex++) + { + struct input_event EventAt = InputEvents[EventIndex]; + + switch(EventAt.type) + { + case EV_KEY: + { + b32 IsDown = EventAt.value; + if(0) {} + else if(EventAt.code == BTN_A) + { + NewController->ActionDown.EndedDown = IsDown; + } + else if(EventAt.code == BTN_B) + { + NewController->ActionRight.EndedDown = IsDown; + } + else if(EventAt.code == BTN_X) + { + NewController->ActionLeft.EndedDown = IsDown; + } + else if(EventAt.code == BTN_Y) + { + NewController->ActionUp.EndedDown = IsDown; + } + else if(EventAt.code == BTN_START) + { + NewController->Start.EndedDown = IsDown; + } + else if(EventAt.code == BTN_BACK) + { + NewController->Back.EndedDown = IsDown; + } + } break; + + case EV_ABS: + { + if(0) {} + else if(EventAt.code == ABS_X) + { + NewController->IsAnalog = true; + + NewController->StickAverageX = LinuxNormalizeAxisValue(EventAt.value, GamePadAt->Axes[LSTICKX]); + } + else if(EventAt.code == ABS_Y) + { + NewController->StickAverageY = -1.0f * LinuxNormalizeAxisValue(EventAt.value, GamePadAt->Axes[LSTICKY]); + } + else if(EventAt.code == ABS_HAT0X) + { + NewController->StickAverageX = EventAt.value; + NewController->IsAnalog = false; + } + else if(EventAt.code == ABS_HAT0Y) + { + NewController->StickAverageY = -EventAt.value; + NewController->IsAnalog = false; + } + } break; +#if 0 + if(EventAt.type) printf("%d %d %d\n", EventAt.type, EventAt.code, EventAt.value); +#endif + } + } + + } + } + } + + if(!GlobalPaused) + { + if(LinuxState.InputRecordingIndex) + { + LinuxRecordInput(&LinuxState, NewInput); + } + if(LinuxState.InputPlayingIndex) + { + LinuxPlayBackInput(&LinuxState, NewInput); + } + + // NOTE(luca): Clear buffer + MemSet(WindowBuffer, 0, WindowBufferSize); + if(Game.UpdateAndRender) + { + Game.UpdateAndRender(&ThreadContext, &GameMemory, NewInput, &OffscreenBuffer); + } + + /* NOTE(luca): How sound works + +Check the delay +Check the available frames in buffer + +1. Too few audio frames in buffer for current frame. +-> Add more + +2. Too many frames available +-> Add less / drain? + +3. Fill first time? +-> Check delay +-> Maybe we should do this every frame? +-> Output needed frames to not have lag, this means to output maybe two frames? + +TODO +- check if delay never changes +- check if buffersize never changes +-> cache these values +*/ + + + r32 SamplesToWrite = 0; + local_persist b32 AudioFillFirstTime = true; + + r32 SingleFrameOfAudioFrames = TargetSecondsPerFrame*SampleRate; + + if(AudioFillFirstTime) + { + struct timespec WorkCounter = LinuxGetWallClock(); + r32 WorkSecondsElapsed = LinuxGetSecondsElapsed(LastCounter, WorkCounter); + r32 SecondsLeftUntilFlip = TargetSecondsPerFrame - WorkSecondsElapsed; + + if(SecondsLeftUntilFlip > 0) + { + SamplesToWrite = SampleRate*(TargetSecondsPerFrame + SecondsLeftUntilFlip); + } + else + { + SamplesToWrite = SingleFrameOfAudioFrames; + } + + AudioFillFirstTime = false; + } + else + { + SamplesToWrite = SingleFrameOfAudioFrames; + } + + + game_sound_output_buffer SoundBuffer = {}; + SoundBuffer.SamplesPerSecond = SampleRate; + SoundBuffer.SampleCount = SamplesToWrite; + SoundBuffer.Samples = (s16 *)AudioSamples; + + if(Game.GetSoundSamples) + { + Game.GetSoundSamples(&ThreadContext, &GameMemory, &SoundBuffer); + } + +#if 0 + snd_pcm_sframes_t AvailableFrames = 0; + snd_pcm_sframes_t DelayFrames; + + //snd_pcm_avail_update(PCMHandle); + AvailableFrames = snd_pcm_avail(PCMHandle); + snd_pcm_delay(PCMHandle, &DelayFrames); + + //printf("PeriodSize: %lu, PeriodTime: %d, BufferSize: %lu\n", PeriodSize, PeriodTime, PCMBufferSize); + printf("BeingWritten: %lu, Avail: %ld, Delay: %ld, ToWrite: %d\n", PCMBufferSize - AvailableFrames, AvailableFrames, DelayFrames, (s32)SamplesToWrite); +#endif + + LastFramesWritten = snd_pcm_writei(PCMHandle, SoundBuffer.Samples, SoundBuffer.SampleCount); + + if(LastFramesWritten < 0) + { + // TODO(luca): Logging + // NOTE(luca): We might want to silence in case of overruns ahead of time. We also probably want to handle latency differently here. + snd_pcm_recover(PCMHandle, LastFramesWritten, 0); + + // underrun + if(LastFramesWritten == -EPIPE) + { + AudioFillFirstTime = true; + } + + } + } + +#if 0 + printf("Expected: %d, Delay: %4d, Being written: %5lu, Written: %d, Ptr: %lu\n", + (int)SamplesToWrite, DelayFrames, PCMBufferSize - AvailableFrames, LastFramesWritten, PCMSoundStatus->hw_ptr); +#endif + + struct timespec WorkCounter = LinuxGetWallClock(); + r32 SecondsElapsedForFrame = LinuxGetSecondsElapsed(LastCounter, WorkCounter); + if(SecondsElapsedForFrame < TargetSecondsPerFrame) + { + + s64 SleepUS = (s64)((TargetSecondsPerFrame - 0.001 - SecondsElapsedForFrame)*1000000.0f); + if(SleepUS > 0) + { + usleep(SleepUS); + } + else + { + // TODO(luca): Logging + } + + r32 TestSecondsElapsedForFrame = (r32)(LinuxGetSecondsElapsed(LastCounter, LinuxGetWallClock())); + if(TestSecondsElapsedForFrame < TargetSecondsPerFrame) + { + // TODO(luca): Log missed sleep + } + + // NOTE(luca): This is to help against sleep granularity. + while(SecondsElapsedForFrame < TargetSecondsPerFrame) + { + SecondsElapsedForFrame = LinuxGetSecondsElapsed(LastCounter, LinuxGetWallClock()); + } + } + else + { + // TODO(luca): Log missed frame rate! + } + + struct timespec EndCounter = LinuxGetWallClock(); + r32 MSPerFrame = (r32)(LinuxGetNSecondsElapsed(LastCounter, EndCounter)/1000000.f); + LastCounter = EndCounter; + + XPutImage(DisplayHandle, WindowHandle, DefaultGC, WindowImage, 0, 0, + 0, 0, + Width, Height); + FlipWallClock = LinuxGetWallClock(); + + game_input *TempInput = NewInput; + NewInput = OldInput; + TempInput = NewInput; + +#if 0 + u64 EndCycleCount = __rdtsc(); + u64 CyclesElapsed = EndCycleCount - LastCycleCount; + LastCycleCount = EndCycleCount; + + r64 FPS = 0; + r64 MCPF = (r64)(CyclesElapsed/(1000.0f*1000.0f)); + printf("%.2fms/f %.2ff/s %.2fmc/f\n", MSPerFrame, FPS, MCPF); +#endif + + } + + } + else + { + // TODO: Log this bad WindowHandle + } + } + else + { + // TODO: Log this could not match visual info + } + } + else + { + // TODO: Log could not get x connection + } + return 0; +} diff --git a/code/linux_handmade.h b/code/linux_handmade.h new file mode 100644 index 0000000..f85320e --- /dev/null +++ b/code/linux_handmade.h @@ -0,0 +1,91 @@ +/* date = April 15th 2025 4:50 pm */ + +#ifndef LINUX_HANDMADE_H +#define LINUX_HANDMADE_H + +struct linux_game_code +{ + game_update_and_render *UpdateAndRender; + game_get_sound_samples *GetSoundSamples; + + void *LibraryHandle; + struct timespec LibraryLastWriteTime; +}; + +enum linux_gamepad_axes_enum +{ + LSTICKX, + LSTICKY, + RSTICKX, + RSTICKY, + LSHOULDER, + RSHOULDER, + DPADX, + DPADY, + AXES_COUNT +}; + +struct linux_gamepad_axis +{ + s32 Minimum; + s32 Maximum; + s32 Fuzz; + s32 Flat; +}; + +struct linux_gamepad +{ + int File; + char FilePath[PATH_MAX]; + + char Name[256]; + int SupportsRumble; + linux_gamepad_axis Axes[AXES_COUNT]; +}; + +struct linux_replay_buffer +{ + int FD; + char FileName[PATH_MAX]; + void *MemoryBlock; +}; +struct linux_state +{ + int InputPlayingIndex; + int InputRecordingIndex; + int InputPlayingFile; + int InputRecordingFile; + + linux_replay_buffer ReplayBuffers[4]; + + char ExecutablePath[PATH_MAX]; + + size_t TotalSize; + void *GameMemoryBlock; +}; + +// --------------------------------------------------------------------------------------- +// IMPORTANT(luca): Copy Pasted from alsa-lib; This is a hack to access the hw_ptr and to +// understand what alsa-lib functions are doing internally better through the debugger. +typedef struct { unsigned char pad[sizeof(time_t) - sizeof(int)]; } __time_pad; +typedef struct +{ + snd_pcm_state_t state; /* stream state */ + __time_pad pad1; /* align to timespec */ + struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ + struct timespec tstamp; /* reference timestamp */ + snd_pcm_uframes_t appl_ptr; /* appl ptr */ + snd_pcm_uframes_t hw_ptr; /* hw ptr */ + snd_pcm_sframes_t delay; /* current delay in frames */ + snd_pcm_uframes_t avail; /* number of frames available */ + snd_pcm_uframes_t avail_max; /* max frames available on hw since last status */ + snd_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */ + snd_pcm_state_t suspended_state; /* suspended stream state */ + __u32 audio_tstamp_data; /* needed for 64-bit alignment, used for configs/report to/from userspace */ + struct timespec audio_tstamp; /* sample counter, wall clock, PHC or on-demand sync'ed */ + struct timespec driver_tstamp; /* useful in case reference system tstamp is reported with delay */ + __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ + unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ +} sound_status; + +#endif //LINUX_HANDMADE_H diff --git a/data/structured_art.bmp b/data/structured_art.bmp Binary files differnew file mode 100755 index 0000000..38ea3b2 --- /dev/null +++ b/data/structured_art.bmp diff --git a/project.4coder b/project.4coder new file mode 100644 index 0000000..9102bd0 --- /dev/null +++ b/project.4coder @@ -0,0 +1,41 @@ +version(2); +project_name = "nothing"; +patterns = { + "*.c", + "*.cpp", + "*.h", + "*.m", + "*.bat", + "*.sh", + "*.4coder", +}; +blacklist_patterns = { + ".*", +}; +load_paths_base = { + { ".", .relative = true, .recursive = true, }, +}; +load_paths = { + .win = load_paths_base, + .linux = load_paths_base, + .mac = load_paths_base, +}; + +commands = { + .build = { .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, + .linux = "./code/build.sh", + .win = ".\code\build.bat", }, + .run = { .out = "*run*", .save_dirty_files = false, + .win = ".\build\win32_handmade.exe", + .linux = "./build/linux_handmade", + .mac = "./build/linux_handmade", }, + .debug = { .footer_panel = false, .save_dirty_files = false, + .linux = "gf2 ./build/linux_handmade", + }, +}; + +fkey_command = { + .F1 = "build", + .F2 = "run", + .F4 = "debug", +}; |