initial upload

master
Ryan Fleury 8 hours ago
commit c815dc1360

12
.gitignore vendored

@ -0,0 +1,12 @@
build/*
local/*
*.exe
*.pdb
*.exp
*.lib
*.obj
*.dll
*.ilk
*.d
*.swp
*.rdbg

@ -0,0 +1,108 @@
@echo off
setlocal
setlocal EnableDelayedExpansion
cd /D "%~dp0"
:: --- Unpack Arguments -------------------------------------------------------
for %%a in (%*) do set "%%a=1"
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
if not "%release%"=="1" set debug=1
if "%debug%"=="1" set release=0 && echo [debug]
if "%release%"=="1" set debug=0 && echo [release]
if "%msvc%"=="1" set clang=0 && echo [msvc]
if "%clang%"=="1" set msvc=0 && echo [clang]
if "%deploy%"=="1" echo [deploy]
:: --- Unpack Command Line Build Mix-ins --------------------------------------
set auto_compile_flags=
set auto_link_flags=
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DBUILD_TELEMETRY=1 && echo [telemetry]
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan]
:: --- Mix Git Commit ID ------------------------------------------------------
git rev-parse --is-inside-work-tree >nul 2>&1 && set in_git_tree=1
if "%in_git_tree%"=="1" (
for /f %%i in ('call git describe --always --dirty') do set auto_compile_flags=%auto_compile_flags% -DBUILD_GIT_HASH=\"%%i\"
for /f %%i in ('call git rev-parse HEAD') do set auto_compile_flags=%auto_compile_flags% -DBUILD_GIT_HASH_FULL=\"%%i\"
)
:: --- [MSVC] Compile/Link Line Definitions -----------------------------------
set cl_common= /I..\code\ /I..\local\ /nologo /FC /Z7
set cl_debug= call cl /Od /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_release= call cl /O2 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% %auto_link_flags%
set cl_out= /out:
:: --- [Clang] Compile/Link Line Definitions ----------------------------------
set clang_common= -g -I..\code\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -ferror-limit=10000
set clang_common_n64= --target=mips-unknown-elf -mcpu=mips3 -mabi=32 -EB -mno-abicalls -fno-pic -ffreestanding -nostdlib -fno-builtin -G 0 -fno-unroll-loops -DN64=1
set clang_debug= call clang -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags%
set clang_release= call clang -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags%
set clang_debug_n64= call clang -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% %clang_common_n64% -c
set clang_release_n64= call clang -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% %clang_common_n64% -c
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% %auto_link_flags%
set clang_out= -o
:: --- [LLD] Link Line Definitions
set lld_link_common=
set lld_link_common_n64= -T "../code/n64/n64.ld"
set lld_link= call ld.lld %lld_link_common% %auto_link_flags%
set lld_link_n64= call ld.lld %lld_link_common% %lld_link_common_n64% %auto_link_flags%
:: --- Choose Compile/Link Lines ----------------------------------------------
if "%msvc%"=="1" set compile_debug=%cl_debug%
if "%msvc%"=="1" set compile_release=%cl_release%
if "%msvc%"=="1" set compile_link=%cl_link%
if "%msvc%"=="1" set out=%cl_out%
if "%clang%"=="1" set compile_debug=%clang_debug%
if "%clang%"=="1" set compile_release=%clang_release%
if "%clang%"=="1" set compile_link=%clang_link%
if "%clang%"=="1" set out=%clang_out%
if "%debug%"=="1" set compile=%compile_debug%
if "%release%"=="1" set compile=%compile_release%
if "%debug%"=="1" set compile_n64=%clang_debug_n64%
if "%release%"=="1" set compile_n64=%clang_release_n64%
set link_n64= %lld_link_n64%
set out_n64= %clang_out%
set romify_n64= n64tool -t "^!n64_rom_name^!" -o "^!n64_rom_name^!.z64" --align 256 "^!n64_rom_name^!.elf"
:: --- Per-Build Settings -----------------------------------------------------
set link_dll=-DLL
if "%msvc%"=="1" set only_compile=-c
if "%clang%"=="1" set only_compile=/c
if "%msvc%"=="1" set EHsc=/EHsc
if "%clang%"=="1" set EHsc=
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
if "%msvc%"=="1" set rc=call rc
if "%clang%"=="1" set rc=call llvm-rc
:: --- Prep Directories -------------------------------------------------------
if not exist build mkdir build
if not exist local mkdir local
:: --- Build n64tool ----------------------------------------------------------
pushd build
if "%n64tool%"=="1" if exist n64tool.exe del n64tool.exe
if not exist n64tool.exe (
%clang_debug% ..\code\third_party\n64tool\n64tool.c %clang_link% %clang_out% n64tool.exe
)
popd
:: --- Build Targets ----------------------------------------------------------
pushd build
if "%n64_test%"=="1" (
set didbuild=1
set "n64_rom_name=n64_test"
%compile_n64% ..\code\n64_test\n64_test.c
%link_n64% n64_test.o %out_n64% !n64_rom_name!.elf
%romify_n64%
)
popd
:: --- Deploy To N64 ----------------------------------------------------------
if "%deploy%"=="1" if not "%n64_rom_name%"=="" (
pushd build
..\tools\sc64deployer upload %n64_rom_name%.z64
popd
)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,676 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef BASE_H
#define BASE_H
////////////////////////////////
//~ rjf: Context Cracking
//- rjf: MSVC Extraction
#if defined(_MSC_VER)
# define COMPILER_MSVC 1
# if defined(_WIN32)
# define PLATFORM_WINDOWS 1
# else
# error _MSC_VER is defined, but _WIN32 is not. This setup is not supported.
# endif
# if defined(_M_AMD64)
# define ARCH_X64 1
# elif defined(_M_IX86)
# define ARCH_X86 1
# elif defined(_M_ARM64)
# define ARCH_ARM64 1
# elif defined(_M_ARM)
# define ARCH_ARM32 1
# else
# error Target architecture is not supported. _MSC_VER is defined, but one of {_M_AMD64, _M_IX86, _M_ARM64, _M_ARM} is not.
# endif
#if _MSC_VER >= 1920
# define COMPILER_MSVC_YEAR 2019
#elif _MSC_VER >= 1910
# define COMPILER_MSVC_YEAR 2017
#elif _MSC_VER >= 1900
# define COMPILER_MSVC_YEAR 2015
#elif _MSC_VER >= 1800
# define COMPILER_MSVC_YEAR 2013
#elif _MSC_VER >= 1700
# define COMPILER_MSVC_YEAR 2012
#elif _MSC_VER >= 1600
# define COMPILER_MSVC_YEAR 2010
#elif _MSC_VER >= 1500
# define COMPILER_MSVC_YEAR 2008
#elif _MSC_VER >= 1400
# define COMPILER_MSVC_YEAR 2005
#else
# define COMPILER_MSVC_YEAR 0
#endif
//- rjf: Clang Extraction
#elif defined(__clang__)
# define COMPILER_CLANG 1
# if defined(__APPLE__) && defined(__MACH__)
# define PLATFORM_MAC 1
# elif defined(__gnu_linux__)
# define PLATFORM_LINUX 1
# elif defined(N64)
# define PLATFORM_N64 1
# else
# error __clang__ is defined, but one of {__APPLE__, __gnu_linux__, N64} is not. This setup is not supported.
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
# define ARCH_X64 1
# elif defined(i386) || defined(__i386) || defined(__i386__)
# define ARCH_X86 1
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# elif defined(__arm__)
# define ARCH_ARM32 1
# elif defined(__mips) && defined(__mips64)
# define ARCH_MIPS64 1
# elif defined(__mips) && !defined(__mips64)
# define ARCH_MIPS32 1
# else
# error Target architecture is not supported. __clang__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__, __mips} is not.
# endif
//- rjf: GCC Extraction
#elif defined(__GNUC__) || defined(__GNUG__)
# define COMPILER_GCC 1
# if defined(__gnu_linux__)
# define PLATFORM_LINUX 1
# else
# error __GNUC__ or __GNUG__ is defined, but __gnu_linux__ is not. This setup is not supported.
# endif
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
# define ARCH_X64 1
# elif defined(i386) || defined(__i386) || defined(__i386__)
# define ARCH_X86 1
# elif defined(__aarch64__)
# define ARCH_ARM64 1
# elif defined(__arm__)
# define ARCH_ARM32 1
# else
# error Target architecture is not supported. __GNU_C__ or __GNUG__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__} is not.
# endif
#else
# error Compiler is not supported. _MSC_VER, __clang__, __GNUC__, or __GNUG__ must be defined.
#endif
#if ARCH_X64 || ARCH_ARM64 || ARCH_MIPS64
# define ARCH_64BIT 1
#elif ARCH_X86 || ARCH_ARM32 || ARCH_MIPS32
# define ARCH_32BIT 1
#endif
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define LITTLE_ENDIAN 0
# define BIG_ENDIAN 1
#else
# define LITTLE_ENDIAN 1
# define BIG_ENDIAN 0
#endif
////////////////////////////////
//~ rjf: Variadic Arguments
#define VariadicS64(args) va_arg(args, S64)
#define VariadicU64(args) va_arg(args, U64)
#if ARCH_X64 || ARCH_ARM64
# define VariadicS32(args) va_arg(args, S32)
# define VariadicU32(args) va_arg(args, U32)
# define VariadicInt(args) va_arg(args, int)
# define VariadicAddr(args) va_arg(args, UAddr)
#elif ARCH_MIPS32 || ARCH_MIPS64
# define VariadicS32(args) (S32)(va_arg(args, U64) & 0xffffffff)
# define VariadicU32(args) (U64)(va_arg(args, U64) & 0xffffffff)
# define VariadicInt(args) (int)(va_arg(args, U64) & 0xffffffff)
# define VariadicAddr(args) (UAddr)(va_arg(args, U64) & 0xffffffff)
#endif
////////////////////////////////
//~ rjf: Keywords
#define function static
#define global static
#define local_persist static
#define align(n) __attribute__((aligned(n)))
////////////////////////////////
//~ rjf: Preprocessor Operations
#define Glue_(A, B) A##B
#define Glue(A, B) Glue_(A, B)
#define Stringify_(S) #S
#define Stringify(S) Stringify_(S)
////////////////////////////////
//~ rjf: Static Assertions
#define StaticAssert(C, ID) global U8 Glue(ID, __LINE__)[(C)?1:-1]
////////////////////////////////////////////////////////////////
//~ rjf: Clamps, Mins, Maxes
#define Min(a, b) (((a)<(b)) ? (a) : (b))
#define Max(a, b) (((a)>(b)) ? (a) : (b))
#define ClampTop(x, a) Min(x,a)
#define ClampBot(a, x) Max(a,x)
#define Clamp(a, x, b) (((a)>(x))?(a):((b)<(x))?(b):(x))
////////////////////////////////////////////////////////////////
//~ rjf: Swaps
#define Swap(T, a, b) do{T c = (a); (a) = (b); (b) = c;}while(0)
////////////////////////////////////////////////////////////////
//~ rjf: Array Counts
#define ArrayCount(a) ((sizeof(a)) / sizeof((a)[0]))
#define ArrayAndCount(a) (a), ArrayCount(a)
#define CountAndArray(a) ArrayCount(a), (a)
////////////////////////////////////////////////////////////////
//~ rjf: Loop Helpers
#define EachIndex(idx, count) (UAddr idx = 0; idx < (count); idx += 1)
#define EachElement(idx, array) (UAddr idx = 0; idx < ArrayCount(array); idx += 1)
#define DeferLoop(start, end) for(int _i_ = ((start), 0); _i_ == 0; (_i_ += 1, (end)))
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
////////////////////////////////////////////////////////////////
//~ rjf: Bit Arrays
#define BitArrayDecl(type, name, count) type name[(count + sizeof(type)*8-1) / sizeof(type)*8]
#define BitArrayAdd(arr, bit) ((arr)[(bit) / (sizeof((arr)[0])*8)] |= (((U64)1) << ((bit) % (sizeof((arr)[0])*8))))
#define BitArrayRemove(arr, bit) ((arr)[(bit) / (sizeof((arr)[0])*8)] &= ~(((U64)1) << ((bit) % (sizeof((arr)[0])*8))))
#define BitArrayGet(arr, bit) (!!((arr)[(bit) / (sizeof((arr)[0])*8)] & (((U64)1) << ((bit) % (sizeof((arr)[0])*8)))))
////////////////////////////////
//~ rjf: Masks
#define Lower16(x) (((x)&0x0000ffff) >> 0)
#define Upper16(x) (((x)&0xffff0000) >> 16)
#define Lower32(x) (((x)&0x00000000ffffffffull) >> 0)
#define Upper32(x) (((x)&0xffffffff00000000ull) >> 32)
////////////////////////////////
//~ rjf: Units
#define KiB(x) ((x)*1024)
#define MiB(x) (KiB(x)*1024)
#define GiB(x) (MiB(x)*1024)
#define TiB(x) (GiB(x)*1024)
////////////////////////////////////////////////////////////////
//~ rjf: Structure Packing Marker Macros
#define pack_begin _Pragma("pack(push, 1)")
#define pack_end _Pragma("pack(pop)")
////////////////////////////////////////////////////////////////
//~ rjf: Type -> Alignment
#if COMPILER_MSVC
# define AlignOf(T) __alignof(T)
#elif COMPILER_CLANG
# define AlignOf(T) __alignof(T)
#elif COMPILER_GCC
# define AlignOf(T) __alignof__(T)
#else
# error AlignOf not defined for this compiler.
#endif
////////////////////////////////
//~ rjf: Basic Types
#include <stdint.h>
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef S8 B8;
typedef S16 B16;
typedef S32 B32;
typedef S64 B64;
typedef float F32;
typedef double F64;
typedef void VoidFunction(void);
#if ARCH_32BIT
typedef S32 SAddr;
typedef U32 UAddr;
#elif ARCH_64BIT
typedef S64 SAddr;
typedef U64 UAddr;
#endif
////////////////////////////////
//~ rjf: C Runtime Implementations
void *memset(void *buffer, int c, UAddr n);
void *memcpy(void *dest, void *src, UAddr n);
////////////////////////////////
//~ rjf: Memory Operations
#define MemoryZero(ptr, size) memset((ptr), 0, (size))
#define MemoryZeroStruct(ptr) MemoryZero((ptr), sizeof(*(ptr)))
#define MemoryCopy(dst, src, size) memcpy((dst), (src), (size))
#define MemoryCopyStruct(dst, src) memcpy((dst), (src), Min(sizeof(*(dst)), sizeof(*(src))))
function inline void
WriteAndInc(void *buffer, void *src, UAddr size, UAddr *cursor)
{
MemoryCopy((U8 *)buffer + *cursor, src, size);
*cursor += size;
}
function inline void
ReadAndInc(void *buffer, void *dst, UAddr size, UAddr *cursor)
{
MemoryCopy(dst, (U8 *)buffer + *cursor, size);
*cursor += size;
}
#define WriteStructAndInc(buffer, ptr, cursor_ptr) WriteAndInc((buffer), (ptr), sizeof(*(ptr)), (cursor_ptr))
#define ReadStructAndInc(buffer, ptr, cursor_ptr) ReadAndInc((buffer), (ptr), sizeof(*(ptr)), (cursor_ptr))
////////////////////////////////
//~ rjf: Float Operations
function inline F32
TruncF32(F32 f)
{
#if ARCH_MIPS32
F32 result_int;
F32 result;
__asm("trunc.w.s %0,%1" : "=f"(result_int) : "f"(f));
__asm("cvt.s.w %0,%1" : "=f"(result) : "f"(result_int));
return result;
#else
# error TruncF32 not implemented for this architecture.
#endif
}
function inline F32
FloorF32(F32 f)
{
#if ARCH_MIPS32
F32 result_int;
F32 result;
__asm("floor.w.s %0,%1" : "=f"(result_int) : "f"(f));
__asm("cvt.s.w %0,%1" : "=f"(result) : "f"(result_int));
return result;
#else
# error FloorF32 not implemented for this architecture.
#endif
}
function inline F32
ModF32(F32 f, F32 d)
{
F32 result = f - TruncF32(f/d)*d;
return result;
}
function inline S32
Fixed112FromF32(F32 f)
{
S32 result = (S32)(f*4.f);
result = Clamp(-4096*4, result, +4095*4);
return result;
}
function inline S32
Fixed1616FromF32(F32 f)
{
S32 result;
if(f >= 32768.f)
{
result = 0x7fffffff;
}
else if(f < -32768.f)
{
result = 0x80000000;
}
else
{
result = (S32)FloorF32(f*65536.f);
}
return result;
}
////////////////////////////////
//~ rjf: Scalar Math Functions
function F32 inline
SquareRootF32(F32 v)
{
#if ARCH_MIPS32
F32 result;
__asm("sqrt.s %0,%1" : "=f"(result) : "f"(v));
return result;
#else
# error SquareRootF32 not implemented for this architecture.
#endif
}
function F32 SinF32(F32 turns);
function F32 inline
CosF32(F32 turns)
{
F32 result = SinF32(turns + 0.25f);
return result;
}
function F32 inline
TanF32(F32 turns)
{
F32 result = SinF32(turns) / CosF32(turns);
return result;
}
////////////////////////////////
//~ rjf: Vector / Matrix Types
typedef union Vec2U32 Vec2U32;
union Vec2U32
{
struct
{
U32 x;
U32 y;
};
U32 v[2];
};
typedef union Vec2F32 Vec2F32;
union Vec2F32
{
struct
{
F32 x;
F32 y;
};
F32 v[2];
};
typedef union Vec3F32 Vec3F32;
union Vec3F32
{
struct
{
F32 x;
F32 y;
F32 z;
};
struct
{
Vec2F32 xy;
F32 z_;
};
struct
{
F32 x_;
Vec2F32 yz;
};
F32 v[3];
};
typedef union Vec4F32 Vec4F32;
union Vec4F32
{
struct
{
F32 x;
F32 y;
F32 z;
F32 w;
};
struct
{
Vec2F32 xy;
Vec2F32 zw;
};
struct
{
Vec3F32 xyz;
F32 w_;
};
struct
{
F32 x_;
Vec3F32 yzw;
};
F32 v[4];
};
typedef struct Mat3x3F32 Mat3x3F32;
struct Mat3x3F32
{
F32 v[3][3];
};
typedef struct Mat4x4F32 Mat4x4F32;
struct Mat4x4F32
{
F32 v[4][4];
};
////////////////////////////////
//~ rjf: Vector Functions
//- rjf: constructors
function Vec2U32 V2U32(U32 x, U32 y);
function Vec2F32 V2F32(F32 x, F32 y);
function Vec3F32 V3F32(F32 x, F32 y, F32 z);
function Vec4F32 V4F32(F32 x, F32 y, F32 z, F32 w);
//- rjf: 2-vector ops
function Vec2F32 Add2F32(Vec2F32 l, Vec2F32 r);
function Vec2F32 Sub2F32(Vec2F32 l, Vec2F32 r);
function Vec2F32 Mul2F32(Vec2F32 l, Vec2F32 r);
function Vec2F32 Div2F32(Vec2F32 l, Vec2F32 r);
function F32 LengthSquared2F32(Vec2F32 v);
function F32 Length2F32(Vec2F32 v);
function Vec2F32 Scale2F32(Vec2F32 v, F32 s);
function Vec2F32 Normalize2F32(Vec2F32 v);
function F32 Dot2F32(Vec2F32 l, Vec2F32 r);
//- rjf: 3-vector ops
function Vec3F32 Add3F32(Vec3F32 l, Vec3F32 r);
function Vec3F32 Sub3F32(Vec3F32 l, Vec3F32 r);
function Vec3F32 Mul3F32(Vec3F32 l, Vec3F32 r);
function Vec3F32 Div3F32(Vec3F32 l, Vec3F32 r);
function F32 LengthSquared3F32(Vec3F32 v);
function F32 Length3F32(Vec3F32 v);
function Vec3F32 Scale3F32(Vec3F32 v, F32 s);
function Vec3F32 Normalize3F32(Vec3F32 v);
function F32 Dot3F32(Vec3F32 l, Vec3F32 r);
function Vec3F32 Cross3F32(Vec3F32 l, Vec3F32 r);
//- rjf: 4-vector ops
function Vec4F32 Add4F32(Vec4F32 l, Vec4F32 r);
function Vec4F32 Sub4F32(Vec4F32 l, Vec4F32 r);
function Vec4F32 Mul4F32(Vec4F32 l, Vec4F32 r);
function Vec4F32 Div4F32(Vec4F32 l, Vec4F32 r);
function F32 LengthSquared4F32(Vec4F32 v);
function F32 Length4F32(Vec4F32 v);
function Vec4F32 Scale4F32(Vec4F32 v, F32 s);
function Vec4F32 Normalize4F32(Vec4F32 v);
function F32 Dot4F32(Vec4F32 l, Vec4F32 r);
function Vec4F32 XForm4F32(Mat4x4F32 m, Vec4F32 v);
////////////////////////////////
//~ rjf: Matrix Functions
//- rjf: constructors
function Mat3x3F32 MakeMat3x3F32(F32 d);
function Mat3x3F32 MakeTranslate3x3F32(Vec2F32 translation);
function Mat3x3F32 MakeScale3x3F32(Vec2F32 scale);
function Mat3x3F32 MakeRotate3x3F32(F32 turns);
function Mat4x4F32 MakeMat4x4F32(F32 d);
function Mat4x4F32 MakeTranslate4x4F32(Vec3F32 translation);
function Mat4x4F32 MakeScale4x4F32(Vec3F32 scale);
function Mat4x4F32 MakePerspective4x4F32(F32 fov, F32 aspect_ratio, F32 near_z, F32 far_z);
function Mat4x4F32 MakeOrthographic4x4F32(F32 left, F32 right, F32 bottom, F32 top, F32 near_z, F32 far_z);
function Mat4x4F32 MakeLookAt4x4F32(Vec3F32 eye, Vec3F32 center, Vec3F32 up);
function Mat4x4F32 MakeRotate4x4F32(Vec3F32 axis, F32 turns);
//- rjf: ops
function Mat3x3F32 Mul3x3F32(Mat3x3F32 a, Mat3x3F32 b);
function Mat3x3F32 Scale3x3F32(Mat3x3F32 m, F32 scale);
function Mat4x4F32 Mul4x4F32(Mat4x4F32 a, Mat4x4F32 b);
function Mat4x4F32 Scale4x4F32(Mat4x4F32 m, F32 scale);
function Mat4x4F32 Inverse4x4F32(Mat4x4F32 m);
function Mat4x4F32 RemoveRotation4x4F32(Mat4x4F32 mat);
////////////////////////////////
//~ rjf: Arenas
typedef struct Arena Arena;
struct Arena
{
UAddr pos;
UAddr cap;
};
function Arena *ArenaMakeStatic(U8 *buffer, UAddr buffer_size);
function void *ArenaPush(Arena *arena, UAddr size, UAddr align);
function UAddr ArenaPos(Arena *arena);
function void ArenaPopTo(Arena *arena, UAddr pos);
function void ArenaClear(Arena *arena);
function void ArenaPop(Arena *arena, UAddr amt);
#define PushArrayNoZeroAligned(a, T, c, align) (T *)ArenaPush((a), sizeof(T)*(c), (align))
#define PushArrayAligned(a, T, c, align) (T *)MemoryZero(PushArrayNoZeroAligned(a, T, c, align), sizeof(T)*(c))
#define PushArrayNoZero(a, T, c) PushArrayNoZeroAligned(a, T, c, AlignOf(T))
#define PushArray(a, T, c) PushArrayAligned(a, T, c, AlignOf(T))
////////////////////////////////
//~ rjf: Arena Temporary Scopes
typedef struct Temp Temp;
struct Temp
{
Arena *arena;
UAddr pos;
};
function Temp TempBegin(Arena *arena);
function void TempEnd(Temp temp);
////////////////////////////////
//~ rjf: Thread Context
typedef struct ThreadCtx ThreadCtx;
struct ThreadCtx
{
Arena *scratch_arenas[2];
};
//- rjf: @per_platform Thread Context Functions
function ThreadCtx *GetThreadCtx(void);
//- rjf: Thread Context Helpers
function Arena *GetScratch(Arena *conflict);
#define ScratchBegin(result_arena) TempBegin(GetScratch(result_arena))
#define ScratchEnd(temp) TempEnd(temp)
////////////////////////////////
//~ rjf: Strings
#include <stdarg.h>
typedef struct String8 String8;
struct String8
{
U8 *str;
UAddr size;
};
function UAddr CStr8Size(char *cstr);
function String8 Str8(U8 *str, UAddr size);
#define Str8Lit(s) Str8((U8 *)(s), sizeof(s)-1)
#define Str8LitComp(s) {(U8 *)(s), sizeof(s)-1}
#define S(s) Str8Lit(s)
function String8 Str8FV(Arena *arena, char *fmt, va_list args);
function String8 Str8F(Arena *arena, char *fmt, ...);
#define SF(...) Str8F(scratch.arena, __VA_ARGS__)
function String8 ByteStringFromData(Arena *arena, String8 data);
global U8 dec_chars[] = "0123456789";
global U8 hex_chars_lower[] = "0123456789abcdef";
global U8 hex_chars_upper[] = "0123456789ABCDEF";
////////////////////////////////
//~ rjf: Colors
function U16 RGBA5551From4F32(Vec4F32 rgba);
function U32 RGBA32From4F32(Vec4F32 rgba);
function Vec4F32 RGBA4F32From32(U32 rgba);
////////////////////////////////
//~ rjf: Game Pads
typedef enum GamePadButtonKind
{
GamePadButtonKind_Null,
GamePadButtonKind_A,
GamePadButtonKind_B,
GamePadButtonKind_CLeft,
GamePadButtonKind_CUp,
GamePadButtonKind_CRight,
GamePadButtonKind_CDown,
GamePadButtonKind_Start,
GamePadButtonKind_DLeft,
GamePadButtonKind_DUp,
GamePadButtonKind_DRight,
GamePadButtonKind_DDown,
GamePadButtonKind_Z,
GamePadButtonKind_LeftBumper,
GamePadButtonKind_RightBumper,
GamePadButtonKind_COUNT
}
GamePadButtonKind;
typedef struct GamePad GamePad;
struct GamePad
{
U32 connect_gen; // incremented on every connection change
BitArrayDecl(U32, last_buttons, GamePadButtonKind_COUNT);
BitArrayDecl(U32, buttons, GamePadButtonKind_COUNT);
F32 left_trigger;
F32 right_trigger;
Vec2F32 sticks[2];
};
#define GAME_PAD_SLOT_COUNT 4
////////////////////////////////
//~ rjf: Program Tick Entry Point
function B32 Run(U64 tick_idx, Arena *permanent_arena, GamePad game_pads[GAME_PAD_SLOT_COUNT]);
#endif // BASE_H

@ -0,0 +1,9 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#include "base.c"
#if PLATFORM_N64
# include "n64/base/n64_base.c"
#else
# error Platform-defined implementations for base layer not defined for this platform.
#endif

@ -0,0 +1,14 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef BASE_INC_H
#define BASE_INC_H
#include "base.h"
#if PLATFORM_N64
# include "n64/base/n64_base.h"
#else
# error Platform-defined implementations for base layer not defined for this platform.
#endif
#endif // BASE_INC_H

@ -0,0 +1,8 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
function ThreadCtx *
GetThreadCtx(void)
{
return &n64_tctx;
}

@ -0,0 +1,7 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef N64_BASE_H
#define N64_BASE_H
#endif // N64_BASE_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
OUTPUT_FORMAT("elf32-bigmips")
OUTPUT_ARCH(mips)
ENTRY(_start)
PHDRS
{
irq PT_LOAD AT (0x80000000);
text PT_LOAD AT (0x80000400);
data PT_LOAD;
}
SECTIONS
{
.intvectors 0x80000000 :
{
. = ALIGN(32);
KEEP(*(.intvectors))
__intvectors_end = .;
}:irq
.text 0x80000400 :
{
*(.text.boot)
*(.text*)
*(.rodata*)
}:text
.data :
{
*(.data*)
n64_static_data_end = .;
}:data
.bss (NOLOAD) :
{
__bss_start = .;
*(.bss*)
*(COMMON)
__bss_end = .;
}
/DISCARD/ :
{
*(.eh_frame*)
*(.comment)
*(.note*)
}
}

@ -0,0 +1,333 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
////////////////////////////////
//~ rjf: Render Resources @per_platform
function R_BufferHandle
R_BufferHandleFromData(void *data, UAddr element_count, UAddr element_size)
{
R_BufferHandle result = {0};
if(n64_r_state.buffers_count < ArrayCount(n64_r_state.buffers))
{
N64_R_Buffer *buffer = &n64_r_state.buffers[n64_r_state.buffers_count];
buffer->data = data;
buffer->element_count = element_count;
buffer->element_size = element_size;
n64_r_state.buffers_count += 1;
result.uaddr[0] = n64_r_state.buffers_count;
}
return result;
}
function R_SubModelHandle
R_SubModelHandleFromBuffers(R_BufferHandle vtx_buffer, R_BufferHandle idx_buffer)
{
R_SubModelHandle result = {0};
if(n64_r_state.sub_models_count < ArrayCount(n64_r_state.sub_models))
{
N64_R_SubModel *sub_model= &n64_r_state.sub_models[n64_r_state.sub_models_count];
sub_model->vtx_buffer_num = (U16)vtx_buffer.uaddr[0];
sub_model->idx_buffer_num = (U16)idx_buffer.uaddr[0];
n64_r_state.sub_models_count += 1;
result.uaddr[0] = n64_r_state.sub_models_count;
}
return result;
}
////////////////////////////////
//~ rjf: Render Commands @per_platform
function void
R_Pass(R_PassParams *params)
{
MemoryCopyStruct(&n64_r_state.pass_params, params);
n64_r_state.pass_view_projection = Mul4x4F32(params->projection, params->view);
n64_r_state.buffers_count = 0;
n64_r_state.sub_models_count = 0;
//- rjf: draw sky
{
// rjf: sync pipe
{
N64_DP_Cmd_Stub cmd = {0};
cmd.id = N64_DP_CmdID_SyncPipe;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
}
// rjf: set other modes
{
N64_DP_Cmd_SetOtherModes cmd = {0};
cmd.id = N64_DP_CmdID_SetOtherModes;
cmd.atomic_prim = 1;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
}
// rjf: draw full-screen triangle for sky
{
N64_DP_Cmd_FillTriangleBase cmd = {0};
cmd.id = N64_DP_CmdID_FillTriangleS;
cmd.flags = N64_DP_Cmd_FillTriangleFlag_LeftMajor;
cmd.yl = Fixed112FromF32(N64_FB_HEIGHT);
cmd.ym = Fixed112FromF32(N64_FB_HEIGHT);
cmd.yh = 0;
cmd.xl = Fixed1616FromF32(N64_FB_WIDTH);
cmd.dxldy = 0;
cmd.xh = 0;
cmd.dxhdy = 0;
cmd.xm = Fixed1616FromF32(N64_FB_WIDTH);
cmd.dxmdy = 0;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
{
F32 pitch = 0.1f;
Vec4F32 top_color_4f32 = V4F32(0.02f, 0.2f - 0.1f*(0.75f + pitch/0.25f), 0.05f - 0.02f*(0.75f + pitch/0.25f), 1.f);
// top_color_4f32 = V4F32(0.02f, 0.15f - 0.1f*(0.75f + pitch/0.25f), 0.3f - 0.02f*(0.75f + pitch/0.25f), 1.f);
S32 top_color_x_s32 = Fixed1616FromF32(top_color_4f32.x*255.f);
S32 top_color_y_s32 = Fixed1616FromF32(top_color_4f32.y*255.f);
S32 top_color_z_s32 = Fixed1616FromF32(top_color_4f32.z*255.f);
S32 top_color_w_s32 = Fixed1616FromF32(top_color_4f32.w*255.f);
S32 dcdy = Fixed1616FromF32(-0.1f);
S32 dcpdy = Fixed1616FromF32(+0.01f);
N64_DP_CmdExt_FillTriangleShading ext = {0};
ext.r_i = Upper16(top_color_x_s32);
ext.g_i = Upper16(top_color_y_s32);
ext.b_i = Upper16(top_color_z_s32);
ext.a_i = Upper16(top_color_w_s32);
ext.r_f = Lower16(top_color_x_s32);
ext.g_f = Lower16(top_color_y_s32);
ext.b_f = Lower16(top_color_z_s32);
ext.a_f = Lower16(top_color_w_s32);
ext.drde_i = Upper16(dcdy);
ext.dgde_i = Upper16(dcdy);
ext.dbde_i = Upper16(dcpdy);
ext.drde_f = Lower16(dcdy);
ext.dgde_f = Lower16(dcdy);
ext.dbde_f = Lower16(dcpdy);
WriteStructAndInc(n64_r_state.rdp_command_buffer, &ext, &n64_r_state.rdp_command_buffer_write_pos);
}
}
}
//- rjf: set up depth tested drawing parameters
{
// rjf: sync pipe
{
N64_DP_Cmd_Stub cmd = {0};
cmd.id = N64_DP_CmdID_SyncPipe;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
}
// rjf: set other modes
{
N64_DP_Cmd_SetOtherModes cmd = {0};
cmd.id = N64_DP_CmdID_SetOtherModes;
cmd.atomic_prim = 1;
cmd.z_update_en = 1;
cmd.z_compare_en = 1;
cmd.antialias_en = 1;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
}
}
}
function void
R_SubModel(R_SubModelHandle handle, R_Material material, Mat4x4F32 xform)
{
Mat4x4F32 view_projection = n64_r_state.pass_view_projection;
UAddr sub_model_num = handle.uaddr[0];
if(0 < sub_model_num && sub_model_num <= n64_r_state.sub_models_count)
{
N64_R_SubModel *sub_model = &n64_r_state.sub_models[sub_model_num-1];
if(0 < sub_model->vtx_buffer_num && sub_model->vtx_buffer_num <= n64_r_state.buffers_count &&
0 < sub_model->idx_buffer_num && sub_model->idx_buffer_num <= n64_r_state.buffers_count)
{
N64_R_Buffer *vtx_buffer = &n64_r_state.buffers[sub_model->vtx_buffer_num-1];
N64_R_Buffer *idx_buffer = &n64_r_state.buffers[sub_model->idx_buffer_num-1];
Vec3F32 material_rgb = material.color.xyz;
if(vtx_buffer->element_size == sizeof(Vec3F32) &&
(idx_buffer->element_size == 2 || idx_buffer->element_size == 4))
{
UAddr tri_count = idx_buffer->element_count/3;
Vec3F32 *vtx = (Vec3F32 *)vtx_buffer->data;
UAddr vtx_count = vtx_buffer->element_count;
UAddr command_bytes_per_tri = sizeof(N64_DP_Cmd_FillTriangleBase) + sizeof(N64_DP_CmdExt_FillTriangleShading) + sizeof(N64_DP_CmdExt_FillTriangleDepth);
UAddr command_bytes_left = ArrayCount(n64_r_state.rdp_command_buffer) - n64_r_state.rdp_command_buffer_write_pos;
UAddr tri_count_max = command_bytes_left / command_bytes_per_tri;
UAddr tri_count_actual = Min(tri_count_max, tri_count);
for EachIndex(tri_idx, tri_count_actual)
{
// rjf: get face nums for this triangle
UAddr face_nums[3];
switch(idx_buffer->element_size)
{
default:{MemoryZero(face_nums, sizeof(face_nums));}break;
case 2:
{
face_nums[0] = ((U16 *)idx_buffer->data)[tri_idx*3+0];
face_nums[1] = ((U16 *)idx_buffer->data)[tri_idx*3+1];
face_nums[2] = ((U16 *)idx_buffer->data)[tri_idx*3+2];
}break;
case 4:
{
face_nums[0] = ((U32 *)idx_buffer->data)[tri_idx*3+0];
face_nums[1] = ((U32 *)idx_buffer->data)[tri_idx*3+1];
face_nums[2] = ((U32 *)idx_buffer->data)[tri_idx*3+2];
}break;
}
// rjf: unpack world-space vertices
Vec4F32 world_v[3] =
{
V4F32(vtx[face_nums[0]-1].x, vtx[face_nums[0]-1].y, vtx[face_nums[0]-1].z, 1.f),
V4F32(vtx[face_nums[1]-1].x, vtx[face_nums[1]-1].y, vtx[face_nums[1]-1].z, 1.f),
V4F32(vtx[face_nums[2]-1].x, vtx[face_nums[2]-1].y, vtx[face_nums[2]-1].z, 1.f),
};
// rjf: world -> clip
Vec4F32 clip_v[] =
{
XForm4F32(view_projection, world_v[0]),
XForm4F32(view_projection, world_v[1]),
XForm4F32(view_projection, world_v[2]),
};
// rjf: clip -> ndc
Vec3F32 ndc_v[] =
{
Scale3F32(clip_v[0].xyz, 1.f/clip_v[0].w),
Scale3F32(clip_v[1].xyz, 1.f/clip_v[1].w),
Scale3F32(clip_v[2].xyz, 1.f/clip_v[2].w),
};
// rjf: early discard of back-facing triangles
{
Vec3F32 normal = Cross3F32(Sub3F32(ndc_v[1], ndc_v[0]), Sub3F32(ndc_v[2], ndc_v[0]));
Vec3F32 eye = V3F32(0, 0, 1);
F32 dot = Dot3F32(normal, eye);
if(dot > 0)
{
continue;
}
}
// rjf: ndc -> screen
Vec3F32 ndc2screen_v = V3F32(N64_FB_WIDTH/2.f, N64_FB_HEIGHT/2.f, 0x7FFF/2.f);
Vec3F32 screen_v[] =
{
Mul3F32(Add3F32(Mul3F32(ndc_v[0], V3F32(-1, -1, 1)), V3F32(1, 1, 1)), ndc2screen_v),
Mul3F32(Add3F32(Mul3F32(ndc_v[1], V3F32(-1, -1, 1)), V3F32(1, 1, 1)), ndc2screen_v),
Mul3F32(Add3F32(Mul3F32(ndc_v[2], V3F32(-1, -1, 1)), V3F32(1, 1, 1)), ndc2screen_v),
};
// rjf: screen -> snapped; ensures joining edges of triangles, otherwise triangles
// disagree on edges in projected space, causing seams.
for EachElement(idx, screen_v)
{
for EachIndex(axis, 3)
{
screen_v[idx].v[axis] = FloorF32(screen_v[idx].v[axis]*4.f)/4.f;
}
}
// rjf: sort vertices into top/mid/bot
Vec3F32 top = screen_v[0];
Vec3F32 mid = screen_v[1];
Vec3F32 bot = screen_v[2];
U8 world_idxs[] =
{
0, 1, 2
};
if(mid.y > bot.y)
{
Swap(Vec3F32, mid, bot);
}
if(top.y > mid.y)
{
Swap(Vec3F32, top, mid);
}
if(mid.y > bot.y)
{
Swap(Vec3F32, mid, bot);
}
// rjf: unpack triangle edges
//
// *
// |\ "M":top2mid
// | \
// "H":top2bot | *
// | /
// |/ "L":mid2bot
// *
//
Vec3F32 top2mid = Sub3F32(mid, top);
Vec3F32 top2bot = Sub3F32(bot, top);
Vec3F32 mid2bot = Sub3F32(bot, mid);
F32 top2bot_invslope = (top2bot.y != 0) ? (top2bot.x / top2bot.y) : 0;
F32 top2mid_invslope = (top2mid.y != 0) ? (top2mid.x / top2mid.y) : 0;
F32 mid2bot_invslope = (mid2bot.y != 0) ? (mid2bot.x / mid2bot.y) : 0;
F32 fy = FloorF32(top.y) - top.y;
F32 nz = top2bot.x*top2mid.y - top2bot.y*top2mid.x;
F32 inv_n = (nz != 0.f) ? (-1.f / nz) : 0.f;
// rjf: fill command
N64_DP_Cmd_FillTriangleBase cmd = {0};
F32 x_h_at_mid = top.x + (mid.y - top.y) * top2bot_invslope;
B32 left_major = (mid.x >= x_h_at_mid);
cmd.id = N64_DP_CmdID_FillTriangleSZ;
cmd.flags = left_major ? N64_DP_Cmd_FillTriangleFlag_LeftMajor : 0;
cmd.yl = Fixed112FromF32(bot.y);
cmd.ym = Fixed112FromF32(mid.y);
cmd.yh = Fixed112FromF32(top.y);
cmd.xl = Fixed1616FromF32(mid.x);
cmd.dxldy = Fixed1616FromF32(mid2bot_invslope);
cmd.xh = Fixed1616FromF32(top.x + fy*top2bot_invslope);
cmd.dxhdy = Fixed1616FromF32(top2bot_invslope);
cmd.xm = Fixed1616FromF32(top.x + fy*top2mid_invslope);
cmd.dxmdy = Fixed1616FromF32(top2mid_invslope);
// rjf: push
WriteStructAndInc(n64_r_state.rdp_command_buffer, &cmd, &n64_r_state.rdp_command_buffer_write_pos);
// rjf: unpack lighting
Vec3F32 normal = Cross3F32(Sub3F32(world_v[2].xyz, world_v[0].xyz), Sub3F32(world_v[1].xyz, world_v[0].xyz));
Vec3F32 keylight_dir = n64_r_state.pass_params.keylight_dir;
F32 normal_dot_keylight_dir = Dot3F32(Normalize3F32(keylight_dir), Normalize3F32(normal));
F32 light_factor_unclamped = 1 - Clamp(0, -normal_dot_keylight_dir, 1);
F32 light_factor = Clamp(0.2f, light_factor_unclamped, 1.f);
// rjf: unpack vertex colors
Vec3F32 rgb_v[] =
{
Scale3F32(material_rgb, light_factor),
Scale3F32(material_rgb, light_factor),
Scale3F32(material_rgb, light_factor),
};
// rjf: extend w/ shading
{
N64_DP_CmdExt_FillTriangleShading ext = {0};
ext.r_i = 255*rgb_v[0].x;
ext.g_i = 255*rgb_v[0].y;
ext.b_i = 255*rgb_v[0].z;
ext.a_i = 255;
WriteStructAndInc(n64_r_state.rdp_command_buffer, &ext, &n64_r_state.rdp_command_buffer_write_pos);
}
// rjf: extend w/ depth
{
F32 dzdx = (top2bot.y*top2mid.z - top2mid.y*top2bot.z) * inv_n;
F32 dzdy = (top2mid.x*top2bot.z - top2bot.x*top2mid.z) * inv_n;
F32 dzde = dzdy + dzdx*top2bot_invslope;
N64_DP_CmdExt_FillTriangleDepth ext = {0};
ext.z = Fixed1616FromF32(top.z + fy * dzde);
ext.dzdx = Fixed1616FromF32(dzdx);
ext.dzdy = Fixed1616FromF32(dzdy);
ext.dzde = Fixed1616FromF32(dzde);
WriteStructAndInc(n64_r_state.rdp_command_buffer, &ext, &n64_r_state.rdp_command_buffer_write_pos);
}
}
}
}
}
}

@ -0,0 +1,37 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef N64_RENDER_H
#define N64_RENDER_H
typedef struct N64_R_Buffer N64_R_Buffer;
struct N64_R_Buffer
{
void *data;
UAddr element_count;
UAddr element_size;
};
typedef struct N64_R_SubModel N64_R_SubModel;
struct N64_R_SubModel
{
U16 vtx_buffer_num;
U16 idx_buffer_num;
};
typedef struct N64_R_State N64_R_State;
struct N64_R_State
{
U8 align(64) rdp_command_buffer[KiB(256)];
UAddr rdp_command_buffer_write_pos;
R_PassParams pass_params;
Mat4x4F32 pass_view_projection;
N64_R_Buffer buffers[1024];
UAddr buffers_count;
N64_R_SubModel sub_models[1024];
UAddr sub_models_count;
};
global N64_R_State n64_r_state = {0};
#endif // N64_RENDER_H

@ -0,0 +1,475 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#include "base/base_inc.h"
#include "n64/n64.h"
#include "render/render_inc.h"
#include "base/base_inc.c"
#include "n64/n64.c"
#include "render/render_inc.c"
typedef struct SubModel SubModel;
struct SubModel
{
U16 material_num;
U16 *idxs;
UAddr idxs_count;
U64 id;
};
typedef struct Model Model;
struct Model
{
Vec3F32 *vtx;
UAddr vtx_count;
SubModel *sub_models;
UAddr sub_models_count;
};
R_Material materials[] =
{
{{1, 0.5f, 0, 1}}, // yellow
{{0, 1, 0, 1}}, // green
{{1, 0, 0, 1}}, // red
{{0, 0, 1, 1}}, // blue
};
extern Model n64_logo_model;
extern Model dg_logo_model;
function B32
Run(U64 tick_idx, Arena *permanent_arena, GamePad game_pads[GAME_PAD_SLOT_COUNT])
{
B32 keep_running = 1;
//- rjf: get/update camera state
local_persist F32 yaw = 0.125f;
local_persist F32 pitch = 0.125f;
local_persist F32 zoom = 5.f;
{
// rjf: stick -> adjust yaw/pitch
yaw += 0.1f * game_pads[0].sticks[0].x;
pitch += 0.1f * game_pads[0].sticks[0].y;
pitch = Clamp(-0.24f, pitch, +0.24f);
// rjf: z -> zoom in
if(BitArrayGet(game_pads[0].buttons, GamePadButtonKind_Z))
{
zoom -= 0.1f;
}
// rjf: r -> zoom out
else if(BitArrayGet(game_pads[0].buttons, GamePadButtonKind_RightBumper))
{
zoom += 0.1f;
}
}
//- rjf: camera state -> view projection
F32 cos_pitch = CosF32(pitch);
F32 cos_pitch_zoom = cos_pitch*zoom;
Vec3F32 eye = V3F32(cos_pitch_zoom*CosF32(yaw),
cos_pitch_zoom*SinF32(yaw),
zoom*SinF32(pitch));
Mat4x4F32 view = MakeLookAt4x4F32(eye, V3F32(0, 0, 0), V3F32(0, 0, 1));
Mat4x4F32 projection = MakePerspective4x4F32(0.25f, (F32)N64_FB_WIDTH/N64_FB_HEIGHT, 0.01f, 50.f);
//- rjf: get/update selected model
local_persist S32 model_num = 0;
if(BitArrayGet(n64_state.game_pads[0].buttons, GamePadButtonKind_CRight) && !BitArrayGet(n64_state.game_pads[0].last_buttons, GamePadButtonKind_CRight))
{
model_num += 1;
if(model_num > 2)
{
model_num = 0;
}
}
if(BitArrayGet(n64_state.game_pads[0].buttons, GamePadButtonKind_CLeft) && !BitArrayGet(n64_state.game_pads[0].last_buttons, GamePadButtonKind_CLeft))
{
model_num -= 1;
if(model_num < 0)
{
model_num = 2;
}
}
Model *model = &n64_logo_model;
switch(model_num)
{
default:
case 0:
{}break;
case 1:
{
model = &dg_logo_model;
}break;
case 2:
{
// model = &n64_controller_model;
}break;
}
//- rjf: set up render pass
R_PassParams pass_params =
{
view,
projection,
V3F32(+0.5f, +0.1f, -1),
};
R_Pass(&pass_params);
//- rjf: draw model
R_BufferHandle vtx_buffer = R_BufferHandleFromData(model->vtx, model->vtx_count, sizeof(model->vtx[0]));
for EachIndex(sub_model_idx, model->sub_models_count)
{
SubModel *sub_model = &model->sub_models[sub_model_idx];
R_Material material = materials[sub_model->material_num-1];
R_BufferHandle idx_buffer = R_BufferHandleFromData(sub_model->idxs, sub_model->idxs_count, sizeof(sub_model->idxs[0]));
R_SubModelHandle handle = R_SubModelHandleFromBuffers(vtx_buffer, idx_buffer);
R_SubModel(handle, material, MakeMat4x4F32(1.f));
}
//- rjf: gradient test
#if 0
#if 0
{
U16 *p = N64_Framebuffer();
int midpoint = N64_FB_WIDTH - (tick_idx%N64_FB_WIDTH);
for(int i = 0; i < N64_FB_WIDTH*N64_FB_HEIGHT; i += 1)
{
// NOTE(rjf): RGBA5551 (R5 G5 B5 A1)
//
// - 0xF801 = bright red
// - 0x07C1 = bright green
// - 0x003F = bright blue
// - 0xFFFF = white
// - 0x0001 = black (with alpha)
//
F32 pct = (F32)(i%N64_FB_WIDTH) / N64_FB_WIDTH;
U16 red = (U16)(pct * 0x1f);
U16 color = 0x0001 | (red<<11);
if((i%N64_FB_WIDTH) > midpoint)
{
F32 pct = (F32)(N64_FB_WIDTH - (i%N64_FB_WIDTH)) / N64_FB_WIDTH;
U16 green = (U16)(pct * 0x1f);
color |= (green<<6);
}
{
F32 pct = ((F32)(i / N64_FB_WIDTH) / N64_FB_HEIGHT);
U16 blue = (U16)(pct * 0x1f);
color |= (blue<<1);
}
p[i] = color;
}
}
#endif
#if 1
U16 *p = N64_Framebuffer();
for(int i = 0; i < N64_FB_WIDTH*N64_FB_HEIGHT; i += 1)
{
if(i%N64_FB_WIDTH > tick_idx%N64_FB_WIDTH)
{
p[i] = 0xf801;
}
else
{
p[i] = 0x0001;
}
}
#endif
Temp scratch = ScratchBegin(0);
#if 0
Vec2F32 text_pos = {150, 64 + 32.f};
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), SF("DP status_flags: %ib", N64_DP_REGS->status_flags)).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), SF("MI_VERSION: %ix", *N64_MI_VERSION)).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), S("ABCDEFGHIJKLMNOPQRSTUVWXYZ")).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), S("abcdefghijklmnopqrstuvwxyz")).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), S("0123456789")).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), S("`~!@#$%^&*()-_=+[]{};:'\"|\\.,<>?/")).y;
text_pos.y += 4;
text_pos.y += N64_DrawDebugString(1, text_pos, V4F32(1, 0.8f, 0, 1), S("Hello, N64!")).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 1, 1, 1), SF("Memory Size = %i", N64_BOOT_INFO->memory_size)).y;
text_pos.y += N64_DrawDebugString(0, text_pos, V4F32(1, 0, 0, 1), SF("DP STATUS = %ib", N64_DP_REGS->status_flags)).y;
N64_DrawMonochromeBitmap(V2F32(320 - 32, 240 - 48), V4F32(1, 1, 0, 1), n64_dgtlgrove_logo_32x48, 32, 48);
#endif
Vec2F32 button_pos = {16, 48};
for(U64 idx = 0; idx < 4; idx += 1)
{
B32 controller_is_connected = (n64_state.joybus_port_states[idx].id == N64_JoyBus_ID_N64Controller);
Vec4F32 color = controller_is_connected ? V4F32(1, 1, 1, 1) : V4F32(1, 0, 0, 1);
N64_DrawMonochromeBitmap(V2F32(16 + 32*idx, 16), color, n64_controller_icon_32x32, 32, 32);
if(controller_is_connected)
{
N64_DrawDebugString(0,
V2F32(16 + 32*idx + 16 - N64_SMALL_DEFAULT_FONT_GLYPH_WIDTH/2 + 8*game_pads[idx].sticks[0].x,
16 + 16 - N64_SMALL_DEFAULT_FONT_GLYPH_HEIGHT/2 + -8*game_pads[idx].sticks[0].y),
V4F32(1, 1, 0, 1), S("*"));
}
if(controller_is_connected)
{
// button_pos.y += N64_DrawDebugString(0, button_pos, V4F32(1, 1, 1, 1), SF("Stick")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_A))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0, 0, 1, 1), S("A")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_B))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0, 1, 0, 1), S("B")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_Start))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(1, 0, 0, 1), S("Start")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_CLeft))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(1, 1, 0, 1), S("C<")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_CUp))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(1, 1, 0, 1), S("C^")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_CRight))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(1, 1, 0, 1), S("C>")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_CDown))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(1, 1, 0, 1), S("Cv")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_DLeft))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("D<")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_DUp))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("D^")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_DRight))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("D>")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_DDown))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("Dv")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_Z))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("Z")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_LeftBumper))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("L")).y;
}
if(BitArrayGet(game_pads[idx].buttons, GamePadButtonKind_RightBumper))
{
button_pos.y += N64_DrawDebugString(1, button_pos, V4F32(0.5f, 0.5f, 0.5f, 1), S("R")).y;
}
}
ScratchEnd(scratch);
#endif
//- rjf: digital grove splash test
#if 0
F32 t_pct = (F32)tick_idx / 80.f;
if(t_pct > 1.f)
{
t_pct = 1.f;
}
{
U16 *p = N64_Framebuffer();
U8 bayer[16] =
{
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
};
F32 dither_step = 1.f / 31.f;
for(U32 off = 0; off < N64_FB_WIDTH*N64_FB_HEIGHT; off += 1)
{
U32 x = off%N64_FB_WIDTH;
U32 y = off/N64_FB_WIDTH;
F32 x_pct = (F32)x/N64_FB_WIDTH;
F32 y_pct = (F32)y/N64_FB_HEIGHT;
Vec4F32 color = V4F32(t_pct * (0.04f + 0.08f*x_pct - 0.03f*y_pct),
t_pct * (0.15f - 0.04f*y_pct),
t_pct * (0.03f + 0.04f*y_pct),
1.f);
U32 x_bayer = x%4;
U32 y_bayer = y%4;
F32 bayer_f = (bayer[y_bayer*4 + x_bayer] / 16.f);
Vec4F32 color_dithered = color;
color_dithered.x += (bayer_f - 0.5f) * dither_step;
color_dithered.y += (bayer_f - 0.5f) * dither_step;
color_dithered.z += (bayer_f - 0.5f) * dither_step;
p[off] = RGBA5551From4F32(color_dithered);
}
}
// Vec4F32 logo_color = V4F32(1*t_pct, 0.8f*t_pct, 0, 1);
// N64_DrawMonochromeBitmap(V2F32(160 - 16, 120 - 24 + 32*(1-t_pct)), logo_color, n64_dgtlgrove_logo_32x48, 32, 48);
// N64_DrawDebugString(1, V2F32(160 - 6.5f*N64_BIG_DEFAULT_FONT_GLYPH_WIDTH, 120+30 + 32*(1-t_pct)), logo_color, S("Digital Grove 64"));
#endif
return keep_running;
}
global Vec3F32 n64_logo_model_vtx[] =
{
{ -0.319213, -0.322617, 0.083041 }, { -0.319213, -0.671946, 0.719425 }, { -0.319213, 0.332592, -0.051930 }, { -0.691264, 0.339679, -0.737678 },
{ -0.691264, -0.321049, -0.737678 }, { -0.691264, -0.319959, 0.719425 }, { -0.691264, 0.689761, 0.087923 }, { -0.319213, 0.339679, -0.737678 },
{ -0.691264, -0.322617, 0.083041 }, { -0.319213, -0.321049, -0.737678 }, { -0.691264, -0.671946, -0.737678 }, { -0.319213, -0.671946, -0.737678 },
{ -0.691264, -0.671946, 0.719425 }, { -0.319213, -0.319959, 0.719425 }, { -0.691264, 0.332592, -0.051930 }, { -0.691264, 0.332592, 0.087923 },
{ -0.319213, 0.332592, 0.087923 }, { -0.319213, 0.689761, 0.087923 }, { -0.691264, 0.689761, -0.737678 }, { -0.319213, 0.689761, -0.737678 },
{ -0.319213, -0.671946, 0.086702 }, { -0.691264, 0.689761, -0.049576 }, { -0.319213, 0.689761, -0.051523 }, { -0.691264, 0.689761, 0.726424 },
{ -0.691264, 0.332592, 0.726424 }, { -0.319213, 0.332592, 0.726424 }, { -0.319213, 0.689761, 0.726424 }, { 0.328262, 0.332592, -0.731953 },
{ 0.328262, 0.689761, -0.731953 }, { 0.328262, 0.332592, -0.040641 }, { 0.328262, 0.689761, -0.040641 }, { 0.663334, 0.332592, -0.731953 },
{ 0.663334, 0.689761, -0.731953 }, { 0.663334, 0.332592, -0.040641 }, { 0.663334, 0.689761, -0.040641 }, { 0.328262, 0.332592, 0.089613 },
{ 0.328262, 0.689761, 0.089613 }, { 0.663334, 0.332592, 0.089613 }, { 0.663334, 0.689761, 0.089613 }, { 0.328262, 0.332592, 0.726182 },
{ 0.328262, 0.689761, 0.726182 }, { 0.663334, 0.332592, 0.726182 }, { 0.663334, 0.689761, 0.726182 }, { 0.663334, -0.324375, -0.734938 },
{ 0.328262, -0.324375, -0.734938 }, { 0.663333, -0.324375, -0.039661 }, { 0.328262, -0.324375, -0.039662 }, { 0.663334, -0.677543, -0.734938 },
{ 0.328262, -0.677543, -0.734938 }, { 0.663333, -0.677543, -0.039661 }, { 0.328262, -0.677543, -0.039662 }, { 0.663333, -0.324375, 0.099964 },
{ 0.328262, -0.324375, 0.099964 }, { 0.663333, -0.677543, 0.099964 }, { 0.328262, -0.677543, 0.099964 }, { 0.663333, -0.324375, 0.720610 },
{ 0.328261, -0.324375, 0.720610 }, { 0.663333, -0.677543, 0.720610 }, { 0.328261, -0.677543, 0.720610 }, { -0.691264, -0.671946, 0.086713 },
{ -0.691264, -0.671946, -0.042679 }, { -0.319213, -0.671946, -0.040508 }, { -0.319213, -0.322617, -0.040018 }, { -0.691264, -0.322617, -0.044321 },
};
global U16 n64_logo_model_tri_faces__yellow[] =
{
14, 13, 2, 27, 25, 26, 40, 43, 41, 57, 58, 56,
14, 6, 13, 27, 24, 25, 40, 42, 43, 57, 59, 58,
};
global U16 n64_logo_model_tri_faces__green[] =
{
15, 8, 3, 9, 14, 1, 63, 9, 1, 12, 5, 10,
12, 61, 11, 3, 16, 15, 7, 27, 18, 18, 22, 7,
8, 19, 20, 47, 1, 14, 23, 19, 22, 25, 63, 26,
29, 32, 28, 37, 8, 20, 23, 37, 20, 31, 33, 29,
34, 36, 30, 31, 39, 35, 36, 3, 8, 37, 43, 39,
46, 53, 52, 48, 51, 49, 44, 49, 45, 50, 55, 51,
55, 58, 59, 57, 34, 30, 60, 2, 13, 62, 60, 61,
21, 51, 2, 1, 49, 21, 47, 44, 45, 38, 40, 36,
15, 4, 8, 9, 6, 14, 63, 64, 9, 12, 11, 5,
12, 62, 61, 3, 17, 16, 7, 24, 27, 18, 23, 22,
8, 4, 19, 47, 45, 1, 23, 20, 19, 25, 64, 63,
29, 33, 32, 37, 36, 8, 23, 41, 37, 31, 35, 33,
34, 38, 36, 31, 37, 39, 36, 40, 3, 37, 41, 43,
46, 47, 53, 48, 50, 51, 44, 48, 49, 50, 54, 55,
55, 54, 58, 57, 56, 34, 60, 21, 2, 62, 21, 60,
21, 49, 51, 1, 45, 49, 47, 46, 44, 38, 42, 40,
};
global U16 n64_logo_model_tri_faces__red[] =
{
10, 16, 17, 40, 23, 3, 2, 47, 14, 52, 28, 32,
10, 5, 16, 40, 41, 23, 2, 51, 47, 52, 53, 28,
};
global U16 n64_logo_model_tri_faces__blue[] =
{
17, 23, 18, 11, 64, 5, 22, 4, 15, 1, 62, 63,
63, 17, 26, 22, 16, 7, 12, 63, 62, 16, 24, 7,
27, 17, 18, 33, 34, 32, 34, 52, 32, 35, 38, 34,
30, 37, 31, 39, 42, 38, 46, 48, 44, 52, 58, 54,
51, 53, 47, 46, 54, 50, 59, 53, 55, 60, 6, 9,
28, 31, 29, 16, 64, 25, 61, 9, 64, 53, 30, 28,
17, 3, 23, 11, 61, 64, 22, 19, 4, 1, 21, 62,
63, 10, 17, 22, 15, 16, 12, 10, 63, 16, 25, 24,
27, 26, 17, 33, 35, 34, 34, 56, 52, 35, 39, 38,
30, 36, 37, 39, 43, 42, 46, 50, 48, 52, 56, 58,
51, 55, 53, 46, 52, 54, 59, 57, 53, 60, 13, 6,
28, 30, 31, 16, 5, 64, 61, 60, 9, 53, 57, 30,
};
SubModel n64_logo_submodels[] =
{
{1, ArrayAndCount(n64_logo_model_tri_faces__yellow)},
{2, ArrayAndCount(n64_logo_model_tri_faces__green)},
{3, ArrayAndCount(n64_logo_model_tri_faces__red)},
{4, ArrayAndCount(n64_logo_model_tri_faces__blue)},
};
Model n64_logo_model =
{
ArrayAndCount(n64_logo_model_vtx),
ArrayAndCount(n64_logo_submodels),
};
global Vec3F32 dg_logo_model_vtx[] =
{
{ 0.085057, 0.094957, -2.584146 }, { 0.084919, -0.027923, -2.658362 }, { 0.083808, -0.171746, -2.550864 }, { 0.083306, -0.107028, -2.394031 },
{ 0.084125, 0.080334, -2.405339 }, { 0.086326, 0.278994, -2.690513 }, { 0.086225, 0.063105, -2.850055 }, { 0.084853, -0.226452, -2.810704 },
{ 0.083159, -0.367724, -2.581724 }, { 0.082095, -0.334552, -2.335907 }, { 0.082196, -0.118662, -2.176362 }, { 0.083569, 0.170893, -2.215714 },
{ 0.085262, 0.312166, -2.444695 }, { 0.082318, -0.135191, -2.215159 }, { 0.075256, -0.133749, -0.766794 }, { 0.068438, -0.894210, -0.004996 },
{ 0.060581, -0.892605, 1.606462 }, { 0.059976, -0.130628, 2.366775 }, { 0.056730, -0.025024, 3.120139 }, { 0.061291, 0.084822, 2.277215 },
{ 0.062657, -0.607715, 1.418925 }, { 0.068886, -0.608987, 0.141494 }, { 0.075700, 0.081880, -0.677655 }, { 0.083340, 0.080320, -2.244440 },
{ 0.064875, -0.875355, 0.740968 }, { 0.057463, -1.609634, 1.646470 }, { 0.065358, -0.664627, 0.818029 }, { 0.078421, 0.011302, -1.294146 },
{ 0.077959, 0.627437, -0.684809 }, { 0.068811, 0.750083, 1.292086 }, { 0.071499, 0.844370, 0.820083 }, { 0.079242, 0.843008, -0.767747 },
{ 0.079871, 0.049410, -1.559573 }, { 0.074583, 0.687116, 0.056670 }, { 0.074556, 1.285580, 0.562082 }, { 0.075410, 0.757468, -0.054058 },
{ 0.056820, -0.262075, 2.903636 }, { 0.056290, -0.354120, 2.935505 }, { 0.054757, -0.443627, 3.174871 }, { 0.056529, -0.201492, 3.013897 },
{ 0.071368, 0.941992, 0.928360 }, { 0.070890, 0.941275, 1.025741 }, { 0.070886, 1.137012, 1.190092 }, { 0.071973, 1.066184, 0.908125 },
{ -0.027071, 0.095414, -2.584693 }, { -0.027210, -0.027466, -2.658910 }, { -0.028321, -0.171288, -2.551411 }, { -0.028822, -0.106571, -2.394578 },
{ -0.028003, 0.080791, -2.405887 }, { -0.025802, 0.279451, -2.691060 }, { -0.025903, 0.063562, -2.850603 }, { -0.027276, -0.225994, -2.811251 },
{ -0.028969, -0.367267, -2.582272 }, { -0.030033, -0.334095, -2.336454 }, { -0.029932, -0.118205, -2.176909 }, { -0.028560, 0.171350, -2.216261 },
{ -0.026866, 0.312623, -2.445242 }, { -0.029810, -0.134734, -2.215707 }, { -0.036872, -0.133292, -0.767341 }, { -0.043690, -0.893753, -0.005543 },
{ -0.051548, -0.892148, 1.605915 }, { -0.052152, -0.130171, 2.366227 }, { -0.055398, -0.024567, 3.119591 }, { -0.050837, 0.085279, 2.276668 },
{ -0.049471, -0.607258, 1.418378 }, { -0.043242, -0.608530, 0.140947 }, { -0.036429, 0.082337, -0.678202 }, { -0.028789, 0.080777, -2.244987 },
{ -0.047254, -0.874897, 0.740421 }, { -0.054666, -1.609177, 1.645923 }, { -0.046771, -0.664170, 0.817482 }, { -0.033708, 0.011759, -1.294693 },
{ -0.034170, 0.627894, -0.685356 }, { -0.043318, 0.750540, 1.291539 }, { -0.040630, 0.844827, 0.819536 }, { -0.032886, 0.843465, -0.768294 },
{ -0.032257, 0.049867, -1.560121 }, { -0.037545, 0.687573, 0.056123 }, { -0.037572, 1.286037, 0.561534 }, { -0.036718, 0.757925, -0.054605 },
{ -0.055308, -0.261618, 2.903088 }, { -0.055839, -0.353663, 2.934958 }, { -0.057372, -0.443170, 3.174324 }, { -0.055599, -0.201035, 3.013350 },
{ -0.040760, 0.942449, 0.927813 }, { -0.041238, 0.941732, 1.025193 }, { -0.041243, 1.137469, 1.189545 }, { -0.040155, 1.066641, 0.907578 },
};
global U16 dg_logo_model_tri_faces[] =
{
1, 13, 5, 2, 6, 1, 18, 20, 19, 17, 20, 18,
17, 21, 20, 16, 21, 17, 16, 22, 21, 16, 23, 22,
15, 23, 16, 15, 24, 23, 14, 24, 15, 1, 6, 13,
3, 4, 10, 2, 3, 8, 5, 13, 12, 4, 11, 10,
3, 9, 8, 2, 7, 6, 4, 5, 11, 5, 12, 11,
3, 10, 9, 2, 8, 7, 45, 49, 57, 46, 45, 50,
62, 63, 64, 61, 62, 64, 61, 64, 65, 60, 61, 65,
60, 65, 66, 60, 66, 67, 59, 60, 67, 59, 67, 68,
58, 59, 68, 45, 57, 50, 47, 54, 48, 46, 52, 47,
49, 56, 57, 48, 54, 55, 47, 52, 53, 46, 50, 51,
48, 55, 49, 49, 55, 56, 47, 53, 54, 46, 51, 52,
53, 8, 9, 54, 9, 10, 67, 22, 23, 55, 10, 11,
60, 15, 16, 63, 18, 19, 56, 11, 12, 57, 12, 13,
68, 23, 24, 64, 19, 20, 49, 1, 5, 62, 17, 18,
59, 14, 15, 45, 2, 1, 58, 24, 14, 46, 3, 2,
47, 4, 3, 65, 20, 21, 48, 5, 4, 61, 16, 17,
50, 13, 6, 51, 6, 7, 52, 7, 8, 66, 21, 22,
53, 52, 8, 54, 53, 9, 67, 66, 22, 55, 54, 10,
60, 59, 15, 63, 62, 18, 56, 55, 11, 57, 56, 12,
68, 67, 23, 64, 63, 19, 49, 45, 1, 62, 61, 17,
59, 58, 14, 45, 46, 2, 58, 68, 24, 46, 47, 3,
47, 48, 4, 65, 64, 20, 48, 49, 5, 61, 60, 16,
50, 57, 13, 51, 50, 6, 52, 51, 7, 66, 65, 21,
25, 27, 26, 69, 70, 71, 70, 25, 26, 71, 26, 27,
69, 27, 25, 70, 69, 25, 71, 70, 26, 69, 71, 27,
29, 31, 30, 29, 32, 31, 29, 33, 32, 28, 33, 29,
73, 74, 75, 73, 75, 76, 73, 76, 77, 72, 73, 77,
76, 31, 32, 77, 32, 33, 73, 28, 29, 72, 33, 28,
75, 30, 31, 74, 29, 30, 76, 75, 31, 77, 76, 32,
73, 72, 28, 72, 77, 33, 75, 74, 30, 74, 73, 29,
34, 36, 35, 78, 79, 80, 80, 35, 36, 79, 34, 35,
78, 36, 34, 80, 79, 35, 79, 78, 34, 78, 80, 36,
38, 40, 39, 38, 37, 40, 82, 83, 84, 82, 84, 81,
82, 37, 38, 84, 39, 40, 83, 38, 39, 81, 40, 37,
82, 81, 37, 84, 83, 39, 83, 82, 38, 81, 84, 40,
42, 44, 43, 41, 44, 42, 86, 87, 88, 85, 86, 88,
88, 43, 44, 87, 42, 43, 86, 41, 42, 85, 44, 41,
88, 87, 43, 87, 86, 42, 86, 85, 41, 85, 88, 44,
};
SubModel dg_logo_submodels[] =
{
{1, ArrayAndCount(dg_logo_model_tri_faces)},
};
Model dg_logo_model =
{
ArrayAndCount(dg_logo_model_vtx),
ArrayAndCount(dg_logo_submodels),
};

@ -0,0 +1,2 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.

@ -0,0 +1,60 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef RENDER_H
#define RENDER_H
////////////////////////////////
//~ rjf: Render Pass Parameters
typedef struct R_PassParams R_PassParams;
struct R_PassParams
{
Mat4x4F32 view;
Mat4x4F32 projection;
Vec3F32 keylight_dir;
};
////////////////////////////////
//~ rjf: Render Resource Types
typedef struct R_Material R_Material;
struct R_Material
{
Vec4F32 color;
};
typedef struct R_TriFace R_TriFace;
struct R_TriFace
{
U16 idx[3];
};
////////////////////////////////
//~ rjf: Render Handles
typedef struct R_BufferHandle R_BufferHandle;
struct R_BufferHandle
{
UAddr uaddr[1];
};
typedef struct R_SubModelHandle R_SubModelHandle;
struct R_SubModelHandle
{
UAddr uaddr[1];
};
////////////////////////////////
//~ rjf: Render Resources @per_platform
function R_BufferHandle R_BufferHandleFromData(void *data, UAddr element_count, UAddr element_size);
function R_SubModelHandle R_SubModelHandleFromBuffers(R_BufferHandle vtx_buffer, R_BufferHandle idx_buffer);
////////////////////////////////
//~ rjf: Render Commands @per_platform
function void R_Pass(R_PassParams *params);
function void R_SubModel(R_SubModelHandle handle, R_Material material, Mat4x4F32 xform);
#endif // RENDER_H

@ -0,0 +1,9 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#include "render.c"
#if PLATFORM_N64
# include "n64/render/n64_render.c"
#else
# error Platform-defined implementations for render layer not defined for this platform.
#endif

@ -0,0 +1,14 @@
// The Digital Grove Codebase
// Copyright (c) Ryan Fleury. All rights reserved.
#ifndef RENDER_INC_H
#define RENDER_INC_H
#include "render.h"
#if PLATFORM_N64
# include "n64/render/n64_render.h"
#else
# error Platform-defined implementations for render layer not defined for this platform.
#endif
#endif // RENDER_INC_H

@ -0,0 +1,72 @@
static const unsigned int crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
unsigned int crc32_update(unsigned int crc, const unsigned char *buffer, unsigned int len)
{
for (unsigned int i = 0; i < len; i++) {
crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
}
return crc;
}
unsigned int crc32(const unsigned char *buffer, unsigned int len)
{
unsigned int crc = 0xffffffffL;
for (int i=0; i<len; i++) {
crc = crc_table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);
}
return crc ^ 0xffffffffL;
}

@ -0,0 +1,540 @@
unsigned char default_ipl3[] = {
0x80, 0x37, 0x12, 0x40, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x69, 0x62, 0x64,
0x72, 0x61, 0x67, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x30, 0x44, 0xd2, 0x36, 0x3c, 0x1d, 0xa4, 0x00,
0x37, 0xbd, 0x0f, 0xf0, 0x27, 0xbd, 0xff, 0xe0, 0x00, 0x00, 0xd8, 0x25,
0xaf, 0xbf, 0x00, 0x1c, 0xaf, 0xb1, 0x00, 0x18, 0xaf, 0xb0, 0x00, 0x14,
0x04, 0x11, 0x02, 0x64, 0x40, 0x04, 0x48, 0x00, 0x3c, 0x02, 0xa4, 0x10,
0x04, 0x11, 0x02, 0x61, 0x8c, 0x44, 0x00, 0x10, 0x00, 0x00, 0x10, 0x25,
0x40, 0x82, 0x68, 0x00, 0x40, 0x82, 0x48, 0x00, 0x40, 0x82, 0x58, 0x00,
0x40, 0x82, 0x90, 0x00, 0x3c, 0x02, 0xa4, 0x30, 0x8c, 0x51, 0x00, 0x04,
0x24, 0x02, 0x00, 0xb0, 0x32, 0x31, 0x00, 0xf0, 0x12, 0x22, 0x00, 0x58,
0x3c, 0x02, 0xa4, 0x70, 0x8c, 0x42, 0x00, 0x0c, 0x10, 0x40, 0x00, 0x11,
0x00, 0x00, 0x80, 0x25, 0x3c, 0x02, 0x12, 0x34, 0x3c, 0x06, 0xa0, 0x00,
0x24, 0x42, 0x56, 0x78, 0x3c, 0x05, 0x00, 0x20, 0x3c, 0x04, 0x00, 0x80,
0x02, 0x06, 0x18, 0x21, 0xac, 0x60, 0x00, 0x00, 0xac, 0x62, 0x00, 0x00,
0x8c, 0x63, 0x00, 0x00, 0x54, 0x62, 0x00, 0x69, 0x24, 0x02, 0x00, 0x01,
0x02, 0x05, 0x80, 0x21, 0x16, 0x04, 0xff, 0xf9, 0x02, 0x06, 0x18, 0x21,
0x10, 0x00, 0x00, 0x64, 0x24, 0x02, 0x00, 0x01, 0x3c, 0x04, 0xa4, 0x00,
0x04, 0x11, 0x01, 0x3d, 0x24, 0x84, 0x03, 0xb4, 0x00, 0x40, 0x80, 0x25,
0x3c, 0x03, 0xb0, 0x00, 0x24, 0x66, 0x10, 0x40, 0x3c, 0x05, 0xa4, 0x60,
0x8c, 0xa2, 0x00, 0x10, 0x30, 0x42, 0x00, 0x03, 0x14, 0x40, 0xff, 0xfd,
0x00, 0x00, 0x00, 0x00, 0x8c, 0x62, 0x10, 0x40, 0x3c, 0x07, 0x60, 0x00,
0x02, 0x02, 0x20, 0x23, 0x3c, 0x03, 0x80, 0x00, 0x24, 0xe7, 0x00, 0x08,
0x00, 0xc7, 0x30, 0x21, 0x00, 0x83, 0x18, 0x21, 0xac, 0xa3, 0x00, 0x00,
0xac, 0xa6, 0x00, 0x04, 0x3c, 0x06, 0xa4, 0x04, 0x8c, 0xc5, 0x00, 0x18,
0x14, 0xa0, 0xff, 0xfe, 0x3c, 0x05, 0xa4, 0x60, 0x24, 0x42, 0xff, 0xff,
0xac, 0xa2, 0x00, 0x0c, 0x40, 0x80, 0xe0, 0x00, 0x40, 0x80, 0xe8, 0x00,
0x3c, 0x02, 0x80, 0x00, 0x24, 0x45, 0x20, 0x00, 0xbc, 0x49, 0x00, 0x00,
0xbc, 0x49, 0x00, 0x10, 0xbc, 0x49, 0x00, 0x20, 0xbc, 0x49, 0x00, 0x30,
0x24, 0x42, 0x00, 0x40, 0x14, 0x45, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x02, 0x80, 0x00, 0x24, 0x45, 0x40, 0x00, 0xbc, 0x48, 0x00, 0x00,
0xbc, 0x48, 0x00, 0x20, 0xbc, 0x48, 0x00, 0x40, 0xbc, 0x48, 0x00, 0x60,
0x24, 0x42, 0x00, 0x80, 0x14, 0x45, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00,
0x00, 0x14, 0x34, 0x00, 0x00, 0x13, 0x16, 0x00, 0x00, 0x46, 0x10, 0x25,
0x3a, 0x31, 0x00, 0xb0, 0x00, 0x15, 0x32, 0x00, 0x00, 0x46, 0x10, 0x25,
0x2e, 0x31, 0x00, 0x01, 0x3c, 0x05, 0xa4, 0x00, 0x00, 0x51, 0x10, 0x25,
0xac, 0xb0, 0x00, 0x00, 0xac, 0xa2, 0x00, 0x08, 0xac, 0xa0, 0x00, 0x0c,
0x3c, 0x05, 0xa4, 0x60, 0x8c, 0xa2, 0x00, 0x10, 0x30, 0x42, 0x00, 0x01,
0x14, 0x40, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x7f, 0xff,
0x34, 0x42, 0xff, 0xf0, 0x00, 0x82, 0x20, 0x21, 0x00, 0x60, 0x00, 0x08,
0x00, 0x80, 0xe8, 0x25, 0x3c, 0x02, 0xa0, 0x00, 0x8c, 0x50, 0x03, 0x18,
0x8c, 0x54, 0x03, 0x00, 0x8c, 0x55, 0x03, 0x0c, 0x3c, 0x02, 0x00, 0x80,
0x12, 0x02, 0x00, 0x33, 0x3c, 0x02, 0x00, 0x40, 0x16, 0x02, 0x00, 0x0c,
0x24, 0x02, 0x00, 0x20, 0x3c, 0x03, 0xa4, 0x60, 0x8c, 0x62, 0x00, 0x10,
0x30, 0x42, 0x00, 0x03, 0x14, 0x40, 0xff, 0xfd, 0x3c, 0x02, 0xb0, 0x00,
0x8c, 0x42, 0x00, 0x08, 0x3c, 0x03, 0x80, 0x40, 0x00, 0x43, 0x10, 0x2b,
0x50, 0x40, 0x00, 0x01, 0x3c, 0x10, 0x00, 0x80, 0x24, 0x02, 0x00, 0x20,
0x00, 0x00, 0x20, 0x25, 0x3c, 0x05, 0xa4, 0x30, 0x8c, 0xa3, 0x00, 0x2c,
0x00, 0x04, 0x20, 0x40, 0x30, 0x63, 0x00, 0x01, 0x24, 0x42, 0xff, 0xff,
0x14, 0x40, 0xff, 0xfb, 0x00, 0x64, 0x20, 0x25, 0x04, 0x11, 0x01, 0xe1,
0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x01, 0x16, 0xa2, 0x00, 0x05,
0x3c, 0x02, 0xa4, 0x04, 0x3c, 0x02, 0x80, 0x00, 0x04, 0x11, 0x01, 0xdb,
0x8c, 0x44, 0x01, 0xa4, 0x3c, 0x02, 0xa4, 0x04, 0x8c, 0x43, 0x00, 0x18,
0x14, 0x60, 0xff, 0xfe, 0x24, 0x03, 0x00, 0xb0, 0x52, 0x23, 0x00, 0x12,
0x3c, 0x02, 0xa4, 0x00, 0x24, 0x03, 0x10, 0x00, 0xac, 0x43, 0x00, 0x00,
0x3c, 0x03, 0x00, 0x80, 0x24, 0x63, 0x20, 0x00, 0xac, 0x43, 0x00, 0x04,
0x24, 0x03, 0x0f, 0xff, 0xac, 0x43, 0x00, 0x08, 0x3c, 0x05, 0xff, 0xff,
0x24, 0xa5, 0x7c, 0x00, 0x3c, 0x04, 0xa0, 0x00, 0x02, 0x05, 0x28, 0x21,
0x04, 0x11, 0x00, 0x17, 0x24, 0x84, 0x04, 0x00, 0x10, 0x00, 0xff, 0x89,
0x3c, 0x03, 0xb0, 0x00, 0x10, 0x00, 0xff, 0xd9, 0x3c, 0x10, 0x00, 0x7c,
0x24, 0x43, 0x10, 0x00, 0x24, 0x42, 0x20, 0x00, 0xac, 0x60, 0x00, 0x00,
0x24, 0x63, 0x00, 0x04, 0x54, 0x62, 0xff, 0xfe, 0xac, 0x60, 0x00, 0x00,
0x10, 0x00, 0xff, 0xf0, 0x3c, 0x05, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x4c, 0x69, 0x62, 0x64, 0x72, 0x61, 0x67,
0x6f, 0x6e, 0x20, 0x49, 0x50, 0x4c, 0x33, 0x20, 0x20, 0x43, 0x6f, 0x64,
0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x52, 0x61, 0x73, 0x6b, 0x79, 0x20,
0x3c, 0x02, 0xa0, 0x00, 0x00, 0x82, 0x20, 0x25, 0xb0, 0x80, 0x00, 0x00,
0xb4, 0x80, 0x00, 0x07, 0x28, 0xa2, 0x00, 0x09, 0x14, 0x40, 0x00, 0x19,
0x24, 0xa5, 0xff, 0xf8, 0x00, 0xa4, 0x10, 0x21, 0xb0, 0x40, 0x00, 0x00,
0xb4, 0x40, 0x00, 0x07, 0x3c, 0x09, 0x00, 0x10, 0x24, 0x84, 0x00, 0x08,
0x24, 0x0a, 0xf0, 0x00, 0x3c, 0x03, 0xa4, 0x04, 0x24, 0x08, 0x10, 0x00,
0x00, 0xa9, 0x30, 0x2a, 0x10, 0xc0, 0x00, 0x05, 0x3c, 0x02, 0x00, 0x10,
0x28, 0xa6, 0x10, 0x00, 0x14, 0xc0, 0x00, 0x02, 0x00, 0xa0, 0x10, 0x25,
0x00, 0xaa, 0x10, 0x24, 0x8c, 0x67, 0x00, 0x14, 0x14, 0xe0, 0xff, 0xfe,
0x24, 0x47, 0xff, 0xff, 0x00, 0xa2, 0x28, 0x23, 0xac, 0x68, 0x00, 0x00,
0xac, 0x64, 0x00, 0x04, 0xac, 0x67, 0x00, 0x0c, 0x1c, 0xa0, 0xff, 0xf1,
0x00, 0x82, 0x20, 0x21, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
0x24, 0x02, 0xff, 0xff, 0x14, 0x82, 0x00, 0x0c, 0x3c, 0x02, 0xa4, 0x04,
0x8c, 0x43, 0x00, 0x18, 0x14, 0x60, 0xff, 0xfe, 0x24, 0x03, 0x10, 0x00,
0xac, 0x43, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x80, 0x24, 0x63, 0x20, 0x00,
0xac, 0x43, 0x00, 0x04, 0x24, 0x03, 0x0f, 0xff, 0xac, 0x43, 0x00, 0x08,
0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x14, 0xa0, 0x00, 0x04,
0x00, 0x04, 0x25, 0x00, 0x3c, 0x05, 0x00, 0x20, 0x10, 0x00, 0xff, 0xcd,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x05, 0x00, 0x1f, 0x10, 0x00, 0xff, 0xfc,
0x34, 0xa5, 0x80, 0x00, 0x30, 0xa6, 0x00, 0x01, 0x50, 0xc0, 0x00, 0x05,
0x03, 0x44, 0x20, 0x04, 0x3c, 0x02, 0xa4, 0x30, 0x24, 0x03, 0x20, 0x00,
0xac, 0x43, 0x00, 0x00, 0x03, 0x44, 0x20, 0x04, 0x00, 0x85, 0x28, 0x21,
0x00, 0x05, 0x28, 0x80, 0x3c, 0x02, 0xa3, 0xf0, 0x00, 0x45, 0x10, 0x21,
0x8c, 0x43, 0x00, 0x00, 0x10, 0xc0, 0x00, 0x03, 0x24, 0x04, 0x10, 0x00,
0x3c, 0x02, 0xa4, 0x30, 0xac, 0x44, 0x00, 0x00, 0x00, 0x03, 0x26, 0x00,
0x00, 0x03, 0x16, 0x02, 0x00, 0x44, 0x10, 0x25, 0x00, 0x03, 0x22, 0x02,
0x30, 0x84, 0xff, 0x00, 0x00, 0x44, 0x10, 0x25, 0x00, 0x03, 0x1a, 0x00,
0x3c, 0x04, 0x00, 0xff, 0x00, 0x64, 0x18, 0x24, 0x03, 0xe0, 0x00, 0x08,
0x00, 0x62, 0x10, 0x25, 0x24, 0x02, 0x01, 0x00, 0x24, 0x42, 0xff, 0xff,
0x14, 0x40, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x1e, 0x00, 0x00, 0x06, 0x16, 0x02,
0x00, 0x43, 0x10, 0x25, 0x00, 0x06, 0x1a, 0x02, 0x30, 0x63, 0xff, 0x00,
0x00, 0x43, 0x10, 0x25, 0x00, 0x06, 0x32, 0x00, 0x3c, 0x03, 0x00, 0xff,
0x00, 0xc3, 0x30, 0x24, 0x00, 0xc2, 0x30, 0x25, 0x24, 0x02, 0xff, 0xff,
0x54, 0x82, 0x00, 0x07, 0x03, 0x44, 0x20, 0x04, 0x00, 0x05, 0x28, 0x80,
0x3c, 0x02, 0xa3, 0xf8, 0x00, 0x45, 0x10, 0x21, 0xac, 0x46, 0x00, 0x00,
0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x28, 0x21,
0x00, 0x05, 0x28, 0x80, 0x10, 0x00, 0xff, 0xf9, 0x3c, 0x02, 0xa3, 0xf0,
0x27, 0xbd, 0xff, 0xe8, 0x38, 0xc7, 0x00, 0x3f, 0x00, 0x80, 0x40, 0x25,
0xaf, 0xbf, 0x00, 0x14, 0x00, 0xa0, 0x48, 0x25, 0x10, 0xa0, 0x00, 0x02,
0x24, 0x06, 0x00, 0x46, 0x24, 0x06, 0x00, 0xc6, 0x3c, 0x03, 0x40, 0x00,
0x00, 0x07, 0x17, 0x80, 0x00, 0x43, 0x10, 0x24, 0x00, 0x07, 0x18, 0xc2,
0x00, 0x03, 0x1f, 0xc0, 0x00, 0x43, 0x10, 0x25, 0x3c, 0x04, 0x00, 0x40,
0x00, 0x07, 0x1d, 0x40, 0x00, 0x64, 0x18, 0x24, 0x00, 0x43, 0x10, 0x25,
0x00, 0x07, 0x1b, 0x00, 0x30, 0x63, 0x40, 0x00, 0x00, 0x43, 0x10, 0x25,
0x3c, 0x04, 0x00, 0x80, 0x00, 0x07, 0x1c, 0xc0, 0x00, 0x64, 0x18, 0x24,
0x00, 0x43, 0x10, 0x25, 0x00, 0x07, 0x1a, 0x80, 0x30, 0x63, 0x80, 0x00,
0x00, 0x43, 0x10, 0x25, 0x00, 0x46, 0x30, 0x25, 0x24, 0x05, 0x00, 0x03,
0x04, 0x11, 0xff, 0xca, 0x01, 0x00, 0x20, 0x25, 0x11, 0x20, 0x00, 0x1b,
0x8f, 0xbf, 0x00, 0x14, 0x24, 0x05, 0x00, 0x03, 0x04, 0x11, 0xff, 0xbf,
0x01, 0x00, 0x20, 0x25, 0x04, 0x11, 0xff, 0xa2, 0x00, 0x00, 0x00, 0x00,
0x24, 0x05, 0x00, 0x03, 0x04, 0x11, 0xff, 0x9f, 0x01, 0x00, 0x20, 0x25,
0x00, 0x02, 0x3f, 0x82, 0x00, 0x02, 0x1d, 0x42, 0x30, 0x63, 0x00, 0x02,
0x30, 0xe7, 0x00, 0x01, 0x00, 0xe3, 0x38, 0x25, 0x00, 0x02, 0x1b, 0x02,
0x30, 0x63, 0x00, 0x04, 0x00, 0xe3, 0x38, 0x25, 0x00, 0x02, 0x1f, 0x02,
0x30, 0x63, 0x00, 0x08, 0x00, 0xe3, 0x38, 0x25, 0x00, 0x02, 0x1c, 0xc2,
0x30, 0x63, 0x00, 0x10, 0x00, 0x02, 0x12, 0x82, 0x00, 0xe3, 0x38, 0x25,
0x30, 0x42, 0x00, 0x20, 0x00, 0xe2, 0x38, 0x25, 0x8f, 0xbf, 0x00, 0x14,
0x00, 0xe0, 0x10, 0x25, 0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x18,
0x27, 0xbd, 0xff, 0xb0, 0x3c, 0x03, 0xa4, 0x70, 0x24, 0x02, 0x00, 0x20,
0xaf, 0xbf, 0x00, 0x34, 0xaf, 0xb4, 0x00, 0x2c, 0xaf, 0xb3, 0x00, 0x28,
0xaf, 0xb2, 0x00, 0x24, 0xaf, 0xb0, 0x00, 0x1c, 0xe7, 0xb7, 0x00, 0x44,
0xaf, 0xb5, 0x00, 0x30, 0xaf, 0xb1, 0x00, 0x20, 0xe7, 0xb9, 0x00, 0x4c,
0xe7, 0xb8, 0x00, 0x48, 0xe7, 0xb6, 0x00, 0x40, 0xe7, 0xb5, 0x00, 0x3c,
0xe7, 0xb4, 0x00, 0x38, 0xac, 0x62, 0x00, 0x04, 0x04, 0x11, 0xff, 0x92,
0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x14, 0xac, 0x60, 0x00, 0x08,
0xac, 0x62, 0x00, 0x0c, 0xac, 0x60, 0x00, 0x00, 0x04, 0x11, 0xff, 0x8c,
0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x0e, 0xac, 0x62, 0x00, 0x00,
0x04, 0x11, 0xff, 0x88, 0x24, 0x03, 0x01, 0x0f, 0x3c, 0x02, 0xa4, 0x30,
0xac, 0x43, 0x00, 0x00, 0x3c, 0x02, 0x18, 0x08, 0x3c, 0x10, 0xa3, 0xf8,
0x24, 0x42, 0x28, 0x38, 0xae, 0x02, 0x00, 0x08, 0x00, 0x80, 0x98, 0x25,
0x00, 0x00, 0x28, 0x25, 0x24, 0x04, 0xff, 0xff, 0x02, 0x60, 0xf8, 0x09,
0x24, 0x1a, 0x00, 0x08, 0x3c, 0x06, 0x00, 0x03, 0x34, 0xc6, 0x80, 0xfc,
0x24, 0x05, 0x00, 0x01, 0x24, 0x04, 0xff, 0xff, 0x04, 0x11, 0xff, 0x7d,
0x3c, 0x14, 0xa4, 0x00, 0x3c, 0x02, 0x44, 0x00, 0xc6, 0x97, 0x09, 0xe4,
0xae, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x90, 0x25, 0xae, 0x00, 0x00, 0x14,
0x00, 0x00, 0x80, 0x25, 0x00, 0x10, 0x30, 0x80, 0x24, 0x05, 0x00, 0x01,
0x04, 0x11, 0xff, 0x73, 0x24, 0x04, 0x01, 0xff, 0x24, 0x06, 0x00, 0x46,
0x24, 0x05, 0x00, 0x03, 0x04, 0x11, 0xff, 0x6f, 0x02, 0x00, 0x20, 0x25,
0x24, 0x05, 0x00, 0x03, 0x04, 0x11, 0xff, 0x4b, 0x02, 0x00, 0x20, 0x25,
0x30, 0x42, 0x00, 0x02, 0x14, 0x40, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x05, 0x00, 0x10, 0x80, 0x43, 0x24, 0x05, 0x00, 0x01,
0x02, 0x60, 0xf8, 0x09, 0x26, 0x04, 0xff, 0xfe, 0x00, 0x10, 0x80, 0x43,
0x24, 0x02, 0x00, 0x01, 0x02, 0x02, 0x10, 0x04, 0x24, 0x42, 0xff, 0xff,
0x3c, 0x03, 0x00, 0x06, 0x24, 0x63, 0x36, 0x34, 0x00, 0x02, 0x14, 0xc0,
0x00, 0x43, 0x10, 0x25, 0x8f, 0xbf, 0x00, 0x34, 0x3c, 0x03, 0xa4, 0x70,
0xac, 0x62, 0x00, 0x10, 0x8c, 0x62, 0x00, 0x10, 0x8f, 0xb5, 0x00, 0x30,
0x8f, 0xb4, 0x00, 0x2c, 0x8f, 0xb3, 0x00, 0x28, 0x8f, 0xb1, 0x00, 0x20,
0x8f, 0xb0, 0x00, 0x1c, 0xc7, 0xb9, 0x00, 0x4c, 0xc7, 0xb8, 0x00, 0x48,
0xc7, 0xb7, 0x00, 0x44, 0xc7, 0xb6, 0x00, 0x40, 0xc7, 0xb5, 0x00, 0x3c,
0xc7, 0xb4, 0x00, 0x38, 0x02, 0x40, 0x10, 0x25, 0x8f, 0xb2, 0x00, 0x24,
0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x50, 0x16, 0x00, 0x00, 0x44,
0x00, 0x00, 0x28, 0x25, 0x44, 0x80, 0xa0, 0x00, 0x3c, 0x02, 0xa4, 0x00,
0x3c, 0x11, 0xa0, 0x00, 0xc4, 0x59, 0x09, 0xe8, 0x02, 0x51, 0x88, 0x21,
0x46, 0x00, 0xa5, 0x86, 0x00, 0x00, 0xa8, 0x25, 0x46, 0x00, 0xa6, 0x06,
0x02, 0x00, 0x20, 0x25, 0x32, 0xa6, 0x00, 0xff, 0x44, 0x80, 0xa8, 0x00,
0x04, 0x11, 0xff, 0x51, 0x00, 0x00, 0x28, 0x25, 0x24, 0x03, 0x00, 0x0a,
0x24, 0x04, 0xff, 0xff, 0xae, 0x24, 0x00, 0x00, 0xae, 0x24, 0x00, 0x04,
0x92, 0x22, 0x00, 0x05, 0x30, 0x42, 0x00, 0xff, 0xa3, 0xa2, 0x00, 0x10,
0x93, 0xa2, 0x00, 0x10, 0x30, 0x42, 0x00, 0xff, 0x14, 0x40, 0x00, 0x33,
0x00, 0x00, 0x00, 0x00, 0x24, 0x63, 0xff, 0xff, 0x14, 0x60, 0xff, 0xf5,
0x00, 0x00, 0x00, 0x00, 0x46, 0x15, 0xc0, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x45, 0x02, 0x00, 0x05, 0x46, 0x19, 0xad, 0x42, 0x8e, 0x24, 0x00, 0x04,
0x04, 0x11, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x46, 0x19, 0xad, 0x42,
0x44, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x80, 0x00, 0x20,
0x46, 0x16, 0xad, 0x81, 0x46, 0x00, 0xb5, 0x82, 0xc6, 0x80, 0x09, 0xe4,
0x46, 0x15, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x05,
0x46, 0x16, 0xa5, 0x00, 0x26, 0xb5, 0x00, 0x01, 0x24, 0x02, 0x00, 0x40,
0x56, 0xa2, 0xff, 0xd8, 0x46, 0x00, 0xad, 0x86, 0x3c, 0x02, 0xa4, 0x00,
0xc4, 0x40, 0x09, 0xec, 0x3c, 0x02, 0xa4, 0x00, 0x46, 0x00, 0xa5, 0x02,
0xc4, 0x40, 0x09, 0xf0, 0x46, 0x00, 0xa5, 0x00, 0x46, 0x00, 0xa0, 0x0d,
0x44, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x40, 0x00, 0x17,
0x00, 0x00, 0x60, 0x25, 0x3c, 0x06, 0x00, 0x03, 0x34, 0xc6, 0x80, 0xf4,
0x24, 0x05, 0x00, 0x01, 0x04, 0x11, 0xff, 0x06, 0x02, 0x00, 0x20, 0x25,
0x10, 0x00, 0xff, 0xa2, 0x00, 0x10, 0x80, 0x43, 0x02, 0x60, 0xf8, 0x09,
0x26, 0x04, 0xff, 0xfe, 0x24, 0x02, 0x00, 0x08, 0x16, 0x02, 0xff, 0xb9,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0x9b, 0x00, 0x10, 0x80, 0x43,
0x93, 0xa2, 0x00, 0x10, 0x30, 0x42, 0x00, 0x01, 0x54, 0x40, 0x00, 0x01,
0x46, 0x17, 0xad, 0x40, 0x93, 0xa2, 0x00, 0x10, 0x30, 0x42, 0x00, 0xff,
0x10, 0x00, 0xff, 0xc2, 0x00, 0x02, 0x10, 0x42, 0x00, 0x00, 0x68, 0x25,
0x00, 0x00, 0x58, 0x25, 0x24, 0x0e, 0x00, 0x40, 0x02, 0x00, 0x20, 0x25,
0x31, 0x66, 0x00, 0xff, 0x04, 0x11, 0xff, 0x05, 0x24, 0x05, 0x00, 0x01,
0x00, 0x4a, 0x18, 0x23, 0x00, 0x03, 0x27, 0xc3, 0x00, 0x83, 0x18, 0x26,
0x11, 0x60, 0x00, 0x3a, 0x00, 0x64, 0x18, 0x23, 0x00, 0x6d, 0x20, 0x2a,
0x54, 0x80, 0x00, 0x02, 0x01, 0x60, 0x60, 0x25, 0x01, 0xa0, 0x18, 0x25,
0x01, 0x42, 0x10, 0x2a, 0x14, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
0x25, 0x6b, 0x00, 0x01, 0x15, 0x6e, 0xff, 0xee, 0x00, 0x60, 0x68, 0x25,
0x11, 0x80, 0xff, 0xd3, 0x31, 0x86, 0x00, 0xff, 0x24, 0x05, 0x00, 0x01,
0x04, 0x11, 0xfe, 0xf1, 0x02, 0x00, 0x20, 0x25, 0x00, 0x00, 0x28, 0x25,
0x04, 0x11, 0xfe, 0xb6, 0x02, 0x00, 0x20, 0x25, 0x00, 0x40, 0x38, 0x25,
0x30, 0x43, 0xf0, 0x00, 0x24, 0x02, 0x10, 0x00, 0x14, 0x62, 0xff, 0xc8,
0x30, 0xe2, 0x0f, 0x00, 0x24, 0x03, 0x09, 0x00, 0x14, 0x43, 0xff, 0xc5,
0x30, 0xe2, 0x00, 0xf0, 0x24, 0x03, 0x00, 0xb0, 0x14, 0x43, 0xff, 0xc2,
0x30, 0xe2, 0x00, 0x04, 0x10, 0x40, 0xff, 0xc0, 0x24, 0x05, 0x00, 0x09,
0x04, 0x11, 0xfe, 0xa7, 0x02, 0x00, 0x20, 0x25, 0x00, 0x02, 0x14, 0x02,
0x24, 0x03, 0x00, 0x05, 0x10, 0x43, 0x00, 0x17, 0x3c, 0x06, 0x04, 0x0a,
0x30, 0xe7, 0x00, 0x01, 0x14, 0xe0, 0x00, 0x03, 0x24, 0xc6, 0x1c, 0x10,
0x3c, 0x06, 0x04, 0x12, 0x24, 0xc6, 0x0c, 0x08, 0x24, 0x05, 0x00, 0x06,
0x04, 0x11, 0xfe, 0xbc, 0x02, 0x00, 0x20, 0x25, 0x3c, 0x02, 0xa0, 0x20,
0x3c, 0x03, 0x00, 0x08, 0x02, 0x42, 0x10, 0x21, 0x8e, 0x24, 0x00, 0x00,
0x8e, 0x24, 0x00, 0x04, 0x02, 0x23, 0x88, 0x21, 0x14, 0x51, 0xff, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x20, 0x26, 0x10, 0x00, 0x02,
0x10, 0x00, 0xff, 0x3a, 0x02, 0x42, 0x90, 0x21, 0x10, 0x00, 0xff, 0xca,
0x00, 0x00, 0x60, 0x25, 0x10, 0x00, 0xff, 0xee, 0x24, 0xc6, 0x1c, 0x10,
0x3f, 0x80, 0x00, 0x00, 0x3c, 0x4c, 0xcc, 0xcd, 0x40, 0x0c, 0xcc, 0xcd,
0x3f, 0x00, 0x00, 0x00, 0x3c, 0x02, 0xcc, 0x9e, 0x24, 0x42, 0x2d, 0x51,
0x00, 0x82, 0x00, 0x18, 0x00, 0x00, 0x10, 0x12, 0x00, 0x02, 0x1c, 0x42,
0x00, 0x02, 0x13, 0xc0, 0x00, 0x43, 0x10, 0x25, 0x3c, 0x03, 0x1b, 0x87,
0x24, 0x63, 0x35, 0x93, 0x00, 0x43, 0x00, 0x18, 0x00, 0x00, 0x10, 0x12,
0x00, 0x5b, 0x10, 0x26, 0x00, 0x02, 0x1c, 0xc2, 0x00, 0x02, 0x13, 0x40,
0x00, 0x62, 0x10, 0x25, 0x00, 0x02, 0x18, 0x80, 0x00, 0x62, 0x18, 0x21,
0x3c, 0x02, 0xe6, 0x54, 0x24, 0x42, 0x6b, 0x64, 0x03, 0xe0, 0x00, 0x08,
0x00, 0x62, 0xd8, 0x21, 0x00, 0x1b, 0x1c, 0x02, 0x3c, 0x02, 0x85, 0xeb,
0x00, 0x7b, 0x18, 0x26, 0x34, 0x42, 0xca, 0x6b, 0x00, 0x62, 0x00, 0x18,
0x00, 0x00, 0x10, 0x12, 0x00, 0x02, 0x1b, 0x42, 0x00, 0x62, 0x18, 0x26,
0x3c, 0x02, 0xc2, 0xb2, 0x34, 0x42, 0xae, 0x35, 0x00, 0x62, 0x00, 0x18,
0x00, 0x00, 0x10, 0x12, 0x00, 0x02, 0x1c, 0x02, 0x03, 0xe0, 0x00, 0x08,
0x00, 0x62, 0x10, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x17,
0xc4, 0x1d, 0x1c, 0xf5, 0x3c, 0x0a, 0xb0, 0x00, 0x3c, 0x09, 0xa4, 0x00,
0x25, 0x4b, 0x0f, 0xc0, 0x25, 0x3d, 0x1f, 0xf0, 0x8d, 0x5f, 0x00, 0x40,
0xad, 0x3f, 0x00, 0x40, 0x25, 0x4a, 0x00, 0x04, 0x15, 0x4b, 0xff, 0xfc,
0x25, 0x29, 0x00, 0x04, 0x00, 0x00, 0x48, 0x25, 0x24, 0x0a, 0x00, 0x40,
0x27, 0xab, 0xe0, 0x50, 0x01, 0x60, 0x00, 0x08, 0x27, 0xbf, 0xf5, 0x60,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe8,
0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xa0, 0x3c, 0x07, 0x10, 0x00,
0x3c, 0x03, 0x7f, 0x45, 0x3c, 0x02, 0x14, 0x00, 0x3c, 0x04, 0xa0, 0x00,
0xaf, 0xbe, 0x00, 0x58, 0xaf, 0xb3, 0x00, 0x44, 0xaf, 0xbf, 0x00, 0x5c,
0xaf, 0xb7, 0x00, 0x54, 0xaf, 0xb6, 0x00, 0x50, 0xaf, 0xb5, 0x00, 0x4c,
0xaf, 0xb4, 0x00, 0x48, 0xaf, 0xb2, 0x00, 0x40, 0xaf, 0xb1, 0x00, 0x3c,
0xaf, 0xb0, 0x00, 0x38, 0x03, 0xa0, 0xf0, 0x25, 0x24, 0xf3, 0x10, 0x00,
0x24, 0x63, 0x4c, 0x46, 0x24, 0x42, 0x10, 0x00, 0x02, 0x64, 0x28, 0x25,
0x8c, 0xa5, 0x00, 0x00, 0x50, 0xa3, 0x00, 0xfa, 0x00, 0x13, 0x12, 0x00,
0x26, 0x73, 0x01, 0x00, 0x16, 0x62, 0xff, 0xfb, 0x02, 0x64, 0x28, 0x25,
0x3c, 0x04, 0xb0, 0x00, 0x10, 0x00, 0x01, 0x01, 0x24, 0x84, 0x17, 0x55,
0x16, 0x22, 0x00, 0x7c, 0x24, 0x14, 0x00, 0x20, 0x24, 0x14, 0x00, 0x38,
0x24, 0x02, 0x00, 0x24, 0x3c, 0x04, 0xa0, 0x00, 0x00, 0x53, 0x10, 0x21,
0x00, 0x44, 0x10, 0x25, 0x24, 0x04, 0x00, 0x02, 0x8c, 0x48, 0x00, 0x00,
0x16, 0x24, 0x00, 0x02, 0x24, 0x02, 0x00, 0x2c, 0x24, 0x02, 0x00, 0x38,
0x3c, 0x04, 0xa0, 0x00, 0x00, 0x53, 0x10, 0x21, 0x00, 0x44, 0x10, 0x25,
0x8c, 0x42, 0x00, 0x00, 0x24, 0x04, 0x00, 0x02, 0x00, 0x02, 0x14, 0x02,
0xaf, 0xc2, 0x00, 0x10, 0x16, 0x24, 0x00, 0x02, 0x24, 0x02, 0x00, 0x18,
0x24, 0x02, 0x00, 0x1c, 0x3c, 0x04, 0xa4, 0x00, 0x8c, 0x83, 0x00, 0x00,
0x00, 0x53, 0x10, 0x21, 0x3c, 0x04, 0xa0, 0x00, 0x00, 0x44, 0x10, 0x25,
0x8c, 0x42, 0x00, 0x00, 0xaf, 0xc3, 0x00, 0x28, 0xaf, 0xc2, 0x00, 0x2c,
0x8f, 0xc2, 0x00, 0x10, 0x01, 0x13, 0x40, 0x21, 0x00, 0x54, 0x00, 0x18,
0x00, 0x00, 0x30, 0x12, 0x24, 0xc2, 0x00, 0x10, 0x03, 0xa2, 0xe8, 0x23,
0x27, 0xb0, 0x00, 0x10, 0x00, 0x10, 0x10, 0x23, 0x30, 0x42, 0x00, 0x0f,
0x02, 0x02, 0x80, 0x21, 0x00, 0xc0, 0x28, 0x25, 0x04, 0x11, 0x00, 0xd8,
0x02, 0x00, 0x20, 0x25, 0x3c, 0x02, 0xa4, 0x60, 0x8c, 0x44, 0x00, 0x10,
0x30, 0x84, 0x00, 0x03, 0x14, 0x80, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00,
0x24, 0xc6, 0xff, 0xff, 0xac, 0x50, 0x00, 0x00, 0xac, 0x48, 0x00, 0x04,
0xac, 0x46, 0x00, 0x0c, 0x04, 0x11, 0x01, 0x36, 0x00, 0x00, 0x00, 0x00,
0x24, 0x03, 0x00, 0x04, 0x3a, 0x22, 0x00, 0x02, 0x14, 0x40, 0x00, 0x03,
0xaf, 0xc3, 0x00, 0x14, 0x24, 0x03, 0x00, 0x0c, 0xaf, 0xc3, 0x00, 0x14,
0x24, 0x03, 0x00, 0x08, 0x14, 0x40, 0x00, 0x03, 0xaf, 0xc3, 0x00, 0x18,
0x24, 0x03, 0x00, 0x14, 0xaf, 0xc3, 0x00, 0x18, 0x24, 0x03, 0x00, 0x0c,
0x14, 0x40, 0x00, 0x03, 0xaf, 0xc3, 0x00, 0x1c, 0x24, 0x03, 0x00, 0x1c,
0xaf, 0xc3, 0x00, 0x1c, 0x24, 0x03, 0x00, 0x10, 0x14, 0x40, 0x00, 0x03,
0xaf, 0xc3, 0x00, 0x20, 0x24, 0x03, 0x00, 0x24, 0xaf, 0xc3, 0x00, 0x20,
0x24, 0x03, 0x00, 0x14, 0x14, 0x40, 0x00, 0x03, 0xaf, 0xc3, 0x00, 0x24,
0x24, 0x03, 0x00, 0x2c, 0xaf, 0xc3, 0x00, 0x24, 0x14, 0x40, 0x00, 0x02,
0x24, 0x17, 0x00, 0x18, 0x24, 0x17, 0x00, 0x04, 0x3c, 0x02, 0xa4, 0x00,
0x24, 0x42, 0x03, 0x30, 0x00, 0x00, 0x90, 0x25, 0x00, 0x00, 0x88, 0x25,
0xaf, 0xc2, 0x00, 0x30, 0xaf, 0xd4, 0x00, 0x34, 0x8f, 0xc2, 0x00, 0x10,
0x02, 0x42, 0x10, 0x2a, 0x54, 0x40, 0x00, 0x23, 0x8f, 0xc2, 0x00, 0x14,
0x3c, 0x02, 0x00, 0xaa, 0x3c, 0x03, 0xa4, 0x04, 0x34, 0x42, 0xaa, 0x0e,
0xac, 0x62, 0x00, 0x10, 0x3c, 0x02, 0xa4, 0x08, 0xac, 0x40, 0x00, 0x00,
0xac, 0x60, 0x00, 0x1c, 0x3c, 0x02, 0xa4, 0x30, 0x24, 0x03, 0x05, 0x55,
0xac, 0x43, 0x00, 0x0c, 0x24, 0x04, 0x00, 0x02, 0xac, 0x43, 0x00, 0x08,
0x3c, 0x03, 0xa4, 0x60, 0xac, 0x64, 0x00, 0x10, 0x3c, 0x03, 0xa4, 0x80,
0xac, 0x60, 0x00, 0x18, 0x3c, 0x03, 0xa4, 0x50, 0xac, 0x60, 0x00, 0x0c,
0x24, 0x03, 0x08, 0x00, 0xac, 0x43, 0x00, 0x00, 0x3c, 0x02, 0xa4, 0x00,
0x24, 0x42, 0x0a, 0x48, 0x00, 0x40, 0xf8, 0x09, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x03, 0xa4, 0x00, 0xac, 0x62, 0x00, 0x04, 0x3c, 0x03, 0x80, 0x00,
0xac, 0x62, 0x01, 0xa4, 0x3c, 0x02, 0xb0, 0x00, 0x24, 0x42, 0x18, 0x28,
0x00, 0x40, 0xf8, 0x09, 0x8f, 0xc4, 0x00, 0x2c, 0x10, 0x00, 0xff, 0x86,
0x24, 0x02, 0x00, 0x1c, 0x3c, 0x03, 0x64, 0xe3, 0x02, 0x02, 0x10, 0x21,
0x8c, 0x49, 0x00, 0x00, 0x8f, 0xc2, 0x00, 0x18, 0x24, 0x64, 0x63, 0x41,
0x02, 0x02, 0x10, 0x21, 0x8c, 0x54, 0x00, 0x00, 0x8f, 0xc2, 0x00, 0x1c,
0x02, 0x02, 0x10, 0x21, 0x8c, 0x55, 0x00, 0x00, 0x8f, 0xc2, 0x00, 0x20,
0x02, 0x02, 0x10, 0x21, 0x8c, 0x56, 0x00, 0x00, 0x8f, 0xc2, 0x00, 0x24,
0x02, 0x02, 0x10, 0x21, 0x8c, 0x4a, 0x00, 0x00, 0x02, 0x17, 0x10, 0x21,
0x8c, 0x4b, 0x00, 0x00, 0x8e, 0x02, 0x00, 0x00, 0x14, 0x44, 0x00, 0x14,
0x24, 0x04, 0x00, 0x01, 0x16, 0x80, 0x00, 0x14, 0x02, 0x80, 0x88, 0x25,
0x26, 0xc2, 0x00, 0x17, 0x00, 0x02, 0x10, 0xc2, 0x00, 0x02, 0x10, 0xc0,
0x03, 0xa2, 0xe8, 0x23, 0x27, 0xb1, 0x00, 0x10, 0x00, 0x11, 0x10, 0x23,
0x30, 0x42, 0x00, 0x0f, 0x02, 0x22, 0x88, 0x21, 0x02, 0xc0, 0x28, 0x25,
0x04, 0x11, 0x00, 0x62, 0x02, 0x20, 0x20, 0x25, 0x16, 0xc0, 0x00, 0x0e,
0x02, 0x20, 0xa0, 0x25, 0x8f, 0xc2, 0x00, 0x34, 0x26, 0x52, 0x00, 0x01,
0x10, 0x00, 0xff, 0xb3, 0x02, 0x02, 0x80, 0x21, 0x14, 0x44, 0xff, 0xfc,
0x8f, 0xc2, 0x00, 0x34, 0x12, 0xc0, 0xff, 0xf9, 0x32, 0x82, 0x00, 0x07,
0x10, 0x40, 0x00, 0x05, 0x31, 0x22, 0x00, 0x01, 0x3c, 0x04, 0xb0, 0x00,
0x10, 0x00, 0x00, 0x51, 0x24, 0x84, 0x17, 0x18, 0x31, 0x22, 0x00, 0x01,
0x50, 0x40, 0x00, 0x04, 0x31, 0x64, 0x10, 0x00, 0x3c, 0x04, 0xb0, 0x00,
0x10, 0x00, 0x00, 0x4b, 0x24, 0x84, 0x16, 0xfa, 0x10, 0x80, 0x00, 0x02,
0x02, 0x80, 0x10, 0x25, 0x02, 0xa0, 0x10, 0x25, 0x8f, 0xc3, 0x00, 0x28,
0x3c, 0x05, 0x80, 0x00, 0x00, 0x4a, 0x10, 0x21, 0x00, 0x65, 0x28, 0x21,
0x00, 0xa2, 0x10, 0x2b, 0x10, 0x40, 0x00, 0x04, 0x24, 0x05, 0xff, 0xfe,
0x3c, 0x04, 0xb0, 0x00, 0x10, 0x00, 0x00, 0x3e, 0x24, 0x84, 0x16, 0xe4,
0x26, 0xc2, 0x00, 0x01, 0x00, 0x45, 0x10, 0x24, 0x01, 0x33, 0x48, 0x21,
0x3c, 0x05, 0xa4, 0x60, 0x8c, 0xaa, 0x00, 0x10, 0x31, 0x4a, 0x00, 0x03,
0x15, 0x40, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0xff,
0xac, 0xb4, 0x00, 0x00, 0xac, 0xa9, 0x00, 0x04, 0xac, 0xa2, 0x00, 0x0c,
0x10, 0x80, 0x00, 0x16, 0x02, 0xc0, 0x28, 0x25, 0x02, 0x80, 0x20, 0x25,
0x02, 0x20, 0xf8, 0x09, 0x02, 0xa0, 0x30, 0x25, 0x00, 0x40, 0x28, 0x25,
0x02, 0xa0, 0x20, 0x25, 0x04, 0x11, 0x00, 0x2b, 0x00, 0x40, 0x48, 0x25,
0x02, 0x95, 0x10, 0x2b, 0x10, 0x40, 0x00, 0x10, 0x02, 0xd4, 0x18, 0x21,
0x02, 0xa3, 0x10, 0x2b, 0x54, 0x40, 0x00, 0x01, 0x02, 0xa0, 0x18, 0x25,
0x00, 0x74, 0x30, 0x23, 0x00, 0xc0, 0x28, 0x25, 0x04, 0x11, 0x00, 0x21,
0x02, 0x80, 0x20, 0x25, 0x8f, 0xc2, 0x00, 0x30, 0x00, 0xc0, 0x28, 0x25,
0x00, 0x40, 0xf8, 0x09, 0x02, 0x80, 0x20, 0x25, 0x04, 0x11, 0x00, 0x84,
0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xff, 0xbb, 0x8f, 0xc2, 0x00, 0x34,
0x01, 0x35, 0x10, 0x21, 0x00, 0x43, 0x20, 0x2b, 0x10, 0x80, 0xff, 0xf9,
0x00, 0x00, 0x00, 0x00, 0x02, 0x82, 0x20, 0x2b, 0x54, 0x80, 0xff, 0xee,
0x00, 0x40, 0xa0, 0x25, 0x10, 0x00, 0xff, 0xed, 0x00, 0x74, 0x30, 0x23,
0x3c, 0x03, 0xa4, 0x00, 0xac, 0x62, 0x00, 0x0c, 0x26, 0x62, 0x00, 0x04,
0x00, 0x44, 0x10, 0x25, 0x8c, 0x42, 0x00, 0x00, 0x3c, 0x03, 0x00, 0xff,
0x00, 0x02, 0x8e, 0x02, 0x00, 0x43, 0x10, 0x24, 0x3c, 0x03, 0x00, 0x01,
0x14, 0x43, 0xff, 0x03, 0x24, 0x02, 0x00, 0x02, 0x3c, 0x04, 0xb0, 0x00,
0x24, 0x84, 0x17, 0x35, 0x04, 0x11, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
0x24, 0x03, 0xff, 0xf0, 0x00, 0x83, 0x18, 0x24, 0x00, 0x83, 0x20, 0x23,
0x00, 0x85, 0x20, 0x21, 0x00, 0x00, 0x10, 0x25, 0x00, 0x44, 0x28, 0x2a,
0x14, 0xa0, 0x00, 0x03, 0x00, 0x43, 0x28, 0x21, 0x03, 0xe0, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0xbc, 0xb5, 0x00, 0x00, 0x10, 0x00, 0xff, 0xf9,
0x24, 0x42, 0x00, 0x10, 0x24, 0x02, 0xff, 0xfc, 0x00, 0x82, 0x10, 0x24,
0x3c, 0x03, 0xa0, 0x00, 0x00, 0x43, 0x10, 0x25, 0x8c, 0x42, 0x00, 0x00,
0x00, 0x04, 0x20, 0x27, 0x00, 0x04, 0x20, 0xc0, 0x00, 0x82, 0x10, 0x06,
0x03, 0xe0, 0x00, 0x08, 0x30, 0x42, 0x00, 0xff, 0x27, 0xbd, 0xff, 0xe8,
0x3c, 0x02, 0xa4, 0x40, 0x3c, 0x03, 0xa0, 0x10, 0xaf, 0xbf, 0x00, 0x14,
0xac, 0x43, 0x00, 0x04, 0x3c, 0x03, 0xa0, 0x12, 0x00, 0x80, 0x38, 0x25,
0x3c, 0x02, 0xa0, 0x10, 0x24, 0x04, 0xc9, 0x50, 0x24, 0x63, 0x58, 0x00,
0xa4, 0x44, 0x00, 0x00, 0x24, 0x42, 0x00, 0x02, 0x54, 0x43, 0xff, 0xfe,
0xa4, 0x44, 0x00, 0x00, 0x3c, 0x02, 0xa4, 0x40, 0x24, 0x03, 0x01, 0x40,
0xac, 0x43, 0x00, 0x08, 0x24, 0x03, 0x02, 0x00, 0xac, 0x43, 0x00, 0x30,
0x3c, 0x06, 0xa0, 0x10, 0x24, 0x03, 0x04, 0x00, 0x3c, 0x08, 0xb0, 0x00,
0xac, 0x43, 0x00, 0x34, 0x24, 0xc6, 0x64, 0x50, 0x25, 0x08, 0x17, 0x6c,
0x24, 0x0b, 0xf7, 0xb2, 0x04, 0x11, 0xff, 0xdb, 0x00, 0xe0, 0x20, 0x25,
0x00, 0x02, 0x1e, 0x00, 0x00, 0x03, 0x1e, 0x03, 0x10, 0x40, 0x00, 0x18,
0x24, 0xe7, 0x00, 0x01, 0x24, 0x62, 0xff, 0xff, 0x00, 0x02, 0x28, 0x80,
0x00, 0xa2, 0x28, 0x21, 0x01, 0x05, 0x28, 0x21, 0x24, 0xac, 0x00, 0x05,
0x00, 0xc0, 0x48, 0x25, 0x24, 0x0d, 0x00, 0x08, 0x04, 0x11, 0xff, 0xce,
0x00, 0xa0, 0x20, 0x25, 0x01, 0x20, 0x20, 0x25, 0x00, 0x00, 0x18, 0x25,
0x00, 0x62, 0x50, 0x07, 0x31, 0x4a, 0x00, 0x01, 0x55, 0x40, 0x00, 0x01,
0xa4, 0x8b, 0x00, 0x00, 0x24, 0x63, 0x00, 0x01, 0x14, 0x6d, 0xff, 0xfa,
0x24, 0x84, 0x02, 0x80, 0x24, 0xa5, 0x00, 0x01, 0x14, 0xac, 0xff, 0xf3,
0x25, 0x29, 0x00, 0x02, 0x10, 0x00, 0xff, 0xe4, 0x24, 0xc6, 0x00, 0x0e,
0x3c, 0x06, 0xa4, 0x00, 0x04, 0x11, 0xff, 0xbd, 0x24, 0xc4, 0x00, 0x09,
0x00, 0x40, 0x28, 0x25, 0x04, 0x11, 0xff, 0xba, 0x24, 0xc4, 0x00, 0x0b,
0x00, 0x05, 0x20, 0xc0, 0x00, 0x85, 0x20, 0x23, 0x3c, 0x03, 0xb0, 0x00,
0x00, 0x04, 0x20, 0x80, 0x24, 0x63, 0x16, 0x90, 0x00, 0x64, 0x18, 0x21,
0x3c, 0x04, 0xa4, 0x40, 0x24, 0x85, 0x00, 0x14, 0x24, 0x84, 0x00, 0x30,
0x8c, 0x66, 0x00, 0x00, 0x24, 0xa5, 0x00, 0x04, 0xac, 0xa6, 0xff, 0xfc,
0x14, 0xa4, 0xff, 0xfc, 0x24, 0x63, 0x00, 0x04, 0x10, 0x40, 0x00, 0x02,
0x24, 0x03, 0x32, 0x02, 0x24, 0x03, 0x12, 0x02, 0x3c, 0x02, 0xa4, 0x40,
0xac, 0x43, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x03, 0xa4, 0x60, 0x8c, 0x62, 0x00, 0x10, 0x30, 0x42, 0x00, 0x03,
0x14, 0x40, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x48, 0x00,
0x3c, 0x19, 0xa4, 0x00, 0x27, 0x39, 0x09, 0xf4, 0x03, 0x20, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x23, 0x3a, 0x00, 0x00, 0x02, 0x71,
0x00, 0x15, 0x0c, 0x69, 0x0c, 0x6f, 0x0c, 0x6e, 0x00, 0x80, 0x03, 0x00,
0x00, 0x5f, 0x02, 0x39, 0x00, 0x09, 0x02, 0x6b, 0x03, 0xe5, 0x22, 0x39,
0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x0c, 0x15, 0x0c, 0x15, 0x0c, 0x15,
0x00, 0x6c, 0x02, 0xec, 0x00, 0x25, 0x01, 0xff, 0x00, 0x0e, 0x02, 0x04,
0x04, 0x65, 0x1e, 0x39, 0x00, 0x00, 0x02, 0x0d, 0x00, 0x04, 0x0c, 0x11,
0x0c, 0x19, 0x0c, 0x1a, 0x00, 0x6c, 0x02, 0xec, 0x00, 0x25, 0x01, 0xff,
0x00, 0x0e, 0x02, 0x04, 0x10, 0x17, 0x11, 0x01, 0x1e, 0x10, 0x12, 0x18,
0x10, 0x19, 0x1f, 0x01, 0x1f, 0x1a, 0x1a, 0x01, 0x17, 0x0c, 0x1d, 0x12,
0x10, 0x00, 0x10, 0x17, 0x11, 0x01, 0x1a, 0x11, 0x11, 0x1e, 0x10, 0x1f,
0x01, 0x19, 0x1a, 0x1f, 0x01, 0x04, 0x01, 0x0d, 0x24, 0x1f, 0x10, 0x01,
0x0c, 0x17, 0x14, 0x12, 0x19, 0x10, 0x0f, 0x00, 0x10, 0x17, 0x11, 0x01,
0x21, 0x0c, 0x0f, 0x0f, 0x1d, 0x01, 0x19, 0x1a, 0x1f, 0x01, 0x0a, 0x01,
0x0d, 0x24, 0x1f, 0x10, 0x01, 0x0c, 0x17, 0x14, 0x12, 0x19, 0x10, 0x0f,
0x00, 0x10, 0x17, 0x11, 0x01, 0x17, 0x14, 0x1f, 0x1f, 0x17, 0x10, 0x01,
0x10, 0x19, 0x0f, 0x14, 0x0c, 0x19, 0x01, 0x19, 0x1a, 0x1f, 0x01, 0x1e,
0x20, 0x1b, 0x1b, 0x1a, 0x1d, 0x1f, 0x10, 0x0f, 0x00, 0x10, 0x17, 0x11,
0x01, 0x13, 0x10, 0x0c, 0x0f, 0x10, 0x1d, 0x01, 0x19, 0x1a, 0x1f, 0x01,
0x11, 0x1a, 0x20, 0x19, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7e, 0xa1, 0x99, 0x85, 0x7e, 0x84, 0x82, 0xff, 0x80, 0x80, 0xc1,
0xa1, 0x91, 0x89, 0x86, 0x89, 0x89, 0x89, 0x89, 0x76, 0x18, 0x14, 0x12,
0xff, 0x10, 0x8f, 0x89, 0x89, 0x89, 0x71, 0x7e, 0x89, 0x89, 0x89, 0x72,
0x01, 0x81, 0x61, 0x19, 0x07, 0x62, 0x95, 0x89, 0x95, 0x62, 0x4e, 0x91,
0x91, 0x91, 0x7e, 0xfe, 0x11, 0x11, 0x11, 0xfe, 0xff, 0x89, 0x89, 0x89,
0x76, 0x7e, 0x81, 0x81, 0x81, 0x81, 0xff, 0x81, 0x81, 0x81, 0x7e, 0xff,
0x89, 0x89, 0x89, 0x89, 0xff, 0x09, 0x09, 0x09, 0x09, 0x7e, 0x81, 0x91,
0x51, 0xf1, 0xff, 0x08, 0x08, 0x08, 0xff, 0x00, 0x81, 0xff, 0x81, 0x00,
0x40, 0x80, 0x80, 0x80, 0x7f, 0xff, 0x08, 0x14, 0x22, 0xc1, 0xff, 0x80,
0x80, 0x80, 0x80, 0xff, 0x02, 0x04, 0x02, 0xff, 0xff, 0x06, 0x18, 0x60,
0xff, 0x7e, 0x81, 0x81, 0x81, 0x7e, 0xff, 0x11, 0x11, 0x11, 0x0e, 0x7e,
0x81, 0xa1, 0xc1, 0xfe, 0xff, 0x11, 0x11, 0x11, 0xee, 0x86, 0x89, 0x89,
0x89, 0x71, 0x01, 0x01, 0xff, 0x01, 0x01, 0x7f, 0x80, 0x80, 0x80, 0x7f,
0x1f, 0x60, 0x80, 0x60, 0x1f, 0xff, 0x40, 0x20, 0x40, 0xff, 0xc7, 0x28,
0x10, 0x28, 0xc7, 0x07, 0x08, 0xf0, 0x08, 0x07, 0xc1, 0xa1, 0x99, 0x85,
0x83, 0x00, 0x00, 0x00, 0x3c, 0x03, 0xa4, 0x80, 0x8c, 0x62, 0x00, 0x18,
0x30, 0x42, 0x00, 0x03, 0x14, 0x40, 0xff, 0xfd, 0x3c, 0x02, 0xbf, 0xc0,
0x24, 0x03, 0x00, 0x08, 0xac, 0x43, 0x07, 0xfc, 0x3c, 0x02, 0xa4, 0x00,
0x8c, 0x43, 0x00, 0x00, 0x40, 0x80, 0xe0, 0x00, 0x40, 0x80, 0xe8, 0x00,
0x3c, 0x02, 0x80, 0x00, 0x24, 0x45, 0x20, 0x00, 0xbc, 0x49, 0x00, 0x00,
0xbc, 0x49, 0x00, 0x10, 0xbc, 0x49, 0x00, 0x20, 0xbc, 0x49, 0x00, 0x30,
0x24, 0x42, 0x00, 0x40, 0x14, 0x45, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x02, 0x80, 0x00, 0x24, 0x45, 0x40, 0x00, 0xbc, 0x48, 0x00, 0x00,
0xbc, 0x48, 0x00, 0x20, 0xbc, 0x48, 0x00, 0x40, 0xbc, 0x48, 0x00, 0x60,
0x24, 0x42, 0x00, 0x80, 0x14, 0x45, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x02, 0xa4, 0x04, 0x8c, 0x45, 0x00, 0x14, 0x14, 0xa0, 0xff, 0xfe,
0x3c, 0x05, 0xa4, 0x00, 0x24, 0xa5, 0x10, 0x00, 0xac, 0x45, 0x00, 0x00,
0x24, 0x65, 0x80, 0x00, 0xac, 0x45, 0x00, 0x04, 0x3c, 0x05, 0x00, 0x01,
0x34, 0xa5, 0xf3, 0xff, 0xac, 0x45, 0x00, 0x0c, 0x3c, 0x02, 0xa4, 0x04,
0x8c, 0x45, 0x00, 0x14, 0x14, 0xa0, 0xff, 0xfe, 0x3c, 0x05, 0x00, 0x80,
0x24, 0xa5, 0x20, 0x00, 0xac, 0x45, 0x00, 0x04, 0x3c, 0x05, 0xa4, 0x00,
0x24, 0xa5, 0x00, 0x10, 0xac, 0x45, 0x00, 0x00, 0x24, 0x05, 0x0f, 0xef,
0xac, 0x45, 0x00, 0x08, 0x3c, 0x05, 0xa4, 0x80, 0x8c, 0xa2, 0x00, 0x18,
0x30, 0x42, 0x00, 0x03, 0x14, 0x40, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00,
0xac, 0xa0, 0x00, 0x18, 0x3c, 0x05, 0xa4, 0x04, 0x8c, 0xa2, 0x00, 0x18,
0x14, 0x40, 0xff, 0xfe, 0x3c, 0x02, 0x7f, 0xff, 0x34, 0x42, 0xff, 0xf0,
0x00, 0x62, 0x18, 0x21, 0x00, 0x80, 0x00, 0x08, 0x00, 0x60, 0xe8, 0x25
};
unsigned int default_ipl3_len = 6444;

@ -0,0 +1,842 @@
/*
n64tool V1.0, a program used to append an n64 header to an arbitrary
sized Nintendo64 binary.
Copyright (C) 2009 DragonMinded (dragonminded@dragonminded.com)
This tool is part of the Libdragon SDK.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "polyfill.h"
#include "crc32.c"
typedef intptr_t ssize_t;
// Default header to use if none is specified
#include "ipl3.h"
#define ROUND_UP(n, d) ({ \
typeof(n) _n = n; typeof(d) _d = d; \
(((_n) + (_d) - 1) / (_d) * (_d)); \
})
// strlcpy() is not available on all platforms, so we provide a simple implementation
#ifndef strlcpy
size_t __strlcpy(char * restrict dst, const char * restrict src, size_t dstsize)
{
strncpy(dst, src, dstsize - 1);
dst[dstsize - 1] = '\0';
return strlen(dst);
}
#define strlcpy __strlcpy
#endif
// Minimum ROM size alignment, used by default. We currently know of two constraints:
// * 64drive firmware has a bug and can only transfer chunks of 512 bytes. Some
// tools like UNFloader and g64drive work around this bug by padding ROMs,
// but others (like the official one) don't. So it's better in general to
// pad to 512 bytes.
// * EverDrive64 also requires ROMs to be transferred in blocks of 512 bytes,
// which means that the ROM has to be padded.
// * iQue player only allows loading ROMs which are multiple of 16 KiB in size.
//
// To allow the maximum compatibility, we pad to 16 KiB by default. Users can still
// force a specific length with --size, if they need to.
// We also allow changing the padding alignment with --padding.
int pad_align = 16384;
#define WRITE_SIZE (1024 * 1024)
#define TITLE_OFFSET 0x20
#define TITLE_SIZE 20
#define CATEGORY_OFFSET 0x3B
#define REGION_OFFSET 0x3E
#define IQUE_ENTRYPOINT_OFFSET 0x8
#define STATUS_OK 0
#define STATUS_ERROR 1
#define STATUS_BADUSAGE 2
#define TOC_SIZE 1024
#define TOC_ALIGN 16
#define TOC_ENTRY_SIZE 64
#define TOC_MAX_ENTRIES ((TOC_SIZE - 16) / 64)
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define SWAPLONG(i) (i)
#define SWAPSHORT(i) (i)
#else
#define SWAPLONG(i) (((uint32_t)((i) & 0xFF000000) >> 24) | ((uint32_t)((i) & 0x00FF0000) >> 8) | ((uint32_t)((i) & 0x0000FF00) << 8) | ((uint32_t)((i) & 0x000000FF) << 24))
#define SWAPSHORT(i) (((uint16_t)((i) & 0xFF00) >> 8) | ((uint16_t)((i) & 0x00FF) << 8))
#endif
static const unsigned char zero[1024] = {0};
static char * tmp_output = NULL;
static uint32_t elf_loadpoint = 0xFFFFFFFF;
// The TOC cookie could be just a 32-bit random number; its goal is just to
// differentiate different ROMs, to detect if a ROM was "swapped" by a flashcart
// during runtime.
// However we don't want to use a random number as we want ROMs to be reproducible,
// so we will instead hash the various file contents to generate a fixed-but-random
// cookie.
static uint32_t toc_cookie = 0xFFFFFFFF;
struct toc_s {
char magic_version[4];
uint32_t cookie;
uint32_t toc_size;
uint16_t entry_size;
uint16_t num_entries;
struct {
uint32_t offset;
uint32_t size;
char name[TOC_ENTRY_SIZE - 8];
} files[TOC_MAX_ENTRIES];
} toc = {
.magic_version = "TOC0",
.toc_size = TOC_SIZE,
.entry_size = TOC_ENTRY_SIZE,
.num_entries = 0,
};
_Static_assert(sizeof(toc) <= TOC_SIZE, "invalid table size");
int print_usage(const char * prog_name)
{
fprintf(stderr, "Usage: %s [flags] [file-flags] <file> [[file-flags] <file> ...]\n\n", prog_name);
fprintf(stderr, "This program creates an N64 ROM from a header and a list of files,\n");
fprintf(stderr, "the first being an Nintendo 64 binary and the rest arbitrary data.\n");
fprintf(stderr, "\n");
fprintf(stderr, "General flags (to be used before any file):\n");
fprintf(stderr, "\t-t, --title <title> Title of ROM (max %d characters).\n", TITLE_SIZE);
fprintf(stderr, "\t-l, --size <size> Force ROM output file size to <size> (min 1 mebibyte).\n");
fprintf(stderr, "\t-P, --padding <size> Padding alignment for the final ROM (default: 16 KiB).\n");
fprintf(stderr, "\t-h, --header <file> Use <file> as IPL3 header (default: use libdragon IPL3).\n");
fprintf(stderr, "\t-o, --output <file> Save output ROM to <file>.\n");
fprintf(stderr, "\t-C, --category <cat> N64 Media Category Code (default: 'N' - N64 Game Pak).\n");
fprintf(stderr, "\t-R, --region <reg> Specify ROM region (default: 'E' - North America).\n");
fprintf(stderr, "\t-T, --toc Create a table of contents in the ROM.\n");
fprintf(stderr, "\n");
fprintf(stderr, "File flags (to be used before each file):\n");
fprintf(stderr, "\t-a, --align <align> Next file is aligned at <align> bytes from top of memory (default: 16).\n");
fprintf(stderr, "\t-s, --offset <offset> Next file starts at <offset> from top of memory. Offset must be 4-byte aligned.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Binary byte size/offset suffix notation:\n");
fprintf(stderr, "\tB for bytes.\n");
fprintf(stderr, "\tK for kibibytes (KiB) [1024 bytes].\n");
fprintf(stderr, "\tM for mebibytes (MiB) [1024 kibibytes].\n");
return STATUS_BADUSAGE;
}
bool check_flag(const char * arg, const char * shortFlag, const char * longFlag)
{
return !strcmp(arg, shortFlag) || !strcmp(arg, longFlag);
}
size_t get_file_size(FILE * fp)
{
size_t restore = ftell(fp);
size_t end = 0;
fseek(fp, 0, SEEK_END);
end = ftell(fp);
fseek(fp, restore, SEEK_SET);
return end;
}
ssize_t copy_file(FILE * dest, const char * file)
{
FILE *read_file = fopen(file, "rb");
uint8_t *buffer;
if(!read_file)
{
fprintf(stderr, "ERROR: Cannot open %s for reading!\n", file);
return -1;
}
ssize_t fsize = get_file_size(read_file);
ssize_t rsize = fsize;
/* Should probably make this read in increments, but whatever */
buffer = malloc(WRITE_SIZE);
if(!buffer)
{
fprintf(stderr, "ERROR: Out of memory!\n");
fclose(read_file);
return -1;
}
/* Weird Windows bug fix, plus this is the right way to do things */
while(fsize > 0)
{
/* Max 1K chunk */
ssize_t write_size = (fsize > WRITE_SIZE) ? WRITE_SIZE : fsize;
fsize -= write_size;
fread(buffer, 1, write_size, read_file);
fwrite(buffer, 1, write_size, dest);
/* Update the TOC cookie with file contents. */
toc_cookie = crc32_update(toc_cookie, buffer, write_size);
}
free(buffer);
fclose(read_file);
return rsize;
}
ssize_t output_zeros(FILE * dest, ssize_t amount)
{
if(amount < 0)
{
/* Can't backward seek */
return -1;
}
while (amount > 0) {
int sz = amount;
if (sz > sizeof(zero))
sz = sizeof(zero);
fwrite(zero, 1, sz, dest);
toc_cookie = crc32_update(toc_cookie, zero, sz);
amount -= sz;
}
return 0;
}
ssize_t parse_bytes(const char * arg)
{
size_t arg_len = strlen(arg);
if(arg_len < 2)
{
/* Need at least 2 characters to parse */
return -1;
}
char * suffix;
size_t size = strtol(arg, &suffix, 10);
/* Multiply by the suffix magnitude */
switch(suffix[0])
{
case 'm':
case 'M':
size *= 1024;
case 'k':
case 'K':
size *= 1024;
case 'b':
case 'B':
default:
return size;
}
}
void remove_tmp_file(void)
{
if(tmp_output)
remove(tmp_output);
}
static uint32_t fread32be_at(FILE *fp, int offset)
{
uint8_t buf[4];
fseek(fp, offset, SEEK_SET);
fread(buf, 1, 4, fp);
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
static uint16_t fread16be_at(FILE *fp, int offset)
{
uint8_t buf[2];
fseek(fp, offset, SEEK_SET);
fread(buf, 1, 2, fp);
return (buf[0] << 8) | buf[1];
}
int parse_elf_loadpoint(const char *elf_fn, uint32_t *loadpoint)
{
FILE *elf = fopen(elf_fn, "rb");
if(!elf)
{
fprintf(stderr, "ERROR: Cannot open %s for reading!\n", elf_fn);
return -1;
}
char id[4];
fread(id, 1, 4, elf);
if (memcmp(id, "\x7F" "ELF", 4) != 0) {
fprintf(stderr, "WARNING: %s is not an ELF file, boot may fail\n", elf_fn);
fclose(elf);
return -1;
}
bool elf64 = fgetc(elf) == 2;
if (fgetc(elf) == 1) {
fprintf(stderr, "WARNING: %s is a little-endian ELF file, boot may fail\n", elf_fn);
fclose(elf);
return -1;
}
int phoff = fread32be_at(elf, (elf64 ? 0x20+4 : 0x1C));
int phnum = fread16be_at(elf, (elf64 ? 0x38 : 0x2C));
enum { PF_N64_COMPRESSED = 0x1000 };
enum { PT_LOAD = 0x1 };
bool found_loadpoint = false;
for (int i=0; i<phnum; i++) {
uint32_t type = fread32be_at(elf, phoff + 0);
uint32_t vaddr = fread32be_at(elf, phoff + (elf64 ? 5 : 2)*4);
uint32_t paddr = fread32be_at(elf, phoff + (elf64 ? 7 : 3)*4);
uint32_t flags = fread32be_at(elf, phoff + (elf64 ? 1 : 6)*4);
if (flags & PF_N64_COMPRESSED)
vaddr = paddr;
if (type == PT_LOAD && !(vaddr >= 0x80000000 && vaddr < 0x80000400)) {
*loadpoint = vaddr;
found_loadpoint = true;
break;
}
phoff += elf64 ? 0x38 : 0x20;
}
if (!found_loadpoint) {
fprintf(stderr, "WARNING: No suitable loading point found in %s, boot may fail on iQue\n", elf_fn);
fclose(elf);
return -1;
}
fclose(elf);
return 0;
}
int main(int argc, char *argv[])
{
winconsole_utf8();
FILE * write_file = NULL;
const char * header = NULL;
const char * output = NULL;
size_t declared_size = 0;
size_t total_bytes_written = 0;
char title[TITLE_SIZE + 1] = { 0, };
bool create_toc = false;
size_t toc_offset = 0;
int header_size = 0;
int align_next = 16;
char category = 'N';
// Some flashcarts (at least Everdrive X7) seem to automatically set the TV type based on the region field.
// As a result, some users might not be able to play the ROM because their TV or capture device doesn't
// support either PAL or NTSC. If the field is 0, the flashcart seems to not overwrite the console's region,
// so we use it as default.
char region = 0;
if(argc <= 1)
{
/* No way we can have just one argument or less */
return print_usage(argv[0]);
}
int i = 1;
const char * arg;
while(i < argc)
{
arg = argv[i++];
if(check_flag(arg, "-b", "--byteswap"))
{
/* Invalid usage */
fprintf(stderr, "ERROR: The byteswap option is no longer supported. ");
fprintf(stderr, "Use another tool to convert the output of this program.\n");
fprintf(stderr, " For example: dd conv=swab if=rom.z64 of=rom.v64\n\n");
return print_usage(argv[0]);
}
if(check_flag(arg, "-h", "--header"))
{
if(header)
{
/* Invalid usage */
fprintf(stderr, "ERROR: The header can only be set once\n\n");
return print_usage(argv[0]);
}
if(i >= argc)
{
/* Invalid usage */
fprintf(stderr, "ERROR: Expected an argument to header flag\n\n");
return print_usage(argv[0]);
}
header = argv[i++];
continue;
}
if(check_flag(arg, "-o", "--output"))
{
if(output)
{
/* Invalid usage */
fprintf(stderr, "ERROR: The output can only be set once\n\n");
return print_usage(argv[0]);
}
if(i >= argc)
{
/* Invalid usage */
fprintf(stderr, "ERROR: Expected an argument to output flag\n\n");
return print_usage(argv[0]);
}
output = argv[i++];
unsigned int needed_size = snprintf(0, 0, "%s.tmp", output) + 1;
tmp_output = calloc(needed_size, 1);
snprintf(tmp_output, needed_size, "%s.tmp", output);
continue;
}
if(check_flag(arg, "-l", "--size"))
{
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to size flag\n\n");
return print_usage(argv[0]);
}
ssize_t size = parse_bytes(argv[i++]);
if (size % 4 != 0)
{
/* Invalid size */
fprintf(stderr, "ERROR: Invalid size argument; must be a multiple of 4 bytes\n\n");
return print_usage(argv[0]);
}
if (size % 512 != 0)
{
fprintf(stderr, "WARNING: Sizes which are not multiple of 512 bytes might have problems being loaded with a 64drive\n\n");
}
declared_size = size;
continue;
}
if(check_flag(arg, "-P", "--padding"))
{
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to padding flag\n\n");
return print_usage(argv[0]);
}
ssize_t size = parse_bytes(argv[i++]);
if (size < 0)
{
/* Invalid size */
fprintf(stderr, "ERROR: Invalid padding argument; must be positive\n\n");
return print_usage(argv[0]);
}
pad_align = size;
continue;
}
if(check_flag(arg, "-T", "--toc"))
{
if(total_bytes_written)
{
fprintf(stderr, "ERROR: -T / --toc must be specified before any input file\n\n");
return print_usage(argv[0]);
}
create_toc = true;
continue;
}
if(check_flag(arg, "-s", "--offset"))
{
if(!output)
{
fprintf(stderr, "ERROR: Need output flag before offset\n\n");
return print_usage(argv[0]);
}
if(!total_bytes_written)
{
fprintf(stderr, "ERROR: The first file cannot have an offset\n\n");
return print_usage(argv[0]);
}
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to offset flag\n\n");
return print_usage(argv[0]);
}
ssize_t offset = parse_bytes(argv[i++]);
if(offset <= 0)
{
/* Invalid offset */
fprintf(stderr, "ERROR: Invalid offset argument\n\n");
return print_usage(argv[0]);
}
if((offset % 4) != 0)
{
fprintf(stderr, "ERROR: Invalid offset argument (must be multiple of 4)\n\n");
return print_usage(argv[0]);
}
/* Write out needed number of zeros */
ssize_t num_zeros = offset - total_bytes_written;
if(output_zeros(write_file, num_zeros))
{
fprintf(stderr, "ERROR: Invalid offset %zd to seek to in %s!\n", offset, output);
return STATUS_ERROR;
}
/* Same as total_bytes_written = offset */
total_bytes_written += num_zeros;
continue;
}
if(check_flag(arg, "-a", "--align"))
{
if(!output)
{
fprintf(stderr, "ERROR: Need output flag before alignment\n\n");
return print_usage(argv[0]);
}
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to align flag\n\n");
return print_usage(argv[0]);
}
int align = atoi(argv[i++]);
if (align < 4)
{
fprintf(stderr, "ERROR: Minimum alignment is 4 bytes\n\n");
return print_usage(argv[0]);
}
align_next = align;
continue;
}
if(check_flag(arg, "-t", "--title"))
{
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to title flag\n\n");
return print_usage(argv[0]);
}
const char * title_arg = argv[i++];
size_t title_len = strlen(title_arg);
if(title_len > TITLE_SIZE)
{
fprintf(stderr, "WARNING: Title will be truncated to %d characters\n", TITLE_SIZE);
title_len = TITLE_SIZE;
}
memcpy(title, title_arg, title_len);
continue;
}
if(check_flag(arg, "-C", "--category"))
{
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to category flag\n\n");
return print_usage(argv[0]);
}
const char * category_arg = argv[i++];
if(strlen(category_arg) != 1)
{
fprintf(stderr, "ERROR: Category must be a single character\n\n");
return print_usage(argv[0]);
}
category = category_arg[0];
continue;
}
if(check_flag(arg, "-R", "--region"))
{
if(i >= argc)
{
/* Expected another argument */
fprintf(stderr, "ERROR: Expected an argument to region flag\n\n");
return print_usage(argv[0]);
}
const char * region_arg = argv[i++];
if (strlen(region_arg) != 1)
{
fprintf(stderr, "ERROR: Region must be a single character\n\n");
return print_usage(argv[0]);
}
region = region_arg[0];
continue;
}
/* Argument is not a flag; treat it as an input file */
/* Can't copy input file unless header and output set */
if(!output)
{
fprintf(stderr, "ERROR: Need output flag before first file\n\n");
return print_usage(argv[0]);
}
/* If this is the first input file, open the output file and write the header */
if(!write_file)
{
/* Create or completely overwrite the output file */
write_file = fopen(tmp_output, "wb");
if(!write_file)
{
fprintf(stderr, "ERROR: Cannot open '%s' for writing\n", output);
return STATUS_ERROR;
}
/* Try to clean up the temporary file if we exit */
atexit(remove_tmp_file);
/* Copy over the ROM header */
if (header)
{
header_size = copy_file(write_file, header);
}
else
{
header_size = sizeof(default_ipl3);
fwrite(default_ipl3, 1, header_size, write_file);
if (parse_elf_loadpoint(arg, &elf_loadpoint) < 0)
return STATUS_ERROR;
}
if(header_size < 0x100)
{
fprintf(stderr, "ERROR: Header file '%s' is too small (minimum is 4096 bytes)\n", header);
return STATUS_ERROR;
}
/* HACK. Unfortunately, n64tool handles both --align and --offset with respect
to file positions/sizes *excluding* the header. The header used to be of
fixed size (4096 bytes), but that's now just a minimum. For full backward
compatibility, we still consider the header to always be 4096 bytes, and
just offset from there. */
total_bytes_written += header_size - 4096;
header_size = 4096;
/* Leave space for the table, if asked to do so. */
if(create_toc && !toc_offset)
{
if (total_bytes_written % TOC_ALIGN)
{
ssize_t num_zeros = TOC_ALIGN - (total_bytes_written % TOC_ALIGN);
output_zeros(write_file, num_zeros);
total_bytes_written += num_zeros;
}
toc_offset = ftell(write_file);
output_zeros(write_file, TOC_SIZE);
total_bytes_written += TOC_SIZE;
}
}
if (align_next)
{
if (total_bytes_written % align_next)
{
ssize_t num_zeros = align_next - (total_bytes_written % align_next);
if(output_zeros(write_file, num_zeros))
{
fprintf(stderr, "ERROR: Invalid alignment %d to seek to in %s!\n", align_next, output);
return STATUS_ERROR;
}
total_bytes_written += num_zeros;
}
}
/* Reset to 16 for next file (default) */
align_next = 16;
size_t offset = ftell(write_file);
/* Copy the input file into the output file */
ssize_t bytes_copied = copy_file(write_file, arg);
if(bytes_copied < 0)
{
fprintf(stderr, "ERROR: Unable to copy file from '%s' to '%s'\n", arg, output);
return STATUS_ERROR;
}
if (toc.num_entries < TOC_MAX_ENTRIES)
{
/* Add the file to the toc */
toc.files[toc.num_entries].offset = offset;
toc.files[toc.num_entries].size = bytes_copied;
const char *basename = strrchr(arg, '/');
if (!basename) basename = strrchr(arg, '\\');
if (!basename) basename = arg;
if (basename[0] == '/' || basename[0] == '\\') basename++;
strlcpy(toc.files[toc.num_entries].name, basename, sizeof(toc.files[toc.num_entries].name));
toc.num_entries++;
}
else
{
if (create_toc)
{
fprintf(stderr, "ERROR: Too many files to add to table.\n");
return STATUS_ERROR;
}
}
/* Keep track to be sure we align properly when they request a memory alignment */
total_bytes_written += bytes_copied;
}
if(!total_bytes_written)
{
/* Didn't write anything! */
printf("ERROR: No input files, nothing written\n\n");
return print_usage(argv[0]);
}
/* If the declared size is too small, error out */
if(declared_size && declared_size < total_bytes_written)
{
fprintf(stderr, "ERROR: Couldn't fit ROM in %zu bytes as requested.\n", declared_size);
return print_usage(argv[0]);
}
/* Pad the output file to the declared size (not including the IPL3 header) */
if(!declared_size) {
/* If the user didn't specify a size, initialize this to the minimum
size that is padded to the correct alignment. Notice that this variable
declares the size WITHOUT header, but the padding refers to the final
ROM and so it must be calculated with the header. */
if (pad_align)
declared_size = ROUND_UP(header_size, pad_align)-header_size;
}
if(declared_size > total_bytes_written)
{
ssize_t num_zeros = declared_size - total_bytes_written;
if(output_zeros(write_file, num_zeros))
{
fprintf(stderr, "ERROR: Couldn't pad %zu bytes to %zu bytes.\n", total_bytes_written, declared_size);
return print_usage(argv[0]);
}
}
else if(pad_align && ((total_bytes_written+header_size) % pad_align) != 0)
{
/* Pad size as required. */
ssize_t num_zeros = pad_align - ((total_bytes_written+header_size) % pad_align);
if(output_zeros(write_file, num_zeros))
{
fprintf(stderr, "ERROR: Couldn't pad %zu bytes to %zu bytes.\n", total_bytes_written, total_bytes_written+num_zeros);
return print_usage(argv[0]);
}
}
/* Set title in header */
fseek(write_file, TITLE_OFFSET, SEEK_SET);
fwrite(title, 1, TITLE_SIZE, write_file);
/* Set category in header */
fseek(write_file, CATEGORY_OFFSET, SEEK_SET);
fwrite(&category, 1, 1, write_file);
/* Set region in header */
fseek(write_file, REGION_OFFSET, SEEK_SET);
fwrite(&region, 1, 1, write_file);
/* If we are using libdragon's IPL3, set the entrypoint in the header
for iQue to match the first valid loadpoint found in the ELF. This make
sure that the iQue OS, in its initial flat-binary loading, will use
the same memory region as the ELF. */
if (elf_loadpoint != 0xFFFFFFFF)
{
elf_loadpoint = SWAPLONG(elf_loadpoint);
fseek(write_file, IQUE_ENTRYPOINT_OFFSET, SEEK_SET);
fwrite(&elf_loadpoint, 1, 4, write_file);
}
/* Write table of contents */
if(create_toc)
{
for (int i=0; i<toc.num_entries; i++) {
toc.files[i].offset = SWAPLONG(toc.files[i].offset);
toc.files[i].size = SWAPLONG(toc.files[i].size);
}
toc.toc_size = SWAPLONG(toc.toc_size);
toc.num_entries = SWAPSHORT(toc.num_entries);
toc.entry_size = SWAPSHORT(toc.entry_size);
toc_cookie = ~crc32_update(toc_cookie, (uint8_t *)&toc, sizeof(toc));
toc.cookie = SWAPLONG(toc_cookie);
fseek(write_file, toc_offset, SEEK_SET);
fwrite(&toc, 1, sizeof(toc), write_file);
}
/* Sync and close the output file */
fclose(write_file);
/* Rename to the final name */
#ifdef _WIN32
/* Windows doesn't support atomic renames, so we have to delete the old file first */
remove(output);
#endif
if(rename(tmp_output, output) != 0) {
fprintf(stderr, "Couldn't rename temporary output file '%s' to '%s': %s", tmp_output, output, strerror(errno));
return STATUS_ERROR;
}
return STATUS_OK;
}

