├── .gitignore ├── README.md ├── build.sh ├── code ├── Makefile ├── osx_asset_builder.cpp ├── osx_asset_builder.h ├── osx_handmade.cpp ├── osx_handmade.h ├── osx_handmade_audio.cpp ├── osx_handmade_debug.cpp ├── osx_handmade_dylib.cpp ├── osx_handmade_file.cpp ├── osx_handmade_game.cpp ├── osx_handmade_hid.cpp ├── osx_handmade_playback.cpp ├── osx_handmade_process.cpp ├── osx_handmade_thread.cpp ├── osx_main.mm └── vsprintf.cpp ├── dynamic_compile.sh ├── fix_handmade_hero_source.sh ├── fonts ├── AUTHORS ├── LICENSE ├── LiberationMono-Regular.ttf ├── LiberationSans-Regular.ttf └── LiberationSerif-Regular.ttf ├── handmade_opengl.cpp.day373.patch ├── handmade_opengl.cpp.day374.patch ├── handmade_opengl.cpp.day375.patch ├── handmade_opengl.cpp.day380.patch ├── handmade_opengl.cpp.day384.patch ├── handmade_opengl.cpp.day387.patch └── xcode ├── Handmade Hero.xcodeproj └── project.pbxproj └── handmade.xcodeproj └── project.pbxproj /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .ycm_extra_conf.py 3 | .ycm_extra_conf.pyc 4 | cpp 5 | data 6 | xcode/Handmade\ Hero.xcodeproj/project.xcworkspace/* 7 | xcode/Handmade\ Hero.xcodeproj/xcuserdata 8 | xcode/handmade.xcodeproj/project.xcworkspace/* 9 | xcode/handmade.xcodeproj/xcuserdata 10 | handmade 11 | handmade.dSYM/ 12 | test_asset_builder 13 | test_asset_builder.dSYM/ 14 | *.dylib 15 | *.so 16 | *.o 17 | test.out 18 | Handmade.app 19 | handmade.cpp 20 | handmade.h 21 | handmade_asset.cpp 22 | handmade_asset.h 23 | handmade_asset.osx.cpp 24 | handmade_asset_type_id.h 25 | handmade_audio.cpp 26 | handmade_audio.h 27 | handmade_config.h 28 | handmade_debug.h 29 | handmade_debug.cpp 30 | handmade_debug_interface.h 31 | handmade_entity.cpp 32 | handmade_entity.h 33 | handmade_file_formats.h 34 | handmade_generated.h 35 | handmade_intrinsics.h 36 | handmade_math.h 37 | handmade_meta.h 38 | handmade_meta.cpp 39 | handmade_optimized.cpp 40 | handmade_platform.h 41 | handmade_random.h 42 | handmade_render_group.cpp 43 | handmade_render_group.h 44 | handmade_sim_region.cpp 45 | handmade_sim_region.h 46 | handmade_tile.cpp 47 | handmade_tile.h 48 | handmade_world.cpp 49 | handmade_world.h 50 | simple_preprocessor.cpp 51 | stb_truetype.h 52 | win32_handmade.cpp 53 | win32_handmade.h 54 | loop_edit*.hmi 55 | build/ 56 | Contents/ 57 | test/ 58 | test2/ 59 | test3/ 60 | test.hha 61 | test1.hha 62 | test2.hha 63 | test3.hha 64 | test_asset_builder.cpp 65 | test_asset_builder.h 66 | 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | osx_handmade 2 | ============ 3 | 4 | A port of Handmade Hero (http://handmadehero.org) for OS X. 5 | 6 | This repository has been merged into the osx_handmade repository 7 | at https://github.com/itfrombit/osx_handmade. 8 | 9 | The osx_handmade repository does not require Xcode or any nib/xib files, 10 | so it adopts the "minimal" original intent of this repository. 11 | 12 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -Wno-c++11-compat-deprecated-writable-strings -c handmade.cpp 3 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -dynamiclib -o libhandmade.dylib handmade.o 4 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -c osx_main.mm 5 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -c osx_handmade.cpp 6 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -c HandmadeView.mm 7 | clang -g -Wall -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -Wno-null-dereference -framework Cocoa -framework QuartzCore -framework OpenGL -framework IOKit -framework AudioUnit -o handmade osx_main.o osx_handmade.o HandmadeView.o 8 | rm -rf Handmade.app 9 | mkdir -p Handmade.app/Contents/MacOS 10 | mkdir -p Handmade.app/Contents/Resources 11 | cp handmade Handmade.app/Contents/MacOS/Handmade 12 | cp libhandmade.dylib Handmade.app/Contents/MacOS/libhandmade.dylib 13 | 14 | -------------------------------------------------------------------------------- /code/Makefile: -------------------------------------------------------------------------------- 1 | CXX = clang 2 | 3 | HANDMADE_CODE_PATH = ../cpp/code 4 | HANDMADE_ASSETS_PATH = ../data 5 | 6 | HANDMADE_FLAGS = -DHANDMADE_PROFILE=1 -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -DHANDMADE_MIN_OSX 7 | 8 | HANDMADE_COMPILER_FLAGS = -fno-exceptions -fno-rtti 9 | HANDMADE_WARNING_FLAGS = -Wno-unused-function -Wno-unused-variable -Wno-c++11-narrowing -Wno-missing-braces -Wno-logical-not-parentheses -Wno-switch -Wno-write-strings -Wno-c++11-compat-deprecated-writable-strings -Wno-tautological-compare -Wno-missing-braces -Wno-null-dereference -Wno-writable-strings 10 | 11 | 12 | # Use the following to force compiling with 10.7 SDK testing: 13 | #HANDMADE_FLAGS = -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -DHANDMADE_MIN_OSX -Wno-null-dereference -isysroot /Applications/Xcode-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk 14 | 15 | COPTS = -g -Wall -fno-inline $(HANDMADE_FLAGS) 16 | #COPTS = -O3 -Wall $(HANDMADE_FLAGS) 17 | 18 | 19 | CPP11_FLAGS = -std=c++11 -stdlib=libc++ -ggdb 20 | CPP11_LD_FLAGS = -lstdc++ 21 | 22 | OSX_FLAGS = 23 | OSX_LD_FLAGS = -framework Cocoa -framework QuartzCore -framework OpenGL -framework IOKit -framework AudioUnit 24 | OSX_CT_LD_FLAGS = -framework CoreText -framework CoreFoundation 25 | #OSX_LD_FLAGS = -framework Cocoa -framework QuartzCore -framework OpenGL -framework IOKit -framework AudioUnit -Wl,-syslibroot /Applications/Xcode-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk 26 | 27 | BINARIES = handmade libhandmade.dylib osx_asset_builder 28 | 29 | DYNAMIC_COMPILE_PATH=$(shell pwd) 30 | DYNAMIC_COMPILE_COMMAND=$(DYNAMIC_COMPILE_PATH)/dynamic_compile.sh 31 | 32 | default: clean libhandmade.dylib handmade package 33 | 34 | quick: libhandmade.dylib handmade 35 | 36 | all: clean libhandmade.dylib handmade package osx_asset_builder 37 | 38 | handmade: osx_main.o osx_handmade.o 39 | $(CXX) $(COPTS) $(OSX_LD_FLAGS) $(CPP11_LD_FLAGS) -o $@ $^ 40 | 41 | package: 42 | rm -rf ../build/Handmade.app 43 | rm -rf ./Contents/Resources 44 | mkdir -p Handmade.app/Contents/MacOS 45 | mkdir -p Handmade.app/Contents/Resources 46 | mkdir -p Handmade.app/Contents/code 47 | cp handmade Handmade.app/Contents/MacOS/Handmade 48 | cp $(HANDMADE_ASSETS_PATH)/test1.hha Handmade.app/Contents/Resources/test1.hha 49 | cp $(HANDMADE_ASSETS_PATH)/test2.hha Handmade.app/Contents/Resources/test2.hha 50 | cp $(HANDMADE_ASSETS_PATH)/test3.hha Handmade.app/Contents/Resources/test3.hha 51 | cp $(HANDMADE_ASSETS_PATH)/testfonts.hha Handmade.app/Contents/Resources/testfonts.hha 52 | cp $(HANDMADE_ASSETS_PATH)/intro_art.hha Handmade.app/Contents/Resources/intro_art.hha 53 | cp libhandmade.dylib Handmade.app/Contents/MacOS/libhandmade.dylib 54 | mv Handmade.app ../build/ 55 | # The 'local' bundle for convenient debugging with lldb 56 | mkdir -p ./Contents/MacOS 57 | mkdir -p ./Contents/Resources 58 | mkdir -p ./Contents/code 59 | cp $(HANDMADE_ASSETS_PATH)/test1.hha ./Contents/Resources/test1.hha 60 | cp $(HANDMADE_ASSETS_PATH)/test2.hha ./Contents/Resources/test2.hha 61 | cp $(HANDMADE_ASSETS_PATH)/test3.hha ./Contents/Resources/test3.hha 62 | cp $(HANDMADE_ASSETS_PATH)/testfonts.hha ./Contents/Resources/testfonts.hha 63 | cp $(HANDMADE_ASSETS_PATH)/intro_art.hha ./Contents/Resources/intro_art.hha 64 | cp libhandmade.dylib ./Contents/MacOS/libhandmade.dylib 65 | 66 | osx_asset_builder: osx_asset_builder.o 67 | $(CXX) $(COPTS) $(OSX_CT_LD_FLAGS) -o $@ $^ 68 | 69 | osx_asset_builder.o: osx_asset_builder.cpp 70 | $(CXX) $(COPTS) -Wno-c++11-compat-deprecated-writable-strings -Wno-missing-braces -c $< 71 | 72 | 73 | #libhandmade.dylib: handmade.o handmade_optimized.o 74 | libhandmade.dylib: handmade.o 75 | $(CXX) $(COPTS) -lstdc++ -dynamiclib -o $@ $^ 76 | 77 | 78 | #handmade_optimized.o: $(HANDMADE_CODE_PATH)/handmade_optimized.cpp 79 | # $(CXX) -O3 -Wall $(HANDMADE_COMPILER_FLAGS) $(HANDMADE_FLAGS) $(HANDMADE_WARNING_FLAGS) $(CPP11_FLAGS) -c $< 80 | 81 | handmade.o: $(HANDMADE_CODE_PATH)/handmade.cpp $(HANDMADE_CODE_PATH)/handmade.h 82 | $(CXX) $(COPTS) $(HANDMADE_COMPILER_FLAGS) $(HANDMADE_WARNING_FLAGS) $(CPP11_FLAGS) -c $< 83 | 84 | 85 | osx_handmade.o: osx_handmade.cpp osx_handmade.h osx_handmade_debug.cpp osx_handmade_file.cpp osx_handmade_process.cpp osx_handmade_thread.cpp osx_handmade_audio.cpp osx_handmade_hid.cpp osx_handmade_dylib.cpp osx_handmade_playback.cpp osx_handmade_game.cpp 86 | $(CXX) $(COPTS) $(CPP11_FLAGS) -I$(HANDMADE_CODE_PATH) -Wno-writable-strings -Wno-deprecated-declarations -Wno-null-dereference -Wno-c++11-compat-deprecated-writable-strings -Wno-unused-function -Wno-unused-variable -Wno-missing-braces -c $< 87 | 88 | osx_main.o: osx_main.mm osx_handmade.cpp osx_handmade.h $(HANDMADE_CODE_PATH)/handmade.h $(HANDMADE_CODE_PATH)/handmade.cpp 89 | $(CXX) $(COPTS) $(CPP11_FLAGS) -I$(HANDMADE_CODE_PATH) -Wno-writable-strings -Wno-deprecated-declarations -Wno-null-dereference -Wno-c++11-compat-deprecated-writable-strings -Wno-unused-function -Wno-unused-variable -c $< 90 | 91 | clean: 92 | rm -rf *.o $(BINARIES) Handmade.app 93 | 94 | -------------------------------------------------------------------------------- /code/osx_asset_builder.cpp: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | $File: $ 3 | $Date: $ 4 | $Revision: $ 5 | $Creator: Casey Muratori $ 6 | $Notice: (C) Copyright 2015 by Molly Rocket, Inc. All Rights Reserved. $ 7 | ======================================================================== */ 8 | 9 | #include "osx_asset_builder.h" 10 | 11 | #pragma pack(push, 1) 12 | struct bitmap_header 13 | { 14 | uint16 FileType; 15 | uint32 FileSize; 16 | uint16 Reserved1; 17 | uint16 Reserved2; 18 | uint32 BitmapOffset; 19 | uint32 Size; 20 | int32 Width; 21 | int32 Height; 22 | uint16 Planes; 23 | uint16 BitsPerPixel; 24 | uint32 Compression; 25 | uint32 SizeOfBitmap; 26 | int32 HorzResolution; 27 | int32 VertResolution; 28 | uint32 ColorsUsed; 29 | uint32 ColorsImportant; 30 | 31 | uint32 RedMask; 32 | uint32 GreenMask; 33 | uint32 BlueMask; 34 | }; 35 | 36 | struct WAVE_header 37 | { 38 | uint32 RIFFID; 39 | uint32 Size; 40 | uint32 WAVEID; 41 | }; 42 | 43 | #define RIFF_CODE(a, b, c, d) (((uint32)(a) << 0) | ((uint32)(b) << 8) | ((uint32)(c) << 16) | ((uint32)(d) << 24)) 44 | enum 45 | { 46 | WAVE_ChunkID_fmt = RIFF_CODE('f', 'm', 't', ' '), 47 | WAVE_ChunkID_data = RIFF_CODE('d', 'a', 't', 'a'), 48 | WAVE_ChunkID_RIFF = RIFF_CODE('R', 'I', 'F', 'F'), 49 | WAVE_ChunkID_WAVE = RIFF_CODE('W', 'A', 'V', 'E'), 50 | }; 51 | struct WAVE_chunk 52 | { 53 | uint32 ID; 54 | uint32 Size; 55 | }; 56 | 57 | struct WAVE_fmt 58 | { 59 | uint16 wFormatTag; 60 | uint16 nChannels; 61 | uint32 nSamplesPerSec; 62 | uint32 nAvgBytesPerSec; 63 | uint16 nBlockAlign; 64 | uint16 wBitsPerSample; 65 | uint16 cbSize; 66 | uint16 wValidBitsPerSample; 67 | uint32 dwChannelMask; 68 | uint8 SubFormat[16]; 69 | }; 70 | 71 | #pragma pack(pop) 72 | 73 | struct entire_file 74 | { 75 | u32 ContentsSize; 76 | void *Contents; 77 | }; 78 | 79 | 80 | entire_file 81 | ReadEntireFile(char *FileName) 82 | { 83 | entire_file Result = {}; 84 | 85 | FILE *In = fopen(FileName, "rb"); 86 | if(In) 87 | { 88 | fseek(In, 0, SEEK_END); 89 | Result.ContentsSize = ftell(In); 90 | fseek(In, 0, SEEK_SET); 91 | 92 | Result.Contents = malloc(Result.ContentsSize); 93 | fread(Result.Contents, Result.ContentsSize, 1, In); 94 | fclose(In); 95 | } 96 | else 97 | { 98 | printf("ERROR: Cannot open file %s.\n", FileName); 99 | } 100 | 101 | return(Result); 102 | } 103 | 104 | 105 | internal loaded_bitmap 106 | LoadBMP(char *FileName) 107 | { 108 | loaded_bitmap Result = {}; 109 | 110 | entire_file ReadResult = ReadEntireFile(FileName); 111 | if(ReadResult.ContentsSize != 0) 112 | { 113 | Result.Free = ReadResult.Contents; 114 | 115 | bitmap_header *Header = (bitmap_header *)ReadResult.Contents; 116 | uint32 *Pixels = (uint32 *)((uint8 *)ReadResult.Contents + Header->BitmapOffset); 117 | Result.Memory = Pixels; 118 | Result.Width = Header->Width; 119 | Result.Height = Header->Height; 120 | 121 | Assert(Result.Height >= 0); 122 | Assert(Header->Compression == 3); 123 | 124 | // NOTE(casey): If you are using this generically for some reason, 125 | // please remember that BMP files CAN GO IN EITHER DIRECTION and 126 | // the height will be negative for top-down. 127 | // (Also, there can be compression, etc., etc... DON'T think this 128 | // is complete BMP loading code because it isn't!!) 129 | 130 | // NOTE(casey): Byte order in memory is determined by the Header itself, 131 | // so we have to read out the masks and convert the pixels ourselves. 132 | uint32 RedMask = Header->RedMask; 133 | uint32 GreenMask = Header->GreenMask; 134 | uint32 BlueMask = Header->BlueMask; 135 | uint32 AlphaMask = ~(RedMask | GreenMask | BlueMask); 136 | 137 | bit_scan_result RedScan = FindLeastSignificantSetBit(RedMask); 138 | bit_scan_result GreenScan = FindLeastSignificantSetBit(GreenMask); 139 | bit_scan_result BlueScan = FindLeastSignificantSetBit(BlueMask); 140 | bit_scan_result AlphaScan = FindLeastSignificantSetBit(AlphaMask); 141 | 142 | Assert(RedScan.Found); 143 | Assert(GreenScan.Found); 144 | Assert(BlueScan.Found); 145 | Assert(AlphaScan.Found); 146 | 147 | int32 RedShiftDown = (int32)RedScan.Index; 148 | int32 GreenShiftDown = (int32)GreenScan.Index; 149 | int32 BlueShiftDown = (int32)BlueScan.Index; 150 | int32 AlphaShiftDown = (int32)AlphaScan.Index; 151 | 152 | uint32 *SourceDest = Pixels; 153 | for(int32 Y = 0; 154 | Y < Header->Height; 155 | ++Y) 156 | { 157 | for(int32 X = 0; 158 | X < Header->Width; 159 | ++X) 160 | { 161 | uint32 C = *SourceDest; 162 | 163 | v4 Texel = {(real32)((C & RedMask) >> RedShiftDown), 164 | (real32)((C & GreenMask) >> GreenShiftDown), 165 | (real32)((C & BlueMask) >> BlueShiftDown), 166 | (real32)((C & AlphaMask) >> AlphaShiftDown)}; 167 | 168 | Texel = SRGB255ToLinear1(Texel); 169 | #if 1 170 | Texel.rgb *= Texel.a; 171 | #endif 172 | Texel = Linear1ToSRGB255(Texel); 173 | 174 | *SourceDest++ = (((uint32)(Texel.a + 0.5f) << 24) | 175 | ((uint32)(Texel.r + 0.5f) << 16) | 176 | ((uint32)(Texel.g + 0.5f) << 8) | 177 | ((uint32)(Texel.b + 0.5f) << 0)); 178 | } 179 | } 180 | } 181 | 182 | Result.Pitch = Result.Width*BITMAP_BYTES_PER_PIXEL; 183 | 184 | #if 0 185 | Result.Memory = (uint8 *)Result.Memory + Result.Pitch*(Result.Height - 1); 186 | Result.Pitch = -Result.Pitch; 187 | #endif 188 | 189 | return(Result); 190 | } 191 | 192 | 193 | internal loaded_font * 194 | LoadFont(char *FileName, char *FontName, int PixelHeight) 195 | { 196 | loaded_font *Font = (loaded_font *)malloc(sizeof(loaded_font)); 197 | 198 | #if USE_FONTS_FROM_WINDOWS 199 | 200 | AddFontResourceExA(FileName, FR_PRIVATE, 0); 201 | Font->Win32Handle = CreateFontA(PixelHeight, 0, 0, 0, 202 | FW_NORMAL, // NOTE(casey): Weight 203 | FALSE, // NOTE(casey): Italic 204 | FALSE, // NOTE(casey): Underline 205 | FALSE, // NOTE(casey): Strikeout 206 | DEFAULT_CHARSET, 207 | OUT_DEFAULT_PRECIS, 208 | CLIP_DEFAULT_PRECIS, 209 | ANTIALIASED_QUALITY, 210 | DEFAULT_PITCH|FF_DONTCARE, 211 | FontName); 212 | 213 | SelectObject(GlobalFontDeviceContext, Font->Win32Handle); 214 | GetTextMetrics(GlobalFontDeviceContext, &Font->TextMetric); 215 | 216 | #else // STB TrueType 217 | 218 | entire_file TTFFile = ReadEntireFile(FileName); 219 | 220 | if(TTFFile.ContentsSize != 0) 221 | { 222 | stbtt_InitFont(&Font->FontInfo, (u8 *)TTFFile.Contents, stbtt_GetFontOffsetForIndex((u8 *)TTFFile.Contents, 0)); 223 | Font->Scale = stbtt_ScaleForPixelHeight(&Font->FontInfo, PixelHeight); 224 | 225 | stbtt_GetFontVMetrics(&Font->FontInfo, 226 | &Font->FontMetric.Ascent, 227 | &Font->FontMetric.Descent, 228 | &Font->FontMetric.Leading); 229 | 230 | Font->FontMetric.Ascent *= Font->Scale; 231 | Font->FontMetric.Descent *= -Font->Scale; 232 | Font->FontMetric.Leading *= Font->Scale; 233 | } 234 | 235 | #endif // USE_FONTS_FROM_WINDOWS 236 | 237 | Font->MinCodePoint = INT_MAX; 238 | Font->MaxCodePoint = 0; 239 | 240 | // NOTE(casey): 5k characters should be more than enough for _anybody_! 241 | Font->MaxGlyphCount = 5000; 242 | Font->GlyphCount = 0; 243 | 244 | u32 GlyphIndexFromCodePointSize = ONE_PAST_MAX_FONT_CODEPOINT*sizeof(u32); 245 | Font->GlyphIndexFromCodePoint = (u32 *)malloc(GlyphIndexFromCodePointSize); 246 | memset(Font->GlyphIndexFromCodePoint, 0, GlyphIndexFromCodePointSize); 247 | 248 | Font->Glyphs = (hha_font_glyph *)malloc(sizeof(hha_font_glyph)*Font->MaxGlyphCount); 249 | size_t HorizontalAdvanceSize = sizeof(r32)*Font->MaxGlyphCount*Font->MaxGlyphCount; 250 | Font->HorizontalAdvance = (r32 *)malloc(HorizontalAdvanceSize); 251 | memset(Font->HorizontalAdvance, 0, HorizontalAdvanceSize); 252 | 253 | Font->OnePastHighestCodepoint = 0; 254 | 255 | // NOTE(casey): Reserve space for the null glyph 256 | Font->GlyphCount = 1; 257 | Font->Glyphs[0].UnicodeCodePoint = 0; 258 | Font->Glyphs[0].BitmapID.Value = 0; 259 | 260 | return(Font); 261 | } 262 | 263 | 264 | internal void 265 | FinalizeFontKerning(loaded_font *Font) 266 | { 267 | 268 | #if USE_FONTS_FROM_WINDOWS 269 | 270 | SelectObject(GlobalFontDeviceContext, Font->Win32Handle); 271 | 272 | DWORD KerningPairCount = GetKerningPairsW(GlobalFontDeviceContext, 0, 0); 273 | KERNINGPAIR *KerningPairs = (KERNINGPAIR *)malloc(KerningPairCount*sizeof(KERNINGPAIR)); 274 | GetKerningPairsW(GlobalFontDeviceContext, KerningPairCount, KerningPairs); 275 | for(DWORD KerningPairIndex = 0; 276 | KerningPairIndex < KerningPairCount; 277 | ++KerningPairIndex) 278 | { 279 | KERNINGPAIR *Pair = KerningPairs + KerningPairIndex; 280 | if((Pair->wFirst < ONE_PAST_MAX_FONT_CODEPOINT) && 281 | (Pair->wSecond < ONE_PAST_MAX_FONT_CODEPOINT)) 282 | { 283 | u32 First = Font->GlyphIndexFromCodePoint[Pair->wFirst]; 284 | u32 Second = Font->GlyphIndexFromCodePoint[Pair->wSecond]; 285 | if((First != 0) && (Second != 0)) 286 | { 287 | Font->HorizontalAdvance[First*Font->MaxGlyphCount + Second] += (r32)Pair->iKernAmount; 288 | } 289 | } 290 | } 291 | 292 | free(KerningPairs); 293 | 294 | #else // STB Truetype 295 | 296 | for(u32 FirstGlyphIndex = 1; 297 | FirstGlyphIndex < Font->GlyphCount; 298 | ++FirstGlyphIndex) 299 | { 300 | hha_font_glyph First = Font->Glyphs[FirstGlyphIndex]; 301 | 302 | for(u32 SecondGlyphIndex = 1; 303 | SecondGlyphIndex < Font->GlyphCount; 304 | ++SecondGlyphIndex) 305 | { 306 | hha_font_glyph Second = Font->Glyphs[SecondGlyphIndex]; 307 | r32 KernAdvance = Font->Scale * stbtt_GetCodepointKernAdvance(&Font->FontInfo, 308 | First.UnicodeCodePoint, 309 | Second.UnicodeCodePoint); 310 | 311 | Font->HorizontalAdvance[SecondGlyphIndex*Font->MaxGlyphCount + FirstGlyphIndex] += KernAdvance; 312 | } 313 | } 314 | 315 | #endif // USE_FONTS_FROM_WINDOWS 316 | } 317 | 318 | 319 | internal void 320 | FreeFont(loaded_font *Font) 321 | { 322 | if(Font) 323 | { 324 | #if USE_FONTS_FROM_WINDOWS 325 | DeleteObject(Font->Win32Handle); 326 | #endif 327 | 328 | free(Font->Glyphs); 329 | free(Font->HorizontalAdvance); 330 | free(Font->GlyphIndexFromCodePoint); 331 | free(Font); 332 | } 333 | } 334 | 335 | 336 | #if USE_FONTS_FROM_WINDOWS 337 | internal void 338 | InitializeFontDC(void) 339 | { 340 | GlobalFontDeviceContext = CreateCompatibleDC(GetDC(0)); 341 | 342 | BITMAPINFO Info = {}; 343 | Info.bmiHeader.biSize = sizeof(Info.bmiHeader); 344 | Info.bmiHeader.biWidth = MAX_FONT_WIDTH; 345 | Info.bmiHeader.biHeight = MAX_FONT_HEIGHT; 346 | Info.bmiHeader.biPlanes = 1; 347 | Info.bmiHeader.biBitCount = 32; 348 | Info.bmiHeader.biCompression = BI_RGB; 349 | Info.bmiHeader.biSizeImage = 0; 350 | Info.bmiHeader.biXPelsPerMeter = 0; 351 | Info.bmiHeader.biYPelsPerMeter = 0; 352 | Info.bmiHeader.biClrUsed = 0; 353 | Info.bmiHeader.biClrImportant = 0; 354 | HBITMAP Bitmap = CreateDIBSection(GlobalFontDeviceContext, &Info, DIB_RGB_COLORS, &GlobalFontBits, 0, 0); 355 | SelectObject(GlobalFontDeviceContext, Bitmap); 356 | SetBkColor(GlobalFontDeviceContext, RGB(0, 0, 0)); 357 | } 358 | #endif 359 | 360 | 361 | internal loaded_bitmap 362 | LoadGlyphBitmap(loaded_font *Font, u32 CodePoint, hha_asset *Asset) 363 | { 364 | loaded_bitmap Result = {}; 365 | 366 | u32 GlyphIndex = Font->GlyphIndexFromCodePoint[CodePoint]; 367 | 368 | #if USE_FONTS_FROM_WINDOWS 369 | 370 | SelectObject(GlobalFontDeviceContext, Font->Win32Handle); 371 | 372 | memset(GlobalFontBits, 0x00, MAX_FONT_WIDTH*MAX_FONT_HEIGHT*sizeof(u32)); 373 | 374 | wchar_t CheesePoint = (wchar_t)CodePoint; 375 | 376 | SIZE Size; 377 | GetTextExtentPoint32W(GlobalFontDeviceContext, &CheesePoint, 1, &Size); 378 | 379 | int PreStepX = 128; 380 | 381 | int BoundWidth = Size.cx + 2*PreStepX; 382 | if(BoundWidth > MAX_FONT_WIDTH) 383 | { 384 | BoundWidth = MAX_FONT_WIDTH; 385 | } 386 | int BoundHeight = Size.cy; 387 | if(BoundHeight > MAX_FONT_HEIGHT) 388 | { 389 | BoundHeight = MAX_FONT_HEIGHT; 390 | } 391 | 392 | // PatBlt(DeviceContext, 0, 0, Width, Height, BLACKNESS); 393 | // SetBkMode(DeviceContext, TRANSPARENT); 394 | SetTextColor(GlobalFontDeviceContext, RGB(255, 255, 255)); 395 | TextOutW(GlobalFontDeviceContext, PreStepX, 0, &CheesePoint, 1); 396 | 397 | s32 MinX = 10000; 398 | s32 MinY = 10000; 399 | s32 MaxX = -10000; 400 | s32 MaxY = -10000; 401 | 402 | u32 *Row = (u32 *)GlobalFontBits + (MAX_FONT_HEIGHT - 1)*MAX_FONT_WIDTH; 403 | for(s32 Y = 0; 404 | Y < BoundHeight; 405 | ++Y) 406 | { 407 | u32 *Pixel = Row; 408 | for(s32 X = 0; 409 | X < BoundWidth; 410 | ++X) 411 | { 412 | #if 0 413 | COLORREF RefPixel = GetPixel(GlobalFontDeviceContext, X, Y); 414 | Assert(RefPixel == *Pixel); 415 | #endif 416 | if(*Pixel != 0) 417 | { 418 | if(MinX > X) 419 | { 420 | MinX = X; 421 | } 422 | 423 | if(MinY > Y) 424 | { 425 | MinY = Y; 426 | } 427 | 428 | if(MaxX < X) 429 | { 430 | MaxX = X; 431 | } 432 | 433 | if(MaxY < Y) 434 | { 435 | MaxY = Y; 436 | } 437 | } 438 | 439 | ++Pixel; 440 | } 441 | Row -= MAX_FONT_WIDTH; 442 | } 443 | 444 | r32 KerningChange = 0; 445 | if(MinX <= MaxX) 446 | { 447 | int Width = (MaxX - MinX) + 1; 448 | int Height = (MaxY - MinY) + 1; 449 | 450 | Result.Width = Width + 2; 451 | Result.Height = Height + 2; 452 | Result.Pitch = Result.Width*BITMAP_BYTES_PER_PIXEL; 453 | Result.Memory = malloc(Result.Height*Result.Pitch); 454 | Result.Free = Result.Memory; 455 | 456 | memset(Result.Memory, 0, Result.Height*Result.Pitch); 457 | 458 | u8 *DestRow = (u8 *)Result.Memory + (Result.Height - 1 - 1)*Result.Pitch; 459 | u32 *SourceRow = (u32 *)GlobalFontBits + (MAX_FONT_HEIGHT - 1 - MinY)*MAX_FONT_WIDTH; 460 | for(s32 Y = MinY; 461 | Y <= MaxY; 462 | ++Y) 463 | { 464 | u32 *Source = (u32 *)SourceRow + MinX; 465 | u32 *Dest = (u32 *)DestRow + 1; 466 | for(s32 X = MinX; 467 | X <= MaxX; 468 | ++X) 469 | { 470 | #if 0 471 | COLORREF Pixel = GetPixel(GlobalFontDeviceContext, X, Y); 472 | Assert(Pixel == *Source); 473 | #else 474 | u32 Pixel = *Source; 475 | #endif 476 | r32 Gray = (r32)(Pixel & 0xFF); 477 | v4 Texel = {255.0f, 255.0f, 255.0f, Gray}; 478 | Texel = SRGB255ToLinear1(Texel); 479 | Texel.rgb *= Texel.a; 480 | Texel = Linear1ToSRGB255(Texel); 481 | 482 | *Dest++ = (((uint32)(Texel.a + 0.5f) << 24) | 483 | ((uint32)(Texel.r + 0.5f) << 16) | 484 | ((uint32)(Texel.g + 0.5f) << 8) | 485 | ((uint32)(Texel.b + 0.5f) << 0)); 486 | 487 | 488 | ++Source; 489 | } 490 | 491 | DestRow -= Result.Pitch; 492 | SourceRow -= MAX_FONT_WIDTH; 493 | } 494 | 495 | Asset->Bitmap.AlignPercentage[0] = (1.0f) / (r32)Result.Width; 496 | Asset->Bitmap.AlignPercentage[1] = (1.0f + (MaxY - (BoundHeight - Font->TextMetric.tmDescent))) / (r32)Result.Height; 497 | 498 | KerningChange = (r32)(MinX - PreStepX); 499 | } 500 | 501 | #if 0 502 | ABC ThisABC; 503 | GetCharABCWidthsW(GlobalFontDeviceContext, CodePoint, CodePoint, &ThisABC); 504 | r32 CharAdvance = (r32)(ThisABC.abcA + ThisABC.abcB + ThisABC.abcC); 505 | #else 506 | INT ThisWidth; 507 | GetCharWidth32W(GlobalFontDeviceContext, CodePoint, CodePoint, &ThisWidth); 508 | r32 CharAdvance = (r32)ThisWidth; 509 | #endif 510 | 511 | #else // STB TrueType 512 | 513 | int Width, Height, XOffset, YOffset; 514 | u8 *MonoBitmap = stbtt_GetCodepointBitmap(&Font->FontInfo, 0, Font->Scale, CodePoint, 515 | &Width, &Height, &XOffset, &YOffset); 516 | 517 | Result.Width = Width + 2; 518 | Result.Height = Height + 2; 519 | Result.Pitch = Result.Width*BITMAP_BYTES_PER_PIXEL; 520 | Result.Memory = malloc(Result.Height*Result.Pitch); 521 | Result.Free = Result.Memory; 522 | 523 | memset(Result.Memory, 0, Result.Height * Result.Pitch); 524 | 525 | u8 *DestRow = (u8 *)Result.Memory + (Result.Height - 2) * Result.Pitch; 526 | u8 *Source = MonoBitmap; 527 | for(s32 Y = 0; 528 | Y < Height; 529 | ++Y) 530 | { 531 | u32 *Dest = ((u32 *)DestRow) + 1; 532 | for(s32 X = 0; 533 | X < Width; 534 | ++X) 535 | { 536 | u32 Pixel = *Source; 537 | r32 Gray = (r32)(Pixel & 0xFF); 538 | v4 Texel = {255.0f, 255.0f, 255.0f, Gray}; 539 | Texel = SRGB255ToLinear1(Texel); 540 | Texel.rgb *= Texel.a; 541 | Texel = Linear1ToSRGB255(Texel); 542 | 543 | *Dest++ = (((u32)(Texel.a + 0.5f) << 24) | 544 | ((u32)(Texel.r + 0.5f) << 16) | 545 | ((u32)(Texel.g + 0.5f) << 8) | 546 | ((u32)(Texel.b + 0.5f) << 0)); 547 | 548 | ++Source; 549 | } 550 | 551 | DestRow -= Result.Pitch; 552 | } 553 | 554 | stbtt_FreeBitmap(MonoBitmap, 0); 555 | r32 VAlignAdjustment = Height + YOffset; 556 | 557 | Asset->Bitmap.AlignPercentage[0] = (1.0f) / (r32)Result.Width; 558 | Asset->Bitmap.AlignPercentage[1] = (1.0f + VAlignAdjustment) / (r32)Result.Height; 559 | 560 | r32 KerningChange = (r32)XOffset; 561 | 562 | s32 ThisWidth; 563 | stbtt_GetCodepointHMetrics(&Font->FontInfo, CodePoint, &ThisWidth, 0); 564 | r32 CharAdvance = Font->Scale * (r32)ThisWidth; 565 | #endif 566 | 567 | for(u32 OtherGlyphIndex = 0; 568 | OtherGlyphIndex < Font->MaxGlyphCount; 569 | ++OtherGlyphIndex) 570 | { 571 | Font->HorizontalAdvance[GlyphIndex*Font->MaxGlyphCount + OtherGlyphIndex] += CharAdvance - KerningChange; 572 | if(OtherGlyphIndex != 0) 573 | { 574 | Font->HorizontalAdvance[OtherGlyphIndex*Font->MaxGlyphCount + GlyphIndex] += KerningChange; 575 | } 576 | } 577 | 578 | return(Result); 579 | } 580 | 581 | struct riff_iterator 582 | { 583 | uint8 *At; 584 | uint8 *Stop; 585 | }; 586 | 587 | inline riff_iterator 588 | ParseChunkAt(void *At, void *Stop) 589 | { 590 | riff_iterator Iter; 591 | 592 | Iter.At = (uint8 *)At; 593 | Iter.Stop = (uint8 *)Stop; 594 | 595 | return(Iter); 596 | } 597 | 598 | inline riff_iterator 599 | NextChunk(riff_iterator Iter) 600 | { 601 | WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At; 602 | uint32 Size = (Chunk->Size + 1) & ~1; 603 | Iter.At += sizeof(WAVE_chunk) + Size; 604 | 605 | return(Iter); 606 | } 607 | 608 | inline bool32 609 | IsValid(riff_iterator Iter) 610 | { 611 | bool32 Result = (Iter.At < Iter.Stop); 612 | 613 | return(Result); 614 | } 615 | 616 | inline void * 617 | GetChunkData(riff_iterator Iter) 618 | { 619 | void *Result = (Iter.At + sizeof(WAVE_chunk)); 620 | 621 | return(Result); 622 | } 623 | 624 | inline uint32 625 | GetType(riff_iterator Iter) 626 | { 627 | WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At; 628 | uint32 Result = Chunk->ID; 629 | 630 | return(Result); 631 | } 632 | 633 | inline uint32 634 | GetChunkDataSize(riff_iterator Iter) 635 | { 636 | WAVE_chunk *Chunk = (WAVE_chunk *)Iter.At; 637 | uint32 Result = Chunk->Size; 638 | 639 | return(Result); 640 | } 641 | 642 | struct loaded_sound 643 | { 644 | uint32 SampleCount; // NOTE(casey): This is the sample count divided by 8 645 | uint32 ChannelCount; 646 | int16 *Samples[2]; 647 | 648 | void *Free; 649 | }; 650 | 651 | internal loaded_sound 652 | LoadWAV(char *FileName, u32 SectionFirstSampleIndex, u32 SectionSampleCount) 653 | { 654 | loaded_sound Result = {}; 655 | 656 | entire_file ReadResult = ReadEntireFile(FileName); 657 | if(ReadResult.ContentsSize != 0) 658 | { 659 | Result.Free = ReadResult.Contents; 660 | 661 | WAVE_header *Header = (WAVE_header *)ReadResult.Contents; 662 | Assert(Header->RIFFID == WAVE_ChunkID_RIFF); 663 | Assert(Header->WAVEID == WAVE_ChunkID_WAVE); 664 | 665 | uint32 ChannelCount = 0; 666 | uint32 SampleDataSize = 0; 667 | int16 *SampleData = 0; 668 | for(riff_iterator Iter = ParseChunkAt(Header + 1, (uint8 *)(Header + 1) + Header->Size - 4); 669 | IsValid(Iter); 670 | Iter = NextChunk(Iter)) 671 | { 672 | switch(GetType(Iter)) 673 | { 674 | case WAVE_ChunkID_fmt: 675 | { 676 | WAVE_fmt *fmt = (WAVE_fmt *)GetChunkData(Iter); 677 | Assert(fmt->wFormatTag == 1); // NOTE(casey): Only support PCM 678 | Assert(fmt->nSamplesPerSec == 48000); 679 | Assert(fmt->wBitsPerSample == 16); 680 | Assert(fmt->nBlockAlign == (sizeof(int16)*fmt->nChannels)); 681 | ChannelCount = fmt->nChannels; 682 | } break; 683 | 684 | case WAVE_ChunkID_data: 685 | { 686 | SampleData = (int16 *)GetChunkData(Iter); 687 | SampleDataSize = GetChunkDataSize(Iter); 688 | } break; 689 | } 690 | } 691 | 692 | Assert(ChannelCount && SampleData); 693 | 694 | Result.ChannelCount = ChannelCount; 695 | u32 SampleCount = SampleDataSize / (ChannelCount*sizeof(int16)); 696 | if(ChannelCount == 1) 697 | { 698 | Result.Samples[0] = SampleData; 699 | Result.Samples[1] = 0; 700 | } 701 | else if(ChannelCount == 2) 702 | { 703 | Result.Samples[0] = SampleData; 704 | Result.Samples[1] = SampleData + SampleCount; 705 | 706 | #if 0 707 | for(uint32 SampleIndex = 0; 708 | SampleIndex < SampleCount; 709 | ++SampleIndex) 710 | { 711 | SampleData[2*SampleIndex + 0] = (int16)SampleIndex; 712 | SampleData[2*SampleIndex + 1] = (int16)SampleIndex; 713 | } 714 | #endif 715 | 716 | for(uint32 SampleIndex = 0; 717 | SampleIndex < SampleCount; 718 | ++SampleIndex) 719 | { 720 | int16 Source = SampleData[2*SampleIndex]; 721 | SampleData[2*SampleIndex] = SampleData[SampleIndex]; 722 | SampleData[SampleIndex] = Source; 723 | } 724 | } 725 | else 726 | { 727 | Assert(!"Invalid channel count in WAV file"); 728 | } 729 | 730 | // TODO(casey): Load right channels! 731 | b32 AtEnd = true; 732 | Result.ChannelCount = 1; 733 | if(SectionSampleCount) 734 | { 735 | Assert((SectionFirstSampleIndex + SectionSampleCount) <= SampleCount); 736 | AtEnd = ((SectionFirstSampleIndex + SectionSampleCount) == SampleCount); 737 | SampleCount = SectionSampleCount; 738 | for(uint32 ChannelIndex = 0; 739 | ChannelIndex < Result.ChannelCount; 740 | ++ChannelIndex) 741 | { 742 | Result.Samples[ChannelIndex] += SectionFirstSampleIndex; 743 | } 744 | } 745 | 746 | if(AtEnd) 747 | { 748 | for(uint32 ChannelIndex = 0; 749 | ChannelIndex < Result.ChannelCount; 750 | ++ChannelIndex) 751 | { 752 | for(u32 SampleIndex = SampleCount; 753 | SampleIndex < (SampleCount + 8); 754 | ++SampleIndex) 755 | { 756 | Result.Samples[ChannelIndex][SampleIndex] = 0; 757 | } 758 | } 759 | } 760 | 761 | Result.SampleCount = SampleCount; 762 | } 763 | 764 | return(Result); 765 | } 766 | 767 | internal void 768 | BeginAssetType(game_assets *Assets, asset_type_id TypeID) 769 | { 770 | Assert(Assets->DEBUGAssetType == 0); 771 | 772 | Assets->DEBUGAssetType = Assets->AssetTypes + TypeID; 773 | Assets->DEBUGAssetType->TypeID = TypeID; 774 | Assets->DEBUGAssetType->FirstAssetIndex = Assets->AssetCount; 775 | Assets->DEBUGAssetType->OnePastLastAssetIndex = Assets->DEBUGAssetType->FirstAssetIndex; 776 | } 777 | 778 | struct added_asset 779 | { 780 | u32 ID; 781 | hha_asset *HHA; 782 | asset_source *Source; 783 | }; 784 | internal added_asset 785 | AddAsset(game_assets *Assets) 786 | { 787 | Assert(Assets->DEBUGAssetType); 788 | Assert(Assets->DEBUGAssetType->OnePastLastAssetIndex < ArrayCount(Assets->Assets)); 789 | 790 | u32 Index = Assets->DEBUGAssetType->OnePastLastAssetIndex++; 791 | asset_source *Source = Assets->AssetSources + Index; 792 | hha_asset *HHA = Assets->Assets + Index; 793 | HHA->FirstTagIndex = Assets->TagCount; 794 | HHA->OnePastLastTagIndex = HHA->FirstTagIndex; 795 | 796 | Assets->AssetIndex = Index; 797 | 798 | added_asset Result; 799 | Result.ID = Index; 800 | Result.HHA = HHA; 801 | Result.Source = Source; 802 | return(Result); 803 | } 804 | 805 | internal bitmap_id 806 | AddBitmapAsset(game_assets *Assets, char *FileName, r32 AlignPercentageX = 0.5f, r32 AlignPercentageY = 0.5f) 807 | { 808 | added_asset Asset = AddAsset(Assets); 809 | Asset.HHA->Bitmap.AlignPercentage[0] = AlignPercentageX; 810 | Asset.HHA->Bitmap.AlignPercentage[1] = AlignPercentageY; 811 | Asset.Source->Type = AssetType_Bitmap; 812 | Asset.Source->Bitmap.FileName = FileName; 813 | 814 | bitmap_id Result = {Asset.ID}; 815 | return(Result); 816 | } 817 | 818 | internal bitmap_id 819 | AddCharacterAsset(game_assets *Assets, loaded_font *Font, u32 Codepoint) 820 | { 821 | added_asset Asset = AddAsset(Assets); 822 | Asset.HHA->Bitmap.AlignPercentage[0] = 0.0f; // NOTE(casey): Set later by extraction 823 | Asset.HHA->Bitmap.AlignPercentage[1] = 0.0f; // NOTE(casey): Set later by extraction 824 | Asset.Source->Type = AssetType_FontGlyph; 825 | Asset.Source->Glyph.Font = Font; 826 | Asset.Source->Glyph.Codepoint = Codepoint; 827 | 828 | bitmap_id Result = {Asset.ID}; 829 | 830 | Assert(Font->GlyphCount < Font->MaxGlyphCount); 831 | u32 GlyphIndex = Font->GlyphCount++; 832 | hha_font_glyph *Glyph = Font->Glyphs + GlyphIndex; 833 | Glyph->UnicodeCodePoint = Codepoint; 834 | Glyph->BitmapID = Result; 835 | Font->GlyphIndexFromCodePoint[Codepoint] = GlyphIndex; 836 | 837 | if(Font->OnePastHighestCodepoint <= Codepoint) 838 | { 839 | Font->OnePastHighestCodepoint = Codepoint + 1; 840 | } 841 | 842 | return(Result); 843 | } 844 | 845 | internal sound_id 846 | AddSoundAsset(game_assets *Assets, char *FileName, u32 FirstSampleIndex = 0, u32 SampleCount = 0) 847 | { 848 | added_asset Asset = AddAsset(Assets); 849 | Asset.HHA->Sound.SampleCount = SampleCount; 850 | Asset.HHA->Sound.Chain = HHASoundChain_None; 851 | Asset.Source->Type = AssetType_Sound; 852 | Asset.Source->Sound.FileName = FileName; 853 | Asset.Source->Sound.FirstSampleIndex = FirstSampleIndex; 854 | 855 | sound_id Result = {Asset.ID}; 856 | return(Result); 857 | } 858 | 859 | internal font_id 860 | AddFontAsset(game_assets *Assets, loaded_font *Font) 861 | { 862 | added_asset Asset = AddAsset(Assets); 863 | Asset.HHA->Font.OnePastHighestCodepoint = Font->OnePastHighestCodepoint; 864 | Asset.HHA->Font.GlyphCount = Font->GlyphCount; 865 | #if USE_FONTS_FROM_WINDOWS 866 | Asset.HHA->Font.AscenderHeight = (r32)Font->TextMetric.tmAscent; 867 | Asset.HHA->Font.DescenderHeight = (r32)Font->TextMetric.tmDescent; 868 | Asset.HHA->Font.ExternalLeading = (r32)Font->TextMetric.tmExternalLeading; 869 | #else 870 | Asset.HHA->Font.AscenderHeight = Font->FontMetric.Ascent; 871 | Asset.HHA->Font.DescenderHeight = Font->FontMetric.Descent; 872 | Asset.HHA->Font.ExternalLeading = Font->FontMetric.Leading; 873 | #endif 874 | Asset.Source->Type = AssetType_Font; 875 | Asset.Source->Font.Font = Font; 876 | 877 | font_id Result = {Asset.ID}; 878 | return(Result); 879 | } 880 | 881 | internal void 882 | AddTag(game_assets *Assets, asset_tag_id ID, real32 Value) 883 | { 884 | Assert(Assets->AssetIndex); 885 | 886 | hha_asset *HHA = Assets->Assets + Assets->AssetIndex; 887 | ++HHA->OnePastLastTagIndex; 888 | hha_tag *Tag = Assets->Tags + Assets->TagCount++; 889 | 890 | Tag->ID = ID; 891 | Tag->Value = Value; 892 | } 893 | 894 | internal void 895 | EndAssetType(game_assets *Assets) 896 | { 897 | Assert(Assets->DEBUGAssetType); 898 | Assets->AssetCount = Assets->DEBUGAssetType->OnePastLastAssetIndex; 899 | Assets->DEBUGAssetType = 0; 900 | Assets->AssetIndex = 0; 901 | } 902 | 903 | internal void 904 | WriteHHA(game_assets *Assets, char *FileName) 905 | { 906 | FILE *Out = fopen(FileName, "wb"); 907 | if(Out) 908 | { 909 | hha_header Header = {}; 910 | Header.MagicValue = HHA_MAGIC_VALUE; 911 | Header.Version = HHA_VERSION; 912 | Header.TagCount = Assets->TagCount; 913 | Header.AssetTypeCount = Asset_Count; // TODO(casey): Do we really want to do this? Sparseness! 914 | Header.AssetCount = Assets->AssetCount; 915 | 916 | u32 TagArraySize = Header.TagCount*sizeof(hha_tag); 917 | u32 AssetTypeArraySize = Header.AssetTypeCount*sizeof(hha_asset_type); 918 | u32 AssetArraySize = Header.AssetCount*sizeof(hha_asset); 919 | 920 | Header.Tags = sizeof(Header); 921 | Header.AssetTypes = Header.Tags + TagArraySize; 922 | Header.Assets = Header.AssetTypes + AssetTypeArraySize; 923 | 924 | fwrite(&Header, sizeof(Header), 1, Out); 925 | fwrite(Assets->Tags, TagArraySize, 1, Out); 926 | fwrite(Assets->AssetTypes, AssetTypeArraySize, 1, Out); 927 | fseek(Out, AssetArraySize, SEEK_CUR); 928 | for(u32 AssetIndex = 1; 929 | AssetIndex < Header.AssetCount; 930 | ++AssetIndex) 931 | { 932 | asset_source *Source = Assets->AssetSources + AssetIndex; 933 | hha_asset *Dest = Assets->Assets + AssetIndex; 934 | 935 | Dest->DataOffset = ftell(Out); 936 | 937 | if(Source->Type == AssetType_Sound) 938 | { 939 | loaded_sound WAV = LoadWAV(Source->Sound.FileName, 940 | Source->Sound.FirstSampleIndex, 941 | Dest->Sound.SampleCount); 942 | 943 | Dest->Sound.SampleCount = WAV.SampleCount; 944 | Dest->Sound.ChannelCount = WAV.ChannelCount; 945 | 946 | for(u32 ChannelIndex = 0; 947 | ChannelIndex < WAV.ChannelCount; 948 | ++ChannelIndex) 949 | { 950 | fwrite(WAV.Samples[ChannelIndex], Dest->Sound.SampleCount*sizeof(s16), 1, Out); 951 | } 952 | 953 | free(WAV.Free); 954 | } 955 | else if(Source->Type == AssetType_Font) 956 | { 957 | loaded_font *Font = Source->Font.Font; 958 | 959 | FinalizeFontKerning(Font); 960 | 961 | u32 GlyphsSize = Font->GlyphCount*sizeof(hha_font_glyph); 962 | fwrite(Font->Glyphs, GlyphsSize, 1, Out); 963 | 964 | u8 *HorizontalAdvance = (u8 *)Font->HorizontalAdvance; 965 | for(u32 GlyphIndex = 0; 966 | GlyphIndex < Font->GlyphCount; 967 | ++GlyphIndex) 968 | { 969 | u32 HorizontalAdvanceSliceSize = sizeof(r32)*Font->GlyphCount; 970 | fwrite(HorizontalAdvance, HorizontalAdvanceSliceSize, 1, Out); 971 | HorizontalAdvance += sizeof(r32)*Font->MaxGlyphCount; 972 | } 973 | } 974 | else 975 | { 976 | loaded_bitmap Bitmap; 977 | if(Source->Type == AssetType_FontGlyph) 978 | { 979 | Bitmap = LoadGlyphBitmap(Source->Glyph.Font, Source->Glyph.Codepoint, Dest); 980 | } 981 | else 982 | { 983 | Assert(Source->Type == AssetType_Bitmap); 984 | Bitmap = LoadBMP(Source->Bitmap.FileName); 985 | } 986 | 987 | Dest->Bitmap.Dim[0] = Bitmap.Width; 988 | Dest->Bitmap.Dim[1] = Bitmap.Height; 989 | 990 | Assert((Bitmap.Width*4) == Bitmap.Pitch); 991 | fwrite(Bitmap.Memory, Bitmap.Width*Bitmap.Height*4, 1, Out); 992 | 993 | free(Bitmap.Free); 994 | } 995 | } 996 | fseek(Out, (u32)Header.Assets, SEEK_SET); 997 | fwrite(Assets->Assets, AssetArraySize, 1, Out); 998 | 999 | fclose(Out); 1000 | } 1001 | else 1002 | { 1003 | printf("ERROR: Couldn't open file :(\n"); 1004 | } 1005 | } 1006 | 1007 | internal void 1008 | Initialize(game_assets *Assets) 1009 | { 1010 | Assets->TagCount = 1; 1011 | Assets->AssetCount = 1; 1012 | Assets->DEBUGAssetType = 0; 1013 | Assets->AssetIndex = 0; 1014 | 1015 | Assets->AssetTypeCount = Asset_Count; 1016 | memset(Assets->AssetTypes, 0, sizeof(Assets->AssetTypes)); 1017 | } 1018 | 1019 | internal void 1020 | WriteFonts(void) 1021 | { 1022 | game_assets Assets_; 1023 | game_assets *Assets = &Assets_; 1024 | Initialize(Assets); 1025 | 1026 | loaded_font *Fonts[] = 1027 | { 1028 | #if USE_FONTS_FROM_WINDOWS 1029 | LoadFont("c:/Windows/Fonts/arial.ttf", "Arial", 128), 1030 | LoadFont("c:/Windows/Fonts/LiberationMono-Regular.ttf", "Liberation Mono", 20), 1031 | #else 1032 | // NOTE(jeff): You can also pick a .ttf or .ttc font on OS X from either: 1033 | // /System/Library/Fonts 1034 | // or 1035 | // ~/Library/Fonts 1036 | // Note that .dfont suitcases do not work with stb_truetype. 1037 | LoadFont("./fonts/LiberationSans-Regular.ttf", "Liberation Sans", 128), 1038 | LoadFont("./fonts/LiberationMono-Regular.ttf", "Liberation Mono", 20), 1039 | #endif 1040 | }; 1041 | 1042 | BeginAssetType(Assets, Asset_FontGlyph); 1043 | for(u32 FontIndex = 0; 1044 | FontIndex < ArrayCount(Fonts); 1045 | ++FontIndex) 1046 | { 1047 | loaded_font *Font = Fonts[FontIndex]; 1048 | 1049 | AddCharacterAsset(Assets, Font, ' '); 1050 | for(u32 Character = '!'; 1051 | Character <= '~'; 1052 | ++Character) 1053 | { 1054 | AddCharacterAsset(Assets, Font, Character); 1055 | } 1056 | 1057 | // NOTE(casey): Kanji OWL!!!!!!! 1058 | AddCharacterAsset(Assets, Font, 0x5c0f); 1059 | AddCharacterAsset(Assets, Font, 0x8033); 1060 | AddCharacterAsset(Assets, Font, 0x6728); 1061 | AddCharacterAsset(Assets, Font, 0x514e); 1062 | } 1063 | EndAssetType(Assets); 1064 | 1065 | // TODO(casey): This is kinda janky, because it means you have to get this 1066 | // order right always! 1067 | BeginAssetType(Assets, Asset_Font); 1068 | AddFontAsset(Assets, Fonts[0]); 1069 | AddTag(Assets, Tag_FontType, FontType_Default); 1070 | AddFontAsset(Assets, Fonts[1]); 1071 | AddTag(Assets, Tag_FontType, FontType_Debug); 1072 | EndAssetType(Assets); 1073 | 1074 | WriteHHA(Assets, "testfonts.hha"); 1075 | } 1076 | 1077 | internal void 1078 | WriteHero(void) 1079 | { 1080 | game_assets Assets_; 1081 | game_assets *Assets = &Assets_; 1082 | Initialize(Assets); 1083 | 1084 | real32 AngleRight = 0.0f*Tau32; 1085 | real32 AngleBack = 0.25f*Tau32; 1086 | real32 AngleLeft = 0.5f*Tau32; 1087 | real32 AngleFront = 0.75f*Tau32; 1088 | 1089 | r32 HeroAlign[] = {0.5f, 0.156682029f}; 1090 | 1091 | BeginAssetType(Assets, Asset_Head); 1092 | AddBitmapAsset(Assets, "test/test_hero_right_head.bmp", HeroAlign[0], HeroAlign[1]); 1093 | AddTag(Assets, Tag_FacingDirection, AngleRight); 1094 | AddBitmapAsset(Assets, "test/test_hero_back_head.bmp", HeroAlign[0], HeroAlign[1]); 1095 | AddTag(Assets, Tag_FacingDirection, AngleBack); 1096 | AddBitmapAsset(Assets, "test/test_hero_left_head.bmp", HeroAlign[0], HeroAlign[1]); 1097 | AddTag(Assets, Tag_FacingDirection, AngleLeft); 1098 | AddBitmapAsset(Assets, "test/test_hero_front_head.bmp", HeroAlign[0], HeroAlign[1]); 1099 | AddTag(Assets, Tag_FacingDirection, AngleFront); 1100 | EndAssetType(Assets); 1101 | 1102 | BeginAssetType(Assets, Asset_Cape); 1103 | AddBitmapAsset(Assets, "test/test_hero_right_cape.bmp", HeroAlign[0], HeroAlign[1]); 1104 | AddTag(Assets, Tag_FacingDirection, AngleRight); 1105 | AddBitmapAsset(Assets, "test/test_hero_back_cape.bmp", HeroAlign[0], HeroAlign[1]); 1106 | AddTag(Assets, Tag_FacingDirection, AngleBack); 1107 | AddBitmapAsset(Assets, "test/test_hero_left_cape.bmp", HeroAlign[0], HeroAlign[1]); 1108 | AddTag(Assets, Tag_FacingDirection, AngleLeft); 1109 | AddBitmapAsset(Assets, "test/test_hero_front_cape.bmp", HeroAlign[0], HeroAlign[1]); 1110 | AddTag(Assets, Tag_FacingDirection, AngleFront); 1111 | EndAssetType(Assets); 1112 | 1113 | BeginAssetType(Assets, Asset_Torso); 1114 | AddBitmapAsset(Assets, "test/test_hero_right_torso.bmp", HeroAlign[0], HeroAlign[1]); 1115 | AddTag(Assets, Tag_FacingDirection, AngleRight); 1116 | AddBitmapAsset(Assets, "test/test_hero_back_torso.bmp", HeroAlign[0], HeroAlign[1]); 1117 | AddTag(Assets, Tag_FacingDirection, AngleBack); 1118 | AddBitmapAsset(Assets, "test/test_hero_left_torso.bmp", HeroAlign[0], HeroAlign[1]); 1119 | AddTag(Assets, Tag_FacingDirection, AngleLeft); 1120 | AddBitmapAsset(Assets, "test/test_hero_front_torso.bmp", HeroAlign[0], HeroAlign[1]); 1121 | AddTag(Assets, Tag_FacingDirection, AngleFront); 1122 | EndAssetType(Assets); 1123 | 1124 | WriteHHA(Assets, "test1.hha"); 1125 | } 1126 | 1127 | internal void 1128 | WriteNonHero(void) 1129 | { 1130 | game_assets Assets_; 1131 | game_assets *Assets = &Assets_; 1132 | Initialize(Assets); 1133 | 1134 | BeginAssetType(Assets, Asset_Shadow); 1135 | AddBitmapAsset(Assets, "test/test_hero_shadow.bmp", 0.5f, 0.156682029f); 1136 | EndAssetType(Assets); 1137 | 1138 | BeginAssetType(Assets, Asset_Tree); 1139 | AddBitmapAsset(Assets, "test2/tree00.bmp", 0.493827164f, 0.295652181f); 1140 | EndAssetType(Assets); 1141 | 1142 | BeginAssetType(Assets, Asset_Sword); 1143 | AddBitmapAsset(Assets, "test2/rock03.bmp", 0.5f, 0.65625f); 1144 | EndAssetType(Assets); 1145 | 1146 | BeginAssetType(Assets, Asset_Grass); 1147 | AddBitmapAsset(Assets, "test2/grass00.bmp"); 1148 | AddBitmapAsset(Assets, "test2/grass01.bmp"); 1149 | EndAssetType(Assets); 1150 | 1151 | BeginAssetType(Assets, Asset_Tuft); 1152 | AddBitmapAsset(Assets, "test2/tuft00.bmp"); 1153 | AddBitmapAsset(Assets, "test2/tuft01.bmp"); 1154 | AddBitmapAsset(Assets, "test2/tuft02.bmp"); 1155 | EndAssetType(Assets); 1156 | 1157 | BeginAssetType(Assets, Asset_Stone); 1158 | AddBitmapAsset(Assets, "test2/ground00.bmp"); 1159 | AddBitmapAsset(Assets, "test2/ground01.bmp"); 1160 | AddBitmapAsset(Assets, "test2/ground02.bmp"); 1161 | AddBitmapAsset(Assets, "test2/ground03.bmp"); 1162 | EndAssetType(Assets); 1163 | 1164 | WriteHHA(Assets, "test2.hha"); 1165 | } 1166 | 1167 | internal void 1168 | WriteSounds(void) 1169 | { 1170 | game_assets Assets_; 1171 | game_assets *Assets = &Assets_; 1172 | Initialize(Assets); 1173 | 1174 | BeginAssetType(Assets, Asset_Bloop); 1175 | AddSoundAsset(Assets, "test3/bloop_00.wav"); 1176 | AddSoundAsset(Assets, "test3/bloop_01.wav"); 1177 | AddSoundAsset(Assets, "test3/bloop_02.wav"); 1178 | AddSoundAsset(Assets, "test3/bloop_03.wav"); 1179 | AddSoundAsset(Assets, "test3/bloop_04.wav"); 1180 | EndAssetType(Assets); 1181 | 1182 | BeginAssetType(Assets, Asset_Crack); 1183 | AddSoundAsset(Assets, "test3/crack_00.wav"); 1184 | EndAssetType(Assets); 1185 | 1186 | BeginAssetType(Assets, Asset_Drop); 1187 | AddSoundAsset(Assets, "test3/drop_00.wav"); 1188 | EndAssetType(Assets); 1189 | 1190 | BeginAssetType(Assets, Asset_Glide); 1191 | AddSoundAsset(Assets, "test3/glide_00.wav"); 1192 | EndAssetType(Assets); 1193 | 1194 | u32 OneMusicChunk = 10*48000; 1195 | u32 TotalMusicSampleCount = 7468095; 1196 | BeginAssetType(Assets, Asset_Music); 1197 | for(u32 FirstSampleIndex = 0; 1198 | FirstSampleIndex < TotalMusicSampleCount; 1199 | FirstSampleIndex += OneMusicChunk) 1200 | { 1201 | u32 SampleCount = TotalMusicSampleCount - FirstSampleIndex; 1202 | if(SampleCount > OneMusicChunk) 1203 | { 1204 | SampleCount = OneMusicChunk; 1205 | } 1206 | sound_id ThisMusic = AddSoundAsset(Assets, "test3/music_test.wav", FirstSampleIndex, SampleCount); 1207 | if((FirstSampleIndex + OneMusicChunk) < TotalMusicSampleCount) 1208 | { 1209 | Assets->Assets[ThisMusic.Value].Sound.Chain = HHASoundChain_Advance; 1210 | } 1211 | } 1212 | EndAssetType(Assets); 1213 | 1214 | BeginAssetType(Assets, Asset_Puhp); 1215 | AddSoundAsset(Assets, "test3/puhp_00.wav"); 1216 | AddSoundAsset(Assets, "test3/puhp_01.wav"); 1217 | EndAssetType(Assets); 1218 | 1219 | WriteHHA(Assets, "test3.hha"); 1220 | } 1221 | 1222 | int 1223 | main(int ArgCount, char **Args) 1224 | { 1225 | #if USE_FONTS_FROM_WINDOWS 1226 | InitializeFontDC(); 1227 | #endif 1228 | 1229 | WriteFonts(); 1230 | WriteNonHero(); 1231 | WriteHero(); 1232 | WriteSounds(); 1233 | } 1234 | -------------------------------------------------------------------------------- /code/osx_asset_builder.h: -------------------------------------------------------------------------------- 1 | #if !defined(TEST_ASSET_BUILDER_H) 2 | /* ======================================================================== 3 | $File: $ 4 | $Date: $ 5 | $Revision: $ 6 | $Creator: Casey Muratori $ 7 | $Notice: (C) Copyright 2015 by Molly Rocket, Inc. All Rights Reserved. $ 8 | ======================================================================== */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "handmade_platform.h" 14 | #include "handmade_file_formats.h" 15 | #include "handmade_intrinsics.h" 16 | #include "handmade_math.h" 17 | 18 | #define ONE_PAST_MAX_FONT_CODEPOINT (0x10FFFF + 1) 19 | 20 | //#define USE_FONTS_FROM_WINDOWS 1 21 | 22 | #if USE_FONTS_FROM_WINDOWS 23 | #include 24 | 25 | #define MAX_FONT_WIDTH 1024 26 | #define MAX_FONT_HEIGHT 1024 27 | 28 | global_variable VOID *GlobalFontBits; 29 | global_variable HDC GlobalFontDeviceContext; 30 | 31 | #else 32 | #define STB_TRUETYPE_IMPLEMENTATION 33 | #include "stb_truetype.h" 34 | #endif 35 | 36 | struct loaded_bitmap 37 | { 38 | int32 Width; 39 | int32 Height; 40 | int32 Pitch; 41 | void *Memory; 42 | 43 | void *Free; 44 | }; 45 | 46 | #if not USE_FONTS_FROM_WINDOWS 47 | struct font_metric 48 | { 49 | int32 Ascent; 50 | int32 Descent; 51 | int32 Leading; 52 | }; 53 | #endif 54 | 55 | struct loaded_font 56 | { 57 | #if USE_FONTS_FROM_WINDOWS 58 | HFONT Win32Handle; 59 | TEXTMETRIC TextMetric; 60 | #else 61 | stbtt_fontinfo FontInfo; 62 | font_metric FontMetric; 63 | r32 Scale; 64 | #endif 65 | 66 | r32 LineAdvance; 67 | 68 | hha_font_glyph *Glyphs; 69 | r32 *HorizontalAdvance; 70 | 71 | u32 MinCodePoint; 72 | u32 MaxCodePoint; 73 | 74 | u32 MaxGlyphCount; 75 | u32 GlyphCount; 76 | 77 | u32 *GlyphIndexFromCodePoint; 78 | u32 OnePastHighestCodepoint; 79 | }; 80 | 81 | enum asset_type 82 | { 83 | AssetType_Sound, 84 | AssetType_Bitmap, 85 | AssetType_Font, 86 | AssetType_FontGlyph, 87 | }; 88 | 89 | struct loaded_font; 90 | struct asset_source_font 91 | { 92 | loaded_font *Font; 93 | }; 94 | 95 | struct asset_source_font_glyph 96 | { 97 | loaded_font *Font; 98 | u32 Codepoint; 99 | }; 100 | 101 | struct asset_source_bitmap 102 | { 103 | char *FileName; 104 | }; 105 | 106 | struct asset_source_sound 107 | { 108 | char *FileName; 109 | u32 FirstSampleIndex; 110 | }; 111 | 112 | struct asset_source 113 | { 114 | asset_type Type; 115 | union 116 | { 117 | asset_source_bitmap Bitmap; 118 | asset_source_sound Sound; 119 | asset_source_font Font; 120 | asset_source_font_glyph Glyph; 121 | }; 122 | }; 123 | 124 | // TODO(casey): Are there larger numbers than 4096? Do we have evidence 125 | // in the natural world of things that can exist in quantities _larger_ than 4096? 126 | #define VERY_LARGE_NUMBER 4096 // NOTE(casey): 4096 should be enough for anybody 127 | 128 | struct game_assets 129 | { 130 | u32 TagCount; 131 | hha_tag Tags[VERY_LARGE_NUMBER]; 132 | 133 | u32 AssetTypeCount; 134 | hha_asset_type AssetTypes[Asset_Count]; 135 | 136 | u32 AssetCount; 137 | asset_source AssetSources[VERY_LARGE_NUMBER]; 138 | hha_asset Assets[VERY_LARGE_NUMBER]; 139 | 140 | hha_asset_type *DEBUGAssetType; 141 | u32 AssetIndex; 142 | }; 143 | 144 | #define TEST_ASSET_BUILDER_H 145 | #endif 146 | -------------------------------------------------------------------------------- /code/osx_handmade.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_main.mm 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2017. All Rights Reserved. 6 | // 7 | 8 | /* 9 | This will be updated to keep parity with Casey's win32 platform layer. 10 | See his win32_handmade.cpp file for TODO details. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include // for OSMemoryBarrier 28 | #include 29 | 30 | #define GL_GLEXT_LEGACY 31 | 32 | #include 33 | #include 34 | //#include 35 | //#include 36 | 37 | #include "handmade_platform.h" 38 | 39 | 40 | #define GL_BGRA_EXT 0x80E1 41 | #define GL_NUM_EXTENSIONS 0x821D 42 | 43 | typedef char GLchar; 44 | 45 | typedef void gl_tex_image_2d_multisample(GLenum target, GLsizei samples, GLenum internalformat, 46 | GLsizei width, GLsizei height, GLboolean fixedsamplelocations); 47 | typedef void gl_bind_framebuffer(GLenum target, GLuint framebuffer); 48 | typedef void gl_gen_framebuffers(GLsizei n, GLuint *framebuffers); 49 | typedef void gl_framebuffer_texture_2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); 50 | typedef GLenum gl_check_framebuffer_status(GLenum target); 51 | typedef void gl_blit_framebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); 52 | typedef void gl_attach_shader(GLuint program, GLuint shader); 53 | typedef void gl_compile_shader(GLuint shader); 54 | typedef GLuint gl_create_program(void); 55 | typedef GLuint gl_create_shader(GLenum type); 56 | typedef void gl_link_program(GLuint program); 57 | typedef void gl_shader_source(GLuint shader, GLsizei count, GLchar **string, GLint *length); 58 | typedef void gl_use_program(GLuint program); 59 | typedef void gl_get_program_info_log(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); 60 | typedef void gl_get_shader_info_log(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); 61 | typedef void gl_validate_program(GLuint program); 62 | typedef void gl_get_program_iv(GLuint program, GLenum pname, GLint *params); 63 | 64 | typedef void type_glBindVertexArray(GLuint array); 65 | typedef void type_glGenVertexArrays(GLsizei n, GLuint *arrays); 66 | typedef GLubyte* type_glGetStringi(GLenum name, GLuint index); 67 | typedef GLubyte* type_glGetStringi(GLenum name, GLuint index); 68 | 69 | typedef void type_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers); 70 | 71 | global_variable gl_tex_image_2d_multisample *glTexImage2DMultisample; 72 | global_variable gl_bind_framebuffer* glBindFramebuffer; 73 | global_variable gl_gen_framebuffers* glGenFramebuffers; 74 | global_variable gl_framebuffer_texture_2D* glFramebufferTexture2D; 75 | global_variable gl_check_framebuffer_status* glCheckFramebufferStatus; 76 | global_variable gl_blit_framebuffer *glBlitFramebuffer; 77 | 78 | #define GL_DEBUG_CALLBACK(Name) void Name(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam) 79 | typedef GL_DEBUG_CALLBACK(GLDEBUGPROC); 80 | typedef void type_glDebugMessageCallbackARB(GLDEBUGPROC *callback, const void *userParam); 81 | 82 | #define OpenGLGlobalFunction(Name) global_variable type_##Name *Name; 83 | OpenGLGlobalFunction(glDebugMessageCallbackARB); 84 | OpenGLGlobalFunction(glGetStringi); 85 | 86 | #if 0 87 | global_variable gl_attach_shader *glAttachShader; 88 | global_variable gl_compile_shader *glCompileShader; 89 | global_variable gl_create_program *glCreateProgram; 90 | global_variable gl_create_shader *glCreateShader; 91 | global_variable gl_link_program *glLinkProgram; 92 | global_variable gl_shader_source *glShaderSource; 93 | global_variable gl_use_program *glUseProgram; 94 | global_variable gl_get_program_info_log *glGetProgramInfoLog; 95 | global_variable gl_get_shader_info_log *glGetShaderInfoLog; 96 | global_variable gl_validate_program *glValidateProgram; 97 | global_variable gl_get_program_iv *glGetProgramiv; 98 | #endif 99 | 100 | OpenGLGlobalFunction(glBindVertexArray); 101 | OpenGLGlobalFunction(glGenVertexArrays); 102 | OpenGLGlobalFunction(glDeleteFramebuffers); 103 | 104 | 105 | //#include "handmade_intrinsics.h" 106 | //#include "handmade_math.h" 107 | #include "handmade_shared.h" 108 | 109 | #include "osx_handmade.h" 110 | 111 | platform_api Platform; 112 | 113 | 114 | global_variable b32 GlobalSoftwareRendering; 115 | global_variable b32 GlobalRunning = 1; 116 | global_variable b32 GlobalPause; 117 | 118 | global_variable GLuint OpenGLDefaultInternalTextureFormat; 119 | 120 | 121 | 122 | 123 | // NOTE(jeff): These are already defined in glext.h. 124 | #undef GL_EXT_texture_sRGB 125 | #undef GL_EXT_framebuffer_sRGB 126 | 127 | #include "handmade_render.h" 128 | #include "handmade_opengl.h" 129 | 130 | global_variable open_gl OpenGL; 131 | 132 | #include "handmade_sort.cpp" 133 | #include "handmade_opengl.cpp" 134 | #include "handmade_render.cpp" 135 | 136 | #include "osx_handmade_debug.cpp" 137 | #include "osx_handmade_file.cpp" 138 | #include "osx_handmade_process.cpp" 139 | #include "osx_handmade_thread.cpp" 140 | #include "osx_handmade_audio.cpp" 141 | #include "osx_handmade_hid.cpp" 142 | #include "osx_handmade_dylib.cpp" 143 | #include "osx_handmade_playback.cpp" 144 | #include "osx_handmade_game.cpp" 145 | 146 | 147 | #if HANDMADE_INTERNAL 148 | DEBUG_PLATFORM_GET_MEMORY_STATS(OSXGetMemoryStats) 149 | { 150 | debug_platform_memory_stats Stats = {}; 151 | 152 | BeginTicketMutex(&GlobalOSXState.MemoryMutex); 153 | osx_memory_block* Sentinel = &GlobalOSXState.MemorySentinel; 154 | 155 | for (osx_memory_block* SourceBlock = Sentinel->Next; 156 | SourceBlock != Sentinel; 157 | SourceBlock = SourceBlock->Next) 158 | { 159 | Assert(SourceBlock->Block.Size <= U32Max); 160 | 161 | ++Stats.BlockCount; 162 | Stats.TotalSize += SourceBlock->Block.Size; 163 | Stats.TotalUsed += SourceBlock->Block.Used; 164 | } 165 | EndTicketMutex(&GlobalOSXState.MemoryMutex); 166 | 167 | return Stats; 168 | } 169 | #endif 170 | 171 | void OSXVerifyMemoryListIntegrity() 172 | { 173 | BeginTicketMutex(&GlobalOSXState.MemoryMutex); 174 | local_persist u32 FailCounter; 175 | 176 | osx_memory_block* Sentinel = &GlobalOSXState.MemorySentinel; 177 | 178 | for (osx_memory_block* SourceBlock = Sentinel->Next; 179 | SourceBlock != Sentinel; 180 | SourceBlock = SourceBlock->Next) 181 | { 182 | Assert(SourceBlock->Block.Size <= U32Max); 183 | } 184 | 185 | ++FailCounter; 186 | 187 | EndTicketMutex(&GlobalOSXState.MemoryMutex); 188 | } 189 | 190 | inline b32x OSXIsInLoop(osx_state* State) 191 | { 192 | b32x Result = (State->InputRecordingIndex || State->InputPlayingIndex); 193 | return Result; 194 | } 195 | 196 | 197 | //#define PLATFORM_ALLOCATE_MEMORY(name) platform_memory_block* name(memory_index Size, u64 Flags) 198 | PLATFORM_ALLOCATE_MEMORY(OSXAllocateMemory) 199 | { 200 | // NOTE(casey): We require memory block headers not to change the cache 201 | // line alignment of an allocation 202 | Assert(sizeof(osx_memory_block) == 128); 203 | 204 | umm PageSize = 4096; 205 | umm TotalSize = Size + sizeof(osx_memory_block); 206 | umm BaseOffset = sizeof(osx_memory_block); 207 | umm ProtectOffset = 0; 208 | 209 | if (Flags & PlatformMemory_UnderflowCheck) 210 | { 211 | TotalSize += Size + 2 * PageSize; 212 | BaseOffset = 2 * PageSize; 213 | ProtectOffset = PageSize; 214 | } 215 | else if (Flags & PlatformMemory_OverflowCheck) 216 | { 217 | umm SizeRoundedUp = AlignPow2(Size, PageSize); 218 | TotalSize += SizeRoundedUp + 2 * PageSize; 219 | BaseOffset = PageSize + SizeRoundedUp - Size; 220 | ProtectOffset = PageSize + SizeRoundedUp; 221 | } 222 | 223 | //osx_memory_block* Block = (osx_memory_block*)malloc(TotalSize); 224 | osx_memory_block* Block = (osx_memory_block*)mmap(0, 225 | TotalSize, 226 | PROT_READ | PROT_WRITE, 227 | MAP_PRIVATE | MAP_ANON, 228 | -1, 229 | 0); 230 | if (Block == MAP_FAILED) 231 | { 232 | printf("OSXAllocateMemory: mmap error: %d %s", errno, strerror(errno)); 233 | } 234 | 235 | Assert(Block); 236 | Block->Block.Base = (u8*)Block + BaseOffset; 237 | Assert(Block->Block.Used == 0); 238 | Assert(Block->Block.ArenaPrev == 0); 239 | 240 | if (Flags & (PlatformMemory_UnderflowCheck|PlatformMemory_OverflowCheck)) 241 | { 242 | int ProtectResult = mprotect((u8*)Block + ProtectOffset, PageSize, PROT_NONE); 243 | if (ProtectResult != 0) 244 | { 245 | } 246 | else 247 | { 248 | printf("OSXAllocateMemory: Underflow mprotect error: %d %s", errno, strerror(errno)); 249 | } 250 | //Block = (osx_memory_block*)((u8*)Block + PageSize); 251 | } 252 | 253 | osx_memory_block* Sentinel = &GlobalOSXState.MemorySentinel; 254 | Block->Next = Sentinel; 255 | Block->Block.Size = Size; 256 | Block->TotalAllocatedSize = TotalSize; 257 | Block->Block.Flags = Flags; 258 | Block->LoopingFlags = OSXIsInLoop(&GlobalOSXState) ? OSXMem_AllocatedDuringLooping : 0; 259 | 260 | BeginTicketMutex(&GlobalOSXState.MemoryMutex); 261 | Block->Prev = Sentinel->Prev; 262 | Block->Prev->Next = Block; 263 | Block->Next->Prev = Block; 264 | EndTicketMutex(&GlobalOSXState.MemoryMutex); 265 | 266 | platform_memory_block* PlatBlock = &Block->Block; 267 | return PlatBlock; 268 | } 269 | 270 | 271 | void OSXFreeMemoryBlock(osx_memory_block* Block) 272 | { 273 | BeginTicketMutex(&GlobalOSXState.MemoryMutex); 274 | Block->Prev->Next = Block->Next; 275 | Block->Next->Prev = Block->Prev; 276 | EndTicketMutex(&GlobalOSXState.MemoryMutex); 277 | 278 | if (munmap(Block, Block->TotalAllocatedSize) != 0) 279 | { 280 | printf("OSXFreeMemoryBlock: munmap error: %d %s", errno, strerror(errno)); 281 | } 282 | } 283 | 284 | //#define PLATFORM_DEALLOCATE_MEMORY(name) void name(platform_memory_block* Memory) 285 | PLATFORM_DEALLOCATE_MEMORY(OSXDeallocateMemory) 286 | { 287 | if (Block) 288 | { 289 | osx_memory_block* OSXBlock = (osx_memory_block*)Block; 290 | 291 | if (OSXIsInLoop(&GlobalOSXState)) 292 | { 293 | OSXBlock->LoopingFlags = OSXMem_FreedDuringLooping; 294 | } 295 | else 296 | { 297 | OSXFreeMemoryBlock(OSXBlock); 298 | } 299 | } 300 | } 301 | 302 | 303 | -------------------------------------------------------------------------------- /code/osx_handmade.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade.h 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | //#import 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | struct osx_offscreen_buffer 32 | { 33 | // NOTE: Pixels are always 32-bits wide. BB GG RR XX 34 | void* Memory; 35 | int Width; 36 | int Height; 37 | int Pitch; 38 | int BytesPerPixel; 39 | }; 40 | 41 | 42 | struct osx_window_dimension 43 | { 44 | int Width; 45 | int Height; 46 | }; 47 | 48 | 49 | struct osx_game_code 50 | { 51 | void* GameCodeDL; 52 | time_t DLLastWriteTime; 53 | 54 | // IMPORTANT(casey): Either of the callbacks can be 0! You must 55 | // check before calling. 56 | game_update_and_render* UpdateAndRender; 57 | game_get_sound_samples* GetSoundSamples; 58 | debug_game_frame_end* DEBUGFrameEnd; 59 | 60 | bool32 IsValid; 61 | }; 62 | 63 | 64 | struct osx_sound_output 65 | { 66 | game_sound_output_buffer SoundBuffer; 67 | u32 SoundBufferSize; 68 | s16* CoreAudioBuffer; 69 | s16* ReadCursor; 70 | s16* WriteCursor; 71 | 72 | AudioStreamBasicDescription AudioDescriptor; 73 | AudioUnit AudioUnit; 74 | 75 | #if 0 76 | AudioQueueRef AudioQueue; 77 | AudioQueueBufferRef AudioBuffers[2]; 78 | bool32 RanAFrame; 79 | #endif 80 | }; 81 | 82 | 83 | void OSXInitCoreAudio(osx_sound_output* SoundOutput); 84 | void OSXStopCoreAudio(osx_sound_output* SoundOutput); 85 | 86 | 87 | struct osx_replay_buffer 88 | { 89 | char Filename[FILENAME_MAX]; 90 | }; 91 | 92 | enum osx_memory_block_flag 93 | { 94 | OSXMem_AllocatedDuringLooping = 0x1, 95 | OSXMem_FreedDuringLooping = 0x2 96 | }; 97 | 98 | struct osx_memory_block 99 | { 100 | platform_memory_block Block; 101 | 102 | osx_memory_block* Prev; 103 | osx_memory_block* Next; 104 | u64 LoopingFlags; 105 | u64 TotalAllocatedSize; 106 | 107 | u64 Pad[7]; 108 | }; 109 | 110 | 111 | struct osx_saved_memory_block 112 | { 113 | u64 BasePointer; 114 | u64 Size; 115 | }; 116 | 117 | 118 | struct osx_state 119 | { 120 | ticket_mutex MemoryMutex; 121 | osx_memory_block MemorySentinel; 122 | 123 | int RecordingHandle; 124 | int InputRecordingIndex; 125 | 126 | int PlaybackHandle; 127 | int InputPlayingIndex; 128 | 129 | char AppFilename[FILENAME_MAX]; 130 | char* OnePastLastAppFilenameSlash; 131 | }; 132 | 133 | 134 | //extern osx_state GlobalOSXState; 135 | 136 | 137 | #ifndef HANDMADE_USE_ASM_RDTSC 138 | // NOTE(jeff): Thanks to @visitect for this suggestion 139 | #define rdtsc __builtin_readcyclecounter 140 | #else 141 | internal inline uint64 142 | rdtsc() 143 | { 144 | u32 eax = 0; 145 | u32 edx; 146 | 147 | __asm__ __volatile__("cpuid;" 148 | "rdtsc;" 149 | : "+a" (eax), "=d" (edx) 150 | : 151 | : "%rcx", "%rbx", "memory"); 152 | 153 | __asm__ __volatile__("xorl %%eax, %%eax;" 154 | "cpuid;" 155 | : 156 | : 157 | : "%rax", "%rbx", "%rcx", "%rdx", "memory"); 158 | 159 | return (((u64)edx << 32) | eax); 160 | } 161 | #endif 162 | 163 | 164 | #if HANDMADE_INTERNAL 165 | DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory); 166 | DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile); 167 | DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteEntireFile); 168 | DEBUG_PLATFORM_EXECUTE_SYSTEM_COMMAND(DEBUGExecuteSystemCommand); 169 | DEBUG_PLATFORM_GET_PROCESS_STATE(DEBUGGetProcessState); 170 | DEBUG_PLATFORM_GET_MEMORY_STATS(OSXGetMemoryStats); 171 | #endif 172 | 173 | struct osx_platform_file_handle 174 | { 175 | int OSXFileHandle; 176 | char Filename[FILENAME_MAX]; 177 | }; 178 | 179 | 180 | struct osx_platform_file_group 181 | { 182 | glob_t GlobResults; 183 | int CurrentIndex; 184 | }; 185 | 186 | 187 | PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(OSXGetAllFilesOfTypeBegin); 188 | PLATFORM_GET_ALL_FILE_OF_TYPE_END(OSXGetAllFilesOfTypeEnd); 189 | PLATFORM_OPEN_FILE(OSXOpenNextFile); 190 | PLATFORM_READ_DATA_FROM_FILE(OSXReadDataFromFile); 191 | PLATFORM_FILE_ERROR(OSXFileError); 192 | 193 | void OSXFreeMemoryBlock(osx_memory_block* Block); 194 | PLATFORM_ALLOCATE_MEMORY(OSXAllocateMemory); 195 | PLATFORM_DEALLOCATE_MEMORY(OSXDeallocateMemory); 196 | 197 | 198 | 199 | void OSXGetAppFilename(osx_state *State); 200 | 201 | void OSXBuildAppPathFilename(osx_state *State, char *Filename, 202 | int DestCount, char *Dest); 203 | 204 | time_t OSXGetLastWriteTime(const char* Filename); 205 | float OSXGetSecondsElapsed(u64 Then, u64 Now); 206 | 207 | osx_game_code OSXLoadGameCode(const char* SourceDLName); 208 | void OSXUnloadGameCode(osx_game_code* GameCode); 209 | 210 | 211 | void OSXGetInputFileLocation(osx_state* State, bool32 InputStream, int SlotIndex, int DestCount, char* Dest); 212 | void OSXBeginRecordingInput(osx_state* State, int InputRecordingIndex); 213 | void OSXEndRecordingInput(osx_state* State); 214 | void OSXBeginInputPlayback(osx_state* State, int InputPlayingIndex); 215 | void OSXEndInputPlayback(osx_state* State); 216 | void OSXRecordInput(osx_state* State, game_input* NewInput); 217 | void OSXPlaybackInput(osx_state* State, game_input* NewInput); 218 | 219 | 220 | struct platform_work_queue_entry 221 | { 222 | platform_work_queue_callback* Callback; 223 | void* Data; 224 | }; 225 | 226 | 227 | struct platform_work_queue 228 | { 229 | u32 volatile CompletionGoal; 230 | u32 volatile CompletionCount; 231 | 232 | u32 volatile NextEntryToWrite; 233 | u32 volatile NextEntryToRead; 234 | dispatch_semaphore_t SemaphoreHandle; 235 | 236 | platform_work_queue_entry Entries[256]; 237 | 238 | b32 NeedsOpenGL; 239 | }; 240 | 241 | 242 | struct osx_thread_startup 243 | { 244 | //int LogicalThreadIndex; 245 | //CGLContextObj OpenGLContext; 246 | platform_work_queue *Queue; 247 | }; 248 | 249 | 250 | void OSXMakeQueue(platform_work_queue* Queue, uint32 ThreadCount); 251 | void OSXAddEntry(platform_work_queue* Queue, platform_work_queue_callback* Callback, void* Data); 252 | bool32 OSXDoNextWorkQueueEntry(platform_work_queue* Queue); 253 | void OSXCompleteAllWork(platform_work_queue *Queue); 254 | 255 | 256 | 257 | #define MAX_HID_BUTTONS 32 258 | 259 | typedef struct osx_game_data 260 | { 261 | // input 262 | IOHIDManagerRef HIDManager; 263 | int HIDX; 264 | int HIDY; 265 | u8 HIDButtons[MAX_HID_BUTTONS]; 266 | 267 | char SourceGameCodeDLFullPath[FILENAME_MAX]; 268 | 269 | //umm FrameTempArenaSize; 270 | //memory_arena FrameTempArena; 271 | 272 | umm CurrentSortMemorySize; 273 | void* SortMemory; 274 | 275 | umm CurrentClipMemorySize; 276 | void* ClipMemory; 277 | 278 | u32 PushBufferSize; 279 | u8* PushBuffer; 280 | 281 | u32 MaxVertexCount; 282 | textured_vertex* VertexArray; 283 | loaded_bitmap** BitmapArray; 284 | 285 | //game_memory GameMemory; 286 | game_offscreen_buffer RenderBuffer; 287 | 288 | game_input Input[2]; 289 | game_input* NewInput; 290 | game_input* OldInput; 291 | 292 | //osx_state OSXState; 293 | osx_game_code Game; 294 | 295 | osx_sound_output SoundOutput; 296 | 297 | platform_work_queue HighPriorityQueue; 298 | platform_work_queue LowPriorityQueue; 299 | 300 | //texture_op_queue TextureOpQueue; 301 | 302 | u32 MonitorRefreshHz; 303 | f32 GameUpdateHz; 304 | 305 | u32 ExpectedFramesPerUpdate; 306 | 307 | u32 TargetFramesPerSecond; 308 | r32 TargetSecondsPerFrame; 309 | 310 | r64 MachTimebaseConversionFactor; 311 | int SetupComplete; 312 | 313 | int RenderAtHalfSpeed; 314 | 315 | u64 LastCounter; 316 | } osx_game_data; 317 | 318 | 319 | void OSXSetupGamepad(osx_game_data* game_data); 320 | 321 | void OSXUpdateGlobalDebugTable(); 322 | 323 | 324 | void OSXToggleGlobalPause(); 325 | 326 | b32 OSXIsGameRunning(); 327 | void OSXStopGame(); 328 | 329 | 330 | 331 | inline void OSXProcessKeyboardMessage(game_button_state *NewState, b32 IsDown) 332 | { 333 | if (NewState->EndedDown != IsDown) 334 | { 335 | NewState->EndedDown = IsDown; 336 | ++NewState->HalfTransitionCount; 337 | } 338 | } 339 | 340 | void OSXKeyProcessing(b32 IsDown, u32 Key, 341 | int CommandKeyFlag, int ControlKeyFlag, int AlternateKeyFlag, 342 | game_input* Input, osx_game_data* GameData); 343 | 344 | #if HANDMADE_INTERNAL 345 | #define OSXDebugLogOpenGLErrors(l) OSXDebugInternalLogOpenGLErrors(l) 346 | #else 347 | #define OSXDebugLogOpenGLErrors(l) {} 348 | #endif 349 | 350 | void OSXDebugInternalLogOpenGLErrors(const char* label); 351 | void OSXSetupSound(osx_game_data* GameData); 352 | void OSXSetupGameData(osx_game_data* GameData, CGLContextObj CGLContext); 353 | void OSXSetupOpenGL(osx_game_data* GameData); 354 | void OSXSetupGameRenderBuffer(osx_game_data* GameData, float Width, float Height, int BytesPerPixel); 355 | 356 | void OSXProcessFrameAndRunGameLogic(osx_game_data* GameData, CGRect WindowFrame, 357 | b32 MouseInWindowFlag, CGPoint MouseLocation, 358 | int MouseButtonMask); 359 | 360 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /code/osx_handmade_audio.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /////////////////////////////////////////////////////////////////////// 5 | // Audio 6 | // 7 | #if 1 // Handmade Hero Sound Buffer 8 | OSStatus OSXAudioUnitCallback(void * inRefCon, 9 | AudioUnitRenderActionFlags * ioActionFlags, 10 | const AudioTimeStamp * inTimeStamp, 11 | UInt32 inBusNumber, 12 | UInt32 inNumberFrames, 13 | AudioBufferList * ioData) 14 | { 15 | // NOTE(jeff): Don't do anything too time consuming in this function. 16 | // It is a high-priority "real-time" thread. 17 | // Even too many printf calls can throw off the timing. 18 | #pragma unused(ioActionFlags) 19 | #pragma unused(inTimeStamp) 20 | #pragma unused(inBusNumber) 21 | 22 | //double currentPhase = *((double*)inRefCon); 23 | 24 | osx_sound_output* SoundOutput = ((osx_sound_output*)inRefCon); 25 | 26 | 27 | if (SoundOutput->ReadCursor == SoundOutput->WriteCursor) 28 | { 29 | SoundOutput->SoundBuffer.SampleCount = 0; 30 | //printf("AudioCallback: No Samples Yet!\n"); 31 | } 32 | 33 | //printf("AudioCallback: SampleCount = %d\n", SoundOutput->SoundBuffer.SampleCount); 34 | 35 | int SampleCount = inNumberFrames; 36 | if (SoundOutput->SoundBuffer.SampleCount < inNumberFrames) 37 | { 38 | SampleCount = SoundOutput->SoundBuffer.SampleCount; 39 | } 40 | 41 | int16* outputBufferL = (int16 *)ioData->mBuffers[0].mData; 42 | int16* outputBufferR = (int16 *)ioData->mBuffers[1].mData; 43 | 44 | for (UInt32 i = 0; i < SampleCount; ++i) 45 | { 46 | outputBufferL[i] = *SoundOutput->ReadCursor++; 47 | outputBufferR[i] = *SoundOutput->ReadCursor++; 48 | 49 | if ((char*)SoundOutput->ReadCursor >= (char*)((char*)SoundOutput->CoreAudioBuffer + SoundOutput->SoundBufferSize)) 50 | { 51 | //printf("Callback: Read cursor wrapped!\n"); 52 | SoundOutput->ReadCursor = SoundOutput->CoreAudioBuffer; 53 | } 54 | } 55 | 56 | for (UInt32 i = SampleCount; i < inNumberFrames; ++i) 57 | { 58 | outputBufferL[i] = 0.0; 59 | outputBufferR[i] = 0.0; 60 | } 61 | 62 | return noErr; 63 | } 64 | 65 | #else // Test Sine Wave 66 | 67 | OSStatus SineWaveRenderCallback(void * inRefCon, 68 | AudioUnitRenderActionFlags * ioActionFlags, 69 | const AudioTimeStamp * inTimeStamp, 70 | UInt32 inBusNumber, 71 | UInt32 inNumberFrames, 72 | AudioBufferList * ioData) 73 | { 74 | #pragma unused(ioActionFlags) 75 | #pragma unused(inTimeStamp) 76 | #pragma unused(inBusNumber) 77 | 78 | //double currentPhase = *((double*)inRefCon); 79 | 80 | osx_sound_output* SoundOutput = ((osx_sound_output*)inRefCon); 81 | 82 | int16* outputBuffer = (int16 *)ioData->mBuffers[0].mData; 83 | const double phaseStep = (SoundOutput->Frequency 84 | / SoundOutput->SoundBuffer.SamplesPerSecond) 85 | * (2.0 * M_PI); 86 | 87 | for (UInt32 i = 0; i < inNumberFrames; i++) 88 | { 89 | outputBuffer[i] = 5000 * sin(SoundOutput->RenderPhase); 90 | SoundOutput->RenderPhase += phaseStep; 91 | } 92 | 93 | // Copy to the stereo (or the additional X.1 channels) 94 | for(UInt32 i = 1; i < ioData->mNumberBuffers; i++) 95 | { 96 | memcpy(ioData->mBuffers[i].mData, outputBuffer, ioData->mBuffers[i].mDataByteSize); 97 | } 98 | 99 | return noErr; 100 | } 101 | 102 | OSStatus SilentCallback(void* inRefCon, 103 | AudioUnitRenderActionFlags* ioActionFlags, 104 | const AudioTimeStamp* inTimeStamp, 105 | UInt32 inBusNumber, 106 | UInt32 inNumberFrames, 107 | AudioBufferList* ioData) 108 | { 109 | #pragma unused(inRefCon) 110 | #pragma unused(ioActionFlags) 111 | #pragma unused(inTimeStamp) 112 | #pragma unused(inBusNumber) 113 | 114 | //double currentPhase = *((double*)inRefCon); 115 | //osx_sound_output* SoundOutput = ((osx_sound_output*)inRefCon); 116 | 117 | Float32* outputBuffer = (Float32 *)ioData->mBuffers[0].mData; 118 | 119 | for (UInt32 i = 0; i < inNumberFrames; i++) 120 | { 121 | outputBuffer[i] = 0.0; 122 | } 123 | 124 | // Copy to the stereo (or the additional X.1 channels) 125 | for(UInt32 i = 1; i < ioData->mNumberBuffers; i++) 126 | { 127 | memcpy(ioData->mBuffers[i].mData, outputBuffer, 128 | ioData->mBuffers[i].mDataByteSize); 129 | } 130 | 131 | return noErr; 132 | } 133 | #endif 134 | 135 | 136 | #if 0 // Use AudioQueues 137 | void OSXAudioQueueCallback(void* data, AudioQueueRef queue, AudioQueueBufferRef buffer) 138 | { 139 | osx_sound_output* SoundOutput = ((osx_sound_output*)data); 140 | 141 | int16* outputBuffer = (int16 *)ioData->mBuffers[0].mData; 142 | const double phaseStep = (SoundOutput->Frequency / SoundOutput->SamplesPerSecond) * (2.0 * M_PI); 143 | 144 | for (UInt32 i = 0; i < inNumberFrames; i++) 145 | { 146 | outputBuffer[i] = 5000 * sin(SoundOutput->RenderPhase); 147 | SoundOutput->RenderPhase += phaseStep; 148 | } 149 | 150 | // Copy to the stereo (or the additional X.1 channels) 151 | for(UInt32 i = 1; i < ioData->mNumberBuffers; i++) 152 | { 153 | memcpy(ioData->mBuffers[i].mData, outputBuffer, ioData->mBuffers[i].mDataByteSize); 154 | } 155 | } 156 | 157 | 158 | void OSXInitCoreAudio(osx_sound_output* SoundOutput) 159 | { 160 | SoundOutput->AudioDescriptor.mSampleRate = SoundOutput->SamplesPerSecond; 161 | SoundOutput->AudioDescriptor.mFormatID = kAudioFormatLinearPCM; 162 | SoundOutput->AudioDescriptor.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsPacked; 163 | SoundOutput->AudioDescriptor.mFramesPerPacket = 1; 164 | SoundOutput->AudioDescriptor.mChannelsPerFrame = 2; 165 | SoundOutput->AudioDescriptor.mBitsPerChannel = sizeof(int16) * 8; 166 | SoundOutput->AudioDescriptor.mBytesPerFrame = sizeof(int16); // don't multiply by channel count with non-interleaved! 167 | SoundOutput->AudioDescriptor.mBytesPerPacket = SoundOutput->AudioDescriptor.mFramesPerPacket * SoundOutput->AudioDescriptor.mBytesPerFrame; 168 | 169 | uint32 err = AudioQueueNewOutput(&SoundOutput->AudioDescriptor, OSXAudioQueueCallback, SoundOutput, NULL, 0, 0, &SoundOutput->AudioQueue); 170 | if (err) 171 | { 172 | printf("Error in AudioQueueNewOutput\n"); 173 | } 174 | 175 | } 176 | 177 | #else // Use raw AudioUnits 178 | 179 | void OSXInitCoreAudio(osx_sound_output* SoundOutput) 180 | { 181 | AudioComponentDescription acd; 182 | acd.componentType = kAudioUnitType_Output; 183 | acd.componentSubType = kAudioUnitSubType_DefaultOutput; 184 | acd.componentManufacturer = kAudioUnitManufacturer_Apple; 185 | 186 | AudioComponent outputComponent = AudioComponentFindNext(NULL, &acd); 187 | 188 | AudioComponentInstanceNew(outputComponent, &SoundOutput->AudioUnit); 189 | AudioUnitInitialize(SoundOutput->AudioUnit); 190 | 191 | #if 1 // uint16 192 | //AudioStreamBasicDescription asbd; 193 | SoundOutput->AudioDescriptor.mSampleRate = SoundOutput->SoundBuffer.SamplesPerSecond; 194 | SoundOutput->AudioDescriptor.mFormatID = kAudioFormatLinearPCM; 195 | SoundOutput->AudioDescriptor.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved | kAudioFormatFlagIsPacked; 196 | SoundOutput->AudioDescriptor.mFramesPerPacket = 1; 197 | SoundOutput->AudioDescriptor.mChannelsPerFrame = 2; // Stereo 198 | SoundOutput->AudioDescriptor.mBitsPerChannel = sizeof(int16) * 8; 199 | SoundOutput->AudioDescriptor.mBytesPerFrame = sizeof(int16); // don't multiply by channel count with non-interleaved! 200 | SoundOutput->AudioDescriptor.mBytesPerPacket = SoundOutput->AudioDescriptor.mFramesPerPacket * SoundOutput->AudioDescriptor.mBytesPerFrame; 201 | #else // floating point - this is the "native" format on the Mac 202 | AudioStreamBasicDescription asbd; 203 | SoundOutput->AudioDescriptor.mSampleRate = SoundOutput->SamplesPerSecond; 204 | SoundOutput->AudioDescriptor.mFormatID = kAudioFormatLinearPCM; 205 | SoundOutput->AudioDescriptor.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved; 206 | SoundOutput->AudioDescriptor.mFramesPerPacket = 1; 207 | SoundOutput->AudioDescriptor.mChannelsPerFrame = 2; 208 | SoundOutput->AudioDescriptor.mBitsPerChannel = sizeof(Float32) * 8; // 1 * sizeof(Float32) * 8; 209 | SoundOutput->AudioDescriptor.mBytesPerFrame = sizeof(Float32); 210 | SoundOutput->AudioDescriptor.mBytesPerPacket = SoundOutput->AudioDescriptor.mFramesPerPacket * SoundOutput->AudioDescriptor.mBytesPerFrame; 211 | #endif 212 | 213 | 214 | // TODO(jeff): Add some error checking... 215 | AudioUnitSetProperty(SoundOutput->AudioUnit, 216 | kAudioUnitProperty_StreamFormat, 217 | kAudioUnitScope_Input, 218 | 0, 219 | &SoundOutput->AudioDescriptor, 220 | sizeof(SoundOutput->AudioDescriptor)); 221 | 222 | AURenderCallbackStruct cb; 223 | cb.inputProc = OSXAudioUnitCallback; 224 | cb.inputProcRefCon = SoundOutput; 225 | 226 | AudioUnitSetProperty(SoundOutput->AudioUnit, 227 | kAudioUnitProperty_SetRenderCallback, 228 | kAudioUnitScope_Global, 229 | 0, 230 | &cb, 231 | sizeof(cb)); 232 | 233 | AudioOutputUnitStart(SoundOutput->AudioUnit); 234 | } 235 | 236 | 237 | void OSXStopCoreAudio(osx_sound_output* SoundOutput) 238 | { 239 | printf("Stopping Core Audio\n"); 240 | AudioOutputUnitStop(SoundOutput->AudioUnit); 241 | AudioUnitUninitialize(SoundOutput->AudioUnit); 242 | AudioComponentInstanceDispose(SoundOutput->AudioUnit); 243 | } 244 | 245 | #endif 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /code/osx_handmade_debug.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_debug.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | #ifndef Assert 9 | 10 | #if HANDMADE_SLOW 11 | // TODO(casey): Complete assertion macro - don't worry everyone! 12 | #define Assert(Expression) if(!(Expression)) {*(int *)0 = 0;} 13 | #else 14 | #define Assert(Expression) 15 | #endif 16 | 17 | #endif 18 | 19 | 20 | 21 | float OSXGetSecondsElapsed(u64 Then, u64 Now) 22 | { 23 | static mach_timebase_info_data_t tb; 24 | 25 | u64 Elapsed = Now - Then; 26 | 27 | if (tb.denom == 0) 28 | { 29 | // First time we need to get the timebase 30 | mach_timebase_info(&tb); 31 | } 32 | 33 | u64 Nanos = Elapsed * tb.numer / tb.denom; 34 | float Result = (float)Nanos * 1.0E-9; 35 | 36 | return Result; 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /code/osx_handmade_dylib.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_dylib.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | 9 | osx_game_code OSXLoadGameCode(const char* SourceDLName) 10 | { 11 | osx_game_code Result = {}; 12 | 13 | // TODO(casey): Need to get the proper path here! 14 | // TODO(casey): Automatic determination of when updates are necessary 15 | 16 | Result.DLLastWriteTime = OSXGetLastWriteTime(SourceDLName); 17 | 18 | Result.GameCodeDL = dlopen(SourceDLName, RTLD_LAZY|RTLD_GLOBAL); 19 | if (Result.GameCodeDL) 20 | { 21 | Result.UpdateAndRender = (game_update_and_render*) 22 | dlsym(Result.GameCodeDL, "GameUpdateAndRender"); 23 | 24 | Result.GetSoundSamples = (game_get_sound_samples*) 25 | dlsym(Result.GameCodeDL, "GameGetSoundSamples"); 26 | 27 | Result.DEBUGFrameEnd = (debug_game_frame_end*) 28 | dlsym(Result.GameCodeDL, "DEBUGGameFrameEnd"); 29 | 30 | Result.IsValid = Result.UpdateAndRender && Result.GetSoundSamples; 31 | } 32 | 33 | if (!Result.IsValid) 34 | { 35 | Result.UpdateAndRender = 0; 36 | Result.GetSoundSamples = 0; 37 | } 38 | 39 | return Result; 40 | } 41 | 42 | 43 | void OSXUnloadGameCode(osx_game_code* GameCode) 44 | { 45 | if (GameCode->GameCodeDL) 46 | { 47 | dlclose(GameCode->GameCodeDL); 48 | GameCode->GameCodeDL = 0; 49 | } 50 | 51 | GameCode->IsValid = false; 52 | GameCode->UpdateAndRender = 0; 53 | GameCode->GetSoundSamples = 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /code/osx_handmade_file.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_file.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | 9 | static void 10 | CatStrings(size_t SourceACount, char *SourceA, 11 | size_t SourceBCount, char *SourceB, 12 | size_t DestCount, char *Dest) 13 | { 14 | // TODO(casey): Dest bounds checking! 15 | 16 | for(int Index = 0; 17 | Index < SourceACount; 18 | ++Index) 19 | { 20 | *Dest++ = *SourceA++; 21 | } 22 | 23 | for(int Index = 0; 24 | Index < SourceBCount; 25 | ++Index) 26 | { 27 | *Dest++ = *SourceB++; 28 | } 29 | 30 | *Dest++ = 0; 31 | } 32 | 33 | 34 | void 35 | OSXGetAppFilename(osx_state *State) 36 | { 37 | // NOTE(casey): Never use MAX_PATH in code that is user-facing, because it 38 | // can be dangerous and lead to bad results. 39 | // 40 | pid_t PID = getpid(); 41 | int r = proc_pidpath(PID, State->AppFilename, sizeof(State->AppFilename)); 42 | 43 | if (r <= 0) 44 | { 45 | fprintf(stderr, "Error getting process path: pid %d: %s\n", PID, strerror(errno)); 46 | } 47 | else 48 | { 49 | printf("process pid: %d path: %s\n", PID, State->AppFilename); 50 | } 51 | 52 | State->OnePastLastAppFilenameSlash = State->AppFilename; 53 | for(char *Scan = State->AppFilename; 54 | *Scan; 55 | ++Scan) 56 | { 57 | if(*Scan == '/') 58 | { 59 | State->OnePastLastAppFilenameSlash = Scan + 1; 60 | } 61 | } 62 | } 63 | 64 | 65 | void 66 | OSXBuildAppPathFilename(osx_state *State, char *Filename, 67 | int DestCount, char *Dest) 68 | { 69 | CatStrings(State->OnePastLastAppFilenameSlash - State->AppFilename, State->AppFilename, 70 | StringLength(Filename), Filename, 71 | DestCount, Dest); 72 | } 73 | 74 | 75 | #if HANDMADE_INTERNAL 76 | DEBUG_PLATFORM_FREE_FILE_MEMORY(DEBUGPlatformFreeFileMemory) 77 | { 78 | if (Memory) 79 | { 80 | free(Memory); 81 | } 82 | } 83 | 84 | 85 | DEBUG_PLATFORM_READ_ENTIRE_FILE(DEBUGPlatformReadEntireFile) 86 | { 87 | debug_read_file_result Result = {}; 88 | 89 | int fd = open(Filename, O_RDONLY); 90 | if (fd != -1) 91 | { 92 | struct stat fileStat; 93 | if (fstat(fd, &fileStat) == 0) 94 | { 95 | uint32 FileSize32 = fileStat.st_size; 96 | 97 | int result = -1; 98 | 99 | #if 1 100 | Result.Contents = (char*)malloc(FileSize32); 101 | if (Result.Contents) 102 | { 103 | result = 0; 104 | } 105 | #else 106 | kern_return_t kresult = vm_allocate((vm_map_t)mach_task_self(), 107 | (vm_address_t*)&Result.Contents, 108 | FileSize32, 109 | VM_FLAGS_ANYWHERE); 110 | 111 | if ((result == KERN_SUCCESS) && Result.Contents) 112 | { 113 | result = 0; 114 | } 115 | #endif 116 | 117 | if (result == 0) 118 | { 119 | ssize_t BytesRead; 120 | BytesRead = read(fd, Result.Contents, FileSize32); 121 | if (BytesRead == FileSize32) // should have read until EOF 122 | { 123 | Result.ContentsSize = FileSize32; 124 | } 125 | else 126 | { 127 | DEBUGPlatformFreeFileMemory(Result.Contents); 128 | Result.Contents = 0; 129 | } 130 | } 131 | else 132 | { 133 | printf("DEBUGPlatformReadEntireFile %s: vm_allocate error: %d: %s\n", 134 | Filename, errno, strerror(errno)); 135 | } 136 | } 137 | else 138 | { 139 | printf("DEBUGPlatformReadEntireFile %s: fstat error: %d: %s\n", 140 | Filename, errno, strerror(errno)); 141 | } 142 | 143 | close(fd); 144 | } 145 | else 146 | { 147 | printf("DEBUGPlatformReadEntireFile %s: open error: %d: %s\n", 148 | Filename, errno, strerror(errno)); 149 | } 150 | 151 | return Result; 152 | } 153 | 154 | 155 | DEBUG_PLATFORM_WRITE_ENTIRE_FILE(DEBUGPlatformWriteEntireFile) 156 | { 157 | bool32 Result = false; 158 | 159 | int fd = open(Filename, O_WRONLY | O_CREAT, 0644); 160 | if (fd != -1) 161 | { 162 | ssize_t BytesWritten = write(fd, Memory, MemorySize); 163 | Result = (BytesWritten == MemorySize); 164 | 165 | if (!Result) 166 | { 167 | // TODO(jeff): Logging 168 | } 169 | 170 | close(fd); 171 | } 172 | else 173 | { 174 | } 175 | 176 | return Result; 177 | } 178 | #endif 179 | 180 | 181 | //#define PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(name) platform_file_group *name(char *Type) 182 | PLATFORM_GET_ALL_FILE_OF_TYPE_BEGIN(OSXGetAllFilesOfTypeBegin) 183 | { 184 | platform_file_group Result = {}; 185 | 186 | osx_platform_file_group* OSXFileGroup = (osx_platform_file_group*)mmap(0, 187 | sizeof(osx_platform_file_group), 188 | PROT_READ | PROT_WRITE, 189 | MAP_PRIVATE | MAP_ANON, 190 | -1, 191 | 0); 192 | Result.Platform = OSXFileGroup; 193 | 194 | const char* WildCard = "*.*"; 195 | switch (Type) 196 | { 197 | case PlatformFileType_AssetFile: 198 | { 199 | WildCard = "*.hha"; 200 | } 201 | break; 202 | 203 | case PlatformFileType_SavedGameFile: 204 | { 205 | WildCard = "*.hhs"; 206 | } 207 | break; 208 | 209 | InvalidDefaultCase; 210 | } 211 | 212 | Result.FileCount = 0; 213 | 214 | if (glob(WildCard, 0, 0, &OSXFileGroup->GlobResults) == 0) 215 | { 216 | Result.FileCount = OSXFileGroup->GlobResults.gl_pathc; 217 | OSXFileGroup->CurrentIndex = 0; 218 | } 219 | 220 | return Result; 221 | } 222 | 223 | 224 | //#define PLATFORM_GET_ALL_FILE_OF_TYPE_END(name) void name(platform_file_group *FileGroup) 225 | PLATFORM_GET_ALL_FILE_OF_TYPE_END(OSXGetAllFilesOfTypeEnd) 226 | { 227 | osx_platform_file_group* OSXFileGroup = (osx_platform_file_group*)FileGroup->Platform; 228 | if (OSXFileGroup) 229 | { 230 | globfree(&OSXFileGroup->GlobResults); 231 | 232 | munmap(OSXFileGroup, sizeof(osx_platform_file_group)); 233 | } 234 | } 235 | 236 | 237 | //#define PLATFORM_OPEN_FILE(name) platform_file_handle *name(platform_file_group *FileGroup) 238 | PLATFORM_OPEN_FILE(OSXOpenNextFile) 239 | { 240 | osx_platform_file_group* OSXFileGroup = (osx_platform_file_group*)FileGroup->Platform; 241 | platform_file_handle Result = {}; 242 | 243 | if (OSXFileGroup->CurrentIndex < FileGroup->FileCount) 244 | { 245 | osx_platform_file_handle *OSXFileHandle = (osx_platform_file_handle*)mmap(0, 246 | sizeof(osx_platform_file_handle), 247 | PROT_READ | PROT_WRITE, 248 | MAP_PRIVATE | MAP_ANON, 249 | -1, 250 | 0); 251 | Result.Platform = OSXFileHandle; 252 | 253 | if (OSXFileHandle) 254 | { 255 | char* Filename = *(OSXFileGroup->GlobResults.gl_pathv + OSXFileGroup->CurrentIndex); 256 | 257 | int i = 0; 258 | while (i < sizeof(OSXFileHandle->Filename) && (Filename[i] != '\0')) 259 | { 260 | OSXFileHandle->Filename[i] = Filename[i]; 261 | ++i; 262 | } 263 | OSXFileHandle->Filename[i] = '\0'; 264 | 265 | //strncpy(OSXFileHandle->Filename, Filename, sizeof(OSXFileHandle->Filename)); 266 | OSXFileHandle->OSXFileHandle = open(Filename, O_RDONLY); 267 | Result.NoErrors = (OSXFileHandle->OSXFileHandle != -1); 268 | 269 | if (OSXFileHandle->OSXFileHandle != -1) 270 | { 271 | printf("Loading asset %s\n", Filename); 272 | } 273 | else 274 | { 275 | printf("Error opening asset file %s\n", Filename); 276 | } 277 | 278 | } 279 | 280 | ++OSXFileGroup->CurrentIndex; 281 | } 282 | else 283 | { 284 | printf("Ran out of assets to load.\n"); 285 | } 286 | 287 | return Result; 288 | } 289 | 290 | 291 | //#define PLATFORM_READ_DATA_FROM_FILE(name) void name(platform_file_handle *Source, u64 Offset, u64 Size, void *Dest) 292 | PLATFORM_READ_DATA_FROM_FILE(OSXReadDataFromFile) 293 | { 294 | osx_platform_file_handle* OSXFileHandle = (osx_platform_file_handle*)Source->Platform; 295 | 296 | if (PlatformNoFileErrors(Source)) 297 | { 298 | // TODO(jeff): Consider mmap instead of open/read for overlapped IO. 299 | // TODO(jeff): If sticking with read, make sure to handle interrupted read. 300 | 301 | u64 BytesRead = pread(OSXFileHandle->OSXFileHandle, Dest, Size, Offset); 302 | 303 | if (BytesRead == Size) 304 | { 305 | // NOTE(jeff): File read succeeded 306 | //printf("Read file: %s read %ld bytes.\n", OSXFileHandle->Filename, BytesRead); 307 | } 308 | else 309 | { 310 | OSXFileError(Source, "Read file failed."); 311 | } 312 | } 313 | else 314 | { 315 | printf("OSXReadDataFromFile had pre-existing file errors on file: %s\n", OSXFileHandle->Filename); 316 | } 317 | } 318 | 319 | 320 | //#define PLATFORM_FILE_ERROR(name) void name(platform_file_handle *Handle, char *Message) 321 | PLATFORM_FILE_ERROR(OSXFileError) 322 | { 323 | #if HANDMADE_INTERNAL 324 | char buffer[256]; 325 | snprintf(buffer, sizeof(buffer), "OSX FILE ERROR: %s\n", Message); 326 | #endif 327 | 328 | Handle->NoErrors = false; 329 | } 330 | 331 | 332 | 333 | time_t 334 | OSXGetLastWriteTime(const char* Filename) 335 | { 336 | time_t LastWriteTime = 0; 337 | 338 | struct stat FileStat; 339 | if (stat(Filename, &FileStat) == 0) 340 | { 341 | LastWriteTime = FileStat.st_mtimespec.tv_sec; 342 | } 343 | 344 | #if 0 345 | int fd = open(Filename, O_RDONLY); 346 | if (fd != -1) 347 | { 348 | struct stat FileStat; 349 | if (fstat(fd, &FileStat) == 0) 350 | { 351 | LastWriteTime = FileStat.st_mtimespec.tv_sec; 352 | } 353 | 354 | close(fd); 355 | } 356 | #endif 357 | 358 | return LastWriteTime; 359 | } 360 | 361 | -------------------------------------------------------------------------------- /code/osx_handmade_game.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | osx_state GlobalOSXState; 4 | 5 | #if HANDMADE_INTERNAL 6 | global_variable debug_table GlobalDebugTable_; 7 | debug_table* GlobalDebugTable = &GlobalDebugTable_; 8 | #endif 9 | 10 | #if 0 11 | CGLPixelFormatAttribute GLPixelFormatAttribs[] = 12 | { 13 | kCGLPFAAccelerated, 14 | kCGLPFADoubleBuffer, 15 | (CGLPixelFormatAttribute)0 16 | }; 17 | #endif 18 | 19 | void OSXToggleGlobalPause() 20 | { 21 | GlobalPause = !GlobalPause; 22 | } 23 | 24 | b32 OSXIsGameRunning() 25 | { 26 | return GlobalRunning; 27 | } 28 | 29 | void OSXStopGame() 30 | { 31 | GlobalRunning = 0; 32 | } 33 | 34 | 35 | 36 | void OSXDebugInternalLogOpenGLErrors(const char* label) 37 | { 38 | GLenum err = glGetError(); 39 | const char* errString = "No error"; 40 | 41 | while (err != GL_NO_ERROR) 42 | { 43 | switch(err) 44 | { 45 | case GL_INVALID_ENUM: 46 | errString = "Invalid Enum"; 47 | break; 48 | 49 | case GL_INVALID_VALUE: 50 | errString = "Invalid Value"; 51 | break; 52 | 53 | case GL_INVALID_OPERATION: 54 | errString = "Invalid Operation"; 55 | break; 56 | 57 | /* 58 | case GL_INVALID_FRAMEBUFFER_OPERATION: 59 | errString = "Invalid Framebuffer Operation"; 60 | break; 61 | */ 62 | case GL_OUT_OF_MEMORY: 63 | errString = "Out of Memory"; 64 | break; 65 | 66 | case GL_STACK_UNDERFLOW: 67 | errString = "Stack Underflow"; 68 | break; 69 | 70 | case GL_STACK_OVERFLOW: 71 | errString = "Stack Overflow"; 72 | break; 73 | 74 | default: 75 | errString = "Unknown Error"; 76 | break; 77 | } 78 | printf("glError on %s: %s\n", label, errString); 79 | 80 | err = glGetError(); 81 | } 82 | } 83 | 84 | 85 | void OSXSetupSound(osx_game_data* GameData) 86 | { 87 | //_SoundOutput.Frequency = 800.0; 88 | GameData->SoundOutput.SoundBuffer.SamplesPerSecond = 48000; 89 | GameData->SoundOutput.SoundBufferSize = GameData->SoundOutput.SoundBuffer.SamplesPerSecond * sizeof(int16) * 2; 90 | 91 | u32 MaxPossibleOverrun = 8 * 2 * sizeof(int16); 92 | 93 | GameData->SoundOutput.SoundBuffer.Samples = (int16*)mmap(0, GameData->SoundOutput.SoundBufferSize + MaxPossibleOverrun, 94 | PROT_READ|PROT_WRITE, 95 | MAP_PRIVATE | MAP_ANON, 96 | -1, 97 | 0); 98 | if (GameData->SoundOutput.SoundBuffer.Samples == MAP_FAILED) 99 | { 100 | printf("Sound Buffer Samples mmap error: %d %s", errno, strerror(errno)); 101 | } 102 | memset(GameData->SoundOutput.SoundBuffer.Samples, 0, GameData->SoundOutput.SoundBufferSize); 103 | 104 | GameData->SoundOutput.CoreAudioBuffer = (int16*)mmap(0, GameData->SoundOutput.SoundBufferSize + MaxPossibleOverrun, 105 | PROT_READ|PROT_WRITE, 106 | MAP_PRIVATE | MAP_ANON, 107 | -1, 108 | 0); 109 | if (GameData->SoundOutput.CoreAudioBuffer == MAP_FAILED) 110 | { 111 | printf("Core Audio Buffer mmap error: %d %s", errno, strerror(errno)); 112 | } 113 | memset(GameData->SoundOutput.CoreAudioBuffer, 0, GameData->SoundOutput.SoundBufferSize); 114 | 115 | GameData->SoundOutput.ReadCursor = GameData->SoundOutput.CoreAudioBuffer; 116 | GameData->SoundOutput.WriteCursor = GameData->SoundOutput.CoreAudioBuffer; 117 | 118 | OSXInitCoreAudio(&GameData->SoundOutput); 119 | } 120 | 121 | 122 | void OSXSetPixelFormat() 123 | { 124 | } 125 | 126 | 127 | void OSXSetupOpenGL(osx_game_data* GameData) 128 | { 129 | void* Image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY); 130 | if (Image) 131 | { 132 | #define OSXGetOpenGLFunction(Module, Name) Name = (type_##Name *)dlsym(Module, #Name) 133 | OSXGetOpenGLFunction(Image, glDebugMessageCallbackARB); 134 | OSXGetOpenGLFunction(Image, glBindVertexArray); 135 | OSXGetOpenGLFunction(Image, glGenVertexArrays); 136 | OSXGetOpenGLFunction(Image, glGetStringi); 137 | 138 | opengl_info Info = OpenGLGetInfo(true); 139 | 140 | glBindFramebuffer = (gl_bind_framebuffer*)dlsym(Image, "glBindFramebuffer"); 141 | glGenFramebuffers = (gl_gen_framebuffers*)dlsym(Image, "glGenFramebuffers"); 142 | glFramebufferTexture2D = (gl_framebuffer_texture_2D*)dlsym(Image, "glFramebufferTexture2D"); 143 | glCheckFramebufferStatus = (gl_check_framebuffer_status*)dlsym(Image, "glCheckFramebufferStatus"); 144 | glTexImage2DMultisample = (gl_tex_image_2d_multisample *)dlsym(Image, "glTexImage2DMultisample"); 145 | glBlitFramebuffer = (gl_blit_framebuffer *)dlsym(Image, "glBlitFramebuffer"); 146 | 147 | OSXGetOpenGLFunction(Image, glDeleteFramebuffers); 148 | #if 0 149 | glAttachShader = (gl_attach_shader *)dlsym("glAttachShader"); 150 | glCompileShader = (gl_compile_shader *)dlsym("glCompileShader"); 151 | glCreateProgram = (gl_create_program *)dlsym("glCreateProgram"); 152 | glCreateShader = (gl_create_shader *)dlsym("glCreateShader"); 153 | glLinkProgram = (gl_link_program *)dlsym("glLinkProgram"); 154 | glShaderSource = (gl_shader_source *)dlsym("glShaderSource"); 155 | glUseProgram = (gl_use_program *)dlsym("glUseProgram"); 156 | glGetProgramInfoLog = (gl_get_program_info_log *)dlsym("glGetProgramInfoLog"); 157 | glGetShaderInfoLog = (gl_get_shader_info_log *)dlsym("glGetShaderInfoLog"); 158 | glValidateProgram = (gl_validate_program *)dlsym("glValidateProgram"); 159 | glGetProgramiv = (gl_get_program_iv *)dlsym("glGetProgramiv"); 160 | #endif 161 | 162 | if (glBindFramebuffer) 163 | { 164 | printf("OpenGL extension functions loaded\n"); 165 | } 166 | else 167 | { 168 | printf("Could not dynamically load glBindFramebuffer\n"); 169 | } 170 | 171 | Assert(glBindFramebuffer); 172 | Assert(glGenFramebuffers); 173 | Assert(glFramebufferTexture2D); 174 | Assert(glCheckFramebufferStatus); 175 | Assert(glTexImage2DMultisample); 176 | Assert(glBlitFramebuffer); 177 | Assert(glAttachShader); 178 | Assert(glCompileShader); 179 | Assert(glCreateProgram); 180 | Assert(glCreateShader); 181 | Assert(glLinkProgram); 182 | Assert(glShaderSource); 183 | Assert(glUseProgram); 184 | Assert(glGetProgramInfoLog); 185 | Assert(glGetShaderInfoLog); 186 | Assert(glValidateProgram); 187 | Assert(glGetProgramiv); 188 | 189 | //OpenGL.SupportsSRGBFramebuffer = true; 190 | OpenGLInit(Info, OpenGL.SupportsSRGBFramebuffer); 191 | 192 | #if 0 193 | OpenGLDefaultInternalTextureFormat = GL_RGBA8; 194 | //OpenGLDefaultInternalTextureFormat = GL_SRGB8_ALPHA8; 195 | glEnable(GL_FRAMEBUFFER_SRGB); 196 | #endif 197 | } 198 | else 199 | { 200 | printf("Could not dynamically load OpenGL\n"); 201 | } 202 | 203 | } 204 | 205 | /////////////////////////////////////////////////////////////////////// 206 | // Game Code 207 | // 208 | 209 | memory_arena FrameTempArena; 210 | game_memory GameMemory; 211 | 212 | 213 | void OSXSetupGameData(osx_game_data* GameData, CGLContextObj CGLContext) 214 | { 215 | if (GameData->SetupComplete) 216 | { 217 | return; 218 | } 219 | 220 | 221 | osx_state* OSXState = &GlobalOSXState; 222 | OSXState->MemorySentinel.Prev = &OSXState->MemorySentinel; 223 | OSXState->MemorySentinel.Next = &OSXState->MemorySentinel; 224 | 225 | 226 | /////////////////////////////////////////////////////////////////// 227 | // Worker Threads 228 | // 229 | 230 | osx_thread_startup HighPriStartups[6] = {}; 231 | //OSXMakeQueue(&GameData->HighPriorityQueue, 6); 232 | OSXMakeQueue(&GameData->HighPriorityQueue, ArrayCount(HighPriStartups), HighPriStartups); 233 | 234 | 235 | osx_thread_startup LowPriStartups[2] = {}; 236 | OSXMakeQueue(&GameData->LowPriorityQueue, ArrayCount(LowPriStartups), LowPriStartups); 237 | 238 | 239 | /////////////////////////////////////////////////////////////////// 240 | // Rendering Frame Rate 241 | // 242 | GameData->RenderAtHalfSpeed = 0; 243 | GameData->MonitorRefreshHz = 60; 244 | GameData->GameUpdateHz = (f32)GameData->MonitorRefreshHz; 245 | GameData->TargetFramesPerSecond = 60.0; 246 | GameData->TargetSecondsPerFrame = 1.0 / 60.0; 247 | 248 | if (GameData->RenderAtHalfSpeed) 249 | { 250 | GameData->TargetSecondsPerFrame += GameData->TargetSecondsPerFrame; 251 | GameData->TargetFramesPerSecond /= 2; 252 | } 253 | 254 | printf("TargetSecondsPerFrame: %f\n", GameData->TargetSecondsPerFrame); 255 | printf("Target frames per second = %d\n", GameData->TargetFramesPerSecond); 256 | 257 | // Get the conversion factor for doing profile timing with mach_absolute_time() 258 | mach_timebase_info_data_t timebase; 259 | mach_timebase_info(&timebase); 260 | GameData->MachTimebaseConversionFactor = (double)timebase.numer / (double)timebase.denom; 261 | 262 | 263 | /////////////////////////////////////////////////////////////////// 264 | // Get the game shared library paths 265 | // 266 | OSXGetAppFilename(OSXState); 267 | 268 | OSXBuildAppPathFilename(OSXState, (char*)"libhandmade.dylib", 269 | sizeof(GameData->SourceGameCodeDLFullPath), 270 | GameData->SourceGameCodeDLFullPath); 271 | 272 | // NOTE(jeff): We don't have to create a temp file 273 | GameData->Game = OSXLoadGameCode(GameData->SourceGameCodeDLFullPath); 274 | 275 | 276 | /////////////////////////////////////////////////////////////////// 277 | // Set up memory 278 | // 279 | //ZeroStruct(GameData->FrameTempArena); 280 | //ZeroStruct(GameData->GameMemory); 281 | 282 | GameData->PushBufferSize = Megabytes(64); 283 | platform_memory_block* PushBufferBlock = OSXAllocateMemory(GameData->PushBufferSize, 284 | PlatformMemory_NotRestored); 285 | GameData->PushBuffer = PushBufferBlock->Base; 286 | 287 | GameData->MaxVertexCount = 65536; 288 | platform_memory_block* VertexArrayBlock = OSXAllocateMemory(GameData->MaxVertexCount * sizeof(textured_vertex), 289 | PlatformMemory_NotRestored); 290 | GameData->VertexArray = (textured_vertex*)VertexArrayBlock->Base; 291 | 292 | platform_memory_block* BitmapArrayBlock = OSXAllocateMemory(GameData->MaxVertexCount * sizeof(loaded_bitmap*), 293 | PlatformMemory_NotRestored); 294 | GameData->BitmapArray = (loaded_bitmap**)BitmapArrayBlock->Base; 295 | 296 | 297 | #if HANDMADE_INTERNAL 298 | char* RequestedAddress = (char*)Gigabytes(8); 299 | uint32 AllocationFlags = MAP_PRIVATE|MAP_ANON|MAP_FIXED; 300 | #else 301 | char* RequestedAddress = (char*)0; 302 | uint32 AllocationFlags = MAP_PRIVATE|MAP_ANON; 303 | #endif 304 | 305 | 306 | #if HANDMADE_INTERNAL 307 | GameMemory.DebugTable = GlobalDebugTable; 308 | #endif 309 | 310 | //OSXState->TotalSize = 0; 311 | //OSXState->GameMemoryBlock = 0; 312 | 313 | #if 0 314 | #ifndef HANDMADE_USE_VM_ALLOCATE 315 | // NOTE(jeff): I switched to mmap as the default, so unless the above 316 | // HANDMADE_USE_VM_ALLOCATE is defined in the build/make process, 317 | // we'll use the mmap version. 318 | 319 | GameData->OSXState.GameMemoryBlock = mmap(RequestedAddress, GameData->OSXState.TotalSize, 320 | PROT_READ|PROT_WRITE, 321 | AllocationFlags, 322 | -1, 323 | 0); 324 | if (GameData->OSXState.GameMemoryBlock == MAP_FAILED) 325 | { 326 | printf("mmap error: %d %s", errno, strerror(errno)); 327 | } 328 | 329 | #else 330 | kern_return_t result = vm_allocate((vm_map_t)mach_task_self(), 331 | (vm_address_t*)&GameData->OSXState.GameMemoryBlock, 332 | GameData->OSXState.TotalSize, 333 | VM_FLAGS_ANYWHERE); 334 | if (result != KERN_SUCCESS) 335 | { 336 | // TODO(jeff): Diagnostic 337 | NSLog(@"Error allocating memory"); 338 | } 339 | #endif 340 | 341 | GameData->GameMemory.PermanentStorage = GameData->OSXState.GameMemoryBlock; 342 | GameData->GameMemory.TransientStorage = ((uint8*)GameData->GameMemory.PermanentStorage 343 | + GameData->GameMemory.PermanentStorageSize); 344 | //GameData->GameMemory.DebugStorage = (u8*)GameData->GameMemory.TransientStorage 345 | // + GameData->GameMemory.TransientStorageSize; 346 | #endif 347 | 348 | GameMemory.HighPriorityQueue = &GameData->HighPriorityQueue; 349 | GameMemory.LowPriorityQueue = &GameData->LowPriorityQueue; 350 | 351 | GameMemory.PlatformAPI.AddEntry = OSXAddEntry; 352 | GameMemory.PlatformAPI.CompleteAllWork = OSXCompleteAllWork; 353 | 354 | GameMemory.PlatformAPI.GetAllFilesOfTypeBegin = OSXGetAllFilesOfTypeBegin; 355 | GameMemory.PlatformAPI.GetAllFilesOfTypeEnd = OSXGetAllFilesOfTypeEnd; 356 | GameMemory.PlatformAPI.OpenNextFile = OSXOpenNextFile; 357 | GameMemory.PlatformAPI.ReadDataFromFile = OSXReadDataFromFile; 358 | GameMemory.PlatformAPI.FileError = OSXFileError; 359 | 360 | GameMemory.PlatformAPI.AllocateMemory = OSXAllocateMemory; 361 | GameMemory.PlatformAPI.DeallocateMemory = OSXDeallocateMemory; 362 | 363 | #if HANDMADE_INTERNAL 364 | GameMemory.PlatformAPI.DEBUGFreeFileMemory = DEBUGPlatformFreeFileMemory; 365 | GameMemory.PlatformAPI.DEBUGReadEntireFile = DEBUGPlatformReadEntireFile; 366 | GameMemory.PlatformAPI.DEBUGWriteEntireFile = DEBUGPlatformWriteEntireFile; 367 | 368 | GameMemory.PlatformAPI.DEBUGExecuteSystemCommand = DEBUGExecuteSystemCommand; 369 | GameMemory.PlatformAPI.DEBUGGetProcessState = DEBUGGetProcessState; 370 | GameMemory.PlatformAPI.DEBUGGetMemoryStats = OSXGetMemoryStats; 371 | #endif 372 | 373 | u32 TextureOpCount = 1024; 374 | platform_texture_op_queue* TextureOpQueue = &GameMemory.TextureOpQueue; 375 | TextureOpQueue->FirstFree = (texture_op*)malloc(TextureOpCount * sizeof(texture_op)); 376 | //(texture_op*)OSXAllocateMemory(TextureOpCount * sizeof(texture_op)); 377 | for (u32 TextureOpIndex = 0; 378 | TextureOpIndex < (TextureOpCount - 1); 379 | ++TextureOpIndex) 380 | { 381 | texture_op* Op = TextureOpQueue->FirstFree + TextureOpIndex; 382 | Op->Next = TextureOpQueue->FirstFree + TextureOpIndex + 1; 383 | } 384 | 385 | 386 | Platform = GameMemory.PlatformAPI; 387 | 388 | /////////////////////////////////////////////////////////////////// 389 | // Set up replay buffers 390 | 391 | 392 | /////////////////////////////////////////////////////////////////// 393 | // Set up input 394 | // 395 | GameData->NewInput = &GameData->Input[0]; 396 | GameData->OldInput = &GameData->Input[1]; 397 | 398 | OSXSetupGamepad(GameData); 399 | 400 | 401 | /////////////////////////////////////////////////////////////////// 402 | // Set up sound buffers and CoreAudio 403 | // 404 | OSXSetupSound(GameData); 405 | 406 | GameData->ExpectedFramesPerUpdate = 1; 407 | GameData->TargetSecondsPerFrame = (f32)GameData->ExpectedFramesPerUpdate / (f32)GameData->GameUpdateHz; 408 | 409 | printf("------------------------------ Game setup complete\n"); 410 | 411 | GameData->SetupComplete = 1; 412 | } 413 | 414 | 415 | void OSXSetupGameRenderBuffer(osx_game_data* GameData, float Width, float Height, int BytesPerPixel) 416 | { 417 | GameData->RenderBuffer.Width = Width; 418 | GameData->RenderBuffer.Height = Height; 419 | 420 | GameData->RenderBuffer.Pitch = Align16(GameData->RenderBuffer.Width * BytesPerPixel); 421 | int BitmapMemorySize = (GameData->RenderBuffer.Pitch * GameData->RenderBuffer.Height); 422 | GameData->RenderBuffer.Memory = mmap(0, 423 | BitmapMemorySize, 424 | PROT_READ | PROT_WRITE, 425 | MAP_PRIVATE | MAP_ANON, 426 | -1, 427 | 0); 428 | 429 | if (GameData->RenderBuffer.Memory == MAP_FAILED) 430 | { 431 | printf("Render Buffer Memory mmap error: %d %s", errno, strerror(errno)); 432 | } 433 | } 434 | 435 | 436 | void OSXKeyProcessing(bool32 IsDown, u32 Key, 437 | int CommandKeyFlag, int ControlKeyFlag, int AlternateKeyFlag, 438 | game_input* Input, osx_game_data* GameData) 439 | { 440 | game_controller_input* Controller = GetController(Input, 0); 441 | 442 | switch (Key) 443 | { 444 | case 'w': 445 | OSXProcessKeyboardMessage(&Controller->MoveUp, IsDown); 446 | break; 447 | 448 | case 'a': 449 | OSXProcessKeyboardMessage(&Controller->MoveLeft, IsDown); 450 | break; 451 | 452 | case 's': 453 | OSXProcessKeyboardMessage(&Controller->MoveDown, IsDown); 454 | break; 455 | 456 | case 'd': 457 | OSXProcessKeyboardMessage(&Controller->MoveRight, IsDown); 458 | break; 459 | 460 | case 'q': 461 | if (IsDown && CommandKeyFlag) 462 | { 463 | OSXStopGame(); 464 | } 465 | else 466 | { 467 | OSXProcessKeyboardMessage(&Controller->LeftShoulder, IsDown); 468 | } 469 | break; 470 | 471 | case 'e': 472 | OSXProcessKeyboardMessage(&Controller->RightShoulder, IsDown); 473 | break; 474 | 475 | case ' ': 476 | OSXProcessKeyboardMessage(&Controller->Start, IsDown); 477 | break; 478 | 479 | case 27: 480 | OSXProcessKeyboardMessage(&Controller->Back, IsDown); 481 | break; 482 | 483 | case 0xF700: //NSUpArrowFunctionKey 484 | OSXProcessKeyboardMessage(&Controller->ActionUp, IsDown); 485 | break; 486 | 487 | case 0xF702: //NSLeftArrowFunctionKey 488 | OSXProcessKeyboardMessage(&Controller->ActionLeft, IsDown); 489 | break; 490 | 491 | case 0xF701: //NSDownArrowFunctionKey 492 | OSXProcessKeyboardMessage(&Controller->ActionDown, IsDown); 493 | break; 494 | 495 | case 0xF703: //NSRightArrowFunctionKey 496 | OSXProcessKeyboardMessage(&Controller->ActionRight, IsDown); 497 | break; 498 | 499 | #if HANDMADE_INTERNAL 500 | case 'p': 501 | if (IsDown) 502 | { 503 | OSXToggleGlobalPause(); 504 | } 505 | break; 506 | 507 | case 'l': 508 | #if 1 509 | if (IsDown) 510 | { 511 | osx_state* OSXState = &GlobalOSXState; 512 | 513 | if (CommandKeyFlag) 514 | { 515 | OSXBeginInputPlayback(OSXState, 1); 516 | } 517 | else 518 | { 519 | if (OSXState->InputPlayingIndex == 0) 520 | { 521 | if (OSXState->InputRecordingIndex == 0) 522 | { 523 | OSXBeginRecordingInput(OSXState, 1); 524 | } 525 | else 526 | { 527 | OSXEndRecordingInput(OSXState); 528 | OSXBeginInputPlayback(OSXState, 1); 529 | } 530 | } 531 | else 532 | { 533 | OSXEndInputPlayback(OSXState); 534 | } 535 | } 536 | } 537 | #endif 538 | break; 539 | #endif 540 | default: 541 | return; 542 | break; 543 | } 544 | } 545 | 546 | 547 | void OSXDisplayBufferInWindow(platform_work_queue* RenderQueue, 548 | game_offscreen_buffer* RenderBuffer, 549 | game_render_commands* Commands, 550 | rectangle2i DrawRegion, 551 | u32 WindowWidth, 552 | u32 WindowHeight, 553 | memory_arena* TempArena) 554 | { 555 | temporary_memory TempMem = BeginTemporaryMemory(TempArena); 556 | 557 | if (!GlobalSoftwareRendering) 558 | { 559 | BEGIN_BLOCK("OpenGLRenderCommands"); 560 | 561 | OpenGLRenderCommands(Commands, DrawRegion, WindowWidth, WindowHeight); 562 | END_BLOCK(); 563 | } 564 | else 565 | { 566 | loaded_bitmap OutputTarget; 567 | OutputTarget.Memory = RenderBuffer->Memory; 568 | OutputTarget.Width = RenderBuffer->Width; 569 | OutputTarget.Height = RenderBuffer->Height; 570 | OutputTarget.Pitch = RenderBuffer->Pitch; 571 | 572 | //BEGIN_BLOCK("SoftwareRenderCommands"); 573 | SoftwareRenderCommands(RenderQueue, Commands, &OutputTarget, TempArena); 574 | //END_BLOCK(); 575 | 576 | // We always display via hardware 577 | 578 | OpenGLDisplayBitmap(RenderBuffer->Width, RenderBuffer->Height, 579 | RenderBuffer->Memory, RenderBuffer->Pitch, 580 | DrawRegion, 581 | Commands->ClearColor, 582 | OpenGL.ReservedBlitTexture); 583 | //SwapBuffers(); 584 | } 585 | 586 | EndTemporaryMemory(TempMem); 587 | } 588 | 589 | 590 | 591 | void OSXProcessFrameAndRunGameLogic(osx_game_data* GameData, CGRect WindowFrame, 592 | b32 MouseInWindowFlag, CGPoint MouseLocation, 593 | int MouseButtonMask) 594 | { 595 | {DEBUG_DATA_BLOCK("Platform"); 596 | DEBUG_VALUE(GameData->ExpectedFramesPerUpdate); 597 | } 598 | {DEBUG_DATA_BLOCK("Platform/Controls"); 599 | DEBUG_B32(GlobalPause); 600 | DEBUG_B32(GlobalSoftwareRendering); 601 | } 602 | 603 | osx_state* OSXState = &GlobalOSXState; 604 | 605 | //printf("***** ProcessFrameAndRunGameLogic\n"); 606 | 607 | GameData->NewInput->dtForFrame = GameData->TargetSecondsPerFrame; 608 | 609 | // 610 | // 611 | // 612 | 613 | BEGIN_BLOCK("Input Processing"); 614 | 615 | game_render_commands RenderCommands = DefaultRenderCommands( 616 | GameData->PushBufferSize, 617 | GameData->PushBuffer, 618 | (u32)GameData->RenderBuffer.Width, 619 | (u32)GameData->RenderBuffer.Height, 620 | GameData->MaxVertexCount, 621 | GameData->VertexArray, 622 | GameData->BitmapArray, 623 | &OpenGL.WhiteBitmap); 624 | 625 | rectangle2i DrawRegion = AspectRatioFit(RenderCommands.Settings.Width, RenderCommands.Settings.Height, 626 | WindowFrame.size.width, WindowFrame.size.height); 627 | 628 | game_controller_input* OldKeyboardController = GetController(GameData->OldInput, 0); 629 | game_controller_input* NewKeyboardController = GetController(GameData->NewInput, 0); 630 | 631 | 632 | // TODO(jeff): Fix this for multiple controllers 633 | game_controller_input* NewController = &GameData->NewInput->Controllers[0]; 634 | 635 | NewController->IsConnected = true; 636 | NewController->StickAverageX = GameData->HIDX; 637 | NewController->StickAverageY = GameData->HIDY; 638 | 639 | NewController->ActionDown.EndedDown = GameData->NewInput->Controllers[0].ActionDown.EndedDown; 640 | NewController->ActionUp.EndedDown = GameData->NewInput->Controllers[0].ActionUp.EndedDown; 641 | NewController->ActionLeft.EndedDown = GameData->NewInput->Controllers[0].ActionLeft.EndedDown; 642 | NewController->ActionRight.EndedDown = GameData->NewInput->Controllers[0].ActionRight.EndedDown; 643 | 644 | NewController->MoveUp.EndedDown = GameData->NewInput->Controllers[0].MoveUp.EndedDown; 645 | NewController->MoveDown.EndedDown = GameData->NewInput->Controllers[0].MoveDown.EndedDown; 646 | NewController->MoveLeft.EndedDown = GameData->NewInput->Controllers[0].MoveLeft.EndedDown; 647 | NewController->MoveRight.EndedDown = GameData->NewInput->Controllers[0].MoveRight.EndedDown; 648 | 649 | 650 | GameData->NewInput->dtForFrame = GameData->TargetSecondsPerFrame; 651 | 652 | if (MouseInWindowFlag) 653 | { 654 | //GameData->NewInput->MouseX = (-0.5f * (r32)GameData->RenderBuffer.Width + 0.5f) + (r32)PointInView.x; 655 | //GameData->NewInput->MouseY = (-0.5f * (r32)GameData->RenderBuffer.Height + 0.5f) + (r32)PointInView.y; 656 | //GameData->NewInput->MouseY = (r32)((GameData->RenderBuffer.Height - 1) - PointInView.y); 657 | 658 | r32 MouseX = (r32)MouseLocation.x; 659 | r32 MouseY = (r32)MouseLocation.y; 660 | 661 | GameData->NewInput->MouseX = RenderCommands.Settings.Width * Clamp01MapToRange(DrawRegion.MinX, MouseX, DrawRegion.MaxX); 662 | GameData->NewInput->MouseY = RenderCommands.Settings.Height * Clamp01MapToRange(DrawRegion.MinY, MouseY, DrawRegion.MaxY); 663 | 664 | 665 | GameData->NewInput->MouseZ = 0; // TODO(casey): Support mousewheel? 666 | 667 | for (u32 ButtonIndex = 0; 668 | ButtonIndex < PlatformMouseButton_Count; 669 | ++ButtonIndex) 670 | { 671 | u32 IsDown = 0; 672 | 673 | if (ButtonIndex > 0) 674 | { 675 | IsDown = (MouseButtonMask >> ButtonIndex) & 0x0001; 676 | } 677 | else 678 | { 679 | IsDown = MouseButtonMask & 0x0001; 680 | } 681 | 682 | // NOTE(jeff): On OS X, Mouse Button 1 is Right, 2 is Middle 683 | u32 MouseButton = ButtonIndex; 684 | if (ButtonIndex == 1) MouseButton = PlatformMouseButton_Right; 685 | else if (ButtonIndex == 2) MouseButton = PlatformMouseButton_Middle; 686 | 687 | GameData->NewInput->MouseButtons[MouseButton] = GameData->OldInput->MouseButtons[MouseButton]; 688 | GameData->NewInput->MouseButtons[MouseButton].HalfTransitionCount = 0; 689 | 690 | OSXProcessKeyboardMessage(&GameData->NewInput->MouseButtons[MouseButton], IsDown); 691 | } 692 | } 693 | else 694 | { 695 | GameData->NewInput->MouseX = GameData->OldInput->MouseX; 696 | GameData->NewInput->MouseY = GameData->OldInput->MouseY; 697 | GameData->NewInput->MouseZ = GameData->OldInput->MouseZ; 698 | } 699 | 700 | //int ModifierFlags = [[NSApp currentEvent] modifierFlags]; 701 | //GameData->NewInput->ShiftDown = (ModifierFlags & NSShiftKeyMask); 702 | //GameData->NewInput->AltDown = (ModifierFlags & NSAlternateKeyMask); 703 | //GameData->NewInput->ControlDown = (ModifierFlags & NSControlKeyMask); 704 | 705 | CGEventFlags ModifierFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState); 706 | GameData->NewInput->ShiftDown = (ModifierFlags & kCGEventFlagMaskShift); 707 | GameData->NewInput->AltDown = (ModifierFlags & kCGEventFlagMaskAlternate); 708 | GameData->NewInput->ControlDown = (ModifierFlags & kCGEventFlagMaskControl); 709 | 710 | #if 0 711 | // NOTE(jeff): Support for multiple controllers here... 712 | 713 | #define HID_MAX_COUNT 5 714 | 715 | uint32 MaxControllerCount = HID_MAX_COUNT; 716 | if (MaxControllerCount > (ArrayCount(GameData->NewInput->Controllers) - 1)) 717 | { 718 | MaxControllerCount = (ArrayCount(GameData->NewInput->Controllers) - 1); 719 | } 720 | 721 | for (uint32 ControllerIndex = 0; ControllerIndex < MaxControllerCount; ++ControllerIndex) 722 | { 723 | // NOTE(jeff): index 0 is the keyboard 724 | uint32 OurControllerIndex = ControllerIndex + 1; 725 | game_controller_input* OldController = GetController(GameData->OldInput, OurControllerIndex); 726 | game_controller_input* NewController = GetController(GameData->NewInput, OurControllerIndex); 727 | } 728 | #endif 729 | 730 | END_BLOCK(); 731 | 732 | // 733 | // 734 | // 735 | 736 | BEGIN_BLOCK("Game Update"); 737 | 738 | 739 | if (!GlobalPause) 740 | { 741 | if (OSXState->InputRecordingIndex) 742 | { 743 | printf("...Recording input...\n"); 744 | OSXRecordInput(OSXState, GameData->NewInput); 745 | } 746 | 747 | if (OSXState->InputPlayingIndex) 748 | { 749 | printf("...Playing back input...\n"); 750 | game_input Temp = *GameData->NewInput; 751 | 752 | OSXPlaybackInput(OSXState, GameData->NewInput); 753 | 754 | for (u32 MouseButtonIndex = 0; 755 | MouseButtonIndex < PlatformMouseButton_Count; 756 | ++MouseButtonIndex) 757 | { 758 | GameData->NewInput->MouseButtons[MouseButtonIndex] = Temp.MouseButtons[MouseButtonIndex]; 759 | } 760 | GameData->NewInput->MouseX = Temp.MouseX; 761 | GameData->NewInput->MouseY = Temp.MouseY; 762 | GameData->NewInput->MouseZ = Temp.MouseZ; 763 | } 764 | 765 | if (GameData->Game.UpdateAndRender) 766 | { 767 | GameData->Game.UpdateAndRender(&GameMemory, GameData->NewInput, &RenderCommands); 768 | 769 | if (GameData->NewInput->QuitRequested) 770 | { 771 | GlobalRunning = false; 772 | } 773 | //HandleDebugCycleCounters(&GameData->GameMemory); 774 | } 775 | } 776 | 777 | END_BLOCK(); 778 | 779 | // 780 | // 781 | // 782 | 783 | BEGIN_BLOCK("Audio Update"); 784 | 785 | if (!GlobalPause) 786 | { 787 | // TODO(jeff): Move this into the sound render code 788 | //GameData->SoundOutput.Frequency = 440.0 + (15 * GameData->hidY); 789 | 790 | if (GameData->Game.GetSoundSamples) 791 | { 792 | // Sample Count is SamplesPerSecond / GameRefreshRate 793 | //GameData->SoundOutput.SoundBuffer.SampleCount = 1600; // (48000samples/sec) / (30fps) 794 | // ^^^ calculate this. We might be running at 30 or 60 fps 795 | GameData->SoundOutput.SoundBuffer.SampleCount = GameData->SoundOutput.SoundBuffer.SamplesPerSecond / GameData->TargetFramesPerSecond; 796 | 797 | GameData->Game.GetSoundSamples(&GameMemory, &GameData->SoundOutput.SoundBuffer); 798 | 799 | int16* CurrentSample = GameData->SoundOutput.SoundBuffer.Samples; 800 | for (int i = 0; i < GameData->SoundOutput.SoundBuffer.SampleCount; ++i) 801 | { 802 | *GameData->SoundOutput.WriteCursor++ = *CurrentSample++; 803 | *GameData->SoundOutput.WriteCursor++ = *CurrentSample++; 804 | 805 | if ((char*)GameData->SoundOutput.WriteCursor >= ((char*)GameData->SoundOutput.CoreAudioBuffer + GameData->SoundOutput.SoundBufferSize)) 806 | { 807 | //printf("Write cursor wrapped!\n"); 808 | GameData->SoundOutput.WriteCursor = GameData->SoundOutput.CoreAudioBuffer; 809 | } 810 | } 811 | 812 | // Prime the pump to get the write cursor out in front of the read cursor... 813 | static bool firstTime = true; 814 | 815 | if (firstTime) 816 | { 817 | firstTime = false; 818 | 819 | GameData->Game.GetSoundSamples(&GameMemory, &GameData->SoundOutput.SoundBuffer); 820 | 821 | int16* CurrentSample = GameData->SoundOutput.SoundBuffer.Samples; 822 | for (int i = 0; i < GameData->SoundOutput.SoundBuffer.SampleCount; ++i) 823 | { 824 | *GameData->SoundOutput.WriteCursor++ = *CurrentSample++; 825 | *GameData->SoundOutput.WriteCursor++ = *CurrentSample++; 826 | 827 | if ((char*)GameData->SoundOutput.WriteCursor >= ((char*)GameData->SoundOutput.CoreAudioBuffer + GameData->SoundOutput.SoundBufferSize)) 828 | { 829 | GameData->SoundOutput.WriteCursor = GameData->SoundOutput.CoreAudioBuffer; 830 | } 831 | } 832 | } 833 | } 834 | } 835 | 836 | END_BLOCK(); 837 | 838 | // 839 | // 840 | // 841 | 842 | 843 | #if HANDMADE_INTERNAL 844 | BEGIN_BLOCK("Debug Collation"); 845 | 846 | b32 ExecutableNeedsToBeReloaded = false; 847 | 848 | time_t NewDLWriteTime = OSXGetLastWriteTime(GameData->SourceGameCodeDLFullPath); 849 | if (NewDLWriteTime != GameData->Game.DLLastWriteTime) 850 | { 851 | ExecutableNeedsToBeReloaded = true; 852 | } 853 | 854 | GameMemory.ExecutableReloaded = false; 855 | 856 | if (ExecutableNeedsToBeReloaded) 857 | { 858 | OSXCompleteAllWork(&GameData->HighPriorityQueue); 859 | OSXCompleteAllWork(&GameData->LowPriorityQueue); 860 | DEBUGSetEventRecording(false); 861 | } 862 | 863 | if (GameData->Game.DEBUGFrameEnd) 864 | { 865 | GameData->Game.DEBUGFrameEnd(&GameMemory, GameData->NewInput, &RenderCommands); 866 | } 867 | 868 | if (ExecutableNeedsToBeReloaded) 869 | { 870 | OSXUnloadGameCode(&GameData->Game); 871 | 872 | for (u32 LoadTryIndex = 0; 873 | !GameData->Game.IsValid && (LoadTryIndex < 100); 874 | ++LoadTryIndex) 875 | { 876 | GameData->Game = OSXLoadGameCode(GameData->SourceGameCodeDLFullPath); 877 | usleep(100); 878 | } 879 | 880 | GameMemory.ExecutableReloaded = true; 881 | DEBUGSetEventRecording(GameData->Game.IsValid); 882 | } 883 | 884 | 885 | END_BLOCK(); 886 | #endif 887 | 888 | 889 | game_input* Temp = GameData->NewInput; 890 | GameData->NewInput = GameData->OldInput; 891 | GameData->OldInput = Temp; 892 | 893 | NewKeyboardController = GetController(GameData->NewInput, 0); 894 | OldKeyboardController = GetController(GameData->OldInput, 0); 895 | memset(NewKeyboardController, 0, sizeof(game_controller_input)); 896 | NewKeyboardController->IsConnected = true; 897 | 898 | for (int ButtonIndex = 0; 899 | ButtonIndex < ArrayCount(NewKeyboardController->Buttons); 900 | ++ButtonIndex) 901 | { 902 | NewKeyboardController->Buttons[ButtonIndex].EndedDown = 903 | OldKeyboardController->Buttons[ButtonIndex].EndedDown; 904 | } 905 | 906 | 907 | 908 | /////////////////////////////////////////////////////////////////// 909 | // Draw the latest frame to the screen 910 | 911 | BEGIN_BLOCK("Frame Display"); 912 | 913 | platform_texture_op_queue* TextureOpQueue = &GameMemory.TextureOpQueue; 914 | 915 | BeginTicketMutex(&TextureOpQueue->Mutex); 916 | texture_op* FirstTextureOp = TextureOpQueue->First; 917 | texture_op* LastTextureOp = TextureOpQueue->Last; 918 | TextureOpQueue->First = 0; 919 | TextureOpQueue->Last = 0; 920 | EndTicketMutex(&TextureOpQueue->Mutex); 921 | 922 | if (FirstTextureOp) 923 | { 924 | Assert(LastTextureOp); 925 | OpenGLManageTextures(FirstTextureOp); 926 | BeginTicketMutex(&TextureOpQueue->Mutex); 927 | LastTextureOp->Next = TextureOpQueue->FirstFree; 928 | TextureOpQueue->FirstFree = FirstTextureOp; 929 | EndTicketMutex(&TextureOpQueue->Mutex); 930 | } 931 | 932 | OSXDisplayBufferInWindow(&GameData->HighPriorityQueue, 933 | &GameData->RenderBuffer, 934 | &RenderCommands, 935 | DrawRegion, 936 | WindowFrame.size.width, 937 | WindowFrame.size.height, 938 | &FrameTempArena); 939 | 940 | RenderCommands.PushBufferDataAt = RenderCommands.PushBufferBase; 941 | RenderCommands.VertexCount = 0; 942 | 943 | END_BLOCK(); 944 | } 945 | 946 | 947 | -------------------------------------------------------------------------------- /code/osx_handmade_hid.cpp: -------------------------------------------------------------------------------- 1 | 2 | /////////////////////////////////////////////////////////////////////// 3 | // HID input 4 | // 5 | 6 | 7 | #define OSX_HANDMADE_MAX_HID_DEVICES 32 8 | #define OSX_HANDMADE_MAX_HID_DEVICE_ELEMENTS 256 9 | 10 | #define OSX_HANDMADE_MAX_HID_MANUFACTURER_LEN 256 11 | #define OSX_HANDMADE_MAX_HID_PRODUCT_LEN 256 12 | 13 | 14 | typedef struct osx_hid_element 15 | { 16 | IOHIDElementRef ElementRef; 17 | IOHIDElementCookie Cookie; 18 | long Type; 19 | long Page; 20 | long Usage; 21 | long Min; 22 | long Max; 23 | } osx_hid_element; 24 | 25 | 26 | typedef struct osx_hid_device 27 | { 28 | IOHIDDeviceRef DeviceRef; 29 | 30 | osx_game_data* GameData; 31 | 32 | char Manufacturer[OSX_HANDMADE_MAX_HID_MANUFACTURER_LEN]; 33 | char Product[OSX_HANDMADE_MAX_HID_PRODUCT_LEN]; 34 | 35 | int ElementCount; 36 | osx_hid_element Elements[OSX_HANDMADE_MAX_HID_DEVICE_ELEMENTS]; 37 | } osx_hid_device; 38 | 39 | 40 | static osx_hid_device* HIDDevices[OSX_HANDMADE_MAX_HID_DEVICES]; 41 | static int HIDDeviceCount = 0; 42 | 43 | 44 | void OSXHIDElementInitialize(osx_hid_element* Element, 45 | IOHIDElementCookie Cookie, 46 | long Type, long Page, long Usage, long Min, long Max) 47 | { 48 | Element->Cookie = Cookie; 49 | Element->Type = Type; 50 | Element->Page = Page; 51 | Element->Usage = Usage; 52 | Element->Min = Min; 53 | Element->Max = Max; 54 | } 55 | 56 | 57 | osx_hid_device* OSXHIDDeviceCreate(IOHIDDeviceRef DeviceRef, 58 | const char* Manufacturer, 59 | const char* Product, 60 | osx_game_data* GameData) 61 | { 62 | Assert(HIDDeviceCount < (OSX_HANDMADE_MAX_HID_DEVICES - 1)); 63 | 64 | osx_hid_device* Device = (osx_hid_device*)malloc(sizeof(osx_hid_device)); 65 | 66 | Device->DeviceRef = DeviceRef; 67 | 68 | strncpy(Device->Manufacturer, Manufacturer, OSX_HANDMADE_MAX_HID_MANUFACTURER_LEN); 69 | strncpy(Device->Product, Product, OSX_HANDMADE_MAX_HID_PRODUCT_LEN); 70 | 71 | Device->ElementCount = 0; 72 | 73 | Device->GameData = GameData; 74 | 75 | HIDDevices[HIDDeviceCount++] = Device; 76 | 77 | return Device; 78 | } 79 | 80 | 81 | 82 | 83 | 84 | void OSXHIDAction(void* Context, IOReturn Result, void* Sender, IOHIDValueRef Value) 85 | { 86 | #pragma unused(Result) 87 | #pragma unused(Sender) 88 | 89 | osx_hid_device* Device = (osx_hid_device*)Context; 90 | 91 | // NOTE(jeff): Check suggested by Filip to prevent an access violation when 92 | // using a PS3 controller. 93 | // TODO(jeff): Investigate this further... 94 | if (IOHIDValueGetLength(Value) > 2) 95 | { 96 | //printf("OSXHIDAction: value length > 2: %ld\n", IOHIDValueGetLength(value)); 97 | return; 98 | } 99 | 100 | IOHIDElementRef ElementRef = IOHIDValueGetElement(Value); 101 | /* 102 | if (CFGetTypeID(ElementRef) != IOHIDElementGetTypeID()) 103 | { 104 | return; 105 | } 106 | */ 107 | 108 | IOHIDElementCookie Cookie = IOHIDElementGetCookie(ElementRef); 109 | int UsagePage = IOHIDElementGetUsagePage(ElementRef); 110 | int Usage = IOHIDElementGetUsage(ElementRef); 111 | 112 | int ElementValue = IOHIDValueGetIntegerValue(Value); 113 | 114 | 115 | osx_game_data* GameData = Device->GameData; 116 | 117 | osx_hid_element* Element = NULL; 118 | 119 | for (int i = 0; i < Device->ElementCount; ++i) 120 | { 121 | if (Device->Elements[i].Cookie == Cookie) 122 | { 123 | Element = &(Device->Elements[i]); 124 | break; 125 | } 126 | } 127 | 128 | if (Element == NULL) 129 | { 130 | printf("Could not find matching element for device\n"); 131 | return; 132 | } 133 | else 134 | { 135 | #if 0 136 | printf("HID Event: Cookie: %ld Page/Usage = %ld/%ld Min/Max = %ld/%ld Value = %d\n", 137 | (long)Element->Cookie, 138 | Element->Page, 139 | Element->Usage, 140 | Element->Min, 141 | Element->Max, 142 | ElementValue); 143 | #endif 144 | } 145 | 146 | // NOTE(jeff): This is just for reference. From the USB HID Usage Tables spec: 147 | // Usage Pages: 148 | // 1 - Generic Desktop (mouse, joystick) 149 | // 2 - Simulation Controls 150 | // 3 - VR Controls 151 | // 4 - Sports Controls 152 | // 5 - Game Controls 153 | // 6 - Generic Device Controls (battery, wireless, security code) 154 | // 7 - Keyboard/Keypad 155 | // 8 - LED 156 | // 9 - Button 157 | // A - Ordinal 158 | // B - Telephony 159 | // C - Consumer 160 | // D - Digitizers 161 | // 10 - Unicode 162 | // 14 - Alphanumeric Display 163 | // 40 - Medical Instrument 164 | 165 | if (UsagePage == 1) // Generic Desktop Page 166 | { 167 | int HatDelta = 16; 168 | 169 | float NormalizedValue = 0.0; 170 | if (Element->Max != Element->Min) 171 | { 172 | NormalizedValue = (float)(ElementValue - Element->Min) / (float)(Element->Max - Element->Min); 173 | } 174 | float ScaledMin = -25.0; 175 | float ScaledMax = 25.0; 176 | 177 | int ScaledValue = ScaledMin + NormalizedValue * (ScaledMax - ScaledMin); 178 | 179 | //printf("page:usage = %d:%d value = %ld ", usagePage, usage, elementValue); 180 | switch(Usage) 181 | { 182 | case 0x30: // x 183 | GameData->HIDX = ScaledValue; 184 | //printf("[x] scaled = %d\n", view->_HIDX); 185 | break; 186 | 187 | case 0x31: // y 188 | GameData->HIDY = ScaledValue; 189 | //printf("[y] scaled = %d\n", view->_HIDY); 190 | break; 191 | 192 | case 0x32: // z 193 | //GameData->HIDX = ScaledValue; 194 | //printf("[z] scaled = %d\n", view->_HIDX); 195 | break; 196 | 197 | case 0x35: // rz 198 | //GameData->HIDY = ScaledValue; 199 | //printf("[rz] scaled = %d\n", view->_HIDY); 200 | break; 201 | 202 | case 0x39: // Hat 0 = up, 2 = right, 4 = down, 6 = left, 8 = centered 203 | { 204 | game_controller_input* Controller = &GameData->NewInput->Controllers[0]; 205 | 206 | OSXProcessKeyboardMessage(&Controller->MoveUp, 0); 207 | OSXProcessKeyboardMessage(&Controller->MoveDown, 0); 208 | OSXProcessKeyboardMessage(&Controller->MoveLeft, 0); 209 | OSXProcessKeyboardMessage(&Controller->MoveRight, 0); 210 | 211 | //printf("[hat] "); 212 | switch(ElementValue) 213 | { 214 | case 0: 215 | GameData->HIDX = 0; 216 | GameData->HIDY = -HatDelta; 217 | OSXProcessKeyboardMessage(&Controller->MoveUp, 1); 218 | //printf("n\n"); 219 | break; 220 | 221 | case 1: 222 | GameData->HIDX = HatDelta; 223 | GameData->HIDY = -HatDelta; 224 | OSXProcessKeyboardMessage(&Controller->MoveUp, 1); 225 | OSXProcessKeyboardMessage(&Controller->MoveRight, 1); 226 | //printf("ne\n"); 227 | break; 228 | 229 | case 2: 230 | GameData->HIDX = HatDelta; 231 | GameData->HIDY = 0; 232 | OSXProcessKeyboardMessage(&Controller->MoveRight, 1); 233 | //printf("e\n"); 234 | break; 235 | 236 | case 3: 237 | GameData->HIDX = HatDelta; 238 | GameData->HIDY = HatDelta; 239 | OSXProcessKeyboardMessage(&Controller->MoveRight, 1); 240 | OSXProcessKeyboardMessage(&Controller->MoveDown, 1); 241 | //printf("se\n"); 242 | break; 243 | 244 | case 4: 245 | GameData->HIDX = 0; 246 | GameData->HIDY = HatDelta; 247 | OSXProcessKeyboardMessage(&Controller->MoveDown, 1); 248 | //printf("s\n"); 249 | break; 250 | 251 | case 5: 252 | GameData->HIDX = -HatDelta; 253 | GameData->HIDY = HatDelta; 254 | OSXProcessKeyboardMessage(&Controller->MoveDown, 1); 255 | OSXProcessKeyboardMessage(&Controller->MoveLeft, 1); 256 | //printf("sw\n"); 257 | break; 258 | 259 | case 6: 260 | GameData->HIDX = -HatDelta; 261 | GameData->HIDY = 0; 262 | OSXProcessKeyboardMessage(&Controller->MoveLeft, 1); 263 | //printf("w\n"); 264 | break; 265 | 266 | case 7: 267 | GameData->HIDX = -HatDelta; 268 | GameData->HIDY = -HatDelta; 269 | OSXProcessKeyboardMessage(&Controller->MoveLeft, 1); 270 | OSXProcessKeyboardMessage(&Controller->MoveUp, 1); 271 | //printf("nw\n"); 272 | break; 273 | 274 | case 8: 275 | GameData->HIDX = 0; 276 | GameData->HIDY = 0; 277 | //printf("up\n"); 278 | break; 279 | } 280 | 281 | } break; 282 | 283 | default: 284 | break; 285 | } 286 | } 287 | else if (UsagePage == 9) // Buttons 288 | { 289 | game_controller_input* Controller = &GameData->NewInput->Controllers[0]; 290 | 291 | if ((ElementValue == 0) || (ElementValue == 1)) 292 | { 293 | GameData->HIDButtons[Usage] = ElementValue; 294 | 295 | if (ElementValue == 1) printf("Button %d pressed\n", Usage); 296 | 297 | switch(Usage) 298 | { 299 | case 1: 300 | OSXProcessKeyboardMessage(&Controller->ActionLeft, ElementValue); 301 | break; 302 | 303 | case 2: 304 | OSXProcessKeyboardMessage(&Controller->ActionDown, ElementValue); 305 | break; 306 | 307 | case 3: 308 | OSXProcessKeyboardMessage(&Controller->ActionRight, ElementValue); 309 | break; 310 | 311 | case 4: 312 | OSXProcessKeyboardMessage(&Controller->ActionUp, ElementValue); 313 | break; 314 | 315 | case 9: 316 | OSXProcessKeyboardMessage(&Controller->Back, ElementValue); 317 | break; 318 | 319 | case 10: 320 | OSXProcessKeyboardMessage(&Controller->Start, ElementValue); 321 | break; 322 | 323 | default: 324 | break; 325 | } 326 | } 327 | else 328 | { 329 | printf("Gamepad Element: Cookie: %ld Page: %d Usage: %d Value: %d _HIDX: %d\n", 330 | (long)Cookie, UsagePage, Usage, ElementValue, GameData->HIDX); 331 | } 332 | } 333 | else if (UsagePage == 7) // Keyboard 334 | { 335 | // NOTE(jeff): Moved to main loop event processing... 336 | } 337 | else 338 | { 339 | //printf("Gamepad Element: %@ Type: %d Page: %d Usage: %d Name: %@ Cookie: %i Value: %ld _HIDX: %d\n", 340 | // element, type, usagePage, usage, name, cookie, elementValue, GameData->HIDX); 341 | } 342 | } 343 | 344 | 345 | 346 | 347 | void OSXHIDAdded(void* Context, IOReturn Result, void* Sender, IOHIDDeviceRef DeviceRef) 348 | { 349 | #pragma unused(Result) 350 | #pragma unused(Sender) 351 | 352 | osx_game_data* GameData = (osx_game_data*)Context; 353 | 354 | CFStringRef ManufacturerCFSR = (CFStringRef)IOHIDDeviceGetProperty(DeviceRef, CFSTR(kIOHIDManufacturerKey)); 355 | CFStringRef ProductCFSR = (CFStringRef)IOHIDDeviceGetProperty(DeviceRef, CFSTR(kIOHIDProductKey)); 356 | 357 | const char* Manufacturer = CFStringGetCStringPtr(ManufacturerCFSR, kCFStringEncodingMacRoman); 358 | const char* Product = CFStringGetCStringPtr(ProductCFSR, kCFStringEncodingMacRoman); 359 | 360 | if (Manufacturer == NULL) Manufacturer = "[unknown]"; 361 | if (Product == NULL) Product = "[unknown]"; 362 | 363 | printf("Gamepad was detected: %s %s", Manufacturer, Product); 364 | 365 | 366 | osx_hid_device* Device = OSXHIDDeviceCreate(DeviceRef, Manufacturer, Product, GameData); 367 | 368 | 369 | CFArrayRef ElementArray = IOHIDDeviceCopyMatchingElements(DeviceRef, NULL, kIOHIDOptionsTypeNone); 370 | int ElementArrayCount = CFArrayGetCount(ElementArray); 371 | 372 | for (int i = 0; i < ElementArrayCount; ++i) 373 | { 374 | IOHIDElementRef ElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(ElementArray, i); 375 | 376 | IOHIDElementCookie Cookie = IOHIDElementGetCookie(ElementRef); 377 | IOHIDElementType ElementType = IOHIDElementGetType(ElementRef); 378 | 379 | #if 0 380 | switch(ElementType) 381 | { 382 | case kIOHIDElementTypeInput_Misc: printf("[misc] "); break; 383 | case kIOHIDElementTypeInput_Button: printf("[button] "); break; 384 | case kIOHIDElementTypeInput_Axis: printf("[axis] "); break; 385 | case kIOHIDElementTypeInput_ScanCodes: printf("[scancode] "); break; 386 | default: continue; 387 | } 388 | #endif 389 | 390 | uint32_t ReportSize = IOHIDElementGetReportSize(ElementRef); 391 | uint32_t ReportCount = IOHIDElementGetReportCount(ElementRef); 392 | if ((ReportSize * ReportCount) > 64) 393 | { 394 | continue; 395 | } 396 | 397 | uint32_t UsagePage = IOHIDElementGetUsagePage(ElementRef); 398 | uint32_t Usage = IOHIDElementGetUsage(ElementRef); 399 | 400 | if (!UsagePage || !Usage) 401 | { 402 | continue; 403 | } 404 | if (Usage == -1) 405 | { 406 | continue; 407 | } 408 | 409 | CFIndex LogicalMin = IOHIDElementGetLogicalMin(ElementRef); 410 | CFIndex LogicalMax = IOHIDElementGetLogicalMax(ElementRef); 411 | 412 | osx_hid_element* Element = &(Device->Elements[Device->ElementCount++]); 413 | OSXHIDElementInitialize(Element, Cookie, ElementType, UsagePage, Usage, LogicalMin, LogicalMax); 414 | } 415 | 416 | CFRelease(ElementArray); 417 | 418 | IOHIDDeviceRegisterInputValueCallback(DeviceRef, OSXHIDAction, Device); 419 | } 420 | 421 | 422 | 423 | void OSXHIDRemoved(void* context, IOReturn result, void* sender, IOHIDDeviceRef device) 424 | { 425 | #pragma unused(context) 426 | #pragma unused(result) 427 | #pragma unused(sender) 428 | #pragma unused(device) 429 | 430 | printf("Gamepad was unplugged\n"); 431 | } 432 | 433 | 434 | 435 | void OSXSetupGamepad(osx_game_data* game_data) 436 | { 437 | game_data->HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); 438 | 439 | if (game_data->HIDManager) 440 | { 441 | CFStringRef keys[2]; 442 | keys[0] = CFSTR(kIOHIDDeviceUsagePageKey); 443 | keys[1] = CFSTR(kIOHIDDeviceUsageKey); 444 | 445 | 446 | int usageValues[3] = { 447 | kHIDUsage_GD_Joystick, 448 | kHIDUsage_GD_GamePad, 449 | kHIDUsage_GD_MultiAxisController 450 | }; 451 | int usageValuesCount = sizeof(usageValues) / sizeof(int); 452 | 453 | CFDictionaryRef dictionaries[usageValuesCount]; 454 | 455 | for (int i = 0; i < usageValuesCount; ++i) 456 | { 457 | CFNumberRef values[2]; 458 | 459 | int pageGDValue = kHIDPage_GenericDesktop; 460 | values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pageGDValue); 461 | values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &(usageValues[i])); 462 | 463 | dictionaries[i] = CFDictionaryCreate(kCFAllocatorDefault, 464 | (const void**)keys, 465 | (const void**)values, 466 | 2, 467 | &kCFTypeDictionaryKeyCallBacks, 468 | &kCFTypeDictionaryValueCallBacks); 469 | CFRelease(values[0]); 470 | CFRelease(values[1]); 471 | } 472 | 473 | #if 0 474 | NSArray* criteria = @[ @{ [NSString stringWithUTF8String:kIOHIDDeviceUsagePageKey]: 475 | [NSNumber numberWithInt:kHIDPage_GenericDesktop], 476 | [NSString stringWithUTF8String:kIOHIDDeviceUsageKey]: 477 | [NSNumber numberWithInt:kHIDUsage_GD_Joystick] 478 | }, 479 | @{ (NSString*)CFSTR(kIOHIDDeviceUsagePageKey): 480 | [NSNumber numberWithInt:kHIDPage_GenericDesktop], 481 | (NSString*)CFSTR(kIOHIDDeviceUsageKey): 482 | [NSNumber numberWithInt:kHIDUsage_GD_GamePad] 483 | }, 484 | @{ (NSString*)CFSTR(kIOHIDDeviceUsagePageKey): 485 | [NSNumber numberWithInt:kHIDPage_GenericDesktop], 486 | (NSString*)CFSTR(kIOHIDDeviceUsageKey): 487 | [NSNumber numberWithInt:kHIDUsage_GD_MultiAxisController] 488 | } 489 | #if 0 490 | , 491 | @{ (NSString*)CFSTR(kIOHIDDeviceUsagePageKey): 492 | [NSNumber numberWithInt:kHIDPage_GenericDesktop], 493 | (NSString*)CFSTR(kIOHIDDeviceUsageKey): 494 | [NSNumber numberWithInt:kHIDUsage_GD_Keyboard] 495 | } 496 | #endif 497 | ]; 498 | #endif 499 | 500 | CFArrayRef criteria = CFArrayCreate(kCFAllocatorDefault, 501 | (const void**)dictionaries, 502 | usageValuesCount, 503 | &kCFTypeArrayCallBacks); 504 | 505 | 506 | // NOTE(jeff): These all return void, so no error checking... 507 | IOHIDManagerSetDeviceMatchingMultiple(game_data->HIDManager, criteria); 508 | IOHIDManagerRegisterDeviceMatchingCallback(game_data->HIDManager, OSXHIDAdded, (void*)game_data); 509 | IOHIDManagerRegisterDeviceRemovalCallback(game_data->HIDManager, OSXHIDRemoved, (void*)game_data); 510 | IOHIDManagerScheduleWithRunLoop(game_data->HIDManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); 511 | 512 | if (IOHIDManagerOpen(game_data->HIDManager, kIOHIDOptionsTypeNone) == kIOReturnSuccess) 513 | { 514 | //IOHIDManagerRegisterInputValueCallback(game_data->HIDManager, OSXHIDAction, (void*)game_data); 515 | } 516 | else 517 | { 518 | // TODO(jeff): Diagnostic 519 | } 520 | 521 | 522 | for (int i = 0; i < usageValuesCount; ++i) 523 | { 524 | CFRelease(dictionaries[i]); 525 | } 526 | 527 | CFRelease(criteria); 528 | } 529 | else 530 | { 531 | // TODO(jeff): Diagnostic 532 | } 533 | } 534 | 535 | 536 | -------------------------------------------------------------------------------- /code/osx_handmade_playback.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_playback.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | extern osx_state GlobalOSXState; 9 | 10 | void OSXGetInputFileLocation(osx_state* State, bool32 InputStream, int SlotIndex, int DestCount, char* Dest) 11 | { 12 | char Temp[64]; 13 | sprintf(Temp, "loop_edit_%d_%s.hmi", SlotIndex, InputStream ? "input" : "state"); 14 | OSXBuildAppPathFilename(State, Temp, DestCount, Dest); 15 | } 16 | 17 | #if 0 18 | static osx_replay_buffer* 19 | OSXGetReplayBuffer(osx_state* State, int unsigned Index) 20 | { 21 | Assert(Index < ArrayCount(State->ReplayBuffers)); 22 | osx_replay_buffer* Result = &State->ReplayBuffers[Index]; 23 | 24 | return Result; 25 | } 26 | #endif 27 | 28 | 29 | void OSXBeginRecordingInput(osx_state* State, int InputRecordingIndex) 30 | { 31 | printf("beginning recording input\n"); 32 | 33 | char Filename[FILENAME_MAX]; 34 | OSXGetInputFileLocation(State, true, InputRecordingIndex, 35 | sizeof(Filename), Filename); 36 | State->RecordingHandle = open(Filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 37 | 38 | if (State->RecordingHandle != -1) 39 | { 40 | // Test case: OSXVerifyMemoryListIntegrity(); 41 | 42 | State->InputRecordingIndex = InputRecordingIndex; 43 | osx_memory_block* Sentinel = &GlobalOSXState.MemorySentinel; 44 | 45 | BeginTicketMutex(&GlobalOSXState.MemoryMutex); 46 | 47 | for (osx_memory_block* SourceBlock = Sentinel->Next; 48 | SourceBlock != Sentinel; 49 | SourceBlock = SourceBlock->Next) 50 | { 51 | if (!(SourceBlock->Block.Flags & PlatformMemory_NotRestored)) 52 | { 53 | osx_saved_memory_block DestBlock; 54 | void* BasePointer = SourceBlock->Block.Base; 55 | DestBlock.BasePointer = (u64)BasePointer; 56 | DestBlock.Size = SourceBlock->Block.Size; 57 | 58 | ssize_t BytesWritten; 59 | BytesWritten = write(State->RecordingHandle, &DestBlock, sizeof(DestBlock)); 60 | 61 | if (BytesWritten == sizeof(DestBlock)) 62 | { 63 | Assert(DestBlock.Size <= U32Max); 64 | BytesWritten = write(State->RecordingHandle, BasePointer, 65 | (u32)DestBlock.Size); 66 | 67 | if (BytesWritten != DestBlock.Size) 68 | { 69 | printf("OSXBeginRecordingInput: Could not write Block contents\n"); 70 | } 71 | } 72 | else 73 | { 74 | printf("OSXBeginRecordingInput: Could not write Block header\n"); 75 | } 76 | } 77 | } 78 | 79 | EndTicketMutex(&GlobalOSXState.MemoryMutex); 80 | 81 | osx_saved_memory_block DestBlock = {}; 82 | write(State->RecordingHandle, &DestBlock, sizeof(DestBlock)); 83 | } 84 | } 85 | 86 | 87 | void OSXEndRecordingInput(osx_state* State) 88 | { 89 | close(State->RecordingHandle); 90 | State->RecordingHandle = -1; 91 | State->InputRecordingIndex = 0; 92 | printf("ended recording input\n"); 93 | } 94 | 95 | void OSXClearBlocksByMask(osx_state* State, u64 Mask) 96 | { 97 | for (osx_memory_block* BlockIter = State->MemorySentinel.Next; 98 | BlockIter != &State->MemorySentinel; 99 | ) 100 | { 101 | osx_memory_block* Block = BlockIter; 102 | BlockIter = BlockIter->Next; 103 | 104 | if ((Block->LoopingFlags & Mask) == Mask) 105 | { 106 | OSXFreeMemoryBlock(Block); 107 | } 108 | else 109 | { 110 | Block->LoopingFlags = 0; 111 | } 112 | } 113 | } 114 | 115 | void OSXBeginInputPlayback(osx_state* State, int InputPlayingIndex) 116 | { 117 | OSXClearBlocksByMask(State, OSXMem_AllocatedDuringLooping); 118 | 119 | printf("beginning input playback\n"); 120 | char Filename[FILENAME_MAX]; 121 | OSXGetInputFileLocation(State, true, InputPlayingIndex, sizeof(Filename), Filename); 122 | State->PlaybackHandle = open(Filename, O_RDONLY); 123 | 124 | if (State->PlaybackHandle != -1) 125 | { 126 | State->InputPlayingIndex = InputPlayingIndex; 127 | 128 | for (;;) 129 | { 130 | osx_saved_memory_block Block = {}; 131 | 132 | ssize_t BytesRead; 133 | BytesRead = read(State->PlaybackHandle, &Block, sizeof(Block)); 134 | 135 | if (Block.BasePointer != 0) 136 | { 137 | void* BasePointer = (void*)Block.BasePointer; 138 | Assert(Block.Size <= U32Max); 139 | BytesRead = read(State->PlaybackHandle, BasePointer, (u32)Block.Size); 140 | } 141 | else 142 | { 143 | break; 144 | } 145 | } 146 | } 147 | else 148 | { 149 | printf("Could not open playback file %s\n", Filename); 150 | } 151 | } 152 | 153 | 154 | void OSXEndInputPlayback(osx_state* State) 155 | { 156 | OSXClearBlocksByMask(State, OSXMem_FreedDuringLooping); 157 | 158 | close(State->PlaybackHandle); 159 | State->PlaybackHandle = -1; 160 | State->InputPlayingIndex = 0; 161 | 162 | printf("ended input playback\n"); 163 | } 164 | 165 | 166 | void OSXRecordInput(osx_state* State, game_input* NewInput) 167 | { 168 | uint32 BytesWritten = write(State->RecordingHandle, NewInput, sizeof(*NewInput)); 169 | 170 | if (BytesWritten != sizeof(*NewInput)) 171 | { 172 | printf("write error recording input: %d: %s\n", errno, strerror(errno)); 173 | } 174 | } 175 | 176 | 177 | void OSXPlaybackInput(osx_state* State, game_input* NewInput) 178 | { 179 | size_t BytesRead = read(State->PlaybackHandle, NewInput, sizeof(*NewInput)); 180 | 181 | if (BytesRead == 0) 182 | { 183 | // NOTE(casey): We've hit the end of the stream, go back to the beginning 184 | int PlayingIndex = State->InputPlayingIndex; 185 | OSXEndInputPlayback(State); 186 | OSXBeginInputPlayback(State, PlayingIndex); 187 | 188 | BytesRead = read(State->PlaybackHandle, NewInput, sizeof(*NewInput)); 189 | 190 | if (BytesRead != sizeof(*NewInput)) 191 | { 192 | printf("read error rewinding playback input: %d: %s\n", errno, strerror(errno)); 193 | } 194 | else 195 | { 196 | printf("rewinding playback...\n"); 197 | } 198 | } 199 | } 200 | 201 | 202 | -------------------------------------------------------------------------------- /code/osx_handmade_process.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_process.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | 9 | /////////////////////////////////////////////////////////////////////// 10 | // External Process Control 11 | 12 | #define STRINGIFY(S) #S 13 | 14 | #if HANDMADE_INTERNAL 15 | DEBUG_PLATFORM_EXECUTE_SYSTEM_COMMAND(DEBUGExecuteSystemCommand) 16 | { 17 | debug_executing_process Result = {}; 18 | 19 | char* Args[] = {"/bin/sh", 20 | STRINGIFY(DYNAMIC_COMPILE_COMMAND), 21 | 0}; 22 | 23 | char* WorkingDirectory = STRINGIFY(DYNAMIC_COMPILE_PATH); 24 | 25 | int PID = fork(); 26 | 27 | switch(PID) 28 | { 29 | case -1: 30 | printf("Error forking process: %d\n", PID); 31 | break; 32 | 33 | case 0: 34 | { 35 | // child 36 | chdir(WorkingDirectory); 37 | int ExecCode = execvp(Args[0], Args); 38 | if (ExecCode == -1) 39 | { 40 | printf("Error in execve: %d\n", errno); 41 | } 42 | break; 43 | } 44 | 45 | default: 46 | // parent 47 | printf("Launched child process %d\n", PID); 48 | break; 49 | } 50 | 51 | 52 | Result.OSHandle = PID; 53 | 54 | return(Result); 55 | } 56 | 57 | 58 | DEBUG_PLATFORM_GET_PROCESS_STATE(DEBUGGetProcessState) 59 | { 60 | debug_process_state Result = {}; 61 | 62 | int PID = (int)Process.OSHandle; 63 | int ExitCode = 0; 64 | 65 | if (PID > 0) 66 | { 67 | Result.StartedSuccessfully = true; 68 | } 69 | 70 | if (waitpid(PID, &ExitCode, WNOHANG) == PID) 71 | { 72 | Result.ReturnCode = WEXITSTATUS(ExitCode); 73 | printf("Child process %d exited with code %d...\n", PID, ExitCode); 74 | } 75 | else 76 | { 77 | Result.IsRunning = true; 78 | } 79 | 80 | return(Result); 81 | } 82 | #endif 83 | 84 | 85 | -------------------------------------------------------------------------------- /code/osx_handmade_thread.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_handmade_thread.cpp 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | 9 | void* OSXQueueThreadProc(void *data) 10 | { 11 | //platform_work_queue* Queue = (platform_work_queue*)data; 12 | osx_thread_startup* Thread = (osx_thread_startup*)data; 13 | platform_work_queue* Queue = Thread->Queue; 14 | 15 | for(;;) 16 | { 17 | if(OSXDoNextWorkQueueEntry(Queue)) 18 | { 19 | dispatch_semaphore_wait(Queue->SemaphoreHandle, DISPATCH_TIME_FOREVER); 20 | } 21 | } 22 | 23 | return(0); 24 | } 25 | 26 | 27 | 28 | void OSXMakeQueue(platform_work_queue* Queue, uint32 ThreadCount, osx_thread_startup* Startups) 29 | { 30 | Queue->CompletionGoal = 0; 31 | Queue->CompletionCount = 0; 32 | 33 | Queue->NextEntryToWrite = 0; 34 | Queue->NextEntryToRead = 0; 35 | 36 | Queue->SemaphoreHandle = dispatch_semaphore_create(0); 37 | 38 | for (uint32 ThreadIndex = 0; 39 | ThreadIndex < ThreadCount; 40 | ++ThreadIndex) 41 | { 42 | osx_thread_startup* Startup = Startups + ThreadIndex; 43 | Startup->Queue = Queue; 44 | 45 | pthread_t ThreadId; 46 | int r = pthread_create(&ThreadId, NULL, OSXQueueThreadProc, Startup); 47 | if (r != 0) 48 | { 49 | printf("Error creating thread %d\n", ThreadIndex); 50 | } 51 | } 52 | } 53 | 54 | 55 | void OSXAddEntry(platform_work_queue* Queue, platform_work_queue_callback* Callback, void* Data) 56 | { 57 | // TODO(casey): Switch to InterlockedCompareExchange eventually 58 | // so that any thread can add? 59 | uint32 NewNextEntryToWrite = (Queue->NextEntryToWrite + 1) % ArrayCount(Queue->Entries); 60 | Assert(NewNextEntryToWrite != Queue->NextEntryToRead); 61 | platform_work_queue_entry *Entry = Queue->Entries + Queue->NextEntryToWrite; 62 | Entry->Callback = Callback; 63 | Entry->Data = Data; 64 | ++Queue->CompletionGoal; 65 | OSMemoryBarrier(); 66 | // Not needed: _mm_sfence(); 67 | Queue->NextEntryToWrite = NewNextEntryToWrite; 68 | dispatch_semaphore_signal(Queue->SemaphoreHandle); 69 | 70 | #if 0 71 | int r = dispatch_semaphore_signal(Queue->SemaphoreHandle); 72 | if (r > 0) 73 | { 74 | printf(" dispatch_semaphore_signal: A thread was woken\n"); 75 | } 76 | else 77 | { 78 | printf(" dispatch_semaphore_signal: No thread was woken\n"); 79 | } 80 | #endif 81 | } 82 | 83 | bool32 OSXDoNextWorkQueueEntry(platform_work_queue* Queue) 84 | { 85 | bool32 WeShouldSleep = false; 86 | 87 | uint32 OriginalNextEntryToRead = Queue->NextEntryToRead; 88 | uint32 NewNextEntryToRead = (OriginalNextEntryToRead + 1) % ArrayCount(Queue->Entries); 89 | 90 | if(OriginalNextEntryToRead != Queue->NextEntryToWrite) 91 | { 92 | // NOTE(jeff): OSAtomicCompareAndSwapXXX functions return 1 if the swap took place, 0 otherwise! 93 | uint32 SwapOccurred = OSAtomicCompareAndSwapIntBarrier(OriginalNextEntryToRead, 94 | NewNextEntryToRead, 95 | (int volatile*)&Queue->NextEntryToRead); 96 | 97 | if (SwapOccurred) 98 | { 99 | platform_work_queue_entry Entry = Queue->Entries[OriginalNextEntryToRead]; 100 | Entry.Callback(Queue, Entry.Data); 101 | //InterlockedIncrement((int volatile *)&Queue->CompletionCount); 102 | OSAtomicIncrement32Barrier((int volatile *)&Queue->CompletionCount); 103 | } 104 | else 105 | { 106 | } 107 | } 108 | else 109 | { 110 | WeShouldSleep = true; 111 | } 112 | 113 | return(WeShouldSleep); 114 | } 115 | 116 | void OSXCompleteAllWork(platform_work_queue *Queue) 117 | { 118 | while (Queue->CompletionGoal != Queue->CompletionCount) 119 | { 120 | OSXDoNextWorkQueueEntry(Queue); 121 | } 122 | 123 | Queue->CompletionGoal = 0; 124 | Queue->CompletionCount = 0; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /code/osx_main.mm: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////// 2 | // osx_main.mm 3 | // 4 | // Jeff Buck 5 | // Copyright 2014-2016. All Rights Reserved. 6 | // 7 | 8 | #include 9 | 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | #include 16 | 17 | #define Maximum(A, B) ((A > B) ? (A) : (B)) 18 | 19 | #import "handmade_platform.h" 20 | #import "handmade_memory.h" 21 | #import "osx_handmade.h" 22 | 23 | #import "handmade_intrinsics.h" 24 | 25 | // Let the command line override 26 | #ifndef HANDMADE_USE_VSYNC 27 | #define HANDMADE_USE_VSYNC 1 28 | #endif 29 | 30 | 31 | global_variable NSOpenGLContext* GlobalGLContext; 32 | global_variable r32 GlobalAspectRatio; 33 | 34 | 35 | /////////////////////////////////////////////////////////////////////// 36 | // Application Delegate 37 | 38 | @interface HandmadeAppDelegate : NSObject 39 | @end 40 | 41 | 42 | @implementation HandmadeAppDelegate 43 | 44 | 45 | /////////////////////////////////////////////////////////////////////// 46 | // Application delegate methods 47 | // 48 | - (void)applicationDidFinishLaunching:(id)sender 49 | { 50 | #pragma unused(sender) 51 | } 52 | 53 | 54 | - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender 55 | { 56 | #pragma unused(sender) 57 | 58 | return YES; 59 | } 60 | 61 | 62 | - (void)applicationWillTerminate:(NSApplication*)sender 63 | { 64 | #pragma unused(sender) 65 | 66 | printf("applicationWillTerminate\n"); 67 | } 68 | 69 | 70 | 71 | /////////////////////////////////////////////////////////////////////// 72 | // Window delegate methods 73 | // 74 | - (void)windowWillClose:(id)sender 75 | { 76 | printf("Main window will close. Stopping game.\n"); 77 | 78 | OSXStopGame(); 79 | } 80 | 81 | 82 | - (NSSize)windowWillResize:(NSWindow*)window 83 | toSize:(NSSize)frameSize 84 | { 85 | // Maintain the proper aspect ratio... 86 | //frameSize.height = frameSize.width / GlobalAspectRatio; 87 | 88 | NSRect WindowRect = [window frame]; 89 | NSRect ContentRect = [window contentRectForFrameRect:WindowRect]; 90 | 91 | r32 WidthAdd = (WindowRect.size.width - ContentRect.size.width); 92 | r32 HeightAdd = (WindowRect.size.height - ContentRect.size.height); 93 | 94 | r32 RenderWidth = 1920; 95 | r32 RenderHeight = 1080; 96 | //r32 RenderWidth = 2560; 97 | //r32 RenderHeight = 1440; 98 | 99 | r32 NewCy = (RenderHeight * (frameSize.width - WidthAdd)) / RenderWidth; 100 | 101 | frameSize.height = NewCy + HeightAdd; 102 | 103 | return frameSize; 104 | } 105 | 106 | 107 | #if 0 108 | - (void)windowDidResize:(NSNotification*)notification 109 | { 110 | NSWindow* window = [notification object]; 111 | 112 | //Assert(GlobalGLContext == [NSOpenGLContext currentContext]); 113 | //[GlobalGLContext update]; 114 | [GlobalGLContext makeCurrentContext]; 115 | [GlobalGLContext update]; 116 | 117 | // OpenGL reshape. Typically done in the view 118 | //glLoadIdentity(); 119 | 120 | NSRect ContentViewFrame = [[window contentView] frame]; 121 | glViewport(0, 0, ContentViewFrame.size.width, ContentViewFrame.size.height); 122 | [GlobalGLContext update]; 123 | } 124 | #endif 125 | 126 | @end 127 | // 128 | // Application Delegate 129 | /////////////////////////////////////////////////////////////////////// 130 | 131 | 132 | void OSXCreateMainMenu() 133 | { 134 | // Create the Menu. Two options right now: 135 | // Toggle Full Screen 136 | // Quit 137 | NSMenu* menubar = [NSMenu new]; 138 | 139 | NSMenuItem* appMenuItem = [NSMenuItem new]; 140 | [menubar addItem:appMenuItem]; 141 | 142 | [NSApp setMainMenu:menubar]; 143 | 144 | NSMenu* appMenu = [NSMenu new]; 145 | 146 | //NSString* appName = [[NSProcessInfo processInfo] processName]; 147 | NSString* appName = @"Handmade Hero"; 148 | 149 | 150 | NSString* toggleFullScreenTitle = @"Toggle Full Screen"; 151 | NSMenuItem* toggleFullScreenMenuItem = [[NSMenuItem alloc] initWithTitle:toggleFullScreenTitle 152 | action:@selector(toggleFullScreen:) 153 | keyEquivalent:@"f"]; 154 | [appMenu addItem:toggleFullScreenMenuItem]; 155 | 156 | NSString* quitTitle = [@"Quit " stringByAppendingString:appName]; 157 | NSMenuItem* quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle 158 | action:@selector(terminate:) 159 | keyEquivalent:@"q"]; 160 | [appMenu addItem:quitMenuItem]; 161 | [appMenuItem setSubmenu:appMenu]; 162 | } 163 | 164 | 165 | void OSXProcessPendingMessages(osx_game_data* GameData) 166 | { 167 | NSEvent* Event; 168 | 169 | do 170 | { 171 | Event = [NSApp nextEventMatchingMask:NSAnyEventMask 172 | untilDate:nil 173 | inMode:NSDefaultRunLoopMode 174 | dequeue:YES]; 175 | 176 | switch ([Event type]) 177 | { 178 | case NSKeyDown: 179 | { 180 | unichar C = [[Event charactersIgnoringModifiers] characterAtIndex:0]; 181 | int ModifierFlags = [Event modifierFlags]; 182 | int CommandKeyFlag = ModifierFlags & NSCommandKeyMask; 183 | int ControlKeyFlag = ModifierFlags & NSControlKeyMask; 184 | int AlternateKeyFlag = ModifierFlags & NSAlternateKeyMask; 185 | 186 | int KeyDownFlag = 1; 187 | 188 | OSXKeyProcessing(KeyDownFlag, C, 189 | CommandKeyFlag, ControlKeyFlag, AlternateKeyFlag, 190 | GameData->NewInput, GameData); 191 | } break; 192 | 193 | case NSKeyUp: 194 | { 195 | unichar C = [[Event charactersIgnoringModifiers] characterAtIndex:0]; 196 | int ModifierFlags = [Event modifierFlags]; 197 | int CommandKeyFlag = ModifierFlags & NSCommandKeyMask; 198 | int ControlKeyFlag = ModifierFlags & NSControlKeyMask; 199 | int AlternateKeyFlag = ModifierFlags & NSAlternateKeyMask; 200 | 201 | int KeyDownFlag = 0; 202 | 203 | OSXKeyProcessing(KeyDownFlag, C, 204 | CommandKeyFlag, ControlKeyFlag, AlternateKeyFlag, 205 | GameData->NewInput, GameData); 206 | } break; 207 | 208 | default: 209 | [NSApp sendEvent:Event]; 210 | } 211 | } while (Event != nil); 212 | } 213 | 214 | 215 | 216 | /////////////////////////////////////////////////////////////////////// 217 | @interface HandmadeView : NSOpenGLView 218 | { 219 | } 220 | @end 221 | 222 | @implementation HandmadeView 223 | 224 | - (id)init 225 | { 226 | self = [super init]; 227 | 228 | return self; 229 | } 230 | 231 | 232 | - (void)prepareOpenGL 233 | { 234 | [super prepareOpenGL]; 235 | [[self openGLContext] makeCurrentContext]; 236 | } 237 | 238 | - (void)reshape 239 | { 240 | [super reshape]; 241 | 242 | NSRect bounds = [self bounds]; 243 | //[[self openGLContext] makeCurrentContext]; 244 | [GlobalGLContext makeCurrentContext]; 245 | [GlobalGLContext update]; 246 | glViewport(0, 0, bounds.size.width, bounds.size.height); 247 | 248 | #if 0 249 | printf("HandmadeView reshape: [%.0f, %.0f] [%.0f, %.0f]\n", 250 | bounds.origin.x, bounds.origin.y, 251 | bounds.size.width, bounds.size.height); 252 | 253 | glLoadIdentity(); 254 | glClearColor(1.0, 0.0, 0.0, 1.0); 255 | glClear(GL_COLOR_BUFFER_BIT); 256 | #endif 257 | } 258 | 259 | 260 | @end 261 | 262 | 263 | /////////////////////////////////////////////////////////////////////// 264 | // Startup 265 | 266 | int main(int argc, const char* argv[]) 267 | { 268 | #pragma unused(argc) 269 | #pragma unused(argv) 270 | 271 | //return NSApplicationMain(argc, argv); 272 | @autoreleasepool 273 | { 274 | 275 | /////////////////////////////////////////////////////////////////// 276 | // NSApplication 277 | // 278 | NSApplication* app = [NSApplication sharedApplication]; 279 | [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 280 | 281 | 282 | OSXCreateMainMenu(); 283 | 284 | 285 | /////////////////////////////////////////////////////////////////// 286 | // Set working directory 287 | // 288 | NSString *dir = [[NSFileManager defaultManager] currentDirectoryPath]; 289 | NSLog(@"working directory: %@", dir); 290 | 291 | NSFileManager* FileManager = [NSFileManager defaultManager]; 292 | NSString* AppPath = [NSString stringWithFormat:@"%@/Contents/Resources", 293 | [[NSBundle mainBundle] bundlePath]]; 294 | if ([FileManager changeCurrentDirectoryPath:AppPath] == NO) 295 | { 296 | Assert(0); 297 | } 298 | 299 | 300 | HandmadeAppDelegate* appDelegate = [[HandmadeAppDelegate alloc] init]; 301 | [app setDelegate:appDelegate]; 302 | 303 | [NSApp finishLaunching]; 304 | 305 | 306 | /////////////////////////////////////////////////////////////////// 307 | // Game Setup 308 | // 309 | NSOpenGLPixelFormatAttribute openGLAttributes[] = 310 | { 311 | NSOpenGLPFAAccelerated, 312 | #if HANDMADE_USE_VSYNC 313 | NSOpenGLPFADoubleBuffer, // Uses vsync 314 | #endif 315 | NSOpenGLPFAColorSize, 24, 316 | NSOpenGLPFAAlphaSize, 8, 317 | NSOpenGLPFADepthSize, 24, 318 | NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, 319 | 0 320 | }; 321 | NSOpenGLPixelFormat* PixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:openGLAttributes]; 322 | GlobalGLContext = [[NSOpenGLContext alloc] initWithFormat:PixelFormat shareContext:NULL]; 323 | 324 | DEBUGSetEventRecording(true); 325 | 326 | // game_data holds the OS X platform layer non-Cocoa data structures 327 | osx_game_data GameData = {}; 328 | 329 | 330 | OSXSetupGameData(&GameData, [GlobalGLContext CGLContextObj]); 331 | 332 | /////////////////////////////////////////////////////////////////// 333 | // NSWindow and NSOpenGLView 334 | // 335 | // Create the main window and the content view 336 | NSRect screenRect = [[NSScreen mainScreen] frame]; 337 | //float Width = 3840.0; 338 | //float Height = 2160.0; 339 | //float Width = 2560.0; 340 | //float Height = 1440.0; 341 | float Width = 1920.0; 342 | float Height = 1080.0; 343 | //float Width = 960.0; 344 | //float Height = 540.0; 345 | int BytesPerPixel = 4; 346 | 347 | GlobalAspectRatio = Width / Height; 348 | 349 | NSRect InitialFrame = NSMakeRect((screenRect.size.width - Width) * 0.5, 350 | (screenRect.size.height - Height) * 0.5, 351 | Width, 352 | Height); 353 | 354 | NSWindow* window = [[NSWindow alloc] initWithContentRect:InitialFrame 355 | styleMask:NSTitledWindowMask 356 | | NSClosableWindowMask 357 | | NSMiniaturizableWindowMask 358 | | NSResizableWindowMask 359 | backing:NSBackingStoreBuffered 360 | defer:NO]; 361 | 362 | [window setBackgroundColor: NSColor.blackColor]; 363 | [window setDelegate:appDelegate]; 364 | 365 | NSView* cv = [window contentView]; 366 | [cv setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 367 | [cv setAutoresizesSubviews:YES]; 368 | 369 | #if 1 370 | HandmadeView* GLView = [[HandmadeView alloc] init]; 371 | [GLView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 372 | [GLView setPixelFormat:PixelFormat]; 373 | [GLView setOpenGLContext:GlobalGLContext]; 374 | [GLView setFrame:[cv bounds]]; 375 | 376 | [cv addSubview:GLView]; 377 | #endif 378 | 379 | [PixelFormat release]; 380 | 381 | [window setMinSize:NSMakeSize(160, 90)]; 382 | [window setTitle:@"Handmade Hero"]; 383 | [window makeKeyAndOrderFront:nil]; 384 | 385 | 386 | OSXSetupGameRenderBuffer(&GameData, Width, Height, BytesPerPixel); 387 | 388 | 389 | /////////////////////////////////////////////////////////////////// 390 | // 391 | // OpenGL setup with Cocoa 392 | // 393 | #if HANDMADE_USE_VSYNC 394 | GLint swapInt = 1; 395 | #else 396 | GLint swapInt = 0; 397 | #endif 398 | [GlobalGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 399 | 400 | //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 401 | 402 | [GlobalGLContext setView:[window contentView]]; 403 | 404 | [GlobalGLContext makeCurrentContext]; 405 | 406 | /////////////////////////////////////////////////////////////////// 407 | // Non-Cocoa OpenGL 408 | // 409 | OSXSetupOpenGL(&GameData); 410 | 411 | 412 | #if 0 413 | // Default to full screen mode at startup... 414 | NSDictionary* fullScreenOptions = 415 | [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:NSFullScreenModeSetting]; 416 | 417 | [[window contentView] enterFullScreenMode:[NSScreen mainScreen] withOptions:fullScreenOptions]; 418 | #endif 419 | 420 | 421 | /////////////////////////////////////////////////////////////////// 422 | // Run loop 423 | // 424 | //uint tickCounter = 0; 425 | u64 CurrentTime = mach_absolute_time(); 426 | GameData.LastCounter = CurrentTime; 427 | float frameTime = 0.0f; 428 | 429 | while (OSXIsGameRunning()) 430 | { 431 | OSXProcessPendingMessages(&GameData); 432 | 433 | [GlobalGLContext makeCurrentContext]; 434 | 435 | 436 | /////////////////////////////////////////////////////////////// 437 | // Main Game Function 438 | // 439 | CGRect WindowFrame = [window frame]; 440 | CGRect ContentViewFrame = [[window contentView] frame]; 441 | 442 | #if 0 443 | printf("WindowFrame: [%.0f, %.0f]", WindowFrame.size.width, WindowFrame.size.height); 444 | printf(" ContentFrame: [%.0f, %.0f]\n", ContentViewFrame.size.width, ContentViewFrame.size.height); 445 | #endif 446 | 447 | CGPoint MouseLocationInScreen = [NSEvent mouseLocation]; 448 | BOOL MouseInWindowFlag = NSPointInRect(MouseLocationInScreen, WindowFrame); 449 | CGPoint MouseLocationInView = {}; 450 | 451 | if (MouseInWindowFlag) 452 | { 453 | // NOTE(jeff): Use this instead of convertRectFromScreen: if you want to support Snow Leopard 454 | // NSPoint PointInWindow = [[self window] convertScreenToBase:[NSEvent mouseLocation]]; 455 | 456 | // We don't actually care what the mouse screen coordinates are, we just want the 457 | // coordinates relative to the content view 458 | NSRect RectInWindow = [window convertRectFromScreen:NSMakeRect(MouseLocationInScreen.x, 459 | MouseLocationInScreen.y, 460 | 1, 1)]; 461 | NSPoint PointInWindow = RectInWindow.origin; 462 | MouseLocationInView = [[window contentView] convertPoint:PointInWindow fromView:nil]; 463 | } 464 | 465 | u32 MouseButtonMask = [NSEvent pressedMouseButtons]; 466 | 467 | OSXProcessFrameAndRunGameLogic(&GameData, ContentViewFrame, 468 | MouseInWindowFlag, MouseLocationInView, 469 | MouseButtonMask); 470 | 471 | // flushes and forces vsync 472 | #if HANDMADE_USE_VSYNC 473 | BEGIN_BLOCK("SwapBuffers"); 474 | [GlobalGLContext flushBuffer]; 475 | END_BLOCK(); 476 | #else 477 | glFlush(); 478 | #endif 479 | 480 | u64 EndCounter = mach_absolute_time(); 481 | 482 | f32 MeasuredSecondsPerFrame = OSXGetSecondsElapsed(GameData.LastCounter, EndCounter); 483 | f32 ExactTargetFramesPerUpdate = MeasuredSecondsPerFrame * (f32)GameData.MonitorRefreshHz; 484 | u32 NewExpectedFramesPerUpdate = RoundReal32ToInt32(ExactTargetFramesPerUpdate); 485 | GameData.ExpectedFramesPerUpdate = NewExpectedFramesPerUpdate; 486 | 487 | GameData.TargetSecondsPerFrame = MeasuredSecondsPerFrame; 488 | 489 | FRAME_MARKER(MeasuredSecondsPerFrame); 490 | 491 | frameTime += MeasuredSecondsPerFrame; 492 | GameData.LastCounter = EndCounter; 493 | 494 | #if 0 495 | ++tickCounter; 496 | if (tickCounter == 60) 497 | { 498 | float avgFrameTime = frameTime / 60.0f; 499 | tickCounter = 0; 500 | frameTime = 0.0f; 501 | //printf("frame time = %f\n", avgFrameTime); 502 | } 503 | #endif 504 | } 505 | 506 | 507 | OSXStopCoreAudio(&GameData.SoundOutput); 508 | 509 | 510 | printf("Handmade Hero finished running\n"); 511 | 512 | 513 | } // @autoreleasepool 514 | } 515 | 516 | -------------------------------------------------------------------------------- /code/vsprintf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int _snprintf_s(char* buffer, size_t offset, size_t junk, char* fmt, ...) 3 | { 4 | va_list args; 5 | va_start(args, fmt); 6 | int n = vsprintf(buffer, fmt, args); 7 | va_end(args); 8 | return n; 9 | } 10 | 11 | int _snprintf_s(char* buffer, size_t offset, char* fmt, ...) 12 | { 13 | va_list args; 14 | va_start(args, fmt); 15 | int n = vsprintf(buffer, fmt, args); 16 | va_end(args); 17 | return n; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /dynamic_compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | echo `pwd` 3 | cp ./Contents/code/handmade_config.h . 4 | clang -O3 -Wall -DTRANSLATION_UNIT_INDEX=1 -fno-exceptions -fno-rtti -DHANDMADE_PROFILE=1 -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -DHANDMADE_MIN_OSX -std=c++11 -Wno-null-dereference -Wno-logical-not-parentheses -Wno-switch -Wno-write-strings -Wno-c++11-compat-deprecated-writable-strings -Wno-tautological-compare -Wno-missing-braces -Wno-unused-variable -Wno-unused-function -c handmade_optimized.cpp 5 | clang -O3 -Wall -Wno-c++11-narrowing -DTRANSLATION_UNIT_INDEX=0 -DHANDMADE_PROFILE=1 -DHANDMADE_INTERNAL=1 -DHANDMADE_SLOW=1 -DHANDMADE_OSX=1 -DHANDMADE_MIN_OSX -std=c++11 -Wno-null-dereference -fno-exceptions -fno-rtti -Wno-missing-braces -Wno-logical-not-parentheses -Wno-switch -Wno-write-strings -Wno-c++11-compat-deprecated-writable-strings -Wno-tautological-compare -Wno-missing-braces -Wno-unused-variable -Wno-unused-function -c handmade.cpp 6 | clang -dynamiclib -o libhandmade.dylib handmade.o handmade_optimized.o 7 | cp libhandmade.dylib Handmade.app/Contents/MacOS/libhandmade.dylib 8 | cp libhandmade.dylib ./Contents/MacOS/libhandmade.dylib 9 | 10 | -------------------------------------------------------------------------------- /fix_handmade_hero_source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | patch cpp/code/handmade_opengl.cpp -i handmade_opengl.cpp.day387.patch 4 | 5 | -------------------------------------------------------------------------------- /fonts/AUTHORS: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | 3 | Current Contributors (sorted alphabetically): 4 | - Pravin Satpute 5 | Project Owner (Current) 6 | Red Hat, Inc. 7 | 8 | Previous Contributors 9 | 10 | - Steve Matteson 11 | Original Designer 12 | Ascender, Inc. 13 | -------------------------------------------------------------------------------- /fonts/LICENSE: -------------------------------------------------------------------------------- 1 | Digitized data copyright (c) 2010 Google Corporation 2 | with Reserved Font Arimo, Tinos and Cousine. 3 | Copyright (c) 2012 Red Hat, Inc. 4 | with Reserved Font Name Liberation. 5 | 6 | This Font Software is licensed under the SIL Open Font License, 7 | Version 1.1. 8 | 9 | This license is copied below, and is also available with a FAQ at: 10 | http://scripts.sil.org/OFL 11 | 12 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 13 | 14 | PREAMBLE The goals of the Open Font License (OFL) are to stimulate 15 | worldwide development of collaborative font projects, to support the font 16 | creation efforts of academic and linguistic communities, and to provide 17 | a free and open framework in which fonts may be shared and improved in 18 | partnership with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. 22 | The fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply to 27 | any document created using the fonts or their derivatives. 28 | 29 | 30 | 31 | DEFINITIONS 32 | "Font Software" refers to the set of files released by the Copyright 33 | Holder(s) under this license and clearly marked as such. 34 | This may include source files, build scripts and documentation. 35 | 36 | "Reserved Font Name" refers to any names specified as such after the 37 | copyright statement(s). 38 | 39 | "Original Version" refers to the collection of Font Software components 40 | as distributed by the Copyright Holder(s). 41 | 42 | "Modified Version" refers to any derivative made by adding to, deleting, 43 | or substituting ? in part or in whole ? 44 | any of the components of the Original Version, by changing formats or 45 | by porting the Font Software to a new environment. 46 | 47 | "Author" refers to any designer, engineer, programmer, technical writer 48 | or other person who contributed to the Font Software. 49 | 50 | 51 | PERMISSION & CONDITIONS 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a 54 | copy of the Font Software, to use, study, copy, merge, embed, modify, 55 | redistribute, and sell modified and unmodified copies of the Font 56 | Software, subject to the following conditions: 57 | 58 | 1) Neither the Font Software nor any of its individual components,in 59 | Original or Modified Versions, may be sold by itself. 60 | 61 | 2) Original or Modified Versions of the Font Software may be bundled, 62 | redistributed and/or sold with any software, provided that each copy 63 | contains the above copyright notice and this license. These can be 64 | included either as stand-alone text files, human-readable headers or 65 | in the appropriate machine-readable metadata fields within text or 66 | binary files as long as those fields can be easily viewed by the user. 67 | 68 | 3) No Modified Version of the Font Software may use the Reserved Font 69 | Name(s) unless explicit written permission is granted by the 70 | corresponding Copyright Holder. This restriction only applies to the 71 | primary font name as presented to the users. 72 | 73 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 74 | Software shall not be used to promote, endorse or advertise any 75 | Modified Version, except to acknowledge the contribution(s) of the 76 | Copyright Holder(s) and the Author(s) or with their explicit written 77 | permission. 78 | 79 | 5) The Font Software, modified or unmodified, in part or in whole, must 80 | be distributed entirely under this license, and must not be distributed 81 | under any other license. The requirement for fonts to remain under 82 | this license does not apply to any document created using the Font 83 | Software. 84 | 85 | 86 | 87 | TERMINATION 88 | This license becomes null and void if any of the above conditions are not met. 89 | 90 | 91 | 92 | DISCLAIMER 93 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 94 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 95 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 96 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 97 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 98 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 99 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 100 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER 101 | DEALINGS IN THE FONT SOFTWARE. 102 | 103 | -------------------------------------------------------------------------------- /fonts/LiberationMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itfrombit/osx_handmade_minimal/832609f3d56b4bfc901ccc0ff3e7c220e25ee957/fonts/LiberationMono-Regular.ttf -------------------------------------------------------------------------------- /fonts/LiberationSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itfrombit/osx_handmade_minimal/832609f3d56b4bfc901ccc0ff3e7c220e25ee957/fonts/LiberationSans-Regular.ttf -------------------------------------------------------------------------------- /fonts/LiberationSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itfrombit/osx_handmade_minimal/832609f3d56b4bfc901ccc0ff3e7c220e25ee957/fonts/LiberationSerif-Regular.ttf -------------------------------------------------------------------------------- /handmade_opengl.cpp.day373.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-04-01 11:37:10.000000000 -0700 2 | +++ handmade_opengl.cpp 2017-04-01 11:31:33.000000000 -0700 3 | @@ -105,7 +105,7 @@ 4 | Result.ShadingLanguageVersion = "(none)"; 5 | } 6 | 7 | - Result.Extensions = (char *)glGetString(GL_EXTENSIONS); 8 | + Result.Extensions = ""; //(char *)glGetString(GL_EXTENSIONS); 9 | 10 | for(char *At = Result.Extensions; 11 | *At; 12 | @@ -705,7 +705,7 @@ 13 | 14 | char Defines[1024]; 15 | FormatString(sizeof(Defines), Defines, 16 | - "#version 130\n" 17 | + "#version 150\n" 18 | "#define ShaderSimTexWriteSRGB %d\n" 19 | "#define ShaderSimTexReadSRGB %d\n", 20 | ShaderSimTexWriteSRGB, 21 | -------------------------------------------------------------------------------- /handmade_opengl.cpp.day374.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-04-01 22:11:32.000000000 -0700 2 | +++ handmade_opengl.cpp 2017-04-01 22:13:05.000000000 -0700 3 | @@ -704,7 +704,7 @@ 4 | 5 | char Defines[1024]; 6 | FormatString(sizeof(Defines), Defines, 7 | - "#version 130\n" 8 | + "#version 150\n" 9 | "#define ShaderSimTexWriteSRGB %d\n" 10 | "#define ShaderSimTexReadSRGB %d\n", 11 | ShaderSimTexWriteSRGB, 12 | -------------------------------------------------------------------------------- /handmade_opengl.cpp.day375.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-04-04 10:54:54.000000000 -0700 2 | +++ handmade_opengl.cpp 2017-04-04 10:55:13.000000000 -0700 3 | @@ -689,7 +689,7 @@ 4 | 5 | char Defines[1024]; 6 | FormatString(sizeof(Defines), Defines, 7 | - "#version 130\n" 8 | + "#version 150\n" 9 | "#define ShaderSimTexWriteSRGB %d\n" 10 | "#define ShaderSimTexReadSRGB %d\n", 11 | ShaderSimTexWriteSRGB, 12 | -------------------------------------------------------------------------------- /handmade_opengl.cpp.day380.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-04-29 16:31:43.000000000 -0400 2 | +++ handmade_opengl.cpp 2017-04-29 16:34:46.000000000 -0400 3 | @@ -669,7 +669,7 @@ 4 | { 5 | char Defines[1024]; 6 | FormatString(sizeof(Defines), Defines, 7 | - "#version 130\n" 8 | + "#version 150\n" 9 | "#define ShaderSimTexWriteSRGB %d\n" 10 | "#define ShaderSimTexReadSRGB %d\n" 11 | "#define DepthPeel %d\n", 12 | -------------------------------------------------------------------------------- /handmade_opengl.cpp.day384.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-05-09 12:41:47.000000000 -0400 2 | +++ handmade_opengl.cpp 2017-05-09 12:42:19.000000000 -0400 3 | @@ -608,7 +608,7 @@ 4 | { 5 | char Defines[1024]; 6 | FormatString(sizeof(Defines), Defines, 7 | - "#version 130\n" 8 | + "#version 150\n" 9 | "#define ShaderSimTexWriteSRGB %d\n" 10 | "#define ShaderSimTexReadSRGB %d\n" 11 | "#define DepthPeel %d\n", 12 | @@ -728,7 +728,7 @@ 13 | { 14 | char Defines[1024]; 15 | FormatString(sizeof(Defines), Defines, 16 | - "#version 130\n" 17 | + "#version 150\n" 18 | "#define ShaderSimTexWriteSRGB %d\n" 19 | "#define ShaderSimTexReadSRGB %d\n" 20 | "#define DepthPeel %d\n", 21 | @@ -813,7 +813,7 @@ 22 | { 23 | char Defines[1024]; 24 | FormatString(sizeof(Defines), Defines, 25 | - "#version 130\n" 26 | + "#version 150\n" 27 | "#define ShaderSimTexWriteSRGB %d\n" 28 | "#define ShaderSimTexReadSRGB %d\n", 29 | OpenGL.ShaderSimTexWriteSRGB, 30 | -------------------------------------------------------------------------------- /handmade_opengl.cpp.day387.patch: -------------------------------------------------------------------------------- 1 | --- cpp/code/handmade_opengl.cpp 2017-06-06 10:02:32.000000000 -0400 2 | +++ handmade_opengl.cpp 2017-06-06 10:03:07.000000000 -0400 3 | @@ -611,7 +611,7 @@ 4 | { 5 | char Defines[1024]; 6 | FormatString(sizeof(Defines), Defines, 7 | - "#version 130\n" 8 | + "#version 150\n" 9 | "#define ShaderSimTexWriteSRGB %d\n" 10 | "#define ShaderSimTexReadSRGB %d\n" 11 | "#define DepthPeel %d\n", 12 | @@ -742,7 +742,7 @@ 13 | { 14 | char Defines[1024]; 15 | FormatString(sizeof(Defines), Defines, 16 | - "#version 130\n" 17 | + "#version 150\n" 18 | "#define ShaderSimTexWriteSRGB %d\n" 19 | "#define ShaderSimTexReadSRGB %d\n" 20 | "#define DepthPeel %d\n", 21 | @@ -957,7 +957,7 @@ 22 | { 23 | char Defines[1024]; 24 | FormatString(sizeof(Defines), Defines, 25 | - "#version 130\n" 26 | + "#version 150\n" 27 | "#define ShaderSimTexWriteSRGB %d\n" 28 | "#define ShaderSimTexReadSRGB %d\n", 29 | OpenGL.ShaderSimTexWriteSRGB, 30 | -------------------------------------------------------------------------------- /xcode/Handmade Hero.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | 4F7317F51C6E885D00D29A61 /* osx_handmade.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade.cpp; path = ../code/osx_handmade.cpp; sourceTree = ""; }; 11 | 4F7317F61C6E885D00D29A61 /* osx_handmade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osx_handmade.h; path = ../code/osx_handmade.h; sourceTree = ""; }; 12 | 4F7317F71C6E885D00D29A61 /* osx_main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = osx_main.mm; path = ../code/osx_main.mm; sourceTree = ""; }; 13 | 4F7317F81C6E887B00D29A61 /* osx_handmade_audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_audio.cpp; path = ../code/osx_handmade_audio.cpp; sourceTree = ""; }; 14 | 4F7317F91C6E887B00D29A61 /* osx_handmade_debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_debug.cpp; path = ../code/osx_handmade_debug.cpp; sourceTree = ""; }; 15 | 4F7317FA1C6E887B00D29A61 /* osx_handmade_dylib.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_dylib.cpp; path = ../code/osx_handmade_dylib.cpp; sourceTree = ""; }; 16 | 4F7317FB1C6E887B00D29A61 /* osx_handmade_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_file.cpp; path = ../code/osx_handmade_file.cpp; sourceTree = ""; }; 17 | 4F7317FC1C6E887B00D29A61 /* osx_handmade_game.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_game.cpp; path = ../code/osx_handmade_game.cpp; sourceTree = ""; }; 18 | 4F7317FD1C6E887B00D29A61 /* osx_handmade_hid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_hid.cpp; path = ../code/osx_handmade_hid.cpp; sourceTree = ""; }; 19 | 4F7317FE1C6E887B00D29A61 /* osx_handmade_playback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_playback.cpp; path = ../code/osx_handmade_playback.cpp; sourceTree = ""; }; 20 | 4F7317FF1C6E887B00D29A61 /* osx_handmade_process.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_process.cpp; path = ../code/osx_handmade_process.cpp; sourceTree = ""; }; 21 | 4F7318001C6E887B00D29A61 /* osx_handmade_thread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = osx_handmade_thread.cpp; path = ../code/osx_handmade_thread.cpp; sourceTree = ""; }; 22 | /* End PBXFileReference section */ 23 | 24 | /* Begin PBXGroup section */ 25 | 4F7317E91C6E850200D29A61 = { 26 | isa = PBXGroup; 27 | children = ( 28 | 4F7317F41C6E883000D29A61 /* code */, 29 | ); 30 | sourceTree = ""; 31 | }; 32 | 4F7317F41C6E883000D29A61 /* code */ = { 33 | isa = PBXGroup; 34 | children = ( 35 | 4F7317F81C6E887B00D29A61 /* osx_handmade_audio.cpp */, 36 | 4F7317F91C6E887B00D29A61 /* osx_handmade_debug.cpp */, 37 | 4F7317FA1C6E887B00D29A61 /* osx_handmade_dylib.cpp */, 38 | 4F7317FB1C6E887B00D29A61 /* osx_handmade_file.cpp */, 39 | 4F7317FC1C6E887B00D29A61 /* osx_handmade_game.cpp */, 40 | 4F7317FD1C6E887B00D29A61 /* osx_handmade_hid.cpp */, 41 | 4F7317FE1C6E887B00D29A61 /* osx_handmade_playback.cpp */, 42 | 4F7317FF1C6E887B00D29A61 /* osx_handmade_process.cpp */, 43 | 4F7318001C6E887B00D29A61 /* osx_handmade_thread.cpp */, 44 | 4F7317F51C6E885D00D29A61 /* osx_handmade.cpp */, 45 | 4F7317F61C6E885D00D29A61 /* osx_handmade.h */, 46 | 4F7317F71C6E885D00D29A61 /* osx_main.mm */, 47 | ); 48 | name = code; 49 | sourceTree = ""; 50 | }; 51 | /* End PBXGroup section */ 52 | 53 | /* Begin PBXLegacyTarget section */ 54 | 4F7317EE1C6E850200D29A61 /* Handmade Hero */ = { 55 | isa = PBXLegacyTarget; 56 | buildArgumentsString = "$(ACTION)"; 57 | buildConfigurationList = 4F7317F11C6E850200D29A61 /* Build configuration list for PBXLegacyTarget "Handmade Hero" */; 58 | buildPhases = ( 59 | ); 60 | buildToolPath = /usr/bin/make; 61 | buildWorkingDirectory = ../code; 62 | dependencies = ( 63 | ); 64 | name = "Handmade Hero"; 65 | passBuildSettingsInEnvironment = 1; 66 | productName = "Handmade Hero"; 67 | }; 68 | /* End PBXLegacyTarget section */ 69 | 70 | /* Begin PBXProject section */ 71 | 4F7317EA1C6E850200D29A61 /* Project object */ = { 72 | isa = PBXProject; 73 | attributes = { 74 | KnownAssetTags = ( 75 | New, 76 | ); 77 | LastUpgradeCheck = 0720; 78 | ORGANIZATIONNAME = "Jeff Buck"; 79 | TargetAttributes = { 80 | 4F7317EE1C6E850200D29A61 = { 81 | CreatedOnToolsVersion = 7.2.1; 82 | }; 83 | }; 84 | }; 85 | buildConfigurationList = 4F7317ED1C6E850200D29A61 /* Build configuration list for PBXProject "Handmade Hero" */; 86 | compatibilityVersion = "Xcode 6.3"; 87 | developmentRegion = English; 88 | hasScannedForEncodings = 0; 89 | knownRegions = ( 90 | en, 91 | Base, 92 | ); 93 | mainGroup = 4F7317E91C6E850200D29A61; 94 | productRefGroup = 4F7317E91C6E850200D29A61; 95 | projectDirPath = ""; 96 | projectRoot = ""; 97 | targets = ( 98 | 4F7317EE1C6E850200D29A61 /* Handmade Hero */, 99 | ); 100 | }; 101 | /* End PBXProject section */ 102 | 103 | /* Begin XCBuildConfiguration section */ 104 | 4F7317EF1C6E850200D29A61 /* Debug */ = { 105 | isa = XCBuildConfiguration; 106 | buildSettings = { 107 | ALWAYS_SEARCH_USER_PATHS = NO; 108 | CLANG_CXX_LANGUAGE_STANDARD = "c++11"; 109 | CLANG_CXX_LIBRARY = "libstdc++"; 110 | CLANG_ENABLE_MODULES = NO; 111 | CLANG_ENABLE_OBJC_ARC = NO; 112 | CLANG_WARN_BOOL_CONVERSION = YES; 113 | CLANG_WARN_CONSTANT_CONVERSION = YES; 114 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 115 | CLANG_WARN_EMPTY_BODY = YES; 116 | CLANG_WARN_ENUM_CONVERSION = YES; 117 | CLANG_WARN_INT_CONVERSION = YES; 118 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 119 | CLANG_WARN_UNREACHABLE_CODE = YES; 120 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 121 | COPY_PHASE_STRIP = NO; 122 | DEBUG_INFORMATION_FORMAT = dwarf; 123 | ENABLE_STRICT_OBJC_MSGSEND = YES; 124 | ENABLE_TESTABILITY = YES; 125 | GCC_C_LANGUAGE_STANDARD = gnu99; 126 | GCC_DYNAMIC_NO_PIC = NO; 127 | GCC_NO_COMMON_BLOCKS = YES; 128 | GCC_OPTIMIZATION_LEVEL = 0; 129 | GCC_PREPROCESSOR_DEFINITIONS = ( 130 | "DEBUG=1", 131 | "$(inherited)", 132 | ); 133 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 134 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 135 | GCC_WARN_UNDECLARED_SELECTOR = YES; 136 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 137 | GCC_WARN_UNUSED_FUNCTION = YES; 138 | GCC_WARN_UNUSED_VARIABLE = YES; 139 | MTL_ENABLE_DEBUG_INFO = YES; 140 | ONLY_ACTIVE_ARCH = YES; 141 | }; 142 | name = Debug; 143 | }; 144 | 4F7317F01C6E850200D29A61 /* Release */ = { 145 | isa = XCBuildConfiguration; 146 | buildSettings = { 147 | ALWAYS_SEARCH_USER_PATHS = NO; 148 | CLANG_CXX_LANGUAGE_STANDARD = "c++11"; 149 | CLANG_CXX_LIBRARY = "libstdc++"; 150 | CLANG_ENABLE_MODULES = NO; 151 | CLANG_ENABLE_OBJC_ARC = NO; 152 | CLANG_WARN_BOOL_CONVERSION = YES; 153 | CLANG_WARN_CONSTANT_CONVERSION = YES; 154 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 155 | CLANG_WARN_EMPTY_BODY = YES; 156 | CLANG_WARN_ENUM_CONVERSION = YES; 157 | CLANG_WARN_INT_CONVERSION = YES; 158 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 159 | CLANG_WARN_UNREACHABLE_CODE = YES; 160 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 161 | COPY_PHASE_STRIP = NO; 162 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 163 | ENABLE_NS_ASSERTIONS = NO; 164 | ENABLE_STRICT_OBJC_MSGSEND = YES; 165 | GCC_C_LANGUAGE_STANDARD = gnu99; 166 | GCC_NO_COMMON_BLOCKS = YES; 167 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 168 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 169 | GCC_WARN_UNDECLARED_SELECTOR = YES; 170 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 171 | GCC_WARN_UNUSED_FUNCTION = YES; 172 | GCC_WARN_UNUSED_VARIABLE = YES; 173 | MTL_ENABLE_DEBUG_INFO = NO; 174 | }; 175 | name = Release; 176 | }; 177 | 4F7317F21C6E850200D29A61 /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | DEBUGGING_SYMBOLS = YES; 181 | DEBUG_INFORMATION_FORMAT = dwarf; 182 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 183 | GCC_OPTIMIZATION_LEVEL = 0; 184 | OTHER_CFLAGS = ""; 185 | OTHER_LDFLAGS = ""; 186 | PRODUCT_NAME = "$(TARGET_NAME)"; 187 | }; 188 | name = Debug; 189 | }; 190 | 4F7317F31C6E850200D29A61 /* Release */ = { 191 | isa = XCBuildConfiguration; 192 | buildSettings = { 193 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 194 | OTHER_CFLAGS = ""; 195 | OTHER_LDFLAGS = ""; 196 | PRODUCT_NAME = "$(TARGET_NAME)"; 197 | }; 198 | name = Release; 199 | }; 200 | /* End XCBuildConfiguration section */ 201 | 202 | /* Begin XCConfigurationList section */ 203 | 4F7317ED1C6E850200D29A61 /* Build configuration list for PBXProject "Handmade Hero" */ = { 204 | isa = XCConfigurationList; 205 | buildConfigurations = ( 206 | 4F7317EF1C6E850200D29A61 /* Debug */, 207 | 4F7317F01C6E850200D29A61 /* Release */, 208 | ); 209 | defaultConfigurationIsVisible = 0; 210 | defaultConfigurationName = Release; 211 | }; 212 | 4F7317F11C6E850200D29A61 /* Build configuration list for PBXLegacyTarget "Handmade Hero" */ = { 213 | isa = XCConfigurationList; 214 | buildConfigurations = ( 215 | 4F7317F21C6E850200D29A61 /* Debug */, 216 | 4F7317F31C6E850200D29A61 /* Release */, 217 | ); 218 | defaultConfigurationIsVisible = 0; 219 | defaultConfigurationName = Release; 220 | }; 221 | /* End XCConfigurationList section */ 222 | }; 223 | rootObject = 4F7317EA1C6E850200D29A61 /* Project object */; 224 | } 225 | -------------------------------------------------------------------------------- /xcode/handmade.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4F41BB2B1C6FC46D00116A0E /* handmade_asset_type_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB0B1C6FC46D00116A0E /* handmade_asset_type_id.h */; }; 11 | 4F41BB2D1C6FC46D00116A0E /* handmade_asset.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB0D1C6FC46D00116A0E /* handmade_asset.h */; }; 12 | 4F41BB2F1C6FC46D00116A0E /* handmade_audio.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB0F1C6FC46D00116A0E /* handmade_audio.h */; }; 13 | 4F41BB301C6FC46D00116A0E /* handmade_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB101C6FC46D00116A0E /* handmade_config.h */; }; 14 | 4F41BB321C6FC46D00116A0E /* handmade_cutscene.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB121C6FC46D00116A0E /* handmade_cutscene.h */; }; 15 | 4F41BB331C6FC46D00116A0E /* handmade_debug_interface.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB131C6FC46D00116A0E /* handmade_debug_interface.h */; }; 16 | 4F41BB351C6FC46D00116A0E /* handmade_debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB151C6FC46D00116A0E /* handmade_debug.h */; }; 17 | 4F41BB371C6FC46D00116A0E /* handmade_entity.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB171C6FC46D00116A0E /* handmade_entity.h */; }; 18 | 4F41BB381C6FC46D00116A0E /* handmade_file_formats.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB181C6FC46D00116A0E /* handmade_file_formats.h */; }; 19 | 4F41BB391C6FC46D00116A0E /* handmade_generated.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB191C6FC46D00116A0E /* handmade_generated.h */; }; 20 | 4F41BB3A1C6FC46D00116A0E /* handmade_intrinsics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB1A1C6FC46D00116A0E /* handmade_intrinsics.h */; }; 21 | 4F41BB3B1C6FC46D00116A0E /* handmade_math.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB1B1C6FC46D00116A0E /* handmade_math.h */; }; 22 | 4F41BB3D1C6FC46D00116A0E /* handmade_meta.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB1D1C6FC46D00116A0E /* handmade_meta.h */; }; 23 | 4F41BB3E1C6FC46D00116A0E /* handmade_optimized.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F41BB1E1C6FC46D00116A0E /* handmade_optimized.cpp */; }; 24 | 4F41BB3F1C6FC46D00116A0E /* handmade_platform.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB1F1C6FC46D00116A0E /* handmade_platform.h */; }; 25 | 4F41BB401C6FC46D00116A0E /* handmade_random.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB201C6FC46D00116A0E /* handmade_random.h */; }; 26 | 4F41BB421C6FC46D00116A0E /* handmade_render_group.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB221C6FC46D00116A0E /* handmade_render_group.h */; }; 27 | 4F41BB441C6FC46D00116A0E /* handmade_sim_region.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB241C6FC46D00116A0E /* handmade_sim_region.h */; }; 28 | 4F41BB461C6FC46D00116A0E /* handmade_world_mode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB261C6FC46D00116A0E /* handmade_world_mode.h */; }; 29 | 4F41BB481C6FC46D00116A0E /* handmade_world.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB281C6FC46D00116A0E /* handmade_world.h */; }; 30 | 4F41BB491C6FC46D00116A0E /* handmade.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F41BB291C6FC46D00116A0E /* handmade.cpp */; }; 31 | 4F41BB4A1C6FC46D00116A0E /* handmade.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F41BB2A1C6FC46D00116A0E /* handmade.h */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 4F41BAC11C6FC29900116A0E /* libhandmade.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libhandmade.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 4F41BB0B1C6FC46D00116A0E /* handmade_asset_type_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_asset_type_id.h; path = ../cpp/code/handmade_asset_type_id.h; sourceTree = ""; }; 37 | 4F41BB0C1C6FC46D00116A0E /* handmade_asset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_asset.cpp; path = ../cpp/code/handmade_asset.cpp; sourceTree = ""; }; 38 | 4F41BB0D1C6FC46D00116A0E /* handmade_asset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_asset.h; path = ../cpp/code/handmade_asset.h; sourceTree = ""; }; 39 | 4F41BB0E1C6FC46D00116A0E /* handmade_audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_audio.cpp; path = ../cpp/code/handmade_audio.cpp; sourceTree = ""; }; 40 | 4F41BB0F1C6FC46D00116A0E /* handmade_audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_audio.h; path = ../cpp/code/handmade_audio.h; sourceTree = ""; }; 41 | 4F41BB101C6FC46D00116A0E /* handmade_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_config.h; path = ../cpp/code/handmade_config.h; sourceTree = ""; }; 42 | 4F41BB111C6FC46D00116A0E /* handmade_cutscene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_cutscene.cpp; path = ../cpp/code/handmade_cutscene.cpp; sourceTree = ""; }; 43 | 4F41BB121C6FC46D00116A0E /* handmade_cutscene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_cutscene.h; path = ../cpp/code/handmade_cutscene.h; sourceTree = ""; }; 44 | 4F41BB131C6FC46D00116A0E /* handmade_debug_interface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_debug_interface.h; path = ../cpp/code/handmade_debug_interface.h; sourceTree = ""; }; 45 | 4F41BB141C6FC46D00116A0E /* handmade_debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_debug.cpp; path = ../cpp/code/handmade_debug.cpp; sourceTree = ""; }; 46 | 4F41BB151C6FC46D00116A0E /* handmade_debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_debug.h; path = ../cpp/code/handmade_debug.h; sourceTree = ""; }; 47 | 4F41BB161C6FC46D00116A0E /* handmade_entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_entity.cpp; path = ../cpp/code/handmade_entity.cpp; sourceTree = ""; }; 48 | 4F41BB171C6FC46D00116A0E /* handmade_entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_entity.h; path = ../cpp/code/handmade_entity.h; sourceTree = ""; }; 49 | 4F41BB181C6FC46D00116A0E /* handmade_file_formats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_file_formats.h; path = ../cpp/code/handmade_file_formats.h; sourceTree = ""; }; 50 | 4F41BB191C6FC46D00116A0E /* handmade_generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_generated.h; path = ../cpp/code/handmade_generated.h; sourceTree = ""; }; 51 | 4F41BB1A1C6FC46D00116A0E /* handmade_intrinsics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_intrinsics.h; path = ../cpp/code/handmade_intrinsics.h; sourceTree = ""; }; 52 | 4F41BB1B1C6FC46D00116A0E /* handmade_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_math.h; path = ../cpp/code/handmade_math.h; sourceTree = ""; }; 53 | 4F41BB1C1C6FC46D00116A0E /* handmade_meta.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_meta.cpp; path = ../cpp/code/handmade_meta.cpp; sourceTree = ""; }; 54 | 4F41BB1D1C6FC46D00116A0E /* handmade_meta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_meta.h; path = ../cpp/code/handmade_meta.h; sourceTree = ""; }; 55 | 4F41BB1E1C6FC46D00116A0E /* handmade_optimized.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_optimized.cpp; path = ../cpp/code/handmade_optimized.cpp; sourceTree = ""; }; 56 | 4F41BB1F1C6FC46D00116A0E /* handmade_platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_platform.h; path = ../cpp/code/handmade_platform.h; sourceTree = ""; }; 57 | 4F41BB201C6FC46D00116A0E /* handmade_random.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_random.h; path = ../cpp/code/handmade_random.h; sourceTree = ""; }; 58 | 4F41BB211C6FC46D00116A0E /* handmade_render_group.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_render_group.cpp; path = ../cpp/code/handmade_render_group.cpp; sourceTree = ""; }; 59 | 4F41BB221C6FC46D00116A0E /* handmade_render_group.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_render_group.h; path = ../cpp/code/handmade_render_group.h; sourceTree = ""; }; 60 | 4F41BB231C6FC46D00116A0E /* handmade_sim_region.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_sim_region.cpp; path = ../cpp/code/handmade_sim_region.cpp; sourceTree = ""; }; 61 | 4F41BB241C6FC46D00116A0E /* handmade_sim_region.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_sim_region.h; path = ../cpp/code/handmade_sim_region.h; sourceTree = ""; }; 62 | 4F41BB251C6FC46D00116A0E /* handmade_world_mode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_world_mode.cpp; path = ../cpp/code/handmade_world_mode.cpp; sourceTree = ""; }; 63 | 4F41BB261C6FC46D00116A0E /* handmade_world_mode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_world_mode.h; path = ../cpp/code/handmade_world_mode.h; sourceTree = ""; }; 64 | 4F41BB271C6FC46D00116A0E /* handmade_world.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade_world.cpp; path = ../cpp/code/handmade_world.cpp; sourceTree = ""; }; 65 | 4F41BB281C6FC46D00116A0E /* handmade_world.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade_world.h; path = ../cpp/code/handmade_world.h; sourceTree = ""; }; 66 | 4F41BB291C6FC46D00116A0E /* handmade.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handmade.cpp; path = ../cpp/code/handmade.cpp; sourceTree = ""; }; 67 | 4F41BB2A1C6FC46D00116A0E /* handmade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handmade.h; path = ../cpp/code/handmade.h; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 4F41BABE1C6FC29900116A0E /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | 4F41BAB81C6FC29900116A0E = { 82 | isa = PBXGroup; 83 | children = ( 84 | 4F41BB0A1C6FC32800116A0E /* handmade */, 85 | 4F41BAC21C6FC29900116A0E /* Products */, 86 | ); 87 | sourceTree = ""; 88 | }; 89 | 4F41BAC21C6FC29900116A0E /* Products */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 4F41BAC11C6FC29900116A0E /* libhandmade.dylib */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | 4F41BB0A1C6FC32800116A0E /* handmade */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 4F41BB0B1C6FC46D00116A0E /* handmade_asset_type_id.h */, 101 | 4F41BB0C1C6FC46D00116A0E /* handmade_asset.cpp */, 102 | 4F41BB0D1C6FC46D00116A0E /* handmade_asset.h */, 103 | 4F41BB0E1C6FC46D00116A0E /* handmade_audio.cpp */, 104 | 4F41BB0F1C6FC46D00116A0E /* handmade_audio.h */, 105 | 4F41BB101C6FC46D00116A0E /* handmade_config.h */, 106 | 4F41BB111C6FC46D00116A0E /* handmade_cutscene.cpp */, 107 | 4F41BB121C6FC46D00116A0E /* handmade_cutscene.h */, 108 | 4F41BB131C6FC46D00116A0E /* handmade_debug_interface.h */, 109 | 4F41BB141C6FC46D00116A0E /* handmade_debug.cpp */, 110 | 4F41BB151C6FC46D00116A0E /* handmade_debug.h */, 111 | 4F41BB161C6FC46D00116A0E /* handmade_entity.cpp */, 112 | 4F41BB171C6FC46D00116A0E /* handmade_entity.h */, 113 | 4F41BB181C6FC46D00116A0E /* handmade_file_formats.h */, 114 | 4F41BB191C6FC46D00116A0E /* handmade_generated.h */, 115 | 4F41BB1A1C6FC46D00116A0E /* handmade_intrinsics.h */, 116 | 4F41BB1B1C6FC46D00116A0E /* handmade_math.h */, 117 | 4F41BB1C1C6FC46D00116A0E /* handmade_meta.cpp */, 118 | 4F41BB1D1C6FC46D00116A0E /* handmade_meta.h */, 119 | 4F41BB1E1C6FC46D00116A0E /* handmade_optimized.cpp */, 120 | 4F41BB1F1C6FC46D00116A0E /* handmade_platform.h */, 121 | 4F41BB201C6FC46D00116A0E /* handmade_random.h */, 122 | 4F41BB211C6FC46D00116A0E /* handmade_render_group.cpp */, 123 | 4F41BB221C6FC46D00116A0E /* handmade_render_group.h */, 124 | 4F41BB231C6FC46D00116A0E /* handmade_sim_region.cpp */, 125 | 4F41BB241C6FC46D00116A0E /* handmade_sim_region.h */, 126 | 4F41BB251C6FC46D00116A0E /* handmade_world_mode.cpp */, 127 | 4F41BB261C6FC46D00116A0E /* handmade_world_mode.h */, 128 | 4F41BB271C6FC46D00116A0E /* handmade_world.cpp */, 129 | 4F41BB281C6FC46D00116A0E /* handmade_world.h */, 130 | 4F41BB291C6FC46D00116A0E /* handmade.cpp */, 131 | 4F41BB2A1C6FC46D00116A0E /* handmade.h */, 132 | ); 133 | name = handmade; 134 | sourceTree = ""; 135 | }; 136 | /* End PBXGroup section */ 137 | 138 | /* Begin PBXHeadersBuildPhase section */ 139 | 4F41BABF1C6FC29900116A0E /* Headers */ = { 140 | isa = PBXHeadersBuildPhase; 141 | buildActionMask = 2147483647; 142 | files = ( 143 | 4F41BB3B1C6FC46D00116A0E /* handmade_math.h in Headers */, 144 | 4F41BB391C6FC46D00116A0E /* handmade_generated.h in Headers */, 145 | 4F41BB4A1C6FC46D00116A0E /* handmade.h in Headers */, 146 | 4F41BB2B1C6FC46D00116A0E /* handmade_asset_type_id.h in Headers */, 147 | 4F41BB3F1C6FC46D00116A0E /* handmade_platform.h in Headers */, 148 | 4F41BB381C6FC46D00116A0E /* handmade_file_formats.h in Headers */, 149 | 4F41BB2D1C6FC46D00116A0E /* handmade_asset.h in Headers */, 150 | 4F41BB3A1C6FC46D00116A0E /* handmade_intrinsics.h in Headers */, 151 | 4F41BB401C6FC46D00116A0E /* handmade_random.h in Headers */, 152 | 4F41BB441C6FC46D00116A0E /* handmade_sim_region.h in Headers */, 153 | 4F41BB3D1C6FC46D00116A0E /* handmade_meta.h in Headers */, 154 | 4F41BB351C6FC46D00116A0E /* handmade_debug.h in Headers */, 155 | 4F41BB421C6FC46D00116A0E /* handmade_render_group.h in Headers */, 156 | 4F41BB331C6FC46D00116A0E /* handmade_debug_interface.h in Headers */, 157 | 4F41BB481C6FC46D00116A0E /* handmade_world.h in Headers */, 158 | 4F41BB301C6FC46D00116A0E /* handmade_config.h in Headers */, 159 | 4F41BB371C6FC46D00116A0E /* handmade_entity.h in Headers */, 160 | 4F41BB2F1C6FC46D00116A0E /* handmade_audio.h in Headers */, 161 | 4F41BB461C6FC46D00116A0E /* handmade_world_mode.h in Headers */, 162 | 4F41BB321C6FC46D00116A0E /* handmade_cutscene.h in Headers */, 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXHeadersBuildPhase section */ 167 | 168 | /* Begin PBXNativeTarget section */ 169 | 4F41BAC01C6FC29900116A0E /* handmade */ = { 170 | isa = PBXNativeTarget; 171 | buildConfigurationList = 4F41BAC51C6FC29900116A0E /* Build configuration list for PBXNativeTarget "handmade" */; 172 | buildPhases = ( 173 | 4F41BABD1C6FC29900116A0E /* Sources */, 174 | 4F41BABE1C6FC29900116A0E /* Frameworks */, 175 | 4F41BABF1C6FC29900116A0E /* Headers */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | ); 181 | name = handmade; 182 | productName = handmade; 183 | productReference = 4F41BAC11C6FC29900116A0E /* libhandmade.dylib */; 184 | productType = "com.apple.product-type.library.dynamic"; 185 | }; 186 | /* End PBXNativeTarget section */ 187 | 188 | /* Begin PBXProject section */ 189 | 4F41BAB91C6FC29900116A0E /* Project object */ = { 190 | isa = PBXProject; 191 | attributes = { 192 | LastUpgradeCheck = 0720; 193 | ORGANIZATIONNAME = "Jeff Buck"; 194 | TargetAttributes = { 195 | 4F41BAC01C6FC29900116A0E = { 196 | CreatedOnToolsVersion = 7.2.1; 197 | }; 198 | }; 199 | }; 200 | buildConfigurationList = 4F41BABC1C6FC29900116A0E /* Build configuration list for PBXProject "handmade" */; 201 | compatibilityVersion = "Xcode 6.3"; 202 | developmentRegion = English; 203 | hasScannedForEncodings = 0; 204 | knownRegions = ( 205 | en, 206 | ); 207 | mainGroup = 4F41BAB81C6FC29900116A0E; 208 | productRefGroup = 4F41BAC21C6FC29900116A0E /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | 4F41BAC01C6FC29900116A0E /* handmade */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXSourcesBuildPhase section */ 218 | 4F41BABD1C6FC29900116A0E /* Sources */ = { 219 | isa = PBXSourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 4F41BB491C6FC46D00116A0E /* handmade.cpp in Sources */, 223 | 4F41BB3E1C6FC46D00116A0E /* handmade_optimized.cpp in Sources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXSourcesBuildPhase section */ 228 | 229 | /* Begin XCBuildConfiguration section */ 230 | 4F41BAC31C6FC29900116A0E /* Debug */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ALWAYS_SEARCH_USER_PATHS = NO; 234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 235 | CLANG_CXX_LIBRARY = "libc++"; 236 | CLANG_ENABLE_MODULES = YES; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_WARN_BOOL_CONVERSION = YES; 239 | CLANG_WARN_CONSTANT_CONVERSION = YES; 240 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 241 | CLANG_WARN_EMPTY_BODY = YES; 242 | CLANG_WARN_ENUM_CONVERSION = YES; 243 | CLANG_WARN_INT_CONVERSION = YES; 244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 245 | CLANG_WARN_UNREACHABLE_CODE = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | CODE_SIGN_IDENTITY = "-"; 248 | COPY_PHASE_STRIP = NO; 249 | DEBUG_INFORMATION_FORMAT = dwarf; 250 | ENABLE_STRICT_OBJC_MSGSEND = YES; 251 | ENABLE_TESTABILITY = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu99; 253 | GCC_DYNAMIC_NO_PIC = NO; 254 | GCC_NO_COMMON_BLOCKS = YES; 255 | GCC_OPTIMIZATION_LEVEL = 0; 256 | GCC_PREPROCESSOR_DEFINITIONS = ( 257 | "DEBUG=1", 258 | "$(inherited)", 259 | ); 260 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 261 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 262 | GCC_WARN_UNDECLARED_SELECTOR = YES; 263 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 264 | GCC_WARN_UNUSED_FUNCTION = YES; 265 | GCC_WARN_UNUSED_VARIABLE = YES; 266 | MACOSX_DEPLOYMENT_TARGET = 10.11; 267 | MTL_ENABLE_DEBUG_INFO = YES; 268 | ONLY_ACTIVE_ARCH = YES; 269 | SDKROOT = macosx; 270 | }; 271 | name = Debug; 272 | }; 273 | 4F41BAC41C6FC29900116A0E /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_MODULES = YES; 280 | CLANG_ENABLE_OBJC_ARC = YES; 281 | CLANG_WARN_BOOL_CONVERSION = YES; 282 | CLANG_WARN_CONSTANT_CONVERSION = YES; 283 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 284 | CLANG_WARN_EMPTY_BODY = YES; 285 | CLANG_WARN_ENUM_CONVERSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | CODE_SIGN_IDENTITY = "-"; 291 | COPY_PHASE_STRIP = NO; 292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 293 | ENABLE_NS_ASSERTIONS = NO; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu99; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | MACOSX_DEPLOYMENT_TARGET = 10.11; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | SDKROOT = macosx; 306 | }; 307 | name = Release; 308 | }; 309 | 4F41BAC61C6FC29900116A0E /* Debug */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | DYLIB_COMPATIBILITY_VERSION = 1; 313 | DYLIB_CURRENT_VERSION = 1; 314 | EXECUTABLE_PREFIX = lib; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SYMROOT = ../build; 317 | VALID_ARCHS = x86_64; 318 | }; 319 | name = Debug; 320 | }; 321 | 4F41BAC71C6FC29900116A0E /* Release */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | DYLIB_COMPATIBILITY_VERSION = 1; 325 | DYLIB_CURRENT_VERSION = 1; 326 | EXECUTABLE_PREFIX = lib; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | SYMROOT = ../build; 329 | VALID_ARCHS = x86_64; 330 | }; 331 | name = Release; 332 | }; 333 | /* End XCBuildConfiguration section */ 334 | 335 | /* Begin XCConfigurationList section */ 336 | 4F41BABC1C6FC29900116A0E /* Build configuration list for PBXProject "handmade" */ = { 337 | isa = XCConfigurationList; 338 | buildConfigurations = ( 339 | 4F41BAC31C6FC29900116A0E /* Debug */, 340 | 4F41BAC41C6FC29900116A0E /* Release */, 341 | ); 342 | defaultConfigurationIsVisible = 0; 343 | defaultConfigurationName = Release; 344 | }; 345 | 4F41BAC51C6FC29900116A0E /* Build configuration list for PBXNativeTarget "handmade" */ = { 346 | isa = XCConfigurationList; 347 | buildConfigurations = ( 348 | 4F41BAC61C6FC29900116A0E /* Debug */, 349 | 4F41BAC71C6FC29900116A0E /* Release */, 350 | ); 351 | defaultConfigurationIsVisible = 0; 352 | defaultConfigurationName = Release; 353 | }; 354 | /* End XCConfigurationList section */ 355 | }; 356 | rootObject = 4F41BAB91C6FC29900116A0E /* Project object */; 357 | } 358 | --------------------------------------------------------------------------------