@ -0,0 +1,412 @@
/*
polyfill: mingw32 polyfills for missing C/POSIX functions
Written by Giovanni Bajo <giovannibajo@gmail.com>
This tool is part of the Libdragon SDK.
This is free and unencumbered software released into the public domain.
For more information, please refer to <http://unlicense.org/>
*/
#ifndef LIBDRAGON_TOOLS_POLYFILL_H
#define LIBDRAGON_TOOLS_POLYFILL_H
#ifdef __MINGW32__
// NOTE: we include both stdio.h and cstdio because both of them will undef
// tmpfile and redefine it to something else. Since we want to provide our
// own implementation, we need to make sure both are included first, so that
// we don't run the risk either of them is included after this file.
#include <stdio.h>
#ifdef __cplusplus
#include <cstdio>
#endif
// NOTE: include both assert.h and cassert because we need to make sure
// _assert and _wassert are declared properly before we mess with them later.
#include <assert.h>
#ifdef __cplusplus
#include <cassert>
#endif
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <process.h>
#include <share.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
// if typedef doesn't exist (msvc, blah)
typedef intptr_t ssize_t;
/* Implementation of 'getline' fetched from: https://stackoverflow.com/a/47229318 */
/* The original code is public domain -- Will Hartung 4/9/09 */
/* Modifications, public domain as well, by Antti Haapala, 11/10/17
- Switched to getc on 5/23/19 */
__attribute__((used))
static ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
size_t pos;
int c;
if (lineptr == NULL || stream == NULL || n == NULL) {
errno = EINVAL;
return -1;
}
c = getc(stream);
if (c == EOF) {
return -1;
}
if (*lineptr == NULL) {
*lineptr = (char*)malloc(128);
if (*lineptr == NULL) {
return -1;
}
*n = 128;
}
pos = 0;
while(c != EOF) {
if (pos + 1 >= *n) {
size_t new_size = *n + (*n >> 2);
if (new_size < 128) {
new_size = 128;
}
char *new_ptr = (char*)realloc(*lineptr, new_size);
if (new_ptr == NULL) {
return -1;
}
*n = new_size;
*lineptr = new_ptr;
}
((unsigned char *)(*lineptr))[pos ++] = c;
if (c == '\n') {
break;
}
c = getc(stream);
}
(*lineptr)[pos] = '\0';
return pos;
}
// Provide implementation of strndup for MSYS2 environments that are missing it (before April 13 2026).
#if defined(MSYS2_RUNTIME_PACMAN_AGE) && MSYS2_RUNTIME_PACMAN_AGE <= 20260413
__attribute__((used))
static char *msys2_fallback_strndup(const char *s, size_t n)
{
size_t len = strnlen(s, n);
char *ret = (char*)malloc(len + 1);
if (!ret) return NULL;
memcpy(ret, s, len);
ret[len] = '\0';
return ret;
}
#ifdef strndup
#undef strndup
#endif
#define strndup msys2_fallback_strndup
#endif
// Replace 'assert' so that it has 'noreturn' behaviour on Windows.
// (soft reverts this MSYS2 commit: https://sourceforge.net/p/mingw-w64/mingw-w64/ci/ecf2328a328d11dec7044b40b2b5e93b5b2b9d9e/)
#if defined(MSYS2_RUNTIME_PACMAN_AGE) && MSYS2_RUNTIME_PACMAN_AGE >= 20260611 && !defined(NDEBUG)
#if defined(_UNICODE) || defined(UNICODE)
__attribute__((used)) __attribute__((noreturn))
static void msys2_wassert_fix(const wchar_t* _Message, const wchar_t* _File, unsigned _Line)
{
_wassert(_Message, _File, _Line);
abort();
__builtin_unreachable();
}
#define _wassert(a,b,c) msys2_wassert_fix(a,b,c)
#else
__attribute__((used)) __attribute__((noreturn))
static void msys2_assert_fix(const char* _Message, const char* _File, unsigned _Line)
{
_assert(_Message, _File, _Line);
abort();
__builtin_unreachable();
}
#define _assert(a,b,c) msys2_assert_fix(a,b,c)
#endif // defined(_UNICODE) || defined(UNICODE)
#endif
#if defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ >= 0xE00
// UCRT is being used so we can use runtime-provided tmpfile() implementation
#else
// tmpfile() in MINGW64 is broken for use (it uses MSVCRT that tries to
// create a file in C:\, which is non-writable nowadays)
#ifdef tmpfile
#undef tmpfile
#endif
#define tmpfile() mingw_tmpfile()
#endif
typedef void* HANDLE;
typedef const char* LPCSTR;
typedef int BOOL;
#define INVALID_HANDLE_VALUE ((HANDLE)(long)-1)
struct _SECURITY_ATTRIBUTES;
// Access rights
#define GENERIC_READ 0x80000000
#define GENERIC_WRITE 0x40000000
// Share modes
#define FILE_SHARE_READ 0x00000001
#define FILE_SHARE_WRITE 0x00000002
#define FILE_SHARE_DELETE 0x00000004
// Creation disposition
#define CREATE_NEW 1
// Flags and attributes
#define FILE_ATTRIBUTE_TEMPORARY 0x00000100
#define FILE_FLAG_DELETE_ON_CLOSE 0x04000000
__declspec(dllimport) HANDLE __stdcall CreateFileA(
LPCSTR lpFileName,
unsigned long dwDesiredAccess,
unsigned long dwShareMode,
struct _SECURITY_ATTRIBUTES* lpSecurityAttributes,
unsigned long dwCreationDisposition,
unsigned long dwFlagsAndAttributes,
HANDLE hTemplateFile
);
__declspec(dllimport) int __stdcall CloseHandle(HANDLE);
__declspec(dllimport) unsigned long __stdcall GetLastError(void);
__declspec(dllimport) unsigned long __stdcall GetTickCount(void);
__attribute__((used))
static FILE *mingw_tmpfile(void) {
static int counter = 0;
char path[260];
for (int i = 0; i < 4096; i++) {
// Generate a random filename. Notice we *purposedly* not make this
// very random with PID, timestamp, etc. because this is the third
// iteration of mingw_tmpfile(): the previous ones were misbehaving
// in various ways on various CRTs, Windows versions, etc.
// We want this code to be exercised often so that it is robust.
snprintf(path, sizeof(path), "mksprite-%04x.tmp", counter++);
HANDLE h = CreateFileA(
path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
NULL
);
if (h != INVALID_HANDLE_VALUE) {
int fd = _open_osfhandle((intptr_t)h, _O_RDWR | _O_BINARY);
if (fd == -1) {
CloseHandle(h);
return NULL;
}
return fdopen(fd, "w+b");
}
// 80 = ERROR_FILE_EXISTS
if (GetLastError() != 80)
break;
}
return NULL;
}
__attribute__((used))
static char* strcasestr(const char* haystack, const char* needle)
{
size_t needle_len = strlen(needle);
size_t haystack_len = strlen(haystack);
size_t i;
if (needle_len > haystack_len)
return NULL;
for (i = 0; i <= haystack_len - needle_len; i++)
{
if (strncasecmp(haystack + i, needle, needle_len) == 0)
return (char*)(haystack + i);
}
return NULL;
}
// Implementation from FreeBSD
__attribute__((used))
static void *memmem(const void *l, size_t l_len, const void *s, size_t s_len)
{
char *cur, *last;
const char *cl = (const char *)l;
const char *cs = (const char *)s;
/* we need something to compare */
if (l_len == 0 || s_len == 0)
return NULL;
/* "s" must be smaller or equal to "l" */
if (l_len < s_len)
return NULL;
/* special case where s_len == 1 */
if (s_len == 1)
return memchr(l, (int)*cs, l_len);
/* the last position where its possible to find "s" in "l" */
last = (char *)cl + l_len - s_len;
for (cur = (char *)cl; cur <= last; cur++)
if (cur[0] == cs[0] && memcmp(cur, cs, s_len) == 0)
return cur;
return NULL;
}
// rename() that ovewrites the destination file
#define rename(a,b) mingw_rename(a,b)
#define MOVEFILE_REPLACE_EXISTING 0x00000001
#define MOVEFILE_WRITE_THROUGH 0x00000008
__declspec(dllimport) int __stdcall MoveFileExA(const char *lpExistingFileName,
const char *lpNewFileName,
unsigned long dwFlags);
__declspec(dllimport) unsigned long __stdcall GetLastError(void);
static void map_windows_error_to_errno(unsigned long err) {
switch (err) {
case 2: errno = ENOENT; break; // ERROR_FILE_NOT_FOUND
case 3: errno = ENOENT; break; // ERROR_PATH_NOT_FOUND
case 5: errno = EACCES; break; // ERROR_ACCESS_DENIED
case 32: errno = EBUSY; break; // ERROR_SHARING_VIOLATION
case 80: errno = EEXIST; break; // ERROR_FILE_EXISTS
case 183: errno = EEXIST; break; // ERROR_ALREADY_EXISTS
default: errno = EIO; break; // Generic error
}
}
__attribute__((used))
static int mingw_rename(const char *oldpath, const char *newpath) {
if (MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
return 0;
} else {
map_windows_error_to_errno(GetLastError());
return -1;
}
}
// POISX mkdir has a mode argument, but mingw's mkdir doesn't
#define mkdir(path, mode) mkdir(path)
typedef struct _PROCESS_BASIC_INFORMATION_MIN {
void* Reserved1;
void* PebBaseAddress;
void* Reserved2[2];
void* UniqueProcessId;
void* InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION_MIN;
#define CURRENT_PROCESS ((HANDLE)(intptr_t)-1)
__declspec(dllimport) long __stdcall NtQueryInformationProcess(
HANDLE ProcessHandle, unsigned long ProcessInformationClass,
void* ProcessInformation, unsigned long ProcessInformationLength,
unsigned long *ReturnLength);
// Enable long path support in the current process.
// This is a hacky workaround for a limitation in Windows where
// file paths longer than 260 characters are not supported.
// The documented ways involve also setting a registry key, and thus
// is not suitable for a tool like this.
// This same approach is used by the Go runtime on Windows, so it is
// reasonably safe to use it here as well.
__attribute__((used))
static void enable_peb_long_path_unsafe(void)
{
PROCESS_BASIC_INFORMATION_MIN pbi; unsigned long retlen;
if (NtQueryInformationProcess(CURRENT_PROCESS, 0, &pbi, sizeof(pbi), &retlen) < 0)
return;
volatile uint8_t *peb = (volatile uint8_t*)pbi.PebBaseAddress;
enum { PEB_BITFIELD_OFFSET = 3, IS_LONG_PATH_AWARE_MASK = 0x80 };
peb[PEB_BITFIELD_OFFSET] |= (uint8_t)IS_LONG_PATH_AWARE_MASK;
}
// If it was defined, undefine it as there's no limit on path length after the hack above
#undef MAX_PATH
__declspec(dllimport) int __stdcall SetConsoleOutputCP(unsigned int);
__declspec(dllimport) int __stdcall SetConsoleCP(unsigned int);
__declspec(dllimport) unsigned int __stdcall GetConsoleOutputCP(void);
__declspec(dllimport) unsigned int __stdcall GetConsoleCP(void);
#define CP_UTF8 65001
static int old_out_cp = 0;
static int old_in_cp = 0;
__attribute__((used))
static void winconsole_restore(void) {
if (old_out_cp)
SetConsoleOutputCP(old_out_cp);
if (old_in_cp)
SetConsoleCP(old_in_cp);
}
__attribute__((used))
static void winconsole_utf8(void) {
// Enable long path support in the current process
enable_peb_long_path_unsafe();
// Save the current code page
old_out_cp = GetConsoleOutputCP();
old_in_cp = GetConsoleCP();
// Enable UTF-8 in the console
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
atexit(winconsole_restore);
}
#ifdef __cplusplus
}
#endif
#else /* __MINGW32__ */
#ifdef __cplusplus
extern "C" {
#endif
__attribute__((used))
static void winconsole_utf8(void) {}
#ifdef __cplusplus
}
#endif
#endif /* __MINGW32__ */
#endif

@ -0,0 +1,81 @@
version(2);
project_name = "DIGITAL GROVE 64";
////////////////////////////////////////////////////////////////
//~ rjf: Indentation
indent_width = "1";
default_tab_width = "1";
////////////////////////////////////////////////////////////////
//~ rjf: Code File Extensions
patterns =
{
"*.c",
"*.cpp",
"*.h",
"*.inc",
"*.hpp",
"*.bat",
"*.sh",
"*.4coder",
"*.glsl",
"*.bfs",
"*.html",
"*.txt",
"*.ds",
"*.mdesk",
"*.asm",
};
////////////////////////////////////////////////////////////////
//~ rjf: Omit Patterns
blacklist_patterns =
{
".*",
};
////////////////////////////////////////////////////////////////
//~ rjf: Load Paths
paths =
{
{ .path = ".", .recursive = false, .relative = true, },
{ .path = "code", .recursive = true , .relative = true, },
{ .path = "notes", .recursive = true , .relative = true, },
};
load_paths =
{
.win = paths,
.linux = paths,
};
////////////////////////////////////////////////////////////////
//~ rjf: Commands
commands =
{
.build_g0_n64 = { .win = "build n64_test clang deploy release", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
};
////////////////////////////////////////////////////////////////
//~ rjf: Default F-Keys
fkey_command =
{
.F1 = "build_g0_n64",
};
////////////////////////////////////////////////////////////////
//~ rjf: Username Overridden F-Keys
fkey_command_override =
{
.rjf =
{
.F1 = "build_g0_n64",
},
};
Loading…
Cancel
Save