Skip to content

Instantly share code, notes, and snippets.

@zloedi
Last active October 19, 2023 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zloedi/d2e71e3c8c211b875ba8aa362cb94f15 to your computer and use it in GitHub Desktop.
Save zloedi/d2e71e3c8c211b875ba8aa362cb94f15 to your computer and use it in GitHub Desktop.
Ingame and Ineditor debug console for Unity in a single source file: https://youtu.be/rtaWs_eZRDE
// THIS FILE WAS GENERATED
#if UNITY_STANDALONE || UNITY_2021_0_OR_NEWER
#define HAS_UNITY
#endif
#define QONSOLE_BOOTSTRAP // if this is defined, the console will try to bootstrap itself
#define QONSOLE_BOOTSTRAP_EDITOR // if this is defined, the console will try to bootstrap itself in the editor
namespace QON {
#if UNITY_STANDALONE || UNITY_2021_0_OR_NEWER
//#define HAS_UNITY
#endif
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
#if SDL || HAS_UNITY
////#define QONSOLE_BOOTSTRAP // if this is defined, the console will try to bootstrap itself
////#define QONSOLE_BOOTSTRAP_EDITOR // if this is defined, the console will try to bootstrap itself in the editor
////#define QONSOLE_QUI // if this is defined, QUI gets properly setup in the bootstrap pump
////#define QONSOLE_KEYBINDS // if this is defined, use the KeyBinds inside the Qonsole loop
#if HAS_UNITY
using UnityEngine;
using QObject = UnityEngine.Object;
#else
using System.Runtime.InteropServices;
using static AppleFont;
using static SDL2.SDL;
using static SDL2.SDL.SDL_BlendMode;
using static SDL2.SDL.SDL_EventType;
using static SDL2.SDL.SDL_Keycode;
using GalliumMath;
using QObject = System.Object;
#endif
using static Qonche;
// you need to import the Qonsole source files inside the Unity editor for the Qonsole to work inside the Scene window
// OR if you work in an outside assembly, setup the Editor parts in a script inside Unity
#if UNITY_EDITOR && QONSOLE_BOOTSTRAP && QONSOLE_BOOTSTRAP_EDITOR
using UnityEditor;
[InitializeOnLoad]
public static class QonsoleEditorSetup {
static QonsoleEditorSetup() {
QonsoleBootstrap.TrySetupQonsole();
void duringSceneGui( SceneView sv ) {
Qonsole.OnEditorSceneGUI( sv.camera, EditorApplication.isPaused,
EditorGUIUtility.pixelsPerPoint,
onRepaint: Qonsole.onEditorRepaint_f );
}
SceneView.duringSceneGui -= duringSceneGui;
SceneView.duringSceneGui += duringSceneGui;
Qonsole.Log( "Qonsole setup to work in the editor." );
}
}
#endif
#if QONSOLE_BOOTSTRAP
public class QonsoleBootstrap : MonoBehaviour {
public static void TrySetupQonsole() {
if ( Qonsole.Started ) {
return;
}
Qonsole.onEditorRepaint_f = c => {};
Qonsole.Init();
Qonsole.Start();
KeyBinds.Log = s => Qonsole.Log( s );
KeyBinds.Error = s => Qonsole.Error( s );
}
void Awake() {
TrySetupQonsole();
}
void Update() {
Qonsole.Update();
}
void OnGUI() {
Qonsole.OnGUI();
}
void OnApplicationQuit() {
Qonsole.OnApplicationQuit();
}
}
#endif // QONSOLE_BOOTSTRAP
public static class Qonsole {
#if HAS_UNITY && QONSOLE_BOOTSTRAP
[RuntimeInitializeOnLoadMethod]
static void CreateBootstrapObject() {
QonsoleBootstrap[] components = GameObject.FindObjectsOfType<QonsoleBootstrap>();
if ( components.Length == 0 ) {
GameObject go = new GameObject( "QonsoleBootstrap" );
GameObject.DontDestroyOnLoad( go );
go.AddComponent<QonsoleBootstrap>();
} else {
Debug.Log( "Already have QonsoleBootstrap" );
}
}
#endif
public static bool Active;
public static bool Started;
public static bool ConsumeEditorInputOnce;
public const string featuresDescription = @"Features:
. Persistent history, browse previously issued commands (in previous app runs) using up/down arrows.
Tries to match previous commands by the string on the prompt.
. Persistent variables stored in config file in the app config directory.
. Versioned config files -- changing the config version resets all vars to defaults.
. Works in the Editor (Scene) window too, if the game is paused or not running, setup vars before running the game.
. No dependencies in the code that uses it, no need of attributes, code using it compiles without Qonsole.
. Can modify persistent console variables from within code.
. Doesn't need any Unity assets; drawn using GL calls and font bytes are part of the source code.
. Supports custom config files by command line param: [ff9000]--cfg=zloedi.cfg[-].
Custom config files don't get erased/reset on config version change (the defaults do).
. Separate configs in Build and inside Unity Editor: qon_default.cfg vs qon_default_ed.cfg
. Autocompletes partial commands, not only start-of-command.
. Supports multiple commands chained together; example:
[ff9000]] open_all_doors ; kill_all_enemies ; spawn_monster living Ally 9 12 ; spawn_monster cityguard 8 10 ; teleport player 6 6[-]
. Repeat commands by prepending a number i.e. [ff9000]] 3clear[-].
. Colorized output.
. Config file supports arbitrary commands.
. Variable descriptions stored as comments in the config file.
. Overlay display -- the last emitted lines could be shown on top of the window and fade out with time
. Hook on different events (Start, Update, Done) by defining Qonsole commands with no dependencies.
and more...
";
[Description( "Part of the screen height occupied by the 'overlay' fading-out lines. If set to zero, Qonsole won't show anything unless Active" )]
static int QonOverlayPercent_kvar = 0;
[Description( "Show the Qonsole output to the system (unity) log too." )]
static bool QonPrintToSystemLog_kvar = true;
[Description( "Console character size." )]
static float QonScale_kvar = 1;
static float QonScale => Mathf.Clamp( QonScale_kvar, 1, 100 );
[Description( "Show the Qonsole in the editor: 0 -- no, 1 -- yes, 2 -- editor only." )]
public static float QonShowInEditor_kvar = 1;
[Description( "Alpha blend value of the Qonsole background." )]
public static float QonAlpha_kvar = 0.65f;
[Description( "When not using RP the GL coordinates are inverted (always the case in Editor Scene window). Set this to false to use inverted GL in the Play window." )]
public static bool QonInvertPlayY_kvar = false;
#if QONSOLE_INVERTED_PLAY_Y
public static bool QonInvertPlayY = true;
#else
public static bool QonInvertPlayY => QonInvertPlayY_kvar;
#endif
// OBSOLETE, USE COMMANDS INSTEAD: stuff to be executed before the .cfg file is loaded
public static Func<string> onPreLoadCfg_f = () => "";
// OBSOLETE, USE COMMANDS INSTEAD: stuff to be executed after the .cfg file is loaded
public static Func<string> onPostLoadCfg_f = () => "";
// provide additional string to be appended to the .cfg file on flush/store
public static Func<string> onStoreCfg_f;
// OBSOLETE, USE COMMANDS INSTEAD: called inside the Update pump (optionally with QUI setup) if QONSOLE_BOOTSTRAP is defined
public static Action tick_f = () => {};
// OBSOLETE, USE COMMANDS INSTEAD:
public static Action onStart_f = () => {};
// OBSOLETE, USE COMMANDS INSTEAD:
public static Action onDone_f = () => {};
// OBSOLETE, USE COMMANDS INSTEAD: called inside OnGUI if QONSOLE_BOOTSTRAP is defined
public static Action onGUI_f = () => {};
#if HAS_UNITY
// we hope it is the main thread?
public static readonly int ThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
// the Unity editor (QGL) repaint callback
public static Action<Camera> onEditorRepaint_f = c => {};
static bool _isEditor => Application.isEditor;
static string _dataPath => Application.persistentDataPath;
static float _textDx => QGL.TextDx;
static float _textDy => QGL.TextDy;
static int _cursorChar => QGL.GetCursorChar();
#else
static bool _isEditor = false;
static string _dataPath = "./";
static int _textDx = AppleFont.APPLEIIF_CW + 1;
static int _textDy = AppleFont.APPLEIIF_CH + 3;
static int _cursorChar => 127;
#endif
static int _totalTime;
static string _historyPath;
static string _configPath;
static int _drawCharStartY;
// how much currently drawn char is faded out in the 'overlay' controlled by QonOverlayPercent_kvar
static float _overlayAlpha = 1;
// the colorization stack for nested tags
static List<Color> _drawCharColorStack = new List<Color>(){ Color.white };
// the internal commands have a different path of execution
// to avoid recursion of Cellophane.TryExecute
static Dictionary<string,Action<string[],object>> _internalCommands =
new Dictionary<string,Action<string[],object>>();
static Action<string> _oneShotCmd_f;
static string [] _history;
static int _historyItem;
#if QONSOLE_QUI
static Vector2 _mousePosition;
#endif
#if QONSOLE_KEYBINDS
static HashSet<KeyCode> _holdKeys = new HashSet<KeyCode>();
#endif
static void DrawCharColorPush( Color newColor ) {
if ( _drawCharColorStack.Count < 16 ) {
_drawCharColorStack.Add( newColor );
}
}
static void DrawCharColorPop() {
if ( _drawCharColorStack.Count > 1 ) {
_drawCharColorStack.RemoveAt( _drawCharColorStack.Count - 1 );
}
}
static Vector2 QoncheToScreen( int x, int y ) {
float screenX = x * _textDx * QonScale;
float screenY = ( y - _drawCharStartY ) * _textDy * QonScale;
return new Vector2( screenX, screenY );
}
// FIXME: remove the allocations here
static Action OverlayGetFade() {
int timestamp = _totalTime;
return () => {
const float solidTime = 4.0f;
float t = ( _totalTime - timestamp ) / 1000f;
float ts = 2f * ( solidTime - t );
_overlayAlpha = t < solidTime ? 1 : Mathf.Max( 0, 1 - ts * ts );
};
}
static void RenderBegin() {
#if HAS_UNITY
_totalTime = ( int )( Time.realtimeSinceStartup * 1000.0f );
#else
_totalTime = ( int )SDL_GetTicks();
#endif
}
static void RenderEnd() {
_overlayAlpha = 1;
_drawCharStartY = 0;
_drawCharColorStack.Clear();
_drawCharColorStack.Add( Color.white );
}
static bool DrawCharBegin( ref int c, int x, int y, bool isCursor, out Color color,
out Vector2 screenPos ) {
color = Color.white;
screenPos = Vector2.zero;
if ( Active ) {
_drawCharStartY = 0;
c = c == 0 ? '~' : c;
} else if ( _overlayAlpha <= 0 ) {
_drawCharStartY = y + 1;
return false;
}
if ( isCursor ) {
c = ( _totalTime & 256 ) != 0 ? c : _cursorChar;
}
if ( c == ' ' ) {
return false;
}
Color stackCol = _drawCharColorStack[_drawCharColorStack.Count - 1];
float a = Active ? stackCol.a : _overlayAlpha;
color = new Color ( stackCol.r, stackCol.g, stackCol.b, a );
screenPos = QoncheToScreen( x, y );
return true;
}
static void InternalCommand( string cmd, object context = null ) {
Action<string[],object> action;
if ( ! _internalCommands.TryGetValue( cmd, out action ) ) {
if ( ! Cellophane.TryFindCommand( cmd, out action ) ) {
return;
}
}
action( null, context );
}
static void Clear_kmd( string [] argv ) {
for ( int i = 0; i < 50; i++ ) {
QON_Putc( '\n' );
}
}
static void Echo_kmd( string [] argv ) {
if ( argv.Length == 1 ) {
return;
}
string text = "";
for ( int i = 1; i < argv.Length; i++ ) {
text += argv[i] + " ";
}
Log( text );
}
static void Help_kmd( string [] argv ) {
Log( "Qonsole history storage: '" + _historyPath + "'" );
Log( "Qonsole config storage: '" + _configPath + "'" );
Log( "[ff9000]~[-] -- Toggle." );
Log( "[ff9000]PgUp/PgDown[-] -- page up / page down." );
Log( "[ff9000]UpArrow/DownArrow[-] -- History." );
Log( "[ff9000]Tab[-] -- Autocomplete." );
Log( "Example method to be parsed as a command: [ff9000]static void Help_kmd(string [] argv)[-]");
Log( "Example static member to be parsed as a variable: [ff9000]static bool ToggleFlag_kvar[-]");
Log( "[ff9000]cmd/cvar[-] and [ff9000]kmd/kvar[-] are valid suffixes for exported names.");
Log( "[ff9000]kmd/kvar[-] ignore class names when exporting to the command line.");
Log( "Type [ff9000]'list'[-] or [ff9000]'ls'[-] to view existing commands." );
Log( "Type [ff9000]'help'[-] for this help." );
Cellophane.PrintInfo();
}
static void Exit_kmd( string [] argv ) {
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#elif HAS_UNITY
if ( _isEditor ) {
Log( "Can't quit if not linked against Editor." );
}
Application.Quit();
#else
Environment.Exit( 1 );
// ...
#endif
}
static void Quit_kmd( string [] argv ) { Exit_kmd( argv ); }
// some stuff need to be initialized before the Start() Unity callback
public static void Init( int configVersion = -1 ) {
Log( featuresDescription );
string fnameCfg = null, fnameHistory;
string[] args = System.Environment.GetCommandLineArgs ();
bool customConfig = false;
foreach ( var a in args ) {
if ( a.StartsWith( "--cfg" ) ) {
string [] cfgArg = a.Split( new []{' ','='}, StringSplitOptions.RemoveEmptyEntries );
if ( cfgArg.Length > 1 ) {
fnameCfg = cfgArg[1].Replace("\"", "");
Log( "Supplied cfg by command line: " + fnameCfg );
customConfig = true;
}
break;
}
}
if ( string.IsNullOrEmpty( fnameCfg ) ) {
if ( _isEditor ) {
fnameCfg = "qon_default_ed.cfg";
} else {
fnameCfg = "qon_default.cfg";
}
}
if ( _isEditor ) {
fnameHistory = "qon_history_ed.cfg";
Log( "Run in Unity Editor." );
} else {
fnameHistory = "qon_history.cfg";
Log( "Run Standalone." );
}
#if HAS_UNITY
Log( $"Unity version: {Application.unityVersion}" );
#endif
Log( "Inverted Y in Play window: " + QonInvertPlayY );
_historyPath = Path.Combine( _dataPath, fnameHistory );
_configPath = Path.Combine( _dataPath, fnameCfg );
string history = string.Empty;
string config = string.Empty;
try {
history = File.ReadAllText( _historyPath );
config = File.ReadAllText( _configPath );
} catch ( Exception ) {
Log( "Didn't read config files." );
}
if ( configVersion >= 0 ) {
Cellophane.ConfigVersion_kvar = configVersion;
}
Cellophane.UseColor = true;
Cellophane.Log = s => Log( s );
Cellophane.Error = s => Error( $"[Cellophane] {s}" );
Cellophane.ScanVarsAndCommands();
InternalCommand( "qonsole_pre_config" );
TryExecuteLegacy( onPreLoadCfg_f() );
Cellophane.ReadHistory( history );
Cellophane.ReadConfig( config, skipVersionCheck: customConfig );
TryExecuteLegacy( onPostLoadCfg_f() );
InternalCommand( "qonsole_post_config" );
Help_kmd( null );
if ( onStoreCfg_f == null ) {
#if QONSOLE_KEYBINDS
onStoreCfg_f = () => KeyBinds.StoreConfig();
#else
onStoreCfg_f = () => "";
#endif
}
#if QONSOLE_QUI
QUI.DrawLineRect = (x,y,w,h) => QGL.LateDrawLineRect(x,y,w,h,color:Color.magenta);
QUI.Log = s => Qonsole.Log( s );
QUI.Error = s => Qonsole.Error( s );
//QUI.canvas = ...
//QUI.whiteTexture = ...
//QUI.defaultFont = ...
#endif
}
#if HAS_UNITY
public static void OnEditorSceneGUI( Camera camera, bool paused, float pixelsPerPoint = 1,
Action<Camera> onRepaint = null ) {
if ( QonShowInEditor_kvar == 0 ) {
return;
}
onRepaint = onRepaint != null ? onRepaint : c => {};
bool notRunning = ! Application.isPlaying || paused;
InternalCommand( "qonsole_on_editor_event" );
if ( ( Active || ConsumeEditorInputOnce ) && notRunning ) {
if ( Event.current.button == 0 ) {
var controlID = GUIUtility.GetControlID( FocusType.Passive );
if ( Event.current.type == EventType.MouseDown ) {
QUI.OnMouseButton( true );
GUIUtility.hotControl = controlID;
} else if ( Event.current.type == EventType.MouseUp ) {
QUI.OnMouseButton( false );
if ( GUIUtility.hotControl == controlID ) {
GUIUtility.hotControl = 0;
}
}
}
}
if ( Event.current.type == EventType.Repaint ) {
QGL.SetContext( camera, pixelsPerPoint, invertedY: true );
if ( notRunning ) {
Vector2 mouse = Event.current.mousePosition * pixelsPerPoint;
QUI.Begin( mouse.x, mouse.y );
}
ConsumeEditorInputOnce = false;
onRepaint( camera );
InternalCommand( "qonsole_on_editor_repaint" );
QGL.LatePrint( "qonsole is running", Screen.width - 100, QGL.ScreenHeight() - 100 );
}
OnGUIInternal();
if ( Event.current.type == EventType.Repaint ) {
QGL.SetContext( null, invertedY: QonInvertPlayY );
if ( notRunning ) {
QUI.End( skipUnityUI: true );
}
}
if ( ( Active || ConsumeEditorInputOnce )
&& Event.current.type != EventType.Repaint
&& Event.current.type != EventType.Layout ) {
Event.current.Use();
}
}
public static void OnGUIInternal( bool skipRender = false ) {
if ( ! Started ) {
return;
}
if ( Event.current.type == EventType.Repaint ) {
RenderGL( skipRender );
} else if ( Active ) {
if ( Event.current.type != EventType.Repaint ) {
// Handling arrows in IsKeyDown/Up on Update doesn't respect
// the OS repeat delay, thus this
// Also can't see a way to acquire a string better than OnGUI
// As a bonus -- no dependency on the legacy Input system
if ( Event.current.type == EventType.KeyDown ) {
//if ( _oneShotCmd_f != null ) {
// if ( Event.current.keyCode == KeyCode.LeftArrow ) {
// QON_MoveLeft( 1 );
// } else if ( Event.current.keyCode == KeyCode.RightArrow ) {
// QON_MoveRight( 1 );
// } else if ( Event.current.keyCode == KeyCode.Home ) {
// QON_MoveLeft( 99999 );
// } else if ( Event.current.keyCode == KeyCode.End ) {
// QON_MoveRight( 99999 );
// } else if ( Event.current.keyCode == KeyCode.Delete ) {
// QON_Delete( 1 );
// } else if ( Event.current.keyCode == KeyCode.Backspace ) {
// QON_Backspace( 1 );
// } else if ( Event.current.keyCode == KeyCode.Escape ) {
// Log( "Canceled..." );
// QON_EraseCommand();
// Active = false;
// _oneShotCmd_f = null;
// } else {
// char c = Event.current.character;
// if ( c == '`' ) {
// } else if ( c == '\t' ) {
// } else if ( c == '\b' ) {
// } else if ( c == '\n' || c == '\r' ) {
// string cmd = QON_GetCommand();
// QON_EraseCommand();
// _oneShotCmd_f( cmd );
// _oneShotCmd_f = null;
// Active = false;
// } else {
// QON_InsertCommand( c.ToString() );
// }
// }
//} else
if ( Event.current.keyCode == KeyCode.BackQuote ) {
Toggle();
} else if ( Event.current.keyCode == KeyCode.LeftArrow ) {
QON_MoveLeft( 1 );
} else if ( Event.current.keyCode == KeyCode.Home ) {
QON_MoveLeft( 99999 );
} else if ( Event.current.keyCode == KeyCode.RightArrow ) {
QON_MoveRight( 1 );
} else if ( Event.current.keyCode == KeyCode.End ) {
QON_MoveRight( 99999 );
} else if ( Event.current.keyCode == KeyCode.Delete ) {
_history = null;
QON_Delete( 1 );
} else if ( Event.current.keyCode == KeyCode.Backspace ) {
_history = null;
QON_Backspace( 1 );
} else if ( Event.current.keyCode == KeyCode.PageUp ) {
QON_PageUp();
} else if ( Event.current.keyCode == KeyCode.PageDown ) {
QON_PageDown();
} else if ( Event.current.keyCode == KeyCode.Escape ) {
if ( _history != null ) {
// cancel history, store last typed-in command
QON_SetCommand( _history[0] );
_history = null;
} else {
// just erase the prompt if no history
QON_EraseCommand();
}
} else if ( Event.current.keyCode == KeyCode.DownArrow
|| Event.current.keyCode == KeyCode.UpArrow ) {
string cmd = QON_GetCommand();
if ( _history == null ) {
_history = Cellophane.GetHistory( cmd );
_historyItem = _history.Length * 100;
}
_historyItem += Event.current.keyCode == KeyCode.DownArrow ? 1 : -1;
if ( _historyItem >= 0 ) {
QON_SetCommand( _history[_historyItem % _history.Length] );
}
} else {
char c = Event.current.character;
if ( c == '`' ) {
} else if ( c == '\t' ) {
string cmd = QON_GetCommand();
string autocomplete = Cellophane.Autocomplete( cmd );
QON_SetCommand( autocomplete );
} else if ( c == '\b' ) {
} else if ( c == '\n' || c == '\r' ) {
OnEnter();
} else {
_history = null;
QON_InsertCommand( c.ToString() );
}
}
}
}
} else if ( Event.current.type == EventType.KeyDown
&& Event.current.keyCode == KeyCode.BackQuote ) {
Toggle();
}
}
public static void OnGUI() {
#if QONSOLE_QUI
_mousePosition = Event.current.mousePosition;
if ( Event.current.button == 0 ) {
if ( Event.current.type == EventType.MouseDown ) {
QUI.OnMouseButton( true );
} else if ( Event.current.type == EventType.MouseUp ) {
QUI.OnMouseButton( false );
}
}
#endif
#if QONSOLE_KEYBINDS
if ( ! Active ) {
KeyCode kc = Event.current.button == 0 ? KeyCode.Mouse0 : KeyCode.Mouse1;
if ( Event.current.type == EventType.MouseDown ) {
KeyBinds.TryExecuteBinds( keyDown: kc );
_holdKeys.Add( kc );
} else if ( Event.current.type == EventType.MouseUp ) {
KeyBinds.TryExecuteBinds( keyUp: kc );
_holdKeys.Remove( kc );
}
if ( Event.current.type == EventType.KeyDown ) {
KeyBinds.TryExecuteBinds( keyDown: Event.current.keyCode );
_holdKeys.Add( Event.current.keyCode );
} else if ( Event.current.type == EventType.KeyUp ) {
KeyBinds.TryExecuteBinds( keyUp: Event.current.keyCode );
_holdKeys.Remove( Event.current.keyCode );
}
}
#endif
InternalCommand( "qonsole_on_gui" );
onGUI_f();
OnGUIInternal( skipRender: _isEditor && QonShowInEditor_kvar == 2 );
}
static void PrintToSystemLog( string s, QObject o ) {
if ( ! QonPrintToSystemLog_kvar ) {
return;
}
// stack trace changes throw exception outside of the Main thread
if ( System.Threading.Thread.CurrentThread.ManagedThreadId != ThreadID ) {
Debug.Log( s, o );
return;
}
StackTraceLogType oldType = Application.GetStackTraceLogType( LogType.Log );
if ( _isEditor ) {
Application.SetStackTraceLogType( LogType.Log, StackTraceLogType.ScriptOnly );
Debug.Log( s, o );
} else {
Application.SetStackTraceLogType( LogType.Log, StackTraceLogType.None );
Debug.Log( s, o );
}
Application.SetStackTraceLogType( LogType.Log, oldType );
}
static void RenderGL( bool skip = false ) {
void drawChar( int c, int x, int y, bool isCursor, object param ) {
if ( DrawCharBegin( ref c, x, y, isCursor, out Color color, out Vector2 screenPos ) ) {
QGL.DrawScreenCharWithOutline( c, screenPos.x, screenPos.y, color, QonScale );
}
}
RenderBegin();
QGL.Begin();
QGL.FlushLates();
//QGL.LateBlitFlush();
//QGL.LatePrintFlush();
//QGL.LateDrawLineFlush();
if ( ! skip ) {
int maxH = ( int )QGL.ScreenHeight();
int cW = ( int )( _textDx * QonScale );
int cH = ( int )( _textDy * QonScale );
int conW = Screen.width / cW;
int conH = maxH / cH;
if ( Active ) {
QGL.SetWhiteTexture();
GL.Begin( GL.QUADS );
GL.Color( new Color( 0, 0, 0, QonAlpha_kvar ) );
QGL.DrawSolidQuad( new Vector2( 0, 0 ), new Vector2( Screen.width, maxH ) );
GL.End();
} else {
int percent = Mathf.Clamp( QonOverlayPercent_kvar, 0, 100 );
conH = conH * percent / 100;
}
QGL.SetFontTexture();
GL.Begin( GL.QUADS );
QON_DrawChar = drawChar;
QON_DrawEx( conW, conH, ! Active, 0 );
GL.End();
}
QGL.End( skipLateFlush: true );
RenderEnd();
}
#else // if not HAS_UNITY
static void PrintToSystemLog( string s, QObject o ) {
if ( QonPrintToSystemLog_kvar ) {
System.Console.Write( Cellophane.ColorTagStripAll( s ) );
}
}
#endif // HAS_UNITY
static void OnEnter() {
_history = null;
string cmdClean, cmdRaw;
QON_GetCommandEx( out cmdClean, out cmdRaw );
QON_EraseCommand();
Log( cmdRaw );
Cellophane.AddToHistory( cmdClean );
TryExecute( cmdClean );
FlushConfig();
}
public static void Update() {
#if QONSOLE_KEYBINDS
foreach ( var k in _holdKeys ) {
KeyBinds.TryExecuteBinds( keyHold: k );
}
#endif
#if QONSOLE_QUI
QUI.Begin( ( int )_mousePosition.x, ( int )_mousePosition.y );
#endif
InternalCommand( "qonsole_tick" );
Qonsole.tick_f();
#if QONSOLE_QUI
QUI.End();
#endif
}
public static void FlushConfig() {
File.WriteAllText( _historyPath, Cellophane.StoreHistory() );
File.WriteAllText( _configPath, Cellophane.StoreConfig() + onStoreCfg_f() );
}
public static void OnApplicationQuit() {
InternalCommand( "qonsole_done" );
onDone_f();
FlushConfig();
}
// == public API ==
public static void Start() {
#if HAS_UNITY
if ( QGL.Start( invertedY: QonInvertPlayY ) ) {
Started = true;
Log( "Qonsole Started." );
InternalCommand( "qonsole_post_start" );
onStart_f();
} else {
Started = false;
}
#else
Started = true;
Log( "Qonsole Started." );
onStart_f();
#endif
}
public static void TryExecute( string cmdLine, object context = null, bool keepJsonTags = false ) {
Cellophane.TryExecuteString( cmdLine, context: context, keepJsonTags: keepJsonTags );
}
public static void TryExecuteLegacy( string cmdLine, object context = null ) {
string [] cmds;
if ( Cellophane.SimpleCommandsSplit( cmdLine, out cmds ) ) {
string [] argv;
foreach ( var cmd in cmds ) {
if ( Cellophane.GetArgv( cmd, out argv ) ) {
Cellophane.TryExecute( argv, context );
}
}
}
}
public static void Toggle() {
Active = ! Active;
}
public static void Error( object o ) {
Error( o.ToString() );
}
public static void Error( string s, QObject o = null ) {
s = "ERROR: " + s;
Action fade = OverlayGetFade();
// lump together colorization and overlay fade
QON_PrintAndAct( s, (x,y) => {
DrawCharColorPush( Color.red );
fade();
} );
QON_PrintAndAct( "\n", (x,y)=>DrawCharColorPop() );
PrintToSystemLog( s, o );
}
// this will ignore color tags
public static void PrintRaw( string s ) {
Action fade = OverlayGetFade();
QON_PrintAndAct( s, (x,y)=>fade() );
}
public static void Log( string s, QObject o = null ) {
Print( s + "\n", o );
}
public static void Log( object o, QObject unityObj = null ) {
Log( o == null ? "null" : o.ToString(), unityObj );
}
public static void PrintAndAct( string s, Action<Vector2,float> a ) {
if ( ! string.IsNullOrEmpty( s ) ) {
QON_PrintAndAct( s, (x,y)=> {
float alpha = Active ? 1 : _overlayAlpha;
if ( alpha > 0 ) {
Vector2 screenPos = QoncheToScreen( x, y );
#if HAS_UNITY
GL.End();
a( screenPos, alpha );
QGL.SetFontTexture();
GL.Begin( GL.QUADS );
#else
a( screenPos, alpha );
#endif
}
} );
} else {
Error( "PrintAndAct: pass a non-empty string." );
}
}
// print (colorized) text
public static void Print( string s, QObject o = null ) {
string sysString = "";
bool skipFade = false;
for ( int i = 0; i < s.Length; i++ ) {
// handle nested colorization tags by lumping their logic into a single pager Action
string tag;
List<Action> actions = new List<Action>();
while ( true ) {
if ( Cellophane.ColorTagLead( s, i, out tag ) ) {
i += tag.Length;
Color c = QGL.TagToCol( tag );
actions.Add( ()=>DrawCharColorPush( c ) );
} else if ( Cellophane.ColorTagClose( s, i, out tag ) ) {
i += tag.Length;
actions.Add( ()=>DrawCharColorPop() );
} else {
break;
}
}
// add the overlay fade just once per string
if ( ! skipFade ) {
actions.Add( OverlayGetFade() );
skipFade = true;
}
if ( actions.Count > 0 ) {
// actual print with colorization and (overlay) fadeout
QON_PrintAndAct( s[i].ToString(), (x,y) => {
foreach( var a in actions ) {
a();
}
} );
} else {
// raw output to qonche (no colorization), never reached
QON_Putc( s[i] );
}
sysString += s[i];
}
PrintToSystemLog( sysString, o );
}
public static void Break( string str ) {
Log( str );
#if HAS_UNITY
UnityEngine.Debug.Break();
#endif
}
public static void OneShotCmd( string fillCommandLine, Action<string> a ) {
QON_SetCommand( fillCommandLine );
Active = true;
_oneShotCmd_f = a;
}
public static float LineHeight() {
return _textDy * QonScale;
}
#if SDL
static IntPtr x_renderer;
static IntPtr x_window;
static void SDLDrawChar( int c, int x, int y, int w, int h, Color32 col ) {
int idx = c & ( APPLEIIF_ROWS * APPLEIIF_CLMS - 1 );
var tex = AppleFont.GetTexture( x_renderer );
SDL_SetTextureAlphaMod( tex, 0xff );
SDL_SetTextureBlendMode( tex, SDL_BLENDMODE_BLEND );
SDL_Rect src = new SDL_Rect {
x = idx % APPLEIIF_CLMS * APPLEIIF_CW,
y = idx / APPLEIIF_CLMS * APPLEIIF_CH,
w = APPLEIIF_CW,
h = APPLEIIF_CH,
};
SDL_SetTextureColorMod( tex, col.r, col.g, col.b );
SDL_Rect dst = new SDL_Rect { x = x, y = y, w = w, h = h };
SDL_RenderCopy( x_renderer, tex, ref src, ref dst );
}
public static void SDLDone() {
OnApplicationQuit();
}
public static bool SDLTick( IntPtr renderer, IntPtr window, bool skipRender = false ) {
x_renderer = renderer;
x_window = window;
while ( SDL_PollEvent( out SDL_Event ev ) != 0 ) {
SDL_Keycode code = ev.key.keysym.sym;
switch( ev.type ) {
case SDL_TEXTINPUT:
byte [] b = new byte[SDL_TEXTINPUTEVENT_TEXT_SIZE];
unsafe {
Marshal.Copy( ( IntPtr )ev.text.text, b, 0, b.Length );
}
string txt = System.Text.Encoding.UTF8.GetString( b, 0, b.Length );
if ( txt.Length > 0 && txt[0] != '`' && txt[0] != '~' ) {
QON_InsertCommand( txt );
}
break;
case SDL_KEYDOWN:
switch ( code ) {
case SDLK_LEFT: QON_MoveLeft( 1 ); break;
case SDLK_RIGHT: QON_MoveRight( 1 ); break;
case SDLK_HOME: QON_MoveLeft( 99999 ); break;
case SDLK_END: QON_MoveRight( 99999 ); break;
case SDLK_PAGEUP: QON_PageUp(); break;
case SDLK_PAGEDOWN: QON_PageDown(); break;
case SDLK_ESCAPE: QON_EraseCommand(); break;
case SDLK_BACKQUOTE: Toggle(); break;
case SDLK_BACKSPACE: {
_history = null;
QON_Backspace( 1 );
break;
}
case SDLK_DELETE: {
_history = null;
QON_Delete( 1 );
break;
}
case SDLK_TAB: {
string autocomplete = Cellophane.Autocomplete( QON_GetCommand() );
QON_SetCommand( autocomplete );
}
break;
case SDLK_RETURN: {
OnEnter();
}
break;
default: break;
}
break;
case SDL_MOUSEMOTION:
//x_mouseX = ev.motion.x;
//x_mouseY = ev.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
//ZH_UI_OnMouseButton( 1 );
break;
case SDL_MOUSEBUTTONUP:
//ZH_UI_OnMouseButton( 0 );
break;
case SDL_QUIT:
return false;
default:
break;
}
}
if ( ! Started ) {
return true;
}
Update();
void drawChar( int c, int x, int y, bool isCursor, object param ) {
if ( DrawCharBegin( ref c, x, y, isCursor, out Color color, out Vector2 screenPos ) ) {
int cw = ( int )( APPLEIIF_CW * QonScale );
int ch = ( int )( APPLEIIF_CH * QonScale );
int cx = ( int )screenPos.x;
int cy = ( int )screenPos.y;
int off = ( int )QonScale;
SDLDrawChar( c, cx + off, cy + off, cw, ch, Color.black );
SDLDrawChar( c, cx, cy, cw, ch, color );
}
}
RenderBegin();
SDL_GetWindowSize( x_window, out int screenW, out int screenH );
int cW = ( int )( _textDx * QonScale );
int cH = ( int )( _textDy * QonScale );
int conW = screenW / cW;
int conH = screenH / cH;
if ( Active ) {
SDL_SetRenderDrawBlendMode( x_renderer, SDL_BLENDMODE_BLEND );
SDL_SetRenderDrawColor( x_renderer, 0, 0, 0, ( byte )( QonAlpha_kvar * 255f ) );
SDL_Rect bgrRect = new SDL_Rect {
x = 0, y = 0, w = screenW, h = screenH
};
SDL_RenderFillRect( x_renderer, ref bgrRect );
} else {
int percent = Mathf.Clamp( QonOverlayPercent_kvar, 0, 100 );
conH = conH * percent / 100;
}
QON_DrawChar = drawChar;
QON_DrawEx( conW, conH, ! Active, 0 );
RenderEnd();
return true;
}
#endif // SDL
} // class Qonsole
#else
// == Multiplatform (non-Unity) API here ==
public static class Qonsole {
static string _configPath = "";
static Qonsole() {
}
public static void Init( int configVersion = 0 ) {
string fnameCfg = null;
string[] args = System.Environment.GetCommandLineArgs ();
bool customConfig = false;
foreach ( var a in args ) {
if ( a.StartsWith( "--cfg" ) ) {
string [] cfgArg = a.Split( new []{' ','='}, StringSplitOptions.RemoveEmptyEntries );
if ( cfgArg.Length > 1 ) {
fnameCfg = cfgArg[1].Replace("\"", "");
Log( "Supplied cfg by command line: " + fnameCfg );
customConfig = true;
}
break;
}
}
if ( string.IsNullOrEmpty( fnameCfg ) ) {
fnameCfg = "qon_default.cfg";
}
string config = string.Empty;
string dir = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetEntryAssembly().Location
);
_configPath = Path.Combine( dir, fnameCfg );
Log( $"Qonsole config storage: '{_configPath}'" );
try {
config = File.ReadAllText( _configPath );
} catch ( Exception e ) {
Log( "Didn't read config files." );
Log( e.Message );
}
Cellophane.ConfigVersion_kvar = configVersion;
Cellophane.UseColor = false;
Cellophane.Log = s => Log( s );
Cellophane.Error = s => Error( $"[Cellophane] {s}" );
Cellophane.ScanVarsAndCommands();
Cellophane.ReadConfig( config, skipVersionCheck: customConfig );
FlushConfig();
}
public static void FlushConfig() {
try {
File.WriteAllText( _configPath, Cellophane.StoreConfig() );
Log( $"Stored qonsole config '{_configPath}'" );
} catch ( Exception e ) {
Log( e.Message );
}
}
public static void TryExecute( string cmdLine, object context = null, bool keepJsonTags = false ) {
Cellophane.TryExecuteString( cmdLine, context: context, keepJsonTags: keepJsonTags );
}
public static void Print( string s ) {
System.Console.Write( Cellophane.ColorTagStripAll( s ) );
}
public static void Log( string s ) {
System.Console.WriteLine( Cellophane.ColorTagStripAll( s ) );
}
public static void Log( object o ) {
Log( o == null ? "null" : o.ToString() );
}
public static void Error( object o ) {
Log( "ERROR: " + o );
}
public static void Break( object o ) {
Log( "BREAK: " + o );
}
}
#endif // UNITY
} namespace QON {
/*
Cellophane is a 'shell-like' interface for C# programs
Exports vars and commands to command line using reflection
Storage of config and history
Command-line interpreter
Autocomplete
*/
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Globalization;
using System;
public static class Cellophane {
class Named : IComparable {
public string rawName;
public string name;
public int CompareTo(object obj) {
if ( obj == null )
return 1;
string other = obj as string;
return this.name.CompareTo( other );
}
}
class Command : Named {
public Action<string[],object> ActionArgv = (sa,context) => {};
}
class Variable : Named {
public string description = "";
public FieldInfo fieldInfo;
public Func<bool> Changed_f;
public string GetValue() {
return Convert.ToString( fieldInfo.GetValue( null ), CultureInfo.InvariantCulture );
}
public void SetupChanged<T>() {
T oldValue = ( T )fieldInfo.GetValue( null );
Changed_f = () => {
T newVal = ( T )fieldInfo.GetValue( null );
bool result = ! oldValue.Equals( newVal );
oldValue = newVal;
return result;
};
}
public void SetupChanged() {
if ( fieldInfo.FieldType == typeof( bool ) ) {
SetupChanged<bool>();
} else if ( fieldInfo.FieldType == typeof( int ) ) {
SetupChanged<int>();
} else if ( fieldInfo.FieldType == typeof( float ) ) {
SetupChanged<float>();
} else if ( fieldInfo.FieldType == typeof( string ) ) {
SetupChanged<string>();
} else {
Changed_f = () => false;
Error( "Unknown var type: " + fieldInfo.FieldType );
}
}
public Action<string> SetValue_f;
}
static Command [] _commands = new Command[0];
static Variable [] _variables = new Variable[0];
static int [] _orderedDist;
static string [] _allNames;
static List<string> _history = new List<string>();
// when sorting the autocomplete buffer, anything above this distance doesn't
// contain the match candidate
const int AutocompleteBorderDist = 10000;
static void History_kmd( string [] argv ) {
foreach ( var h in _history ) {
Log(" " + h);
}
Log("======");
}
static void ls_kmd( string [] argv ) {
List_kmd( argv );
}
static void List_kmd( string [] argv ) {
if ( Array.IndexOf(argv, "--raw") > -1 ) {
foreach ( var c in _commands ) {
Log( c.name + " -> " + c.rawName + "()" );
}
Log( "" );
foreach ( var v in _variables ) {
Log( v.name + " -> " + v.rawName );
}
} else {
foreach ( var c in _commands ) {
Log( c.name );
}
Log( "" );
foreach ( var v in _variables ) {
string str = v.name + " = " + v.GetValue();
if ( v.description.Length > 0 ) {
str += " : " + v.description;
}
Log( str );
}
}
Log( "" );
Log( "Num Commands: " + _commands.Length );
Log( "Num Variables: " + _variables.Length );
Log( "Use with --raw to show function names." );
}
static bool ValidSuffixVar( string name ) {
return name.EndsWith( "_cvar" ) || name.EndsWith( "_kvar" );
}
static bool ValidSuffixCmd( string name ) {
return name.EndsWith( "_cmd" ) || name.EndsWith( "_kmd" );
}
static string NormalizeNameVar( string varName ) {
if ( varName.Length < 6 ) {
return varName.ToLowerInvariant();
}
int n = ValidSuffixVar( varName ) ? varName.Length - 5 : varName.Length;
return NormalizeName( varName, n );
}
static string NormalizeNameCmd( string cmdName ) {
if ( cmdName.Length < 5 ) {
return cmdName.ToLowerInvariant();
}
int n = ValidSuffixCmd( cmdName ) ? cmdName.Length - 4 : cmdName.Length;
return NormalizeName( cmdName, n );
}
static void OnVariable( Variable cvar, string [] argv ) {
if ( argv.Length > 1 ) {
int i;
for ( i = 1; i < argv.Length; i++ ) {
if ( ! argv[i].Contains( "=" ) ) {
break;
}
}
cvar.SetValue_f( argv[i] );
Log( cvar.name + " = " + cvar.GetValue() );
} else {
string log = cvar.name + " = " + cvar.GetValue();
if ( ! string.IsNullOrEmpty( cvar.description ) ) {
Log( log + " : " + cvar.description );
} else {
Log( log );
}
}
}
static string SubstrToFirstDiff( string a, string b ) {
string result = "";
int n = Math.Min( a.Length, b.Length );
for ( int i = 0; i < n; i++ ) {
if ( a[i] != b[i] ) {
break;
}
result += a[i];
}
return result;
}
static int LevenshteinDistance( string s, string t ) {
int n = s.Length;
int m = t.Length;
int[,] d = new int[n + 1, m + 1];
// Step 1
if (n == 0)
{
return m;
}
if (m == 0)
{
return n;
}
// Step 2
for (int i = 0; i <= n; d[i, 0] = i++)
{
}
for (int j = 0; j <= m; d[0, j] = j++)
{
}
// Step 3
for (int i = 1; i <= n; i++)
{
//Step 4
for (int j = 1; j <= m; j++)
{
// Step 5
int cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
// Step 6
d[i, j] = Math.Min(
Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
d[i - 1, j - 1] + cost);
}
}
// Step 7
return d[n, m];
}
static string GetSorted( int k ) {
return _allNames[_orderedDist[k] & 0xffff];
}
static int GetDist( int k ) {
return _orderedDist[k] >> 16;
}
static void PrintSuggestions( int maxToPrint, string hilight = null,
bool skipWeakMatches = false ) {
Log( "" );
int i;
for ( i = maxToPrint - 1; i >= 0; i-- ) {
if ( GetDist( i ) < AutocompleteBorderDist ) {
break;
}
if ( ! skipWeakMatches ) {
Log( "[b0b0b0]" + GetSorted( i ) + "[-]" );
}
}
string lit = "[ff9000]" + hilight + "[-]";
for ( ; i >= 0; i-- ) {
Variable v;
string raw = GetSorted( i );
string str;
if ( hilight != null ) {
str = raw.Replace( hilight, lit );
} else {
str = raw;
}
if ( TryFindVariable( raw, out v ) ) {
string log = str + " = " + v.GetValue();
log += v.description.Length > 0 ? ( "[c0c0c0] : " + v.description + "[-]" ) : "";
Log( log );
} else {
Log( str );
}
}
}
static void CollectItems() {
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
List<Type> asmTypes = new List<Type>();
int numAssemblies = 0;
foreach ( var a in assemblies ) {
string name = a.GetName().Name;
if ( name.Contains( "Unity." ) ) continue;
if ( name.Contains( "UnityEditor." ) ) continue;
if ( name.Contains( "Engine." ) ) continue;
if ( name.Contains( "UnityEngine." ) ) continue;
if ( name.Contains( "System." ) ) continue;
if ( name.Contains( "Photon" ) ) continue;
if ( name.Contains( "Microsoft" ) ) continue;
if ( name.Contains( "Autodesk" ) ) continue;
if ( name.Contains( "Sony" ) ) continue;
if ( name.Contains( "mscorlib" ) ) continue;
numAssemblies++;
asmTypes.AddRange( a.GetTypes() );
}
Assembly currentAssembly = Assembly.GetExecutingAssembly();
Type [] types;
try {
if ( asmTypes.Count > 0 ) {
types = asmTypes.ToArray();
Log( $"Num assemblies parsed: {numAssemblies}." );
} else {
types = currentAssembly.GetTypes();
}
} catch(Exception e) {
Error( "Cellophane: Failed to parse commands: " + e );
_commands = new Command [] {};
_variables = new Variable [] {};
return;
}
List<Command> cmds = new List<Command>();
List<Variable> vars = new List<Variable>();
foreach (Type type in types) {
FieldInfo [] fields = type.GetFields( BFS );
foreach ( FieldInfo fi in fields ) {
if ( ! ValidSuffixVar( fi.Name ) ) {
continue;
}
string name = fi.Name.EndsWith( "_kvar" ) ? fi.Name : type.Name + "_" + fi.Name;
Variable cvar = new Variable {
fieldInfo = fi,
name = NormalizeNameVar( name ),
rawName = type.Name + "." + fi.Name,
};
foreach ( var ca in fi.GetCustomAttributes() ) {
DescriptionAttribute da = ca as DescriptionAttribute;
if ( da != null ) {
cvar.description = da.Description;
}
}
if ( fi.FieldType == typeof( bool ) ) {
cvar.SetValue_f = (s) => {
string tl = s.ToLowerInvariant();
bool val = tl != "false" && tl != "0";
cvar.fieldInfo.SetValue( null, val );
};
} else if ( fi.FieldType == typeof( int ) ) {
cvar.SetValue_f = (s) => {
int i;
if ( int.TryParse( s, out i ) ) {
cvar.fieldInfo.SetValue( null, i );
}
};
} else if ( fi.FieldType == typeof( float ) ) {
cvar.SetValue_f = (s) => {
if ( AtoF( s, out float f ) ) {
cvar.fieldInfo.SetValue( null, f );
}
};
} else if ( fi.FieldType == typeof( string ) ) {
cvar.SetValue_f = s => cvar.fieldInfo.SetValue( null, s );
} else {
Error( "Cellophane: Unsupported type of var " + fi.FieldType.ToString() );
}
vars.Add( cvar );
}
MethodInfo [] methods = type.GetMethods( BFS );
var objs1 = new object[1];
var objs2 = new object[2];
foreach ( MethodInfo mi in methods ) {
if ( ! ValidSuffixCmd( mi.Name ) ) {
continue;
}
ParameterInfo[] parameters = mi.GetParameters();
if ( parameters.Length == 0 ) {
continue;
}
ParameterInfo pi = parameters[0];
if ( ! pi.ParameterType.IsArray ) {
continue;
}
if (pi.ParameterType.GetElementType() != typeof(string)) {
continue;
}
string name = mi.Name.EndsWith("_kmd") ? mi.Name : type.Name + "_" + mi.Name;
Command cmd = new Command {
name = NormalizeNameCmd( name ),
rawName = type.Name + "." + mi.Name,
};
if ( parameters.Length == 1 ) {
cmd.ActionArgv = (a,context) => {
objs1[0] = a;
mi.Invoke( mi, objs1 );
};
} else {
cmd.ActionArgv = (a,context) => {
if ( context != null ) {
if ( context.GetType() == parameters[1].ParameterType ) {
objs2[0] = a;
objs2[1] = context;
mi.Invoke( mi, objs2 );
} else {
Error( cmd.name
+ " requires '"
+ parameters[1].ParameterType
+ "' context but got " + context.GetType() );
}
} else {
Error( cmd.name
+ " requires '"
+ parameters[1].ParameterType
+ "' context but got null." );
}
};
}
if ( cmd.name == "cellophane_on_register" ) {
cmd.ActionArgv( new string [] { cmd.name, type.Name }, null );
}
cmds.Add(cmd);
}
}
vars.Sort((a,b) => string.Compare(a.name, b.name));
_variables = vars.ToArray();
cmds.Sort( ( a,b ) => string.Compare( a.name, b.name ) );
_commands = cmds.ToArray();
int n = _variables.Length + _commands.Length;
_orderedDist = new int[n];
_allNames = new string[n];
for ( int i = 0; i < _variables.Length; i++ ) {
_allNames[i] = _variables[i].name;
}
for ( int i = 0; i < _commands.Length; i++ ) {
_allNames[i + _variables.Length] = _commands[i].name;
}
}
static bool TryFindVariable( string str, out Variable v ) {
int idx = Array.BinarySearch( _variables, str );
if ( idx >= 0 ) {
v = _variables[idx];
return true;
}
v = null;
return false;
}
static bool TryFindCommand( string str, out Command c ) {
int idx = Array.BinarySearch( _commands, str );
if ( idx >= 0 ) {
c = _commands[idx];
return true;
}
c = null;
return false;
}
// == Public API ==
public const BindingFlags BFS = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
public static bool UseColor = false;
public static Action<string> Log = (s) => {};
public static Action<string> Error = (s) => {};
// optionally fill this from the app before reading the config
public static int ConfigVersion_kvar;
public static string NormalizeName( string name, int n = 0 ) {
n = n == 0 ? name.Length : n;
List<char> chars = new List<char>();
for (int i = 0; i < n - 1; i++) {
char curr = name[i];
char next = name[i + 1];
chars.Add(curr);
if ( curr != '_'
&& ! Char.IsUpper( curr )
&& Char.IsUpper( next ) ) {
chars.Add( '_' );
}
}
chars.Add( name[n - 1] );
return new string( chars.ToArray() ).ToLowerInvariant();
}
public static string FtoA( float f ) {
return Convert.ToString( f, CultureInfo.InvariantCulture );
}
public static bool AtoF( string a, out float f ) {
return float.TryParse( a, NumberStyles.Any, CultureInfo.InvariantCulture, out f );
}
public static float AtoF( string a ) {
float.TryParse( a, NumberStyles.Any, CultureInfo.InvariantCulture, out float f );
return f;
}
public static bool TryFindCommand( string str, out Action<string[],object> action ) {
if ( TryFindCommand( str, out Command c ) ) {
action = c.ActionArgv;
return true;
}
action = null;
return false;
}
public static string Autocomplete( string input ) {
if ( _allNames.Length < 2 ) {
return input;
}
string [] argv;
if ( ! GetArgv( input, out argv ) ) {
return input;
}
string toMatch = argv[0].ToLowerInvariant();
for (int i = 0; i < _allNames.Length; i++) {
string name = _allNames[i];
int d;
if ( name == toMatch ) {
d = 0;
} else if ( name.Contains( toMatch ) ) {
d = 1000;
} else {
d = AutocompleteBorderDist + LevenshteinDistance( toMatch, name );
}
_orderedDist[i] = ( d << 16 ) | i;
}
// sort by distance
Array.Sort( _orderedDist );
string autocomplete = toMatch;
int maxToPrint = Math.Min( 32, _orderedDist.Length );
if ( GetDist( 0 ) == 0 ) {
// if filled full command, just print closest matches
PrintSuggestions( maxToPrint );
} else {
// if top match contains the candidate and is more than levenshtein
// distance apart from the second match, this is the one true
// autocomplete candidate
int d0 = GetDist( 0 );
int d1 = GetDist( 1 );
if ( d0 < AutocompleteBorderDist && d0 < d1 && d1 - d0 < AutocompleteBorderDist ) {
autocomplete = GetSorted( 0 );
} else {
// if we ended up here, there is more than one match (containing the command line)
PrintSuggestions( maxToPrint, hilight: autocomplete );
}
}
input = autocomplete;
for ( int i = 1; i < argv.Length; i++ ) {
input += " " + argv[i];
}
return input;
}
public static void AddToHistory( string str ) {
if ( ! string.IsNullOrEmpty( str ) ) {
if ( _history.Count == 0 || str != _history[_history.Count - 1] ) {
_history.Add( str );
if ( _history.Count > 128 ) {
_history.RemoveAt( 0 );
}
}
}
}
public static string StripJSONTags( string str ) {
if ( GetArgv( str, out string [] argv, keepJsonTags: false ) ) {
return argv[0];
}
return str;
}
static List<string> _argvTokens = new List<string>();
public static bool GetArgv( string str, out string [] argv, bool keepJsonTags = false,
bool keepQuotes = false ) {
if ( string.IsNullOrEmpty( str ) ) {
argv = new string[0];
// spams on the console too
//Log( "GetArgv: Empty string to split." );
return false;
}
_argvTokens.Clear();
int comment = 0;
int quoted = 0;
string token = "";
bool json = false;
void addToken() {
if ( token.StartsWith( "<json>" ) ) {
token = token.Substring( "<json>".Length );
json = true;
}
if ( token.EndsWith( "</json>" ) ) {
token = token.Substring( 0, token.Length - "</json>".Length );
if ( keepJsonTags ) {
token = $"<json>{token}</json>";
}
json = false;
}
if ( comment < 2 && ! json && token.Length > 0 ) {
if ( keepQuotes && quoted == 2 ) {
_argvTokens.Add( '"' + token + '"' );
} else {
_argvTokens.Add( token );
}
token = "";
}
}
for ( int i = 0; i < str.Length; i++ ) {
int c = str[i];
if ( json ) {
token += ( char )c;
if ( token.EndsWith( "</json>" ) ) {
addToken();
}
} else {
if ( comment >= 2 ) {
token = "";
if ( c == '\n' || c == '\r' ) {
comment = 0;
}
} else if ( c == '"' ) {
quoted++;
if ( quoted == 2 ) {
addToken();
quoted = 0;
}
} else if ( quoted == 0 && ( c == '\n' || c == '\r' || c == ' ' || c == '\t' ) ) {
addToken();
} else if ( quoted == 0 && c == '=' ) {
addToken();
token = "=";
addToken();
} else if ( quoted == 0 && c == ';' ) {
addToken();
token = ";";
addToken();
} else if ( quoted == 0 && c == '/' ) {
comment++;
} else {
token += ( char )c;
if ( token.StartsWith( "<json>" ) ) {
addToken();
}
}
}
}
addToken();
argv = _argvTokens.ToArray();
return argv.Length > 0;
}
// bare minimum tokenizer -- no quotes, no json, no comments
public static bool GetArgvBare( string str, out string [] argv ) {
_argvTokens.Clear();
string token = "";
void addToken() {
if ( token.Length > 0 ) {
_argvTokens.Add( token );
token = "";
}
}
for ( int i = 0; i < str.Length; i++ ) {
int c = str[i];
if ( c == '\n' || c == '\r' || c == ' ' || c == '\t' ) {
addToken();
} else if ( c == ';' ) {
addToken();
token = ";";
addToken();
} else {
token += ( char )c;
}
}
addToken();
argv = _argvTokens.ToArray();
return argv.Length > 0;
}
// ignores any quoted or json strings, just split along the semicolon
public static bool SimpleCommandsSplit( string str, out string [] cmds ) {
cmds = str.Split( new []{';'}, StringSplitOptions.RemoveEmptyEntries );
return cmds.Length > 0;
}
// handles properly ';' inside tags and quotes
static List<string> _splitCmds = new List<string>();
public static bool SplitCommands( string str, out string [] cmds ) {
_splitCmds.Clear();
if ( GetArgv( str, out string [] argv, keepJsonTags: true, keepQuotes: true ) ) {
string cmd = argv[0];
for ( int i = 1; i < argv.Length; i++ ) {
if ( argv[i] == ";" ) {
_splitCmds.Add( cmd + ';' );
cmd = string.Empty;
} else {
cmd += $" {argv[i]}";
}
}
_splitCmds.Add( cmd );
cmds = _splitCmds.ToArray();
return cmds.Length > 0;
}
cmds = new string[0];
return false;
}
// handles properly ';' inside tags and quotes
static List<string> _exeTokens = new List<string>();
public static bool TryExecuteString( string str, object context = null, bool silent = false,
bool keepJsonTags = false ) {
if ( GetArgv( str, out string [] argv, keepJsonTags: keepJsonTags ) ) {
_exeTokens.Clear();
for ( int i = 0; i < argv.Length; i++ ) {
if ( argv[i] == ";" ) {
if ( _exeTokens.Count > 0 ) {
TryExecute( _exeTokens.ToArray(), context, silent );
_exeTokens.Clear();
}
} else {
_exeTokens.Add( argv[i] );
}
}
if ( _exeTokens.Count > 0 ) {
TryExecute( _exeTokens.ToArray(), context, silent );
}
return true;
}
return false;
}
public static bool TryExecute( string [] argv, object context = null, bool silent = false ) {
if ( argv.Length == 0 ) {
if ( ! silent ) {
Error( "Zero argv-s in TryExecute." );
}
return false;
}
string str = argv[0].ToLowerInvariant();
Variable v;
if ( TryFindVariable( str, out v ) ) {
OnVariable( v, argv );
return true;
}
string cmdName;
int repeat = 0;
if ( char.IsNumber( str[0] ) ) {
cmdName = "";
string count = "";
for ( int i = 0; i < str.Length; i++ ) {
char c = str[i];
if ( ! char.IsNumber( c ) ) {
if ( repeat == 0 && ! int.TryParse( count, out repeat ) ) {
repeat = 1;
}
}
if ( repeat == 0 ) {
count += c;
} else {
cmdName += c;
}
}
} else {
cmdName = str;
repeat = 1;
}
Command cmd;
if ( TryFindCommand( cmdName, out cmd ) ) {
for ( int i = 0; i < repeat; i++ ) {
cmd.ActionArgv( argv, context );
}
return true;
}
if ( ! silent ) {
Log( "Unknown var/command: '" + str + "'" );
}
return false;
}
public static string [] GetHistory( string currentCmd ) {
List<string> res = new List<string>{ currentCmd };
if ( currentCmd.Length > 0 ) {
foreach ( var s in _history ) {
if ( s.Contains( currentCmd ) ) {
res.Add( s );
}
}
} else {
res.AddRange( _history );
}
return res.ToArray();
}
public static void ReadConfig( string val, bool skipVersionCheck = false ) {
Log( "Parsing config..." );
var vals = val.Split( new[]{'\n'}, StringSplitOptions.RemoveEmptyEntries );
Action execute = () => {
// silent while executing
Action<string> tempLog = Log;
Log = (s)=>{};
foreach ( var v in vals ) {
string [] argv;
if ( GetArgv( v, out argv, keepJsonTags: true ) ) {
TryExecute( argv );
}
}
// no longer silent
Log = tempLog;
};
if ( skipVersionCheck ) {
Log( "Skipping version check." );
execute();
} else {
// force version to some invalid value before parsing it out
int srcVersion = ConfigVersion_kvar;
ConfigVersion_kvar = -1;
foreach ( var v in vals ) {
string [] argv;
if ( GetArgv( v, out argv) && argv[0] == "config_version" ) {
TryExecute( argv );
Log( $"Config Version in cfg file: {ConfigVersion_kvar} hardcoded: {srcVersion}" );
break;
}
}
if ( srcVersion == ConfigVersion_kvar ) {
execute();
} else {
ConfigVersion_kvar = srcVersion;
Log( "Resetting Variables to defaults because different hardcoded cfg version!" );
}
}
Log( "Done parsing config." );
}
public static string StoreConfig() {
string val = "";
foreach ( var v in _variables ) {
if ( v.description.Length > 0 ) {
val += $"{v.name} {v.GetValue()} // {v.description}\n";
} else {
val += $"{v.name} {v.GetValue()}\n";
}
}
return val;
}
public static void ReadHistory( string val ) {
var vals = val.Split( new[]{'\n'}, StringSplitOptions.RemoveEmptyEntries );
_history = new List<string>( vals );
}
public static string StoreHistory() {
string val = "";
foreach ( var s in _history ) {
val += s + "\n";
}
return val;
}
public static void PrintInfo() {
Log( "Num variables: " + _variables.Length );
Log( "Num commands: " + _commands.Length );
}
public static void ScanVarsAndCommands() {
var log = Log;
Log = (s) => log( UseColor ? s : ColorTagStripAll( s ) );
CollectItems();
}
static readonly int tagLen = "[000000]".Length;
public static bool ColorTagLead( string str, int i, out string tag ) {
tag = string.Empty;
if ( str.Length <= i ) {
return false;
}
if ( str[i] != '[' ) {
return false;
}
int n = Math.Min( str.Length, i + tagLen );
for ( int k = i; k < n; k++ ) {
tag += str[k];
}
if ( tag.Length != tagLen || tag[tagLen - 1] != ']' ) {
return false;
}
for ( int k = 1; k < tagLen - 1; k++ ) {
if ( ! Uri.IsHexDigit( tag[k] ) ) {
return false;
}
}
return true;
}
public static bool ColorTagClose( string str, int i, out string tag ) {
tag = "[-]";
if ( str.Length - i < 3 ) {
return false;
}
return str[i + 0] == '[' && str[i + 1] == '-' && str[i + 2] == ']';
}
public static string ColorTagStripAll( string s ) {
string result = "";
for ( int i = 0; i < s.Length; ) {
string tag;
if ( ColorTagLead( s, i, out tag ) ) {
i += tag.Length;
} else if ( ColorTagClose( s, i, out tag ) ) {
i += tag.Length;
} else {
result += s[i];
i++;
}
}
return result;
}
static Dictionary<string,Variable> _changeStash = new Dictionary<string,Variable>();
public static bool VarChanged( string name, Type type = null ) {
if ( name.EndsWith( "_cvar" ) ) {
if ( type == null ) {
Error( "Need to supply type for VarChanged for '_cvar'" );
return false;
}
name = type.Name + "_" + name;
}
bool result;
Variable v;
if ( _changeStash.TryGetValue( name, out v ) ) {
result = v.Changed_f();
} else {
string normName = NormalizeNameVar( name );
if ( TryFindVariable( normName, out v ) ) {
if ( v.Changed_f == null ) {
v.SetupChanged();
}
result = v.Changed_f();
_changeStash[name] = v;
} else {
Error( "Can't find variable '" + normName + "'" );
//v.Changed_f = () => false;
result = false;
}
}
return result;
}
}
} namespace QON {
#if UNITY_2021_1_OR_NEWER
using UnityEngine;
public static class CodePage437 {
public const int FontTexSide = 192;
public const int FontSz = 16;
public const int CharSz = FontTexSide / FontSz;
public static Texture2D _texture;
public const float CharUV = CharSz / ( float )FontTexSide;
public static readonly Vector3 [] CharVerts = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( CharSz, 0, 0 ),
new Vector3( CharSz, CharSz, 0 ),
new Vector3( 0, CharSz, 0 ),
};
public static readonly Vector3 [] CharVertsInv = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( CharSz, 0, 0 ),
new Vector3( CharSz, -CharSz, 0 ),
new Vector3( 0, -CharSz, 0 ),
};
public static readonly Vector3 [] CharUVs = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( CharUV, 0, 0 ),
new Vector3( CharUV, CharUV, 0 ),
new Vector3( 0, CharUV, 0 ),
};
public static Texture2D GetTexture() {
if ( ! _texture ) {
_texture = new Texture2D(FontTexSide, FontTexSide,
textureFormat: TextureFormat.RGBA32,
mipChain: false,
linear: false);
_texture.filterMode = FilterMode.Point;
for ( int y = 0, i = 0; y < FontTexSide; y++ ) {
for ( int x = 0; x < FontTexSide; x += 8, i++ ) {
_texture.SetPixel( x + 0, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 7 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 1, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 6 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 2, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 5 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 3, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 4 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 4, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 3 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 5, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 2 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 6, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 1 ) ) == 0 ? (byte)0x00 : (byte)0xff));
_texture.SetPixel( x + 7, y, new Color32(0xff, 0xff, 0xff, ( Bitmap[i] & ( 1 << 0 ) ) == 0 ? (byte)0x00 : (byte)0xff));
}
}
_texture.Apply();
}
return _texture;
}
public static readonly byte [] Bitmap = new byte [FontTexSide * FontTexSide / 8] {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,0x00,0xff,
0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf8,0x1f,0x80,0x00,0x00,0x00,
0x60,0x06,0x00,0x00,0xff,0xf0,0x00,0xff,0xf0,0xf8,0x0f,0x00,0x7c,0x1f,0xe0,0x00,
0x00,0x03,0x0c,0x3f,0xc3,0x18,0x06,0x00,0xf0,0x0f,0x00,0x00,0xff,0xf0,0xf0,0xf0,
0xf0,0x38,0x19,0x80,0x64,0x18,0x60,0x60,0x00,0x02,0x04,0x3f,0xc7,0xbc,0x0f,0x00,
0xf0,0x1f,0x80,0x00,0xff,0xf1,0xf8,0xe0,0x70,0xe8,0x19,0x80,0x64,0x1f,0xe3,0x6c,
0x00,0x02,0x94,0x36,0xc7,0xfc,0x1f,0x83,0xfc,0x3f,0xc0,0xf0,0xf0,0xf3,0x9c,0xc6,
0x31,0xc8,0x19,0x80,0x7c,0x18,0x61,0xf8,0x00,0x02,0x04,0x3f,0xc7,0xfc,0x3f,0xc7,
0x9e,0x3f,0xc1,0xf8,0xe0,0x73,0x0c,0xcf,0x33,0xe0,0x0f,0x00,0x60,0x18,0x63,0x9c,
0x00,0x02,0xf4,0x30,0xc3,0xf8,0x3f,0xc7,0x9e,0x1f,0x81,0xf8,0xe0,0x73,0x0c,0xcf,
0x33,0x30,0x06,0x00,0x60,0x18,0x63,0x9c,0x00,0x02,0x64,0x39,0xc1,0xf0,0x1f,0x83,
0x6c,0x06,0x00,0xf0,0xf0,0xf3,0x9c,0xc6,0x33,0x30,0x1f,0x81,0xe0,0x18,0xe1,0xf8,
0x00,0x03,0x0c,0x3f,0xc0,0xe0,0x0f,0x00,0x60,0x06,0x00,0x00,0xff,0xf1,0xf8,0xe0,
0x73,0x30,0x06,0x03,0xe0,0x39,0xe3,0x6c,0x00,0x01,0xf8,0x1f,0x80,0x40,0x06,0x01,
0xf8,0x1f,0x80,0x00,0xff,0xf0,0xf0,0xf0,0xf1,0xe0,0x06,0x01,0xc0,0x78,0xc0,0x60,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xf0,0x00,0xff,
0xf0,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xf0,0x00,0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x06,0x01,0x98,0x1f,0xc1,
0xf8,0x00,0x00,0x60,0x06,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x30,0x00,0x0c,0x0f,0x01,0x98,0x36,0xc1,0x8c,0x00,0x00,0xf0,0x0f,0x00,0x60,0x00,
0x00,0x00,0x00,0x00,0x00,0x04,0x07,0xfc,0x3c,0x00,0x3c,0x1f,0x81,0x98,0x36,0xc0,
0xc0,0x00,0x01,0xf8,0x1f,0x80,0x60,0x03,0x00,0xc0,0x00,0x01,0x08,0x04,0x03,0xf8,
0x3f,0x00,0xfc,0x06,0x01,0x98,0x36,0xc0,0xf0,0x00,0x00,0x60,0x06,0x00,0x60,0x01,
0x81,0x80,0x30,0x03,0x0c,0x0e,0x01,0xf0,0x3f,0xc3,0xfc,0x06,0x01,0x98,0x1e,0xc1,
0x98,0x00,0x00,0x60,0x06,0x00,0x60,0x3f,0xc3,0xfc,0x30,0x07,0xfe,0x0e,0x01,0xf0,
0x3f,0x00,0xfc,0x06,0x00,0x00,0x06,0xc1,0x98,0x00,0x00,0x60,0x06,0x00,0x60,0x01,
0x81,0x80,0x30,0x03,0x0c,0x1f,0x00,0xe0,0x3c,0x00,0x3c,0x1f,0x80,0x00,0x06,0xc0,
0xf0,0x3f,0xc1,0xf8,0x06,0x01,0xf8,0x03,0x00,0xc0,0x3f,0xc1,0x08,0x1f,0x00,0xe0,
0x30,0x00,0x0c,0x0f,0x01,0x98,0x06,0xc0,0x30,0x3f,0xc0,0xf0,0x06,0x00,0xf0,0x00,
0x00,0x00,0x00,0x00,0x00,0x3f,0x80,0x40,0x20,0x00,0x04,0x06,0x01,0x98,0x06,0xc3,
0x18,0x3f,0xc0,0x60,0x06,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xc0,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf8,0x00,0x01,0xf8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x19,0x81,0xb0,0x06,0x00,
0x00,0x1c,0x00,0x60,0x03,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
0x00,0x00,0xf0,0x19,0x81,0xb0,0x0f,0x80,0x00,0x36,0x00,0x60,0x06,0x00,0xc0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0xf0,0x19,0x83,0xf8,0x18,0x01,
0x88,0x36,0x00,0x60,0x0c,0x00,0x60,0x19,0x80,0x60,0x00,0x00,0x00,0x00,0x00,0x18,
0x00,0x00,0xf0,0x09,0x01,0xb0,0x18,0x01,0x98,0x1c,0x00,0xc0,0x18,0x00,0x30,0x0f,
0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x60,0x00,0x01,0xb0,0x0f,0x00,
0x30,0x3e,0x80,0x00,0x18,0x00,0x30,0x3f,0xc1,0xf8,0x00,0x03,0xfc,0x00,0x00,0x60,
0x00,0x00,0x60,0x00,0x01,0xb0,0x01,0x80,0x60,0x37,0x80,0x00,0x18,0x00,0x30,0x0f,
0x01,0xf8,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x03,0xf8,0x01,0x80,
0xc0,0x33,0x00,0x00,0x0c,0x00,0x60,0x19,0x80,0x60,0x00,0x00,0x00,0x00,0x01,0x80,
0x00,0x00,0x60,0x00,0x01,0xb0,0x1f,0x01,0x98,0x37,0x00,0x00,0x06,0x00,0xc0,0x00,
0x00,0x60,0x0e,0x00,0x00,0x0e,0x03,0x00,0x00,0x00,0x60,0x00,0x01,0xb0,0x06,0x01,
0x18,0x1d,0x80,0x00,0x03,0x01,0x80,0x00,0x00,0x00,0x0e,0x00,0x00,0x0e,0x02,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x20,0x0f,0x00,0xf0,0x03,0x01,
0xf8,0x07,0x03,0xf8,0x0f,0x00,0xf0,0x00,0x00,0x00,0x01,0x80,0x00,0x18,0x00,0xf0,
0x31,0x80,0x60,0x19,0x81,0x98,0x07,0x01,0x80,0x0c,0x03,0x18,0x19,0x81,0x98,0x00,
0x00,0x00,0x03,0x00,0x00,0x0c,0x01,0x98,0x33,0x81,0xe0,0x19,0x80,0x18,0x0f,0x01,
0x80,0x18,0x03,0x18,0x19,0x81,0x98,0x0e,0x00,0xe0,0x06,0x00,0x00,0x06,0x00,0x18,
0x37,0x80,0x60,0x01,0x80,0x18,0x1b,0x01,0x80,0x18,0x00,0x18,0x1d,0x81,0x98,0x0e,
0x00,0xe0,0x0c,0x01,0xf8,0x03,0x00,0x30,0x35,0x80,0x60,0x03,0x00,0x70,0x33,0x01,
0xf0,0x1f,0x00,0x30,0x0f,0x00,0xf8,0x00,0x00,0x00,0x18,0x00,0x00,0x01,0x80,0x60,
0x3d,0x80,0x60,0x06,0x00,0x18,0x3f,0x80,0x18,0x19,0x80,0x60,0x1b,0x80,0x30,0x00,
0x00,0x00,0x0c,0x00,0x00,0x03,0x00,0x60,0x39,0x80,0x60,0x0c,0x00,0x18,0x03,0x00,
0x18,0x19,0x80,0xc0,0x19,0x80,0x30,0x0e,0x00,0xe0,0x06,0x01,0xf8,0x06,0x00,0x00,
0x31,0x80,0x60,0x19,0x81,0x98,0x03,0x01,0x98,0x19,0x80,0xc0,0x19,0x80,0x60,0x0e,
0x00,0xe0,0x03,0x00,0x00,0x0c,0x00,0x60,0x1f,0x01,0xf8,0x1f,0x80,0xf0,0x07,0x80,
0xf0,0x0f,0x00,0xc0,0x0f,0x00,0xe0,0x00,0x00,0x60,0x01,0x80,0x00,0x18,0x00,0x60,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x00,0x60,0x3f,0x00,0xf0,0x3e,0x03,
0xf8,0x3f,0x80,0xf0,0x19,0x80,0xf0,0x07,0x83,0x98,0x3c,0x03,0x18,0x31,0x80,0xe0,
0x31,0x80,0xf0,0x19,0x81,0x98,0x1b,0x01,0x88,0x19,0x81,0x98,0x19,0x80,0x60,0x03,
0x01,0x98,0x18,0x03,0xb8,0x31,0x81,0xb0,0x31,0x81,0x98,0x19,0x83,0x18,0x19,0x81,
0x80,0x18,0x83,0x18,0x19,0x80,0x60,0x03,0x01,0xb0,0x18,0x03,0xf8,0x39,0x83,0x18,
0x37,0x81,0x98,0x19,0x83,0x00,0x19,0x81,0x90,0x19,0x03,0x00,0x19,0x80,0x60,0x03,
0x01,0xb0,0x18,0x03,0xf8,0x3d,0x83,0x18,0x37,0x81,0x98,0x1f,0x03,0x00,0x19,0x81,
0xf0,0x1f,0x03,0x00,0x1f,0x80,0x60,0x03,0x01,0xe0,0x18,0x03,0x58,0x3f,0x83,0x18,
0x37,0x81,0xf8,0x19,0x83,0x00,0x19,0x81,0x90,0x19,0x03,0x38,0x19,0x80,0x60,0x33,
0x01,0xb0,0x18,0x83,0x18,0x37,0x83,0x18,0x30,0x01,0x98,0x19,0x83,0x18,0x19,0x81,
0x80,0x18,0x03,0x18,0x19,0x80,0x60,0x33,0x01,0xb0,0x19,0x83,0x18,0x33,0x83,0x18,
0x30,0x01,0x98,0x19,0x81,0x98,0x1b,0x01,0x88,0x18,0x01,0x98,0x19,0x80,0x60,0x33,
0x01,0x98,0x19,0x83,0x18,0x31,0x81,0xb0,0x1f,0x01,0x98,0x3f,0x00,0xf0,0x3e,0x03,
0xf8,0x3c,0x00,0xf8,0x19,0x80,0xf0,0x1e,0x03,0x98,0x3f,0x83,0x18,0x31,0x80,0xe0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x3f,0x00,0xe0,0x3f,0x00,0xf0,0x1f,0x81,
0x98,0x19,0x83,0x18,0x19,0x81,0x98,0x3f,0x80,0xf0,0x20,0x00,0xf0,0x0e,0x00,0x00,
0x19,0x81,0xb0,0x19,0x81,0x98,0x16,0x81,0x98,0x19,0x83,0x18,0x19,0x81,0x98,0x33,
0x80,0xc0,0x30,0x00,0x30,0x1b,0x00,0x00,0x19,0x83,0x18,0x19,0x81,0x98,0x06,0x01,
0x98,0x19,0x83,0x18,0x19,0x81,0x98,0x26,0x00,0xc0,0x18,0x00,0x30,0x31,0x80,0x00,
0x19,0x83,0x18,0x19,0x81,0x80,0x06,0x01,0x98,0x19,0x83,0x18,0x0f,0x01,0x98,0x06,
0x00,0xc0,0x0c,0x00,0x30,0x00,0x00,0x00,0x1f,0x03,0x18,0x1f,0x00,0xe0,0x06,0x01,
0x98,0x19,0x83,0x58,0x06,0x00,0xf0,0x0c,0x00,0xc0,0x06,0x00,0x30,0x00,0x00,0x00,
0x18,0x03,0x38,0x1b,0x00,0x30,0x06,0x01,0x98,0x19,0x83,0x58,0x0f,0x00,0x60,0x18,
0x00,0xc0,0x03,0x00,0x30,0x00,0x00,0x00,0x18,0x03,0x78,0x19,0x81,0x98,0x06,0x01,
0x98,0x19,0x81,0xb0,0x19,0x80,0x60,0x18,0x80,0xc0,0x01,0x80,0x30,0x00,0x00,0x00,
0x18,0x01,0xf0,0x19,0x81,0x98,0x06,0x01,0x98,0x0f,0x01,0xb0,0x19,0x80,0x60,0x31,
0x80,0xc0,0x00,0xc0,0x30,0x00,0x00,0x00,0x3c,0x00,0x30,0x39,0x80,0xf0,0x0f,0x00,
0xf0,0x06,0x01,0xb0,0x19,0x80,0xf0,0x3f,0x80,0xf0,0x00,0x40,0xf0,0x00,0x00,0x00,
0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x38,0x00,0x00,0x07,0x00,
0x00,0x07,0x00,0x00,0x38,0x00,0x60,0x03,0x03,0x80,0x1e,0x00,0x00,0x00,0x00,0x00,
0x06,0x00,0x00,0x18,0x00,0x00,0x03,0x00,0x00,0x0d,0x80,0x00,0x18,0x00,0x60,0x03,
0x01,0x80,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x03,0x00,
0x00,0x0c,0x00,0x00,0x18,0x00,0x00,0x00,0x01,0x80,0x06,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0xe0,0x1f,0x00,0xf0,0x1f,0x00,0xf0,0x0c,0x01,0xd8,0x1b,0x01,0xe0,0x0f,
0x01,0x98,0x06,0x03,0xf0,0x1f,0x00,0xf0,0x00,0x00,0x30,0x19,0x81,0x98,0x33,0x01,
0x98,0x1f,0x03,0x30,0x1d,0x80,0x60,0x03,0x01,0xb0,0x06,0x03,0x58,0x19,0x81,0x98,
0x00,0x01,0xf0,0x19,0x81,0x80,0x33,0x01,0xf8,0x0c,0x03,0x30,0x19,0x80,0x60,0x03,
0x01,0xe0,0x06,0x03,0x58,0x19,0x81,0x98,0x00,0x03,0x30,0x19,0x81,0x80,0x33,0x01,
0x80,0x0c,0x03,0x30,0x19,0x80,0x60,0x03,0x01,0xb0,0x06,0x03,0x58,0x19,0x81,0x98,
0x00,0x03,0x30,0x19,0x81,0x98,0x33,0x01,0x98,0x0c,0x01,0xf0,0x19,0x80,0x60,0x03,
0x01,0x98,0x06,0x03,0x58,0x19,0x81,0x98,0x00,0x01,0xd8,0x37,0x00,0xf0,0x1d,0x80,
0xf0,0x1e,0x00,0x30,0x39,0x81,0xf8,0x33,0x03,0x98,0x1f,0x83,0x18,0x19,0x80,0xf0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x30,0x00,0x00,0x00,0x33,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0xe0,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x06,0x01,0xc0,0x1c,0xc0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x60,0x06,0x00,0x60,0x36,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x06,0x00,0x60,0x33,0x80,0x40,
0x37,0x01,0xd8,0x3b,0x00,0xf0,0x3f,0x03,0x30,0x19,0x83,0x18,0x31,0x81,0x98,0x1f,
0x80,0xc0,0x06,0x00,0x30,0x00,0x00,0xe0,0x19,0x83,0x30,0x1b,0x81,0x98,0x18,0x03,
0x30,0x19,0x83,0x18,0x1b,0x01,0x98,0x11,0x81,0x80,0x00,0x00,0x18,0x00,0x01,0xb0,
0x19,0x83,0x30,0x1d,0x80,0xc0,0x18,0x03,0x30,0x19,0x83,0x58,0x0e,0x01,0x98,0x03,
0x00,0xc0,0x06,0x00,0x30,0x00,0x03,0x18,0x19,0x83,0x30,0x18,0x00,0x30,0x18,0x03,
0x30,0x19,0x83,0x58,0x0e,0x01,0x98,0x0c,0x00,0x60,0x06,0x00,0x60,0x00,0x03,0x18,
0x19,0x83,0x30,0x18,0x01,0x98,0x1b,0x03,0x30,0x0f,0x01,0xb0,0x1b,0x00,0xf0,0x18,
0x80,0x60,0x06,0x00,0x60,0x00,0x03,0xf8,0x1f,0x01,0xf0,0x3c,0x00,0xf0,0x0e,0x01,
0xd8,0x06,0x01,0xb0,0x31,0x80,0x30,0x1f,0x80,0x38,0x06,0x01,0xc0,0x00,0x00,0x00,
0x18,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x78,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x80,0xc0,0x00,0x03,0x00,0x07,0x00,0x00,0x06,0x00,0x00,0x18,
0x00,0x00,0x04,0x01,0x80,0x00,0x00,0xf0,0x0f,0x03,0x30,0x03,0x01,0xe0,0x33,0x01,
0x80,0x0d,0x80,0x00,0x0f,0x01,0x98,0x0c,0x01,0xb0,0x0e,0x00,0xc0,0x19,0x81,0x98,
0x19,0x83,0x30,0x06,0x03,0x30,0x33,0x00,0xc0,0x0d,0x80,0x00,0x19,0x81,0x98,0x06,
0x01,0xb0,0x1b,0x00,0x60,0x00,0x01,0x98,0x19,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xf0,
0x18,0x03,0x30,0x0f,0x01,0xe0,0x1e,0x01,0xe0,0x1f,0x00,0xf0,0x0f,0x00,0xf0,0x0f,
0x01,0xe0,0x1e,0x01,0xe0,0x0f,0x00,0xf0,0x18,0x03,0x30,0x19,0x80,0x30,0x03,0x00,
0x30,0x01,0x81,0x98,0x19,0x81,0x98,0x19,0x80,0x60,0x06,0x00,0x60,0x19,0x81,0x98,
0x18,0x03,0x30,0x1f,0x81,0xf0,0x1f,0x01,0xf0,0x0f,0x81,0x80,0x1f,0x81,0xf8,0x1f,
0x80,0x60,0x06,0x00,0x60,0x19,0x81,0x98,0x19,0x83,0x30,0x18,0x03,0x30,0x33,0x03,
0x30,0x19,0x81,0x80,0x18,0x01,0x80,0x18,0x00,0x60,0x06,0x00,0x60,0x1f,0x81,0xf8,
0x19,0x83,0x30,0x19,0x83,0x30,0x33,0x03,0x30,0x19,0x81,0x98,0x18,0x01,0x80,0x18,
0x00,0x60,0x06,0x00,0x60,0x19,0x81,0x98,0x0f,0x01,0xd8,0x0f,0x01,0xd8,0x1d,0x81,
0xd8,0x0e,0xc0,0xf0,0x0f,0x80,0xf8,0x0f,0x81,0xf8,0x1f,0x81,0xf8,0x19,0x81,0x98,
0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,0x00,0x60,0x00,0x01,0x80,0x0c,0x03,0x00,0x00,0x01,0x98,0x19,
0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x0f,0x80,0xf0,0x19,0x80,
0xc0,0x1e,0x01,0x80,0x19,0x80,0x00,0x00,0x00,0x60,0x0f,0x01,0x98,0x3c,0x00,0x38,
0x0c,0x00,0x00,0x1e,0x01,0x98,0x19,0x80,0x60,0x33,0x00,0xc0,0x19,0x80,0xf0,0x19,
0x80,0x60,0x19,0x81,0x98,0x22,0x00,0x6c,0x3f,0x00,0x00,0x36,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x01,0x98,0x19,0x80,0xf0,0x18,0x01,0x98,0x22,0x00,0x60,
0x31,0x03,0xf8,0x36,0x00,0xf0,0x0f,0x00,0xf0,0x33,0x03,0x30,0x19,0x81,0x98,0x19,
0x81,0x98,0x18,0x01,0x98,0x22,0x00,0x60,0x30,0x00,0x6c,0x3f,0x81,0x98,0x19,0x81,
0x98,0x33,0x03,0x30,0x19,0x81,0x98,0x19,0x81,0x80,0x18,0x00,0xf0,0x3c,0x01,0xf8,
0x3e,0x01,0xfc,0x36,0x01,0x98,0x19,0x81,0x98,0x33,0x03,0x30,0x19,0x81,0x98,0x19,
0x81,0x80,0x3f,0x01,0xf8,0x22,0x00,0x60,0x30,0x03,0x60,0x36,0x01,0x98,0x19,0x81,
0x98,0x33,0x03,0x30,0x19,0x81,0x98,0x19,0x81,0x98,0x18,0x00,0x60,0x27,0x80,0x60,
0x31,0x03,0x60,0x36,0x01,0x98,0x19,0x81,0x98,0x33,0x03,0x30,0x0f,0x01,0x98,0x19,
0x80,0xf0,0x18,0x01,0xf8,0x23,0x00,0x60,0x3f,0x03,0xbc,0x37,0x80,0xf0,0x0f,0x00,
0xf0,0x1d,0x81,0xd8,0x03,0x00,0xf0,0x0f,0x00,0x60,0x30,0x00,0x60,0x23,0x43,0x60,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,
0x00,0x60,0x3f,0x80,0x60,0x21,0x81,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x00,0x30,0x01,0x80,0x30,0x00,0x01,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x60,0x03,0x00,0x60,0x1d,0x83,
0x70,0x1e,0x01,0xe0,0x06,0x00,0x00,0x00,0x03,0x0c,0x30,0xc0,0x60,0x00,0x00,0x00,
0x0c,0x00,0xc0,0x06,0x00,0xc0,0x37,0x00,0x00,0x33,0x03,0x30,0x06,0x00,0x00,0x00,
0x07,0x18,0x71,0x80,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,
0x18,0x33,0x03,0x30,0x00,0x00,0x00,0x00,0x03,0x30,0x33,0x00,0x00,0x0c,0xc3,0x30,
0x1e,0x01,0xe0,0x0f,0x03,0x30,0x3e,0x03,0x98,0x1f,0x81,0xe0,0x06,0x03,0xfc,0x3f,
0xc3,0x60,0x36,0x00,0x60,0x19,0x81,0x98,0x03,0x00,0x60,0x19,0x83,0x30,0x33,0x03,
0xd8,0x00,0x00,0x00,0x0c,0x03,0x00,0x00,0xc0,0xc0,0x0d,0xc0,0x60,0x33,0x00,0xcc,
0x1f,0x00,0x60,0x19,0x83,0x30,0x33,0x03,0x78,0x3f,0x83,0xf8,0x18,0x03,0x00,0x00,
0xc1,0xbc,0x1b,0xc0,0xf0,0x33,0x00,0xcc,0x33,0x00,0x60,0x19,0x83,0x30,0x33,0x03,
0x38,0x00,0x00,0x00,0x18,0x03,0x00,0x00,0xc3,0x06,0x36,0xc0,0xf0,0x19,0x81,0x98,
0x33,0x00,0x60,0x19,0x83,0x30,0x33,0x03,0x18,0x00,0x00,0x00,0x19,0x80,0x00,0x00,
0x02,0x0c,0x2c,0xc0,0xf0,0x0c,0xc3,0x30,0x1d,0x81,0xf8,0x0f,0x01,0xd8,0x33,0x03,
0x18,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x18,0x0f,0xc0,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3e,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x11,0x15,0x55,0xdd,0xd0,0x60,0x06,0x00,0x60,0x19,0x80,0x00,0x00,0x01,0x98,0x19,
0x80,0x00,0x19,0x81,0x98,0x06,0x00,0x00,0x44,0x4a,0xaa,0x77,0x70,0x60,0x06,0x00,
0x60,0x19,0x80,0x00,0x00,0x01,0x98,0x19,0x80,0x00,0x19,0x81,0x98,0x06,0x00,0x00,
0x11,0x15,0x55,0xdd,0xd0,0x60,0x06,0x00,0x60,0x19,0x80,0x00,0x00,0x01,0x98,0x19,
0x80,0x00,0x19,0x81,0x98,0x06,0x00,0x00,0x44,0x4a,0xaa,0x77,0x70,0x60,0x06,0x0f,
0xe0,0x19,0x80,0x00,0xfe,0x0f,0x98,0x19,0x8f,0xf8,0xf9,0x81,0x98,0xfe,0x00,0x00,
0x11,0x15,0x55,0xdd,0xd0,0x60,0x06,0x0f,0xe0,0x19,0x80,0x00,0xfe,0x0f,0x98,0x19,
0x8f,0xf8,0xf9,0x81,0x98,0xfe,0x00,0x00,0x44,0x4a,0xaa,0x77,0x70,0x60,0xfe,0x00,
0x60,0xf9,0x8f,0xf8,0x06,0x00,0x18,0x19,0x80,0x18,0x01,0x8f,0xf8,0x06,0x0f,0xe0,
0x11,0x15,0x55,0xdd,0xd0,0x60,0xfe,0x00,0x60,0xf9,0x8f,0xf8,0x06,0x00,0x18,0x19,
0x80,0x18,0x01,0x8f,0xf8,0x06,0x0f,0xe0,0x44,0x4a,0xaa,0x77,0x70,0x60,0x06,0x0f,
0xe0,0x19,0x81,0x98,0xfe,0x0f,0x98,0x19,0x8f,0x98,0xff,0x80,0x00,0xfe,0x00,0x60,
0x11,0x15,0x55,0xdd,0xd0,0x60,0x06,0x0f,0xe0,0x19,0x81,0x98,0xfe,0x0f,0x98,0x19,
0x8f,0x98,0xff,0x80,0x00,0xfe,0x00,0x60,0x44,0x4a,0xaa,0x77,0x70,0x60,0x06,0x00,
0x60,0x19,0x81,0x98,0x06,0x01,0x98,0x19,0x81,0x98,0x00,0x00,0x00,0x00,0x00,0x60,
0x11,0x15,0x55,0xdd,0xd0,0x60,0x06,0x00,0x60,0x19,0x81,0x98,0x06,0x01,0x98,0x19,
0x81,0x98,0x00,0x00,0x00,0x00,0x00,0x60,0x44,0x4a,0xaa,0x77,0x70,0x60,0x06,0x00,
0x60,0x19,0x81,0x98,0x06,0x01,0x98,0x19,0x81,0x98,0x00,0x00,0x00,0x00,0x00,0x60,
0x06,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x06,0x01,0x98,0x19,0x80,0x00,0x19,
0x80,0x00,0x19,0x80,0x00,0x19,0x80,0x60,0x06,0x00,0x60,0x00,0x00,0x60,0x00,0x00,
0x60,0x06,0x01,0x98,0x19,0x80,0x00,0x19,0x80,0x00,0x19,0x80,0x00,0x19,0x80,0x60,
0x06,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x06,0x01,0x98,0x19,0x80,0x00,0x19,
0x80,0x00,0x19,0x80,0x00,0x19,0x80,0x60,0x06,0x00,0x60,0x00,0x00,0x60,0x00,0x00,
0x60,0x07,0xf1,0x98,0x19,0xf1,0xff,0xf9,0xff,0xff,0x19,0xff,0xff,0xf9,0xff,0xff,
0x06,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x07,0xf1,0x98,0x19,0xf1,0xff,0xf9,
0xff,0xff,0x19,0xff,0xff,0xf9,0xff,0xff,0x07,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,
0xff,0x06,0x01,0x9f,0x18,0x01,0x80,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,
0x07,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0x06,0x01,0x9f,0x18,0x01,0x80,0x00,
0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x60,0x00,0x00,
0x60,0x07,0xf1,0x98,0x1f,0xf1,0x9f,0xff,0xff,0x9f,0x19,0xff,0xff,0xf9,0xff,0xff,
0x00,0x00,0x00,0x06,0x00,0x60,0x00,0x00,0x60,0x07,0xf1,0x98,0x1f,0xf1,0x9f,0xff,
0xff,0x9f,0x19,0xff,0xff,0xf9,0xff,0xff,0x00,0x00,0x00,0x06,0x00,0x60,0x00,0x00,
0x60,0x06,0x01,0x98,0x00,0x01,0x98,0x00,0x01,0x98,0x19,0x80,0x00,0x19,0x80,0x00,
0x00,0x00,0x00,0x06,0x00,0x60,0x00,0x00,0x60,0x06,0x01,0x98,0x00,0x01,0x98,0x00,
0x01,0x98,0x19,0x80,0x00,0x19,0x80,0x00,0x00,0x00,0x00,0x06,0x00,0x60,0x00,0x00,
0x60,0x06,0x01,0x98,0x00,0x01,0x98,0x00,0x01,0x98,0x19,0x80,0x00,0x19,0x80,0x00,
0x19,0x80,0x00,0x00,0x01,0x98,0x06,0x00,0x00,0x00,0x01,0x98,0x06,0x00,0x60,0x00,
0x0f,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,0x19,0x80,0x00,0x00,0x01,0x98,0x06,0x00,
0x00,0x00,0x01,0x98,0x06,0x00,0x60,0x00,0x0f,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,
0x19,0x80,0x00,0x00,0x01,0x98,0x06,0x00,0x00,0x00,0x01,0x98,0x06,0x00,0x60,0x00,
0x0f,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,0x19,0x8f,0xff,0x00,0x01,0x98,0x07,0xf0,
0x7f,0x00,0x01,0x98,0xff,0xf0,0x60,0x00,0x0f,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,
0x19,0x8f,0xff,0x00,0x01,0x98,0x07,0xf0,0x7f,0x00,0x01,0x98,0xff,0xf0,0x60,0x00,
0x0f,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,0xff,0xf0,0x00,0xff,0xf1,0xff,0x06,0x00,
0x60,0x1f,0xff,0x9f,0x00,0x0f,0xe0,0x07,0xff,0xff,0x00,0x0f,0xc0,0x03,0xff,0xff,
0xff,0xf0,0x00,0xff,0xf1,0xff,0x06,0x00,0x60,0x1f,0xff,0x9f,0x00,0x0f,0xe0,0x07,
0xff,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,0x00,0x0f,0xff,0x19,0x80,0x00,0x07,0xf0,
0x7f,0x19,0x81,0x98,0xff,0xf0,0x00,0x06,0x0f,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,
0x00,0x0f,0xff,0x19,0x80,0x00,0x07,0xf0,0x7f,0x19,0x81,0x98,0xff,0xf0,0x00,0x06,
0x0f,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,0x00,0x00,0x60,0x19,0x80,0x00,0x00,0x00,
0x60,0x19,0x81,0x98,0x06,0x00,0x00,0x06,0x0f,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,
0x00,0x00,0x60,0x19,0x80,0x00,0x00,0x00,0x60,0x19,0x81,0x98,0x06,0x00,0x00,0x06,
0x0f,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,0x00,0x00,0x60,0x19,0x80,0x00,0x00,0x00,
0x60,0x19,0x81,0x98,0x06,0x00,0x00,0x06,0x0f,0xff,0xff,0xff,0xc0,0x03,0xf0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x1f,0x83,0xfc,0x1f,0x80,
0x00,0x00,0x00,0x00,0x1f,0x80,0xf0,0x1f,0x00,0x78,0x00,0x00,0x00,0x07,0x80,0x00,
0x00,0x01,0x98,0x19,0x81,0x98,0x18,0x80,0x00,0x00,0x00,0x00,0x06,0x01,0x98,0x31,
0x80,0xc0,0x00,0x00,0x18,0x0c,0x00,0xf0,0x1d,0x81,0x98,0x19,0x81,0x98,0x0c,0x80,
0x00,0x00,0x01,0xd8,0x0f,0x01,0x98,0x31,0x80,0x60,0x1d,0x81,0xf0,0x18,0x01,0x98,
0x37,0x81,0xb0,0x18,0x01,0x98,0x0c,0x00,0xfc,0x19,0x83,0x70,0x19,0x81,0x98,0x31,
0x80,0xf0,0x36,0xc3,0x78,0x18,0x01,0x98,0x33,0x01,0x98,0x18,0x01,0x98,0x06,0x01,
0x90,0x19,0x80,0x60,0x19,0x81,0xf8,0x31,0x81,0x98,0x36,0xc3,0x58,0x1f,0x81,0x98,
0x33,0x01,0x98,0x18,0x01,0x98,0x0c,0x01,0x98,0x19,0x80,0x60,0x19,0x81,0x98,0x1b,
0x01,0x98,0x36,0xc3,0xd8,0x18,0x01,0x98,0x37,0x81,0x98,0x18,0x01,0x98,0x0c,0x81,
0x98,0x19,0x80,0x60,0x0f,0x01,0x98,0x1b,0x01,0x98,0x1b,0x81,0xf0,0x18,0x01,0x98,
0x1d,0x81,0xf0,0x18,0x01,0x98,0x18,0x81,0x98,0x19,0x80,0x60,0x06,0x01,0x98,0x1b,
0x01,0x98,0x00,0x03,0x00,0x0c,0x01,0x98,0x00,0x01,0x80,0x18,0x01,0x8c,0x1f,0x80,
0xf0,0x1e,0xc0,0x38,0x1f,0x80,0xf0,0x3b,0x80,0xf0,0x00,0x00,0x00,0x07,0x81,0x98,
0x00,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x30,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x38,0x1b,0x01,0xe0,0x00,0x00,0x00,
0x3f,0xc0,0x60,0x0c,0x00,0x30,0x07,0x00,0x30,0x06,0x01,0xcc,0x19,0x80,0x00,0x00,
0x00,0x20,0x0d,0x80,0x30,0x3f,0xc3,0xfc,0x00,0x00,0x60,0x06,0x00,0x60,0x0d,0x80,
0x30,0x06,0x03,0x6c,0x19,0x80,0x00,0x00,0x00,0x20,0x0d,0x80,0x60,0x3f,0xc2,0x04,
0x00,0x01,0xf8,0x03,0x00,0xc0,0x0d,0x80,0x30,0x00,0x03,0x38,0x19,0x80,0x00,0x00,
0x00,0x20,0x0d,0x80,0xc0,0x3f,0xc2,0x04,0x3f,0xc1,0xf8,0x03,0x00,0xc0,0x0c,0x00,
0x30,0x3f,0xc0,0x00,0x0f,0x00,0x60,0x00,0x02,0x20,0x0d,0x81,0xf0,0x3f,0xc2,0x04,
0x00,0x00,0x60,0x06,0x00,0x60,0x0c,0x00,0x30,0x3f,0xc1,0xcc,0x00,0x00,0x60,0x06,
0x03,0x20,0x00,0x00,0x00,0x3f,0xc2,0x04,0x00,0x00,0x60,0x0c,0x00,0x30,0x0c,0x01,
0xb0,0x00,0x03,0x6c,0x00,0x00,0x00,0x00,0x01,0xa0,0x00,0x00,0x00,0x3f,0xc2,0x04,
0x3f,0xc0,0x00,0x00,0x00,0x00,0x0c,0x01,0xb0,0x06,0x03,0x38,0x00,0x00,0x00,0x00,
0x00,0xe0,0x00,0x00,0x00,0x3f,0xc2,0x04,0x00,0x01,0xf8,0x1f,0x81,0xf8,0x0c,0x00,
0xe0,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x3f,0xc3,0xfc,
0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
}
#endif
} namespace QON {
#if UNITY_2021_1_OR_NEWER
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using UnityEngine;
public static class QGL {
static Texture2D _texWhite = Texture2D.whiteTexture;
static Material _material;
static int _context;
static Camera _camera;
static bool _invertedY;
class Late {
public int context;
public Color color;
}
class LateLine : Late {
public List<Vector2> line;
}
class LateText : Late {
public float x, y;
public float scale;
public string str;
}
class LateImage : Late {
public float x, y, w, h;
public Texture texture;
public Material material;
}
// these are postponed and drawn after all geometry in scene
// FIXME: methinks these are obsolete, _lates are used instead
static List<LateText> _texts = new List<LateText>();
static List<LateText> _textsNokia = new List<LateText>();
static List<LateImage> _images = new List<LateImage>();
static List<LateLine> _lines = new List<LateLine>();
static List<Late> _lates = new List<Late>();
static void BlitSlow( Texture texture, Vector2 srcPos, Vector2 srcSize, Vector3 dstPos,
Vector3 dstSize, Color? color = null, Material material = null) {
Color col = color == null ? Color.white : color.Value;
texture = texture ? texture : _texWhite;
float y = _invertedY ? ScreenHeight() - dstPos.y : dstPos.y;
float dy = _invertedY ? y - dstSize.y : y + dstSize.y;
float tw = texture.width > 0 ? texture.width : 1;
float th = texture.height > 0 ? texture.height : 1;
float u0 = srcPos.x / tw;
float u1 = u0 + srcSize.x / tw;
float v0 = 1 - srcPos.y / th;
float v1 = v0 - srcSize.y / th;
GL.PushMatrix();
if ( material != null ) {
material.SetPass(0);
material.SetColor("_Color", color.Value);
} else {
SetTexture( texture );
}
GL.LoadPixelMatrix();
GL.Begin( GL.QUADS );
GL.Color( col );
GL.TexCoord( new Vector3( u0, v0, 0 ) );
GL.Vertex( new Vector3( dstPos.x, y, 0 ) );
GL.TexCoord( new Vector3( u1, v0, 0 ) );
GL.Vertex( new Vector3( dstPos.x + dstSize.x, y, 0 ) );
GL.TexCoord( new Vector3( u1, v1, 0 ) );
GL.Vertex( new Vector3( dstPos.x + dstSize.x, dy, 0 ) );
GL.TexCoord( new Vector3( u0, v1, 0 ) );
GL.Vertex( new Vector3( dstPos.x, dy, 0 ) );
GL.End();
GL.PopMatrix();
}
static void DrawText( string s, float x, float y ) {
for ( int i = 0; i < s.Length; i++ ) {
DrawScreenChar( s[i], x + i * TextDx, y, 1 );
}
}
static int _font => _fonts == null ? 0 : Font_cvar % _fonts.Length;
static int _fontNumColumns => _font == 0 ? AppleFont.APPLEIIF_CLMS : CodePage437.FontSz;
static int _fontNumRows => _font == 0 ? AppleFont.APPLEIIF_ROWS : CodePage437.FontSz;
static int _fontCharWidth => _font == 0 ? AppleFont.APPLEIIF_CW : CodePage437.CharSz;
static int _fontCharHeight => _font == 0 ? AppleFont.APPLEIIF_CH : CodePage437.CharSz;
static int GetCharInFont( int c ) {
return c % ( _fontNumColumns * _fontNumRows );
}
// == Public API ==
static int CharSpacingX_cvar = -3;
static int CharSpacingY_cvar = 3;
static int Font_cvar = 0;
public static float pixelsPerPoint = 1;
public static float TextDx => Mathf.Max( AppleFont.APPLEIIF_CW + 1, _fontCharWidth + CharSpacingX_cvar );
public static float TextDy => _fontCharHeight + CharSpacingY_cvar;
public static Color TagToCol( string tag ) {
int [] rgb = new int[3 * 2];
if ( tag.Length > rgb.Length ) {
for ( int i = 0; i < rgb.Length; i++ ) {
rgb[i] = Uri.FromHex( tag[i + 1] );
}
}
return new Color( ( ( rgb[0] << 4 ) | rgb[1] ) / 255.999f,
( ( rgb[2] << 4 ) | rgb[3] ) / 255.999f,
( ( rgb[4] << 4 ) | rgb[5] ) / 255.999f );
}
public static int GetCursorChar() {
return _font == 0 ? 127 : 0xdb;
}
public static float ScreenWidth() {
Camera cam = _camera ? _camera : Camera.main;
if ( cam ) {
return cam.pixelWidth;
}
return Screen.width;
}
public static float ScreenHeight() {
Camera cam = _camera ? _camera : Camera.main;
if ( cam ) {
return cam.pixelHeight;
}
return Screen.height;
}
public static bool Start( bool invertedY = false ) {
Shader shader = Shader.Find( "GLSprites" );
if ( ! shader ) {
shader = Shader.Find( "GUI/Text Shader" );
}
if ( shader ) {
_material = new Material( shader );
_material.hideFlags = HideFlags.HideAndDontSave;
SetContext( null, invertedY: invertedY );
return true;
}
Debug.LogError( "Can't find GL shader" );
return false;
}
public static Vector2 MeasureString( string s, float scale = 1 ) {
float x = 0, y = TextDy * scale, max = 0;
for ( int i = 0; i < s.Length; i++ ) {
if ( s[i] == '\n' ) {
x = 0;
y += TextDy * scale;
} else {
x += TextDx * scale;
max = Mathf.Max( max, x );
}
}
return new Vector2( max, y );
}
public static Vector2Int MeasureStringNokiaInt( string s, int scale = 1 ) {
int cx = 0;
int cy = NokiaFont.NOKIA_LN_H * scale;
int max = 0;
foreach ( var cc in s ) {
int c = cc & 255;
NokiaFont.Glyph g = NokiaFont.glyphs[c];
cx += c == '\n' ? -cx : g.xadvance * scale;
cy += c == '\n' ? NokiaFont.NOKIA_LN_H * scale : 0;
max = Mathf.Max( max, cx );
}
return new Vector2Int( max, cy );
}
public static Vector2 MeasureStringNokia( string s, float scale = 1 ) {
float cx = 0;
float cy = NokiaFont.NOKIA_LN_H * scale;
float max = 0;
foreach ( var cc in s ) {
int c = cc & 255;
NokiaFont.Glyph g = NokiaFont.glyphs[c];
cx += c == '\n' ? -cx : g.xadvance * scale;
cy += c == '\n' ? NokiaFont.NOKIA_LN_H * scale : 0;
max = Mathf.Max( max, cx );
}
return new Vector2( max, cy );
}
public static void DrawTextNokia( string s, float x, float y, Color color, float scale = 1 ) {
y = _invertedY ? ScreenHeight() - y : y;
float cx = 0;
float cy = 0;
foreach ( var cc in s ) {
int c = cc & 255;
NokiaFont.Glyph g = NokiaFont.glyphs[c];
var src = new float[] {
g.x,
g.y,
g.width,
g.height,
};
var dst = new float[] {
x + cx,
y + cy - g.yoffset * scale,
g.width,
g.height,
};
Vector3 uvOff = new Vector3( src[0] / NokiaFont.NOKIA_IMG_W,
src[1] / NokiaFont.NOKIA_IMG_H );
float charU = src[2] / NokiaFont.NOKIA_IMG_W;
float charV = src[3] / NokiaFont.NOKIA_IMG_H;
var uv = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( charU, 0, 0 ),
new Vector3( charU, charV, 0 ),
new Vector3( 0, charV, 0 ),
};
for ( int i = 0; i < 4; i++ ) {
uv[i] += uvOff;
}
Vector3 [] verts;
if ( _invertedY ) {
verts = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( dst[2], 0, 0 ),
new Vector3( dst[2], -dst[3], 0 ),
new Vector3( 0, -dst[3], 0 ),
};
} else {
verts = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( dst[2], 0, 0 ),
new Vector3( dst[2], dst[3], 0 ),
new Vector3( 0, dst[3], 0 ),
};
}
GL.Color( color );
for ( int i = 0; i < 4; i++ ) {
GL.TexCoord( uv[i] );
GL.Vertex( verts[i] * scale + new Vector3( dst[0], dst[1] ) );
}
cx += c == '\n' ? -cx : g.xadvance * scale;
cy += c == '\n' ? -NokiaFont.NOKIA_LN_H * scale : 0;
}
}
static List<Color> _colStack = new List<Color>();
public static void DrawTextWithOutline( string s, float x, float y, Color color, float scale = 1 ) {
for ( int i = 0, j = 0; i < s.Length; i++ ) {
if ( Cellophane.ColorTagLead( s, i, out string tl ) ) {
_colStack.Add( TagToCol( tl ) );
i += tl.Length;
} else if ( Cellophane.ColorTagClose( s, i, out string tc ) ) {
_colStack.RemoveAt( _colStack.Count - 1 );
i += tc.Length;
}
if ( s[i] == '\n' ) {
j = 0;
y += TextDy * scale;
} else {
var c = _colStack.Count > 0 ? _colStack[_colStack.Count - 1] : color;
DrawScreenCharWithOutline( s[i], x + j * TextDx * scale, y, c, scale );
j++;
}
}
}
public static void DrawScreenCharWithOutline( int c, float screenX, float screenY, Color color,
float scale = 1 ) {
// == outline ==
Vector2 [] outline = new Vector2 [] {
new Vector3( scale, 0 ),
new Vector3( 0, scale ),
new Vector3( scale, scale ),
new Vector3( -scale, scale ),
};
GL.Color( new Color( 0, 0, 0, 1 * ( color.a * color.a * color.a ) ) );
for ( int i = 0; i < outline.Length; i++ ) {
DrawScreenChar( c, screenX + outline[i].x, screenY + outline[i].y, scale );
DrawScreenChar( c, screenX - outline[i].x, screenY - outline[i].y, scale );
}
// == actual character ==
GL.Color( color );
DrawScreenChar( c, screenX, screenY, scale );
}
static Texture2D _texFont;
static Texture2D [] _fonts;
public static void SetFontTexture() {
// make sure we work when going back to edit mode
_texFont = _fonts == null ? null : _fonts[_font];
if ( ! _texFont ) {
_fonts = new Texture2D [] {
AppleFont.GetTexture(),
CodePage437.GetTexture(),
};
_texFont = _fonts[_font];
}
SetTexture( _texFont );
}
public static void SetWhiteTexture() {
SetTexture( _texWhite );
}
public static void SetMaterialColor( Color color ) {
_material.color = color;
}
public static void SetTexture( Texture tex ) {
_material.SetTexture( "_MainTex", tex );
_material.SetPass( 0 );
}
public static void DrawQuad( Vector2 pos, Vector2 size,
Vector2? srcOrigin = null, Vector2? srcSize = null ) {
Vector2 uv0 = srcOrigin != null ? srcOrigin.Value : Vector2.zero;
Vector2 uv1 = srcSize != null ? ( uv0 + srcSize.Value ) : Vector2.one;
float y = _invertedY ? ScreenHeight() - pos.y : pos.y;
float dy = _invertedY ? y - size.y : y + size.y;
GL.TexCoord( new Vector3( uv0.x, uv0.y, 0 ) );
GL.Vertex( new Vector3( pos.x, y, 0 ) );
GL.TexCoord( new Vector3( uv1.x, uv0.y, 0 ) );
GL.Vertex( new Vector3( pos.x + size.x, y, 0 ) );
GL.TexCoord( new Vector3( uv1.x, uv1.y, 0 ) );
GL.Vertex( new Vector3( pos.x + size.x, dy, 0 ) );
GL.TexCoord( new Vector3( uv0.x, uv1.y, 0 ) );
GL.Vertex( new Vector3( pos.x, dy, 0 ) );
}
public static void DrawSolidQuad( Vector2 pos, Vector2 size ) {
float y = _invertedY ? ScreenHeight() - pos.y : pos.y;
float dy = _invertedY ? y - size.y : y + size.y;
GL.Vertex( new Vector3( pos.x, y, 0 ) );
GL.Vertex( new Vector3( pos.x + size.x, y, 0 ) );
GL.Vertex( new Vector3( pos.x + size.x, dy, 0 ) );
GL.Vertex( new Vector3( pos.x, dy, 0 ) );
}
struct CharInfo {
public Vector3 [] uv;
public Vector3 [] verts;
}
static Dictionary<int,CharInfo> _charsMap = new Dictionary<int,CharInfo>();
public static void DrawScreenChar( int c, float screenX, float screenY, float scale ) {
int idx = GetCharInFont( c );
float y = _invertedY ? ScreenHeight() - screenY : screenY;
Vector3 vertOff = new Vector3( screenX, y );
int a = _font | ( ( _invertedY ? 1 : 0 ) << 8 );
int b = idx;
int hash = ( a + b ) * ( ( a + b + 1 ) >> 1 ) + a;
if ( ! _charsMap.TryGetValue( hash, out CharInfo ci ) ) {
float tw = ( float )_fontCharWidth / _texFont.width;
float th = ( float )_fontCharHeight / _texFont.height;
Vector3 uvOff = new Vector3( ( idx % _fontNumColumns ) * tw, ( idx / _fontNumColumns ) * th );
float charU = ( float )_texFont.width / _fontNumColumns / _texFont.width;
float charV = ( float )_texFont.height / _fontNumRows / _texFont.height;
ci.uv = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( charU, 0, 0 ),
new Vector3( charU, charV, 0 ),
new Vector3( 0, charV, 0 ),
};
for ( int i = 0; i < 4; i++ ) {
ci.uv[i] += uvOff;
}
if ( _invertedY ) {
ci.verts = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( _fontCharWidth, 0, 0 ),
new Vector3( _fontCharWidth, -_fontCharHeight, 0 ),
new Vector3( 0, -_fontCharHeight, 0 ),
};
} else {
ci.verts = new Vector3[4] {
new Vector3( 0, 0, 0 ),
new Vector3( _fontCharWidth, 0, 0 ),
new Vector3( _fontCharWidth, _fontCharHeight, 0 ),
new Vector3( 0, _fontCharHeight, 0 ),
};
}
_charsMap[hash] = ci;
}
for ( int i = 0; i < 4; i++ ) {
GL.TexCoord( ci.uv[i] );
GL.Vertex( ci.verts[i] * scale + vertOff );
}
}
public static Vector2 LatePrintWorld( object o, Vector3 worldPos, Color? color = null,
float scale = 1 ) {
return LatePrintWorld( o.ToString(), worldPos, color, scale );
}
public static Vector2 LatePrintWorld( string str, Vector3 worldPos, Color? color = null,
float scale = 1 ) {
Vector2 pt = WorldToScreenPos( worldPos );
LatePrint( str, pt.x, pt.y, color, scale );
return pt;
}
public static void LatePrint( object o, Vector2 xy, Color? color = null, float scale = 1 ) {
LatePrint( o.ToString(), xy.x, xy.y, color, scale );
}
public static void LatePrint( object o, float x, float y, Color? color = null, float scale = 1 ) {
LatePrint( o.ToString(), x, y, color, scale );
}
static void AddCenteredText( List<LateText> texts, string str, Vector2 sz, float x, float y,
Color? color = null, float scale = 1 ) {
var txt = new LateText {
context = _context,
x = Mathf.Round( x - ( int )sz.x / 2 ),
y = Mathf.Round( y - ( int )sz.y / 2 ),
scale = scale,
str = str,
color = color == null ? Color.green : color.Value,
};
texts.Add( txt );
_lates.Add( txt );
}
static void AddText( List<LateText> texts, string str, float x, float y, Color? color = null,
float scale = 1 ) {
var txt = new LateText {
context = _context,
x = ( int )x,
y = ( int )y,
scale = scale,
str = str,
color = color == null ? Color.green : color.Value,
};
texts.Add( txt );
_lates.Add( txt );
}
public static void LatePrint( string str, float x, float y, Color? color = null, float scale = 1 ) {
Vector2 sz = MeasureString( str, scale );
AddCenteredText( _texts, str, sz, x, y, color, scale );
}
// top-left version of the late prints (which are centered)
public static void LatePrint_tl( object o, Vector2 xy, Color? color = null, float scale = 1 ) {
LatePrint_tl( o.ToString(), xy.x, xy.y, color, scale );
}
public static void LatePrint_tl( object o, float x, float y, Color? color = null, float scale = 1 ) {
LatePrint_tl( o.ToString(), x, y, color, scale );
}
public static void LatePrint_tl( string str, float x, float y, Color? color = null, float scale = 1 ) {
AddText( _texts, str, x, y, color, scale );
}
public static void LatePrintNokia( string str, Vector2Int xy, Color? color = null,
float scale = 1 ) {
LatePrintNokia( str, xy.x, xy.y, color, scale );
}
public static void LatePrintNokia( string str, float x, float y, Color? color = null,
float scale = 1 ) {
Vector2 sz = MeasureStringNokia( str, scale );
AddCenteredText( _textsNokia, str, sz, x, y, color, scale );
}
public static void LatePrintNokia_tl( string str, float x, float y, Color? color = null,
float scale = 1 ) {
AddText( _textsNokia, str, x, y, color, scale );
}
public static void LatePrintFlush() {
SetFontTexture();
GL.Begin( GL.QUADS );
foreach ( var s in _texts ) {
if ( s.context == _context ) {
DrawTextWithOutline( s.str, s.x, s.y, s.color, s.scale );
}
}
GL.End();
SetTexture( NokiaFont.GetTexture() );
GL.Begin( GL.QUADS );
foreach ( var s in _textsNokia ) {
if ( s.context == _context ) {
DrawTextNokia( s.str, s.x, s.y, s.color, s.scale );
}
}
GL.End();
void removeTexts( List<LateText> texts ) {
for ( int i = texts.Count - 1; i >= 0; i-- ) {
if ( texts[i].context == _context ) {
texts.RemoveAt( i );
}
}
}
removeTexts( _texts );
removeTexts( _textsNokia );
}
public static Vector2 LateBlitWorld( Texture2D tex, Vector3 worldPos, float w, float h,
Color? color = null ) {
Vector2 pt = WorldToScreenPos( worldPos );
LateBlit( tex, pt.x - w / 2, pt.y - h / 2, w, h, color: color );
return pt;
}
public static Vector2 LateBlitWorld( Vector3 worldPos, float w, float h, Color? color = null ) {
Vector2 pt = WorldToScreenPos( worldPos );
LateBlit( null, pt.x - w / 2, pt.y - h / 2, w, h, color: color );
return pt;
}
public static void LateBlit( Vector2 xy, Vector2 sz, Color? color = null ) {
LateBlit( null, xy, sz.x, sz.y, color );
}
public static void LateBlit( Texture tex, Vector2 xy, float w, float h, Color? color = null ) {
LateBlit( tex, xy.x, xy.y, w, h, color );
}
public static void LateBlit( float x, float y, float w, float h, Color? color = null ) {
LateBlit( null, x, y, w, h, color );
}
public static void LateBlit( Texture tex, float x, float y, float w, float h, Color? color = null,
Material mat = null ) {
var img = new LateImage {
context = _context,
x = x,
y = y,
w = w,
h = h,
color = color == null ? Color.white : color.Value,
texture = tex != null ? tex : _texWhite,
material = mat,
};
_images.Add( img );
_lates.Add( img );
}
public static void LateBlitFlush() {
foreach ( var i in _images ) {
if ( i.context == _context ) {
Vector2 srcPos = new Vector2( 0, 0 );
Vector2 srcSize = new Vector2( i.texture.width, i.texture.height );
Vector2 dstPos = new Vector2( i.x, i.y );
Vector2 dstSize = new Vector2( i.w, i.h );
BlitSlow( i.texture, srcPos, srcSize, dstPos, dstSize, i.color, i.material );
}
}
for ( int i = _images.Count - 1; i >= 0; i-- ) {
if ( _images[i].context == _context ) {
_images.RemoveAt( i );
}
}
}
public static void LateDrawLineLoopWorld( IList<Vector3> worldLine, Color? color = null ) {
List<Vector2> l = new List<Vector2>();
foreach ( var p in worldLine ) {
l.Add( WorldToScreenPos( p ) );
}
LateDrawLineLoop( l, color );
}
public static void LateDrawLineWorld( Vector3 a, Vector3 b, Color? color = null ) {
LateDrawLineWorld( new [] { a, b }, color );
}
public static void LateDrawLineWorld( IList<Vector3> worldLine, Color? color = null ) {
List<Vector2> l = new List<Vector2>();
foreach ( var p in worldLine ) {
l.Add( WorldToScreenPos( p ) );
}
LateDrawLine( l, color );
}
public static void LateDrawLine( float ax, float ay, float bx, float by, Color? color = null ) {
LateDrawLine( new Vector2( ax, ay ), new Vector2( bx, by ), color );
}
public static void LateDrawLine( Vector2 a, Vector2 b, Color? color = null ) {
LateDrawLine( new [] { a, b }, color );
}
public static void LateDrawLineLoop( IList<Vector2> line, Color? color = null ) {
List<Vector2> loop = new List<Vector2>( line );
loop.Add( line[0] );
LateDrawLine( loop, color );
}
private static Vector2 [] _lineRect = new Vector2[4];
public static void LateDrawLineRect( float x, float y, float w, float h, Color? color = null ) {
_lineRect[0] = new Vector2( x, y );
_lineRect[1] = new Vector2( x + w, y );
_lineRect[2] = new Vector2( x + w, y + h );
_lineRect[3] = new Vector2( x, y + h );
LateDrawLineLoop( _lineRect, color );
}
public static void LateDrawLine( IList<Vector2> line, Color? color = null ) {
var l = new List<Vector2>( line );
for ( int i = 0; i < l.Count; i++ ) {
float y = _invertedY ? ScreenHeight() - l[i].y : l[i].y;
l[i] = new Vector2( l[i].x, y );
}
var ln = new LateLine {
context = _context,
line = l,
color = color == null ? Color.white : color.Value,
};
_lines.Add( ln );
_lates.Add( ln );
}
public static void LateDrawLineFlush() {
SetWhiteTexture();
GL.Begin( GL.LINES);
foreach ( var l in _lines ) {
if ( l.context == _context ) {
GL.Color( l.color );
for ( int i = 0; i < l.line.Count - 1; i++ ) {
GL.Vertex( l.line[i + 0] );
GL.Vertex( l.line[i + 1] );
}
}
}
GL.End();
for ( int i = _lines.Count - 1; i >= 0; i-- ) {
if ( _lines[i].context == _context ) {
_lines.RemoveAt( i );
}
}
}
public static Vector2 WorldToScreenPos( Vector3 worldPos ) {
Camera cam = _camera ? _camera : Camera.main;
if ( cam ) {
Vector2 pt = cam.WorldToScreenPoint( worldPos );
pt.y = ScreenHeight() - pt.y;
return pt;
}
return Vector2.zero;
}
public static void SetContext( Camera camera, float pixelsPerPoint = 1, bool invertedY = false ) {
_context = camera ? camera.GetHashCode() : 0;
_camera = camera;
_invertedY = invertedY;
QGL.pixelsPerPoint = pixelsPerPoint;
}
public static void Begin() {
GL.PushMatrix();
GL.LoadPixelMatrix();
}
public static void FlushLates() {
#if false
LateBlitFlush();
LatePrintFlush();
LateDrawLineFlush();
#else
for ( int li = 0; li < _lates.Count; ) {
while ( _lates[li].context != _context ) {
li++;
}
int start;
// == texts ==
for ( start = li; li < _lates.Count && _lates[li] is LateText; li++ )
{}
if ( start < li ) {
SetFontTexture();
GL.Begin( GL.QUADS );
for ( int i = start; i < li; i++ ) {
var lt = ( LateText )_lates[i];
DrawTextWithOutline( lt.str, lt.x, lt.y, lt.color, lt.scale );
}
GL.End();
}
// == images ==
for ( start = li; li < _lates.Count && _lates[li] is LateImage; li++ )
{}
for ( int i = start; i < li; i++ ) {
var img = ( LateImage )_lates[i];
Vector2 srcPos = new Vector2( 0, 0 );
Vector2 srcSize = new Vector2( img.texture.width, img.texture.height );
Vector2 dstPos = new Vector2( img.x, img.y );
Vector2 dstSize = new Vector2( img.w, img.h );
BlitSlow( img.texture, srcPos, srcSize, dstPos, dstSize, img.color,
img.material );
}
// == lines ==
for ( start = li; li < _lates.Count && _lates[li] is LateLine; li++ )
{}
if ( start < li ) {
SetWhiteTexture();
GL.Begin( GL.LINES);
for ( int i = start; i < li; i++ ) {
var l = ( LateLine )_lates[i];
GL.Color( l.color );
for ( int j = 0; j < l.line.Count - 1; j++ ) {
GL.Vertex( l.line[j + 0] );
GL.Vertex( l.line[j + 1] );
}
}
GL.End();
}
}
for ( int li = _lates.Count - 1; li >= 0; li-- ) {
if ( _lates[li].context == _context ) {
_lates.RemoveAt( li );
}
}
_texts.Clear();
_textsNokia.Clear();
_images.Clear();
_lines.Clear();
#endif
}
public static void End( bool skipLateFlush = false ) {
if ( ! skipLateFlush ) {
if ( _material ) {
LateBlitFlush();
LatePrintFlush();
LateDrawLineFlush();
} else {
Debug.LogError( "Can't find GL material. Should call QGL.Start()" );
}
}
GL.PopMatrix();
}
}
#endif // UNITY
} namespace QON {
// define this to have Unity UI API support
//#define QUI_USE_UNITY_UI
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
#if QUI_USE_UNITY_UI
using UnityEngine;
using UnityEngine.UI;
#endif
public static class QUI {
enum MouseButtonState {
None,
Down = 1 << 0,
Up = 1 << 1,
}
public enum WidgetResult {
Idle,
Hot,
Pressed,
Active,
Released,
Dropped,
Count,
}
struct UIRect {
public float x, y, w, h;
public int handle;
public bool scissor;
}
public static Action<float,float,float,float> DrawLineRect = (x,y,w,h)=>{};
public static Action<string> Log = (s) => {};
public static Action<string> Error = (s) => {};
public static bool DebugShowRects_cvar;
static List<UIRect> _rects = new List<UIRect>();
static MouseButtonState _mouseButton;
// this widget is hovered over
public static int hotWidget;
// this widget is usually pressed but not released yet
public static int activeWidget;
public static float cursorX;
public static float cursorY;
static float _oldCursorX;
static float _oldCursorY;
public static bool CursorInRect( float x, float y, float w, float h ) {
return cursorX >= x && cursorY >= y && cursorX < x + w && cursorY < y + h;
}
// this callback might be called multiple times inside a single frame
public static bool OnMouseButton( bool down ) {
if ( down ) {
_mouseButton |= MouseButtonState.Down;
} else {
_mouseButton |= MouseButtonState.Up;
}
return hotWidget != 0 || activeWidget != 0;
}
// assumes top-left origin for mouse
public static void Begin( float inCursorX, float inCursorY ) {
cursorX = inCursorX;
cursorY = inCursorY;
#if QUI_USE_UNITY_UI
BeginUnityUI();
#endif
}
static UIRect Clip( UIRect r, UIRect clip ) {
float x0 = Math.Max( clip.x, r.x );
float y0 = Math.Max( clip.y, r.y );
float x1 = Math.Min( clip.x + clip.w, r.x + r.w );
float y1 = Math.Min( clip.y + clip.h, r.y + r.h );
return new UIRect {
x = x0,
y = y0,
w = Math.Max( 0, x1 - x0 ),
h = Math.Max( 0, y1 - y0 ),
handle = r.handle,
};
}
public static void End( bool skipUnityUI = false ) {
bool BUTTON_RELEASED() {
return ( ( _mouseButton & MouseButtonState.Up ) != 0
|| _mouseButton == MouseButtonState.None );
}
UIRect s = new UIRect { x = 0, y = 0, w = 99999, h = 99999 };
for ( int i = 0; i < _rects.Count; i++ ) {
if ( _rects[i].scissor ) {
s = _rects[i];
} else {
_rects[i] = Clip( _rects[i], s );
}
}
if ( DebugShowRects_cvar ) {
foreach ( var r in _rects ) {
if ( r.w > 0 && r.h > 0 ) {
DrawLineRect( r.x, r.y, r.w, r.h );
}
}
}
// check if 'active' widget is still present on screen
if ( activeWidget != 0 ) {
int i;
for ( i = 0; i < _rects.Count; i++ ) {
if ( _rects[i].handle == activeWidget ) {
break;
}
}
// 'active' is no longer drawn/tested
if ( i == _rects.Count ) {
activeWidget = 0;
}
}
// go back-to-front in the rectangles stack and check for hits
hotWidget = 0;
for ( int i = _rects.Count - 1; i >= 0; i-- ) {
UIRect r = _rects[i];
if ( ! r.scissor && CursorInRect( r.x, r.y, r.w, r.h ) ) {
if ( BUTTON_RELEASED() ) {
// there is only one hot widget
activeWidget = 0;
hotWidget = r.handle;
} else if ( activeWidget == 0 ) {
activeWidget = r.handle;
}
break;
}
}
if ( BUTTON_RELEASED() ) {
activeWidget = 0;
}
_rects.Clear();
if ( ( hotWidget == 0 && activeWidget == 0 ) || ( _mouseButton & MouseButtonState.Up ) != 0 ) {
_mouseButton = MouseButtonState.None;
}
_oldCursorX = cursorX;
_oldCursorY = cursorY;
#if QUI_USE_UNITY_UI
if ( ! skipUnityUI ) {
EndUnityUI();
}
#endif
}
public static void DragPosition( WidgetResult res, ref float ioX, ref float ioY ) {
if ( res == WidgetResult.Active ) {
float dx = cursorX - _oldCursorX;
float dy = cursorY - _oldCursorY;
ioX += dx;
ioY += dy;
}
}
public static WidgetResult Drag_wg( ref float ioX, ref float ioY, float w, float h, int handle ) {
WidgetResult res = ClickRect_wg( ioX, ioY, w, h, handle );
DragPosition( res, ref ioX, ref ioY );
return res;
}
public static WidgetResult ClickRect_wg( float x, float y, float w, float h, int handle ) {
WidgetResult res = WidgetResult.Idle;
// push rectangle in the list
_rects.Add( new UIRect { x = x, y = y, w = w, h = h, handle = handle, } );
// click
if ( activeWidget == handle ) {
if ( ( _mouseButton & MouseButtonState.Up ) != 0 && CursorInRect( x, y, w, h ) ) {
res = WidgetResult.Released;
} else if ( ( _mouseButton & MouseButtonState.Up ) != 0 ) {
res = WidgetResult.Dropped;
} else {
res = WidgetResult.Active;
}
} else if ( handle == hotWidget ) {
if ( ( _mouseButton & MouseButtonState.Down ) != 0 && CursorInRect( x, y, w, h ) ) {
res = WidgetResult.Pressed;
} else {
res = WidgetResult.Hot;
}
}
return res;
}
public static int NextHashWg( int hash, int val ) {
return hash * 31 + val + 1;
}
public static int HashWg( int lineNumber, string caller ) {
int id = 23;
id = NextHashWg( id, lineNumber + 1 );
id = NextHashWg( id, caller.GetHashCode() );
return id;
}
public static WidgetResult ClickRect( float x, float y, float w, float h, int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
return ClickRect_wg( x, y, w, h, NextHashWg( HashWg( lineNumber, caller ), handle ) );
}
public static WidgetResult Drag( ref float x, ref float y, float w, float h, int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
return Drag_wg( ref x, ref y, w, h, NextHashWg( HashWg( lineNumber, caller ), handle ) );
}
public static void Scissor( float x, float y, float w, float h ) {
_rects.Add( new UIRect { x = x, y = y, w = w, h = h, scissor = true, } );
}
// == implementation of IMGUI on top of retained mode Unity UI ==
#if QUI_USE_UNITY_UI
class TickItem {
public bool skipSort;
public RectTransform rt;
public Rect scissor;
public float garbageAge;
};
static Dictionary<RectTransform,RectTransform[]> _refChildren =
new Dictionary<RectTransform,RectTransform[]>();
static HashSet<TickItem> _garbage = new HashSet<TickItem>();
static Dictionary<int,TickItem> _cache = new Dictionary<int,TickItem>();
static List<TickItem> _dead = new List<TickItem>();
static List<TickItem> _tickItems = new List<TickItem>();
static TextGenerator _textGen = new TextGenerator();
// 1 -- show creation, 2 -- show destruction, 3 -- show all
public static int DebugLogGraphicLife_cvar;
public static RectTransform [] RegisterChildren( RectTransform rt, string [] refChildren ) {
RectTransform [] result;
if ( ! _refChildren.TryGetValue( rt, out result ) ) {
var found = new List<RectTransform>();
if ( refChildren != null ) {
foreach ( var rc in refChildren ) {
var t = rt.Find( rc );
if ( ! t ) {
Error( $"Couldn't find {rc} in {rt}. Will have empty children refs array." );
return null;
}
found.Add( t as RectTransform );
}
}
// add the root rect transform as last element
found.Add( rt );
result = found.ToArray();
_refChildren[rt] = result;
Log( "Registered referenced children of " + rt );
}
return result;
}
static int HashTransform( float x, float y, float w, float h ) {
int hash = 23;
hash = NextHashWg( hash, ( int )x );
hash = NextHashWg( hash, ( int )y );
hash = NextHashWg( hash, ( int )w );
hash = NextHashWg( hash, ( int )h );
return hash;
}
static int HashTransform( RectTransform rt ) {
return HashTransform( rt.position.x,
( Screen.height - rt.position.y ),
rt.rect.width,
rt.rect.height );
}
static UnityEngine.UI.Text TextInternal( string content, float x, float y, float w, float h,
int handle, Font font = null, int fontSize = 0,
TextAnchor align = TextAnchor.UpperLeft,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null ) {
UnityEngine.UI.Text txt = RegisterGraphic<UnityEngine.UI.Text>( x, y, w, h, handle, color );
font = font == null ? defaultFont : font;
fontSize = fontSize == 0 ? ( int )( h * 0.7f ) : fontSize;
if ( txt.fontSize != fontSize ) {
txt.fontSize = fontSize;
}
if ( txt.font != font ) {
txt.font = font;
}
if ( txt.alignment != align ) {
txt.alignment = align;
}
if ( txt.text != content ) {
//Log( "setting text content" );
txt.text = content;
}
if ( txt.verticalOverflow != overflow ) {
txt.verticalOverflow = overflow;
}
return txt;
}
static void InitImageGrapic( Image img ) {
img.maskable = false;
}
static void ImageGraphicCommon( Image img, float ppuMultiplier, Image.Type type ) {
if ( img.type != type ) {
img.type = type;
}
if ( img.pixelsPerUnitMultiplier != ppuMultiplier ) {
img.pixelsPerUnitMultiplier = ppuMultiplier;
}
}
static void SpriteInternal( float x, float y, float w, float h, int handle, Texture2D tex = null,
Color? color = null,
bool scissor = false,
Vector4? border = null,
float ppuMultiplier = 0,
Image.Type type = Image.Type.Simple ) {
Image img = RegisterGraphic<Image>( x, y, w, h, handle, color, InitImageGrapic, scissor );
if ( ! img.sprite || img.sprite.texture != tex ) {
UnityEngine.Object.Destroy( img.sprite );
img.sprite = UnityEngine.Sprite.Create( tex, new Rect( 0.0f, 0.0f, tex.width, tex.height ),
Vector2.zero, 100f, 0, SpriteMeshType.FullRect,
border != null ? border.Value : Vector4.zero );
}
ImageGraphicCommon( img, ppuMultiplier, type );
}
static void SpriteInternal( float x, float y, float w, float h, int handle, Sprite sprite,
Color? color = null,
bool scissor = false,
float ppuMultiplier = 0,
Image.Type type = Image.Type.Simple ) {
Image img = RegisterGraphic<Image>( x, y, w, h, handle, color, InitImageGrapic, scissor );
if ( ! img.sprite || img.sprite != sprite ) {
img.sprite = sprite;
}
ImageGraphicCommon( img, ppuMultiplier, type );
}
static void RegisterItem( TickItem item, float x = float.MaxValue, float y = float.MaxValue,
float w = float.MaxValue, float h = float.MaxValue, int handle = 0,
bool isScissor = false, bool skipSort = false ) {
var rt = item.rt;
x = ( x != float.MaxValue ) ? x : rt.position.x;
y = ( y != float.MaxValue ) ? y : Screen.height - rt.position.y;
w = ( w != float.MaxValue ) ? w : rt.rect.width;
h = ( h != float.MaxValue ) ? h : rt.rect.height;
if ( HashTransform( rt ) != HashTransform( x, y, w, h ) ) {
rt.position = new Vector2( x, Screen.height - y );
rt.sizeDelta = new Vector2( w, h );
//Log( "resize/move: " + rt.name + " " + ( int )x + "," + ( int )y + "," + ( int )w + "," + ( int )h );
}
Rect scissor = Rect.zero;
if ( isScissor ) {
Scissor( x, y, w, h );
Rect cvs = canvas.GetComponent<RectTransform>().rect;
scissor = new Rect( x + cvs.x, -y - cvs.y - h, w, h );
}
item.scissor = scissor;
item.skipSort = skipSort;
item.rt = rt;
_tickItems.Add( item );
}
static bool TryGetItemFromCache( int handle, out TickItem item ) {
return _cache.TryGetValue( handle, out item ) && item != null && item.rt != null;
}
static T RegisterGraphic<T>( float x, float y, float w, float h, int handle, Color? color = null,
Action<T> onCreate = null, bool isScissor = false ) where T : Graphic {
if ( ! TryGetItemFromCache( handle, out TickItem item ) ) {
GameObject go = new GameObject();
go.transform.parent = canvas.transform;
go.name = typeof( T ).Name + "_" + handle.ToString( "X4" );
T comp = go.AddComponent<T>();
if ( onCreate != null ) {
onCreate( comp );
}
comp.rectTransform.pivot = new Vector3( 0, 1 );
comp.raycastTarget = false;
item = _cache[handle] = new TickItem {
rt = comp.rectTransform,
};
if ( DebugLogGraphicLife_cvar == 1 || DebugLogGraphicLife_cvar == 3 ) {
Log( $"Created a graphic {comp}" );
}
}
Graphic graphic = item.rt.GetComponent<Graphic>();
Color c = color == null ? Color.white : color.Value;
if ( graphic.color != c ) {
graphic.color = c;
}
RegisterItem( item, x, y, w, h, handle, isScissor );
return ( T )graphic;
}
static RectTransform RegisterPrefab( float x, float y, float w, float h, int handle,
GameObject prefab = null, bool isScissor = false ) {
if ( ! TryGetItemFromCache( handle, out TickItem item ) ) {
string name = "Prefab_" + handle.ToString( "X4" );
RectTransform rt;
if ( prefab ) {
GameObject go = GameObject.Instantiate( prefab );
go.name = name;
go.transform.position = prefab.transform.position;
if ( prefab.transform.parent == null ) {
go.transform.SetParent( canvas.transform );
} else {
Log( "Parented prefab, won't be sorted " + prefab );
go.transform.SetParent( prefab.transform.parent );
go.transform.localScale = prefab.transform.localScale;
}
rt = go.GetComponent<RectTransform>();
var pfrt = prefab.GetComponent<RectTransform>();
if ( pfrt ) {
rt.pivot = pfrt.pivot;
rt.anchorMin = pfrt.anchorMin;
rt.anchorMax = pfrt.anchorMax;
rt.anchoredPosition = pfrt.anchoredPosition;
rt.sizeDelta = pfrt.sizeDelta;
}
Log( "Instantiated prefab " + prefab );
} else {
GameObject go = new GameObject( name, typeof( RectTransform ) );
go.transform.SetParent( canvas.transform );
rt = go.GetComponent<RectTransform>();
Log( "Creating new object. rt: " + rt );
}
item = _cache[handle] = new TickItem {
rt = rt,
};
}
RegisterItem( item, x, y, w, h, handle, isScissor: isScissor,
skipSort: item.rt.parent != canvas.transform );
return item.rt;
}
// == public Unity UI API ==
public static Canvas canvas;
public static Font defaultFont;
public static void BeginUnityUI() {
if ( ! defaultFont ) {
defaultFont = Resources.GetBuiltinResource<Font>( "Arial.ttf" );
}
// the items from the previous tick are potentially garbage
foreach ( var i in _tickItems ) {
_garbage.Add( i );
}
_tickItems.Clear();
}
public static void EndUnityUI() {
if ( ! Application.isPlaying ) {
return;
}
if ( ! canvas ) {
Error( "No canvas for QUI. Assign canvas before use." );
return;
}
Rect scissor = canvas.GetComponent<RectTransform>().rect;
// expand the scissor a bit
scissor.x -= 10;
scissor.y -= 10;
scissor.width += 20;
scissor.height += 20;
foreach ( var i in _tickItems ) {
_garbage.Remove( i );
}
_dead.Clear();
foreach ( var g in _garbage ) {
g.garbageAge += Time.deltaTime;
if ( ! g.rt ) {
_dead.Add( g );
continue;
}
if ( g.garbageAge > 5f ) {
if ( DebugLogGraphicLife_cvar == 2 || DebugLogGraphicLife_cvar == 3 ) {
string comp = g.rt.GetComponent<Graphic>()?.ToString();
if ( comp == null ) {
comp = g.rt.ToString();
}
Log( $"Destroyed '{comp}', num visible: {_tickItems.Count}" );
}
GameObject.Destroy( g.rt.gameObject );
_dead.Add( g );
} else {
// hide the item
g.rt.gameObject.SetActive( false );
}
}
foreach ( var d in _dead ) {
_garbage.Remove( d );
}
for ( int i = 0; i < _tickItems.Count; i++ ) {
var ti = _tickItems[i];
RectTransform rt = ti.rt;
// make sure we are active
rt.gameObject.SetActive( true );
// reset the wait-for-death timer each tick we are apparent
ti.garbageAge = -i * 0.1f;
// sort by order of calling
if ( ! _tickItems[i].skipSort ) {
rt.SetSiblingIndex( i );
}
// handle scissors
IClippable c = rt.GetComponent<Graphic>() as IClippable;
if ( c != null ) {
c.Cull( scissor, true);
c.SetClipRect( scissor, true );
}
Rect s = _tickItems[i].scissor;
if ( s.width + s.height > 0 ) {
scissor = s;
}
}
}
public static void EnableScissor_wg( float x, float y, float w, float h, int handle ) {
RegisterPrefab( x, y, w, h, handle, isScissor: true );
}
public static void EnableScissor( float x, float y, float w, float h, int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
EnableScissor_wg( x, y, w, h, handle );
}
public static void DisableScissor_wg( int handle ) {
RegisterPrefab( 0, 0, Screen.width, Screen.height, handle, isScissor: true );
}
public static void DisableScissor( int handle = 0, [CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
DisableScissor_wg( handle );
}
public static void SpriteTex_wg( float x, float y, float w, float h, int handle,
Texture2D tex = null,
Color? color = null,
bool scissor = false,
Vector4? border = null,
float ppuMultiplier = 1,
Image.Type type = Image.Type.Simple ) {
SpriteInternal( x, y, w, h, handle, tex, color, scissor, border, ppuMultiplier, type );
}
public static void SpriteTex( float x, float y, float w, float h, Texture2D tex = null,
Color? color = null,
bool scissor = false,
Vector4? border = null,
float ppuMultiplier = 1,
Image.Type type = Image.Type.Simple,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
SpriteInternal( x, y, w, h, handle, tex, color, scissor, border, ppuMultiplier, type );
}
public static void Sprite_wg( float x, float y, float w, float h, Sprite sprite, int handle,
Color? color = null,
bool scissor = false,
float ppuMultiplier = 1,
Image.Type type = Image.Type.Simple ) {
SpriteInternal( x, y, w, h, handle, sprite, color, scissor, ppuMultiplier, type );
}
public static void Sprite( float x, float y, float w, float h, Sprite sprite,
Color? color = null,
bool scissor = false,
float ppuMultiplier = 1,
Image.Type type = Image.Type.Simple,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
SpriteInternal( x, y, w, h, handle, sprite, color, scissor, ppuMultiplier, type );
}
public static void Texture_wg( float x, float y, float w, float h, int handle, Texture2D tex = null,
Color? color = null,
bool scissor = false ) {
void initImage( RawImage i ) {
i.maskable = false;
}
RawImage img = RegisterGraphic<RawImage>( x, y, w, h, handle, color, initImage, scissor );
if ( img.texture != tex ) {
img.texture = tex;
}
}
public static void Texture( float x, float y, float w, float h, Texture2D tex = null,
Color? color = null, bool scissor = false,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
Texture_wg( x, y, w, h, handle, tex, color, scissor );
}
public static RectTransform [] PrefabWH( float x, float y, float w, float h,
GameObject prefab = null,
string [] refChildren = null,
bool scissor = false, int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
RectTransform rt = RegisterPrefab( x, y, float.MaxValue, float.MaxValue, handle, prefab, scissor );
rt.localScale = new Vector2( w / rt.sizeDelta.x, h / rt.sizeDelta.y );
return RegisterChildren( rt, refChildren );
}
public static void GetRTPosAndSize( RectTransform rt, out float x, out float y,
out float w, out float h ) {
w = rt.sizeDelta.x * rt.localScale.x;
h = rt.sizeDelta.y * rt.localScale.y;
x = rt.pivot.x * w;
y = ( 1 - rt.pivot.y ) * h;
}
public static void GetClickRect( RectTransform rt, float canvasScale,
float screenHeight, out float x, out float y,
out float w, out float h ) {
QUI.GetRTPosAndSize( rt, out x, out y, out w, out h );
x = rt.position.x - canvasScale * x;
y = screenHeight - rt.position.y - canvasScale * y;
w *= canvasScale;
h *= canvasScale;
}
public static RectTransform [] Prefab( float posX = float.MaxValue, float posY = float.MaxValue,
float scale = float.MaxValue, GameObject prefab = null,
string [] refChildren = null, bool scissor = false,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
RectTransform rt = RegisterPrefab( posX, posY, float.MaxValue, float.MaxValue, handle, prefab,
scissor );
if ( scale != float.MaxValue ) {
rt.localScale = Vector2.one * scale;
}
return RegisterChildren( rt, refChildren );
}
public static void MeasuredText_wg( string content, float x, float y, float w, float h, int handle,
out float measureW, out float measureH,
Font font = null, int fontSize = 0,
TextAnchor align = TextAnchor.UpperLeft,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null ) {
var txt = TextInternal( content, x, y, w, h, handle, font, fontSize, align, overflow, color );
TextGenerationSettings tgs = txt.GetGenerationSettings( txt.rectTransform.rect.size );
measureW = Mathf.Min( w, _textGen.GetPreferredWidth( content, tgs ) );
measureH = _textGen.GetPreferredHeight( content, tgs );
// QUI End() will activate it, keep it invisible for now, so string can be measured and drawn separately
txt.gameObject.SetActive( false );
}
public static void MeasuredText( string content, float x, float y, float w, float h,
out float measureW, out float measureH,
Font font = null, int fontSize = 0,
TextAnchor align = TextAnchor.UpperLeft,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
MeasuredText_wg( content, x, y, w, h, handle, out measureW, out measureH, font,
fontSize, align, overflow, color );
}
public static void Text_wg( string content, float x, float y, float w, float h,
Font font = null, int fontSize = 0,
TextAnchor align = TextAnchor.UpperLeft,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null,
int handle = 0 ) {
TextInternal( content, x, y, w, h, handle, font, fontSize, align, overflow, color );
}
public static void Text( string content, float x, float y, float w, float h,
Font font = null, int fontSize = 0,
TextAnchor align = TextAnchor.UpperLeft,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
TextInternal( content, x, y, w, h, handle, font, fontSize, align, overflow, color );
}
public static WidgetResult ClickText( string content, float x, float y, float w, float h,
Font font = null, TextAnchor align = TextAnchor.UpperLeft,
int fontSize = 0,
VerticalWrapMode overflow = VerticalWrapMode.Overflow,
Color? color = null,
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
handle = NextHashWg( HashWg( lineNumber, caller ), handle );
TextInternal( content, x, y, w, h, handle, font, fontSize, align, overflow, color );
return ClickRect_wg( x, y, w, h, handle );
}
public static WidgetResult Panel( float x, float y, float w, float h,
Texture2D texture= null, Color? color = null,
// use this handle for loops
int handle = 0,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null ) {
int id = NextHashWg( HashWg( lineNumber, caller ), handle );
WidgetResult r = ClickRect_wg( x, y, w, h, id );
Texture( x, y, w, h, handle: handle, tex: texture, color: color );
return r;
}
#endif // QUI_USE_UNITY_UI
}
} namespace QON {
// Copyright (c) 2021 Stoiko Todorov
// This work is licensed under the terms of the MIT license.
// For a copy, see https://opensource.org/licenses/MIT.
#if UNITY_2021_1_OR_NEWER
//#define HAS_UNITY
#endif
// apple II font
#if HAS_UNITY
using UnityEngine;
#elif SDL
using System.Runtime.InteropServices;
using static SDL2.SDL;
using static SDL2.SDL.SDL_TextureAccess;
#endif
using System;
public static class AppleFont {
public const int APPLEIIF_WIDTH = 96;
public const int APPLEIIF_HEIGHT = 64;
public const int APPLEIIF_CLMS = 16;
public const int APPLEIIF_ROWS = 8;
public const int APPLEIIF_CW = (APPLEIIF_WIDTH/APPLEIIF_CLMS);
public const int APPLEIIF_CH = (APPLEIIF_HEIGHT/APPLEIIF_ROWS);
public static readonly byte [] bitmap = new byte[APPLEIIF_WIDTH * APPLEIIF_HEIGHT / 8] {
0x0e,0xf1,0x38,0xcf,0xf7,0x79,0x91,0x03,0x45,0x41,0x14,0x39,0x91,0x12,0x45,0x51,
0x10,0x04,0x11,0x01,0x25,0xc1,0x16,0x45,0x55,0x14,0x05,0x51,0x10,0x04,0x11,0x01,
0x15,0x41,0x35,0x45,0x5d,0xf4,0x04,0xd1,0xf3,0x04,0x1f,0x01,0x0d,0x41,0x55,0x45,
0xcd,0x17,0x05,0x51,0x10,0x64,0x11,0x01,0x15,0x41,0x94,0x45,0x41,0x14,0x45,0x51,
0x10,0x44,0x11,0x11,0x25,0x41,0x14,0x45,0x5e,0xf4,0x38,0xcf,0x17,0x78,0x91,0xe3,
0x44,0x5f,0x14,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x8f,0xf3,0x38,0x5f,0x14,0x45,0x51,0xf4,0x7d,0xc0,0x07,0x00,0x51,0x14,0x45,0x44,
0x14,0x45,0x51,0x04,0x0d,0x01,0x06,0x00,0x51,0x14,0x05,0x44,0x14,0x45,0x8a,0x82,
0x0c,0x02,0x46,0x00,0x4f,0xf4,0x38,0x44,0x14,0x55,0x04,0x41,0x0c,0x04,0xa6,0x00,
0x41,0x55,0x40,0x44,0x14,0x55,0x0a,0x21,0x0c,0x08,0x16,0x01,0x41,0x92,0x44,0x44,
0xa4,0x6c,0x11,0x11,0x0c,0x10,0x06,0x00,0x81,0x15,0x39,0x84,0x43,0x44,0x11,0xf1,
0x7d,0xc0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,
0x00,0xa1,0x28,0xc4,0x20,0x10,0x04,0x41,0x00,0x00,0x00,0x00,0x00,0xa1,0x28,0xde,
0x54,0x10,0x02,0x52,0x11,0x00,0x00,0x40,0x00,0xa1,0x7c,0x05,0x52,0x10,0x01,0xe4,
0x10,0x00,0x00,0x20,0x00,0x01,0x28,0x0e,0x21,0x00,0x01,0x44,0x7c,0xc0,0x07,0x10,
0x00,0x01,0x7c,0x94,0x50,0x01,0x01,0xe4,0x10,0x04,0x00,0x08,0x00,0x00,0x28,0x4f,
0x96,0x00,0x02,0x52,0x11,0x04,0x00,0x04,0x00,0x01,0x28,0x04,0x66,0x01,0x04,0x41,
0x00,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0e,0xe1,0x7c,0xc8,0xc7,0x7d,0x8e,0x03,0x00,0x08,0x20,0x38,0x91,0x11,0x41,0x4c,
0x20,0x40,0x51,0x04,0x00,0x04,0x40,0x44,0x19,0x01,0x21,0xca,0x13,0x20,0x51,0x44,
0x10,0xc2,0x87,0x20,0x15,0xc1,0x30,0x09,0xf4,0x10,0x8e,0x07,0x00,0x01,0x00,0x11,
0x13,0x21,0x40,0x1f,0x14,0x09,0x11,0x44,0x10,0xc2,0x87,0x10,0x11,0x11,0x44,0x48,
0x14,0x09,0x11,0x02,0x10,0x04,0x40,0x00,0x8e,0xf3,0x39,0x88,0xe3,0x08,0xce,0x01,
0x08,0x08,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0e,0xf1,0x38,0xcf,0xf7,0x79,0x91,0x03,0x45,0x41,0x14,0x39,0x91,0x12,0x45,0x51,
0x10,0x04,0x11,0x01,0x25,0xc1,0x16,0x45,0x55,0x14,0x05,0x51,0x10,0x04,0x11,0x01,
0x15,0x41,0x35,0x45,0x5d,0xf4,0x04,0xd1,0xf3,0x04,0x1f,0x01,0x0d,0x41,0x55,0x45,
0xcd,0x17,0x05,0x51,0x10,0x64,0x11,0x01,0x15,0x41,0x94,0x45,0x41,0x14,0x45,0x51,
0x10,0x44,0x11,0x11,0x25,0x41,0x14,0x45,0x5e,0xf4,0x38,0xcf,0x17,0x78,0x91,0xe3,
0x44,0x5f,0x14,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x8f,0xf3,0x38,0x5f,0x14,0x45,0x51,0xf4,0x7d,0xc0,0x07,0x00,0x51,0x14,0x45,0x44,
0x14,0x45,0x51,0x04,0x0d,0x01,0x06,0x00,0x51,0x14,0x05,0x44,0x14,0x45,0x8a,0x82,
0x0c,0x02,0x46,0x00,0x4f,0xf4,0x38,0x44,0x14,0x55,0x04,0x41,0x0c,0x04,0xa6,0x00,
0x41,0x55,0x40,0x44,0x14,0x55,0x0a,0x21,0x0c,0x08,0x16,0x01,0x41,0x92,0x44,0x44,
0xa4,0x6c,0x11,0x11,0x0c,0x10,0x06,0x00,0x81,0x15,0x39,0x84,0x43,0x44,0x11,0xf1,
0x7d,0xc0,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,
0x02,0x10,0x00,0x10,0xc0,0x00,0x01,0x81,0x04,0x06,0x00,0x00,0x04,0x10,0x00,0x10,
0x20,0x01,0x01,0x00,0x04,0x04,0x00,0x00,0x88,0xf3,0x78,0x9e,0x23,0x38,0x8f,0xc1,
0x44,0xc4,0xf6,0x38,0x00,0x14,0x05,0x51,0xf4,0x44,0x11,0x81,0x24,0x44,0x15,0x45,
0x80,0x17,0x05,0xd1,0x27,0x44,0x11,0x81,0x1c,0x44,0x15,0x45,0x40,0x14,0x05,0x51,
0x20,0x78,0x11,0x81,0x24,0x44,0x15,0x45,0x80,0xf7,0x78,0x9e,0x27,0x40,0x91,0x93,
0x44,0x4e,0x14,0x39,0x00,0x00,0x00,0x00,0x00,0x38,0x00,0x60,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x70,0xc4,0x61,0x01,0x00,0x00,0x00,0x02,
0x00,0x00,0x00,0x00,0x18,0x04,0xd3,0x54,0x8f,0xd7,0x79,0x4f,0x14,0x45,0x51,0xf4,
0x19,0x04,0x03,0x28,0x51,0x34,0x04,0x42,0x14,0x45,0x4a,0x84,0x0c,0x04,0x06,0x54,
0x51,0x14,0x38,0x42,0x14,0x55,0x44,0x44,0x18,0x04,0x03,0x28,0x8f,0x17,0x40,0x52,
0xa6,0x54,0x8a,0x27,0x18,0x04,0x03,0x54,0x01,0x14,0x3c,0x8c,0x45,0x6c,0x11,0xf4,
0x71,0xc4,0x01,0x00,0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x03,0x00,0x04,0x00,0x00,
};
public static void MeasureString( string s, out float w, out float h,
float scale = 1, float extraX = 0, float extraY = 0 ) {
float cw = scale * ( APPLEIIF_CW + extraX );
float ch = scale * ( APPLEIIF_CH + extraY );
float x = 0, y = ch, max = 0;
foreach ( var c in s ) {
if ( c == '\n' ) {
x = 0;
y += ch;
} else {
x += cw;
max = Math.Max( max, x );
}
}
w = max;
h = y;
}
#if HAS_UNITY
static Texture2D _texture;
public static Texture2D GetTexture() {
if ( _texture ) {
return _texture;
}
_texture = new Texture2D( APPLEIIF_WIDTH, APPLEIIF_HEIGHT, textureFormat: TextureFormat.RGBA32,
mipChain: false, linear: false );
_texture.filterMode = FilterMode.Point;
int srcW = APPLEIIF_WIDTH / 8;
for ( int y = 0; y < APPLEIIF_HEIGHT; y++ ) {
for ( int x = 0; x < srcW; x++ ) {
int b = bitmap[x + y * srcW];
for ( int i = 0; i < 8; i++ ) {
int alpha = ( b & ( 1 << i ) ) != 0 ? 0xff : 0;
Color32 c = new Color32( 0xff, 0xff, 0xff, ( byte )alpha );
_texture.SetPixel( x * 8 + i, y, c );
}
}
}
_texture.Apply();
return _texture;
}
public static Texture2D CreateStringTexture( string s, int extraX = 0, int extraY = 0 ) {
MeasureString( s, out float w, out float h, extraX: extraX, extraY: extraY );
var tex = new Texture2D( ( int )( w + 0.5f ), ( int )( h + 0.5f ),
textureFormat: TextureFormat.RGBA32, mipChain: false, linear: false );
tex.filterMode = FilterMode.Point;
for ( int y = 0; y < tex.height; y++ ) {
for ( int x = 0; x < tex.width; x++ ) {
tex.SetPixel( x, y, new Color32( 0, 0, 0, 0 ) );
}
}
int cx = 0;
int cy = 0;
int cw = APPLEIIF_CW + extraX;
int ch = APPLEIIF_CH + extraY;
foreach ( var c in s ) {
if ( c == '\n' ) {
cx = 0;
cy += ch;
continue;
}
int idx = c % ( APPLEIIF_CLMS * APPLEIIF_ROWS );
int minU = ( idx % APPLEIIF_CLMS ) * APPLEIIF_CW;
int minV = ( idx / APPLEIIF_CLMS ) * APPLEIIF_CH;
for ( int y = 0; y < APPLEIIF_CH; y++ ) {
for ( int x = 0; x < APPLEIIF_CW; x++ ) {
int dstX = cx + x;
int dstY = cy + y;
int u = minU + x;
int v = minV + y;
int b = bitmap[( u >> 3 ) + v * ( APPLEIIF_WIDTH >> 3 )];
b &= 1 << ( u & 7 );
Color32 color = new Color32( 0xff, 0xff, 0xff, ( byte )( b != 0 ? 0xff : 0 ) );
tex.SetPixel( dstX, tex.height - dstY - 1, color );
}
}
cx += cw;
}
tex.Apply();
return tex;
}
#elif SDL
static IntPtr _texture;
public static IntPtr GetTexture( IntPtr renderer ) {
if ( _texture != null && _texture != IntPtr.Zero ) {
return _texture;
}
SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "0" );
_texture = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_ABGR8888,
( int )SDL_TEXTUREACCESS_STATIC, APPLEIIF_WIDTH, APPLEIIF_HEIGHT );
int pitch = APPLEIIF_WIDTH * 4;
int bw = APPLEIIF_WIDTH / 8;
byte [] bytes = new byte[pitch * APPLEIIF_HEIGHT];
for ( int y = 0, idx = 0; y < APPLEIIF_HEIGHT; y++ ) {
for ( int x = 0; x < bw; x++ ) {
int bt = bitmap[x + y * bw];
for ( int i = 0; i < 8; i++, idx += 4 ) {
int alpha = ( bt & ( 1 << i ) ) != 0 ? 0xff : 0;
bytes[idx + 0] = 0xff;
bytes[idx + 1] = 0xff;
bytes[idx + 2] = 0xff;
bytes[idx + 3] = ( byte )alpha;
}
}
}
IntPtr unmanagedPointer = Marshal.AllocHGlobal( bytes.Length );
Marshal.Copy( bytes, 0, unmanagedPointer, bytes.Length );
//SDL_Rect r = new SDL_Rect();
SDL_UpdateTexture( _texture, IntPtr.Zero, unmanagedPointer, pitch );
return _texture;
}
#endif
}
} namespace QON {
#if UNITY_STANDALONE || UNITY_2021_0_OR_NEWER
using System;
using System.Collections.Generic;
using UnityEngine;
public static class KeyBinds {
public static Action<string> Log = s => {};
public static Action<string> Error = s => {};
public static readonly KeyCode[] keys = new KeyCode [] {
KeyCode.None, //Not assigned (never returned as the result of a keystroke).
KeyCode.Backspace, //The backspace key.
KeyCode.Delete, //The forward delete key.
KeyCode.Tab, //The tab key.
KeyCode.Clear, //The Clear key.
KeyCode.Return, //Return key.
KeyCode.Pause, //Pause on PC machines.
KeyCode.Escape, //Escape key.
KeyCode.Space, //Space key.
KeyCode.Keypad0, //Numeric keypad 0.
KeyCode.Keypad1, //Numeric keypad 1.
KeyCode.Keypad2, //Numeric keypad 2.
KeyCode.Keypad3, //Numeric keypad 3.
KeyCode.Keypad4, //Numeric keypad 4.
KeyCode.Keypad5, //Numeric keypad 5.
KeyCode.Keypad6, //Numeric keypad 6.
KeyCode.Keypad7, //Numeric keypad 7.
KeyCode.Keypad8, //Numeric keypad 8.
KeyCode.Keypad9, //Numeric keypad 9.
KeyCode.KeypadPeriod, //Numeric keypad '.'.
KeyCode.KeypadDivide, //Numeric keypad '/'.
KeyCode.KeypadMultiply, //Numeric keypad '*'.
KeyCode.KeypadMinus, //Numeric keypad '='.
KeyCode.KeypadPlus, //Numeric keypad '+'.
KeyCode.KeypadEnter, //Numeric keypad enter.
KeyCode.KeypadEquals, //Numeric keypad '='.
KeyCode.UpArrow, //Up arrow key.
KeyCode.DownArrow, //Down arrow key.
KeyCode.RightArrow, //Right arrow key.
KeyCode.LeftArrow, //Left arrow key.
KeyCode.Insert, //Insert key key.
KeyCode.Home, //Home key.
KeyCode.End, //End key.
KeyCode.PageUp, //Page up.
KeyCode.PageDown, //Page down.
KeyCode.F1, //F1 function key.
KeyCode.F2, //F2 function key.
KeyCode.F3, //F3 function key.
KeyCode.F4, //F4 function key.
KeyCode.F5, //F5 function key.
KeyCode.F6, //F6 function key.
KeyCode.F7, //F7 function key.
KeyCode.F8, //F8 function key.
KeyCode.F9, //F9 function key.
KeyCode.F10, //F10 function key.
KeyCode.F11, //F11 function key.
KeyCode.F12, //F12 function key.
KeyCode.F13, //F13 function key.
KeyCode.F14, //F14 function key.
KeyCode.F15, //F15 function key.
KeyCode.Alpha0, //The '0' key on the top of the alphanumeric keyboard.
KeyCode.Alpha1, //The '1' key on the top of the alphanumeric keyboard.
KeyCode.Alpha2, //The '2' key on the top of the alphanumeric keyboard.
KeyCode.Alpha3, //The '3' key on the top of the alphanumeric keyboard.
KeyCode.Alpha4, //The '4' key on the top of the alphanumeric keyboard.
KeyCode.Alpha5, //The '5' key on the top of the alphanumeric keyboard.
KeyCode.Alpha6, //The '6' key on the top of the alphanumeric keyboard.
KeyCode.Alpha7, //The '7' key on the top of the alphanumeric keyboard.
KeyCode.Alpha8, //The '8' key on the top of the alphanumeric keyboard.
KeyCode.Alpha9, //The '9' key on the top of the alphanumeric keyboard.
KeyCode.Exclaim, //Exclamation mark key '!'.
KeyCode.DoubleQuote, //Double quote key '"'.
KeyCode.Hash, //Hash key '#'.
KeyCode.Dollar, //Dollar sign key '$'.
KeyCode.Ampersand, //Ampersand key '&'.
KeyCode.Quote, //Quote key '.
KeyCode.LeftParen, //Left Parenthesis key '('.
KeyCode.RightParen, //Right Parenthesis key ')'.
KeyCode.Asterisk, //Asterisk key '*'.
KeyCode.Plus, //Plus key '+'.
KeyCode.Comma, //Comma ',' key.
KeyCode.Minus, //Minus '-' key.
KeyCode.Equals, //Equals '=' key.
KeyCode.Period, //Period '.' key.
KeyCode.Slash, //Slash '/' key.
KeyCode.Colon, //Colon ':' key.
KeyCode.Semicolon, //Semicolon ',' key.
KeyCode.Less, //Less than '' key.
KeyCode.Question, //Question mark '?' key.
KeyCode.At, //At key '@'.
KeyCode.LeftBracket, //Left square bracket key '['.
KeyCode.Backslash, //Backslash key '\'.
KeyCode.RightBracket, //Right square bracket key ']'.
KeyCode.Caret, //Caret key '^'.
KeyCode.Underscore, //Underscore '_' key.
KeyCode.BackQuote, //Back quote key '`'.
KeyCode.A, //'a' key.
KeyCode.B, //'b' key.
KeyCode.C, //'c' key.
KeyCode.D, //'d' key.
KeyCode.E, //'e' key.
KeyCode.F, //'f' key.
KeyCode.G, //'g' key.
KeyCode.H, //'h' key.
KeyCode.I, //'i' key.
KeyCode.J, //'j' key.
KeyCode.K, //'k' key.
KeyCode.L, //'l' key.
KeyCode.M, //'m' key.
KeyCode.N, //'n' key.
KeyCode.O, //'o' key.
KeyCode.P, //'p' key.
KeyCode.Q, //'q' key.
KeyCode.R, //'r' key.
KeyCode.S, //'s' key.
KeyCode.T, //'t' key.
KeyCode.U, //'u' key.
KeyCode.V, //'v' key.
KeyCode.W, //'w' key.
KeyCode.X, //'x' key.
KeyCode.Y, //'y' key.
KeyCode.Z, //'z' key.
KeyCode.Numlock, //Numlock key.
KeyCode.CapsLock, //Capslock key.
KeyCode.ScrollLock, //Scroll lock key.
KeyCode.RightShift, //Right shift key.
KeyCode.LeftShift, //Left shift key.
KeyCode.RightControl, //Right Control key.
KeyCode.LeftControl, //Left Control key.
KeyCode.RightAlt, //Right Alt key.
KeyCode.LeftAlt, //Left Alt key.
// already added (not unique)
// KeyCode.LeftCommand, //Left Command key.
KeyCode.LeftApple, //Left Command key.
KeyCode.LeftWindows, //Left Windows key.
KeyCode.RightCommand, //Right Command key.
// already added (not unique)
//KeyCode.RightApple, //Right Command key.
KeyCode.RightWindows, //Right Windows key.
KeyCode.AltGr, //Alt Gr key.
KeyCode.Help, //Help key.
KeyCode.Print, //Print key.
KeyCode.SysReq, //Sys Req key.
KeyCode.Break, //Break key.
KeyCode.Menu, //Menu key.
KeyCode.Mouse0, //First (primary) mouse button.
KeyCode.Mouse1, //Second (secondary) mouse button.
KeyCode.Mouse2, //Third mouse button.
KeyCode.Mouse3, //Fourth mouse button.
KeyCode.Mouse4, //Fifth mouse button.
KeyCode.Mouse5, //Sixth mouse button.
KeyCode.Mouse6, //Seventh mouse button.
#if false // no joystick
KeyCode.JoystickButton0, //Button 0 on any joystick.
KeyCode.JoystickButton1, //Button 1 on any joystick.
KeyCode.JoystickButton2, //Button 2 on any joystick.
KeyCode.JoystickButton3, //Button 3 on any joystick.
KeyCode.JoystickButton4, //Button 4 on any joystick.
KeyCode.JoystickButton5, //Button 5 on any joystick.
KeyCode.JoystickButton6, //Button 6 on any joystick.
KeyCode.JoystickButton7, //Button 7 on any joystick.
KeyCode.JoystickButton8, //Button 8 on any joystick.
KeyCode.JoystickButton9, //Button 9 on any joystick.
KeyCode.JoystickButton10, //Button 10 on any joystick.
KeyCode.JoystickButton11, //Button 11 on any joystick.
KeyCode.JoystickButton12, //Button 12 on any joystick.
KeyCode.JoystickButton13, //Button 13 on any joystick.
KeyCode.JoystickButton14, //Button 14 on any joystick.
KeyCode.JoystickButton15, //Button 15 on any joystick.
KeyCode.JoystickButton16, //Button 16 on any joystick.
KeyCode.JoystickButton17, //Button 17 on any joystick.
KeyCode.JoystickButton18, //Button 18 on any joystick.
KeyCode.JoystickButton19, //Button 19 on any joystick.
KeyCode.Joystick1Button0, //Button 0 on first joystick.
KeyCode.Joystick1Button1, //Button 1 on first joystick.
KeyCode.Joystick1Button2, //Button 2 on first joystick.
KeyCode.Joystick1Button3, //Button 3 on first joystick.
KeyCode.Joystick1Button4, //Button 4 on first joystick.
KeyCode.Joystick1Button5, //Button 5 on first joystick.
KeyCode.Joystick1Button6, //Button 6 on first joystick.
KeyCode.Joystick1Button7, //Button 7 on first joystick.
KeyCode.Joystick1Button8, //Button 8 on first joystick.
KeyCode.Joystick1Button9, //Button 9 on first joystick.
KeyCode.Joystick1Button10, //Button 10 on first joystick.
KeyCode.Joystick1Button11, //Button 11 on first joystick.
KeyCode.Joystick1Button12, //Button 12 on first joystick.
KeyCode.Joystick1Button13, //Button 13 on first joystick.
KeyCode.Joystick1Button14, //Button 14 on first joystick.
KeyCode.Joystick1Button15, //Button 15 on first joystick.
KeyCode.Joystick1Button16, //Button 16 on first joystick.
KeyCode.Joystick1Button17, //Button 17 on first joystick.
KeyCode.Joystick1Button18, //Button 18 on first joystick.
KeyCode.Joystick1Button19, //Button 19 on first joystick.
KeyCode.Joystick2Button0, //Button 0 on second joystick.
KeyCode.Joystick2Button1, //Button 1 on second joystick.
KeyCode.Joystick2Button2, //Button 2 on second joystick.
KeyCode.Joystick2Button3, //Button 3 on second joystick.
KeyCode.Joystick2Button4, //Button 4 on second joystick.
KeyCode.Joystick2Button5, //Button 5 on second joystick.
KeyCode.Joystick2Button6, //Button 6 on second joystick.
KeyCode.Joystick2Button7, //Button 7 on second joystick.
KeyCode.Joystick2Button8, //Button 8 on second joystick.
KeyCode.Joystick2Button9, //Button 9 on second joystick.
KeyCode.Joystick2Button10, //Button 10 on second joystick.
KeyCode.Joystick2Button11, //Button 11 on second joystick.
KeyCode.Joystick2Button12, //Button 12 on second joystick.
KeyCode.Joystick2Button13, //Button 13 on second joystick.
KeyCode.Joystick2Button14, //Button 14 on second joystick.
KeyCode.Joystick2Button15, //Button 15 on second joystick.
KeyCode.Joystick2Button16, //Button 16 on second joystick.
KeyCode.Joystick2Button17, //Button 17 on second joystick.
KeyCode.Joystick2Button18, //Button 18 on second joystick.
KeyCode.Joystick2Button19, //Button 19 on second joystick.
KeyCode.Joystick3Button0, //Button 0 on third joystick.
KeyCode.Joystick3Button1, //Button 1 on third joystick.
KeyCode.Joystick3Button2, //Button 2 on third joystick.
KeyCode.Joystick3Button3, //Button 3 on third joystick.
KeyCode.Joystick3Button4, //Button 4 on third joystick.
KeyCode.Joystick3Button5, //Button 5 on third joystick.
KeyCode.Joystick3Button6, //Button 6 on third joystick.
KeyCode.Joystick3Button7, //Button 7 on third joystick.
KeyCode.Joystick3Button8, //Button 8 on third joystick.
KeyCode.Joystick3Button9, //Button 9 on third joystick.
KeyCode.Joystick3Button10, //Button 10 on third joystick.
KeyCode.Joystick3Button11, //Button 11 on third joystick.
KeyCode.Joystick3Button12, //Button 12 on third joystick.
KeyCode.Joystick3Button13, //Button 13 on third joystick.
KeyCode.Joystick3Button14, //Button 14 on third joystick.
KeyCode.Joystick3Button15, //Button 15 on third joystick.
KeyCode.Joystick3Button16, //Button 16 on third joystick.
KeyCode.Joystick3Button17, //Button 17 on third joystick.
KeyCode.Joystick3Button18, //Button 18 on third joystick.
KeyCode.Joystick3Button19, //Button 19 on third joystick.
KeyCode.Joystick4Button0, //Button 0 on forth joystick.
KeyCode.Joystick4Button1, //Button 1 on forth joystick.
KeyCode.Joystick4Button2, //Button 2 on forth joystick.
KeyCode.Joystick4Button3, //Button 3 on forth joystick.
KeyCode.Joystick4Button4, //Button 4 on forth joystick.
KeyCode.Joystick4Button5, //Button 5 on forth joystick.
KeyCode.Joystick4Button6, //Button 6 on forth joystick.
KeyCode.Joystick4Button7, //Button 7 on forth joystick.
KeyCode.Joystick4Button8, //Button 8 on forth joystick.
KeyCode.Joystick4Button9, //Button 9 on forth joystick.
KeyCode.Joystick4Button10, //Button 10 on forth joystick.
KeyCode.Joystick4Button11, //Button 11 on forth joystick.
KeyCode.Joystick4Button12, //Button 12 on forth joystick.
KeyCode.Joystick4Button13, //Button 13 on forth joystick.
KeyCode.Joystick4Button14, //Button 14 on forth joystick.
KeyCode.Joystick4Button15, //Button 15 on forth joystick.
KeyCode.Joystick4Button16, //Button 16 on forth joystick.
KeyCode.Joystick4Button17, //Button 17 on forth joystick.
KeyCode.Joystick4Button18, //Button 18 on forth joystick.
KeyCode.Joystick4Button19, //Button 19 on forth joystick.
KeyCode.Joystick5Button0, //Button 0 on fifth joystick.
KeyCode.Joystick5Button1, //Button 1 on fifth joystick.
KeyCode.Joystick5Button2, //Button 2 on fifth joystick.
KeyCode.Joystick5Button3, //Button 3 on fifth joystick.
KeyCode.Joystick5Button4, //Button 4 on fifth joystick.
KeyCode.Joystick5Button5, //Button 5 on fifth joystick.
KeyCode.Joystick5Button6, //Button 6 on fifth joystick.
KeyCode.Joystick5Button7, //Button 7 on fifth joystick.
KeyCode.Joystick5Button8, //Button 8 on fifth joystick.
KeyCode.Joystick5Button9, //Button 9 on fifth joystick.
KeyCode.Joystick5Button10, //Button 10 on fifth joystick.
KeyCode.Joystick5Button11, //Button 11 on fifth joystick.
KeyCode.Joystick5Button12, //Button 12 on fifth joystick.
KeyCode.Joystick5Button13, //Button 13 on fifth joystick.
KeyCode.Joystick5Button14, //Button 14 on fifth joystick.
KeyCode.Joystick5Button15, //Button 15 on fifth joystick.
KeyCode.Joystick5Button16, //Button 16 on fifth joystick.
KeyCode.Joystick5Button17, //Button 17 on fifth joystick.
KeyCode.Joystick5Button18, //Button 18 on fifth joystick.
KeyCode.Joystick5Button19, //Button 19 on fifth joystick.
KeyCode.Joystick6Button0, //Button 0 on sixth joystick.
KeyCode.Joystick6Button1, //Button 1 on sixth joystick.
KeyCode.Joystick6Button2, //Button 2 on sixth joystick.
KeyCode.Joystick6Button3, //Button 3 on sixth joystick.
KeyCode.Joystick6Button4, //Button 4 on sixth joystick.
KeyCode.Joystick6Button5, //Button 5 on sixth joystick.
KeyCode.Joystick6Button6, //Button 6 on sixth joystick.
KeyCode.Joystick6Button7, //Button 7 on sixth joystick.
KeyCode.Joystick6Button8, //Button 8 on sixth joystick.
KeyCode.Joystick6Button9, //Button 9 on sixth joystick.
KeyCode.Joystick6Button10, //Button 10 on sixth joystick.
KeyCode.Joystick6Button11, //Button 11 on sixth joystick.
KeyCode.Joystick6Button12, //Button 12 on sixth joystick.
KeyCode.Joystick6Button13, //Button 13 on sixth joystick.
KeyCode.Joystick6Button14, //Button 14 on sixth joystick.
KeyCode.Joystick6Button15, //Button 15 on sixth joystick.
KeyCode.Joystick6Button16, //Button 16 on sixth joystick.
KeyCode.Joystick6Button17, //Button 17 on sixth joystick.
KeyCode.Joystick6Button18, //Button 18 on sixth joystick.
KeyCode.Joystick6Button19, //Button 19 on sixth joystick.
KeyCode.Joystick7Button0, //Button 0 on seventh joystick.
KeyCode.Joystick7Button1, //Button 1 on seventh joystick.
KeyCode.Joystick7Button2, //Button 2 on seventh joystick.
KeyCode.Joystick7Button3, //Button 3 on seventh joystick.
KeyCode.Joystick7Button4, //Button 4 on seventh joystick.
KeyCode.Joystick7Button5, //Button 5 on seventh joystick.
KeyCode.Joystick7Button6, //Button 6 on seventh joystick.
KeyCode.Joystick7Button7, //Button 7 on seventh joystick.
KeyCode.Joystick7Button8, //Button 8 on seventh joystick.
KeyCode.Joystick7Button9, //Button 9 on seventh joystick.
KeyCode.Joystick7Button10, //Button 10 on seventh joystick.
KeyCode.Joystick7Button11, //Button 11 on seventh joystick.
KeyCode.Joystick7Button12, //Button 12 on seventh joystick.
KeyCode.Joystick7Button13, //Button 13 on seventh joystick.
KeyCode.Joystick7Button14, //Button 14 on seventh joystick.
KeyCode.Joystick7Button15, //Button 15 on seventh joystick.
KeyCode.Joystick7Button16, //Button 16 on seventh joystick.
KeyCode.Joystick7Button17, //Button 17 on seventh joystick.
KeyCode.Joystick7Button18, //Button 18 on seventh joystick.
KeyCode.Joystick7Button19, //Button 19 on seventh joystick.
KeyCode.Joystick8Button0, //Button 0 on eighth joystick.
KeyCode.Joystick8Button1, //Button 1 on eighth joystick.
KeyCode.Joystick8Button2, //Button 2 on eighth joystick.
KeyCode.Joystick8Button3, //Button 3 on eighth joystick.
KeyCode.Joystick8Button4, //Button 4 on eighth joystick.
KeyCode.Joystick8Button5, //Button 5 on eighth joystick.
KeyCode.Joystick8Button6, //Button 6 on eighth joystick.
KeyCode.Joystick8Button7, //Button 7 on eighth joystick.
KeyCode.Joystick8Button8, //Button 8 on eighth joystick.
KeyCode.Joystick8Button9, //Button 9 on eighth joystick.
KeyCode.Joystick8Button10, //Button 10 on eighth joystick.
KeyCode.Joystick8Button11, //Button 11 on eighth joystick.
KeyCode.Joystick8Button12, //Button 12 on eighth joystick.
KeyCode.Joystick8Button13, //Button 13 on eighth joystick.
KeyCode.Joystick8Button14, //Button 14 on eighth joystick.
KeyCode.Joystick8Button15, //Button 15 on eighth joystick.
KeyCode.Joystick8Button16, //Button 16 on eighth joystick.
KeyCode.Joystick8Button17, //Button 17 on eighth joystick.
KeyCode.Joystick8Button18, //Button 18 on eighth joystick.
KeyCode.Joystick8Button19, //Button 19 on eighth joystick.
#endif
};
private static Dictionary<string,string[]> _bindContext = new Dictionary<string,string[]>();
private static Dictionary<KeyCode,int> _keyToIndex = new Dictionary<KeyCode,int>();
static KeyBinds() {
for ( int i = 0; i < keys.Length; i++ ) {
_keyToIndex[keys[i]] = i;
}
}
public static void BindClearAll_kmd( string [] argv ) {
_bindContext.Clear();
Log( "Cleared all Key Bindings." );
}
public static void Bind_kmd( string [] argv ) {
if ( argv.Length < 3 ) {
Log( "Usage: bind <KeyCode> <command> [context]" );
foreach ( var kv in _bindContext ) {
string context = kv.Key;
string [] ctxCommands = kv.Value;
for ( int i = 0; i < keys.Length; i++ ) {
KeyCode key = keys[i];
string cmd = ctxCommands[i];
if ( cmd.Length > 0 ) {
Log( $"{key}: [ff9000]{cmd}[-] {context}" );
}
}
}
return;
}
{
string context = "";
if ( argv.Length > 3 ) {
context = argv[3];
}
string [] ctxCommands;
if ( ! _bindContext.TryGetValue( context, out ctxCommands ) ) {
ctxCommands = new string[keys.Length];
for ( int i = 0; i < ctxCommands.Length; i++ ) {
ctxCommands[i] = "";
}
_bindContext[context] = ctxCommands;
}
if ( Enum.TryParse( argv[1], out KeyCode code ) ) {
int idx;
if ( _keyToIndex.TryGetValue( code, out idx ) ) {
ctxCommands[idx] = argv[2];
} else {
Error( "Unsupported key code " + code );
}
//Log( "Bound command " + argv[2] + " to key " + code );
} else {
Error( "Couldn't find " + argv[1] + " in valid keys." );
}
}
}
private static bool GetCmd( KeyCode k, string context, out string cmd ) {
string [] ctxCommands;
if ( _bindContext.TryGetValue( context, out ctxCommands ) ) {
cmd = ctxCommands[_keyToIndex[k]];
} else {
cmd = "";
}
return cmd.Length > 0;
}
public static string StoreConfig() {
string cfg = "";
foreach ( var kv in _bindContext ) {
string context = kv.Key;
string [] ctxCommands = kv.Value;
for ( int i = 0; i < keys.Length; i++ ) {
KeyCode key = keys[i];
string cmd = ctxCommands[i];
if ( cmd.Length > 0 ) {
cfg += $"bind {key} \"{cmd}\" {context}\n";
}
}
}
return cfg;
}
private static bool Execute( KeyCode key, string cmdLine ) {
//Log( "Execute key binding: " + key + " " + cmdLine );
return Cellophane.TryExecuteString( cmdLine );
}
public static bool TryExecuteBinds( KeyCode keyDown = KeyCode.None, KeyCode keyUp = KeyCode.None,
KeyCode keyHold = KeyCode.None,
string context = "" ) {
#if KEYBINDS_LEGACY
string cmd;
foreach ( var key in keys ) {
if ( Input.GetKeyDown( key ) && GetCmd( key, context, out cmd ) ) {
if ( cmd[0] != '+' && cmd[0] != '-' ) {
Execute( key, cmd );
} else if ( cmd[0] == '+' ) {
Execute( key, cmd.Substring( 1 ) );
}
} else if ( Input.GetKeyUp( key ) && GetCmd( key, context, out cmd ) ) {
if ( cmd[0] == '-' ) {
Execute( key, cmd.Substring( 1 ) );
}
}
}
#else
bool result = false;
string cmd;
if ( GetCmd( keyDown, context, out cmd ) ) {
if ( cmd[0] != '-' && cmd[0] != '+' ) {
if ( Execute( keyDown, cmd ) ) result = true;
}
}
if ( GetCmd( keyHold, context, out cmd ) ) {
if ( cmd[0] == '+' ) {
if ( Execute( keyHold, cmd.Substring( 1 ) ) ) result = true;
}
}
if ( GetCmd( keyUp, context, out cmd ) ) {
if ( cmd[0] == '-' ) {
if ( Execute( keyUp, cmd.Substring( 1 ) ) ) result = true;
}
}
return result;
#endif
}
}
#endif
} namespace QON {
using System;
using System.Text;
using System.Collections.Generic;
public static class Qonche {
const int QON_MAX_CMD = 512;
const int QON_MAX_PAGER = 256 * 1024;
const int QON_MAX_PAGER_MASK = QON_MAX_PAGER - 1;
const string QON_PROMPT = "] ";
const string QON_TRAILING_SPACE = " ";
// how many lines to scan up offscreen for line breaks
const int QON_MAX_OFFSCREEN_LOOKUP = 256;
static int qon_prevPage = QON_MAX_PAGER;
static int qon_nextPage = QON_MAX_PAGER;
static int qon_currPage = QON_MAX_PAGER;
static int qon_pagerHead = QON_MAX_PAGER;
static byte [] qon_pager = new byte [QON_MAX_PAGER];
static Action<int,int> [] qon_pagerActions = new Action<int,int>[QON_MAX_PAGER];
static int qon_cursor = QON_PROMPT.Length;
static byte [] qon_cmdBuf = new byte[QON_MAX_CMD];
static Qonche() {
byte [] ba = Encoding.UTF8.GetBytes( QON_PROMPT + QON_TRAILING_SPACE );
Array.Copy( ba, qon_cmdBuf, ba.Length );
}
static int QON_Min( int a, int b ) {
return a < b ? a : b;
}
static int QON_Max( int a, int b ) {
return a > b ? a : b;
}
static int QON_Len( byte [] p ) {
int n;
for ( n = 0; p[n] != 0; n++ ) {}
return n;
}
static byte [] GetZT( string str ) {
List<byte> bytes = new List<byte>( Encoding.UTF8.GetBytes( str ) );
bytes.Add( 0 );
return bytes.ToArray();
}
static void QON_Dummy( int x, int y ) {}
static int QON_Printn( byte [] str, int n ) {
#if false // no callbacks buffer and stuff
return QON_PrintClamp( str, n );
#else
return QON_PrintAndActClamp( str, n, QON_Dummy );
#endif
}
static int QON_PrintClamp( byte [] str, int n ) {
int i;
for ( i = 0; i < n && str[i] != 0; i++, qon_pagerHead++ ) {
qon_pager[qon_pagerHead & QON_MAX_PAGER_MASK] = str[i];
}
qon_pager[qon_pagerHead & QON_MAX_PAGER_MASK] = 0;
qon_currPage = qon_pagerHead;
return i;
}
static int QON_GetPagerChar( int i ) {
return qon_pagerHead - i >= QON_MAX_PAGER ? 0 : qon_pager[i & QON_MAX_PAGER_MASK];
}
static bool QON_IsLineInc( int idx, int x, int conWidth, int c ) {
// handle the case where the last character in the buffer is not a new line
return ( idx == qon_pagerHead - 1 && c != '\n' )
|| x == conWidth - 1
|| c == 0
|| c == '\n';
}
static int QON_PrintAndActClamp( byte [] str, int n, Action<int,int> act ) {
// replace callbacks in the pager string
qon_pagerActions[qon_pagerHead & QON_MAX_PAGER_MASK] = act;
// FIXME: no action on empty strings?
for ( int i = 1; i < n && str[i] != 0; i++ ) {
int idx = qon_pagerHead + i;
qon_pagerActions[idx & QON_MAX_PAGER_MASK] = QON_Dummy;
}
// actual printing to pager
return QON_PrintClamp( str, n );
}
static byte [] QON_GetCommandBuf( out int cmdBufLen ) {
// skip the trailing space
cmdBufLen = QON_Len( qon_cmdBuf ) - 1;
int n = cmdBufLen - QON_PROMPT.Length;
byte [] outBuf = new byte[n];
for ( int i = 0; i < n; i++ ) {
outBuf[i] = qon_cmdBuf[QON_PROMPT.Length + i];
}
return outBuf;
}
// == Public API ==
public static Action<int,int,int,bool,object> QON_DrawChar = (c, x, y, isCursor, obj) => {};
public static void QON_MoveRight( int numChars ) {
int max = QON_Len( qon_cmdBuf ) - 1 - qon_cursor;
numChars = QON_Min( numChars, max );
qon_cursor += numChars;
}
public static void QON_MoveLeft( int numChars ) {
int max = qon_cursor - QON_PROMPT.Length;
numChars = QON_Min( numChars, max );
qon_cursor -= numChars;
}
public static void QON_Delete( int numChars ) {
int bufLen = QON_Len( qon_cmdBuf );
// keep the trailing space
int max = ( bufLen - 1 ) - qon_cursor;
int shift = QON_Min( numChars, max );
if ( shift > 0 ) {
int n = bufLen - shift;
for ( int i = qon_cursor; i < n; i++ ) {
qon_cmdBuf[i] = qon_cmdBuf[i + shift];
}
Array.Clear( qon_cmdBuf, n, shift );
}
}
public static void QON_Backspace( int numChars ) {
// always keep the prompt
int max = qon_cursor - QON_PROMPT.Length;
int shift = QON_Min( numChars, max );
if ( shift > 0 ) {
int bufLen = QON_Len( qon_cmdBuf );
for ( int i = qon_cursor; i < bufLen; i++ ) {
qon_cmdBuf[i - shift] = qon_cmdBuf[i];
}
Array.Clear( qon_cmdBuf, bufLen - shift, shift );
qon_cursor -= shift;
}
}
public static void QON_InsertCommand( string str ) {
if ( string.IsNullOrEmpty( str ) ) {
return;
}
byte [] strBytes = GetZT( str );
int bufLen = QON_Len( qon_cmdBuf );
// always leave a trailing space along with the term zero
int max = ( QON_MAX_CMD - 2 ) - bufLen;
int shift = QON_Min( QON_Len( strBytes ), max );
if ( shift > 0 ) {
for ( int i = bufLen - 1; i >= qon_cursor; i-- ) {
qon_cmdBuf[i + shift] = qon_cmdBuf[i];
}
for ( int i = 0; i < shift; i++ ) {
qon_cmdBuf[qon_cursor + i] = strBytes[i];
}
// deletion always fills zeros, no need to zero terminate here
qon_cursor += shift;
}
// cancel the page-up if started typing
qon_currPage = qon_pagerHead;
}
static byte [] qon_putcBuf = new byte[2];
public static void QON_Putc( int c ) {
qon_putcBuf[0] = ( byte )c;
QON_Printn( qon_putcBuf, 1 );
}
public static int QON_Print( string str ) {
return QON_Printn( GetZT( str ), QON_MAX_PAGER );
}
public static int QON_PrintAndAct( string str, Action<int,int> act ) {
return QON_PrintAndActClamp( GetZT( str ), QON_MAX_PAGER, act );
}
public static void QON_EraseCommand() {
QON_MoveLeft( QON_MAX_CMD );
QON_Delete( QON_MAX_CMD );
}
public static void QON_SetCommand( string str ) {
QON_EraseCommand();
QON_InsertCommand( str );
}
public static string QON_GetCommand() {
int cmdBufLen;
byte [] outBuf = QON_GetCommandBuf( out cmdBufLen );
return System.Text.Encoding.UTF8.GetString( outBuf, 0, outBuf.Length );
}
public static void QON_GetCommandEx( out string cmdClean, out string cmdRaw ) {
int cmdBufLen;
byte [] outBuf = QON_GetCommandBuf( out cmdBufLen );
cmdClean = System.Text.Encoding.UTF8.GetString( outBuf, 0, outBuf.Length );
cmdRaw = System.Text.Encoding.UTF8.GetString( qon_cmdBuf, 0, cmdBufLen );
}
public static string QON_EmitCommand() {
string cmdClean, cmdRaw;
QON_GetCommandEx( out cmdClean, out cmdRaw );
QON_Print( cmdRaw + "\n" );
QON_EraseCommand();
return cmdClean;
}
public static void QON_PageUp() {
qon_currPage = qon_prevPage;
}
public static void QON_PageDown() {
qon_currPage = qon_nextPage;
}
public static void QON_DrawEx( int conWidth, int conHeight, bool skipCommandLine,
object drawCharParam ) {
int numCmdLines = 0;
// == command field ==
// don't show the prompt if paged up from the head
if ( qon_currPage == qon_pagerHead && ! skipCommandLine ) {
// ignore the trailing space when counting lines
int cmdLen = QON_Len( qon_cmdBuf ) - 1;
// command may take more than one screen of lines, clamp it to screen
// always atleast one line
numCmdLines = QON_Min( conHeight, cmdLen / conWidth + 1 );
// cursor is always inside the window
int numLinesToCursor = qon_cursor / conWidth + 1;
int start = QON_Max( numLinesToCursor - conHeight, 0 ) * conWidth;
int numChars = QON_Min( conHeight * conWidth, QON_MAX_CMD - start );
int cmdCaret = ( conHeight - numCmdLines ) * conWidth;
int caretCursor = cmdCaret + qon_cursor - start;
for ( int i = 0; i < numChars; i++, cmdCaret++ ) {
int c = qon_cmdBuf[i + start];
//Debug.Log( c );
if ( c == 0 ) {
break;
}
int x = cmdCaret % conWidth;
int y = cmdCaret / conWidth;
QON_DrawChar( c, x, y, cmdCaret == caretCursor, drawCharParam );
}
}
// out of lines for the pager
if ( numCmdLines >= conHeight ) {
return;
}
// == pager ==
{
int maxY = conHeight - numCmdLines;
int start = QON_Min( qon_pagerHead, qon_currPage ) - 1;
int x = 0;
int y = maxY;
// go up the pager to the nearest offscreen new line character
while ( true ) {
int c = QON_GetPagerChar( start );
if ( y < -QON_MAX_OFFSCREEN_LOOKUP && ( c == 0 || c == '\n' ) ) {
x = 0;
break;
}
if ( QON_IsLineInc( start, x, conWidth, c ) ) {
x = 0;
y--;
} else {
x++;
}
start--;
}
qon_prevPage = qon_currPage;
int i;
for ( i = start + 1; y < 2 * maxY - 1; i++ ) {
int c = QON_GetPagerChar( i );
if ( c != 0 ) {
qon_pagerActions[i & QON_MAX_PAGER_MASK]( x, y );
}
if ( y >= 0 && y < maxY ) {
// previous page ends with the first line of the current one
// don't bother going above any zeros/out of buffer
if ( y == 1 && c != 0 ) {
qon_prevPage = i;
}
if ( c == 0 ) {
QON_DrawChar( 0, 0, y, false, drawCharParam );
} else if ( c == '\n' ) {
// TODO: debug draw the new lines
} else {
QON_DrawChar( c, x, y, false, drawCharParam );
}
}
if ( QON_IsLineInc( i, x, conWidth, c ) ) {
x = 0;
y++;
} else {
x++;
}
}
// will eventually overflow
qon_nextPage = QON_Min( qon_pagerHead, i );
}
}
public static void QON_Draw( int conWidth, int conHeight ) {
QON_DrawEx( conWidth, conHeight, false, 0 );
}
}
} namespace QON {
#if UNITY_2021_1_OR_NEWER
//#define HAS_UNITY
#endif
#if HAS_UNITY
using UnityEngine;
#endif
// This file contains the nokia-cellphone font baked in a bitmap, along with the character coordinates inside the bitmap.
// The ttf could be found here: https://www.dafont.com/nokia-cellphone.font
static class NokiaFont {
public const int NOKIA_LN_H = 10;
public const int NOKIA_LN_BASE = 8;
public const int NOKIA_IMG_W = 128;
public const int NOKIA_IMG_H = 64;
public struct Glyph {public int x, y, width, height, xoffset, yoffset, xadvance;}
public static readonly Glyph [] glyphs = new Glyph[256];
static NokiaFont() {
glyphs[32 ] = new Glyph{x=9 , y=17, width=1, height=1, xoffset=0, yoffset=0, xadvance=3,};
glyphs[33 ] = new Glyph{x=67 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[34 ] = new Glyph{x=0 , y=57, width=3, height=2, xoffset=0, yoffset=1, xadvance=4,};
glyphs[35 ] = new Glyph{x=6 , y=19, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[36 ] = new Glyph{x=15 , y=0 , width=5, height=8, xoffset=0, yoffset=1, xadvance=6,};
glyphs[37 ] = new Glyph{x=102, y=0 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[38 ] = new Glyph{x=98 , y=8 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[39 ] = new Glyph{x=126, y=19, width=1, height=2, xoffset=0, yoffset=1, xadvance=2,};
glyphs[40 ] = new Glyph{x=52 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[41 ] = new Glyph{x=56 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[42 ] = new Glyph{x=18 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[43 ] = new Glyph{x=25 , y=49, width=5, height=5, xoffset=0, yoffset=2, xadvance=6,};
glyphs[44 ] = new Glyph{x=116, y=47, width=2, height=3, xoffset=0, yoffset=6, xadvance=3,};
glyphs[45 ] = new Glyph{x=2 , y=9 , width=4, height=1, xoffset=0, yoffset=4, xadvance=5,};
glyphs[46 ] = new Glyph{x=125, y=46, width=2, height=2, xoffset=0, yoffset=6, xadvance=3,};
glyphs[47 ] = new Glyph{x=124, y=8 , width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[48 ] = new Glyph{x=54 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[49 ] = new Glyph{x=24 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[50 ] = new Glyph{x=66 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[51 ] = new Glyph{x=72 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[52 ] = new Glyph{x=112, y=8 , width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[53 ] = new Glyph{x=78 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[54 ] = new Glyph{x=84 , y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[55 ] = new Glyph{x=90 , y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[56 ] = new Glyph{x=96 , y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[57 ] = new Glyph{x=102, y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[58 ] = new Glyph{x=100, y=47, width=2, height=5, xoffset=0, yoffset=3, xadvance=3,};
glyphs[59 ] = new Glyph{x=121, y=40, width=2, height=6, xoffset=0, yoffset=3, xadvance=3,};
glyphs[60 ] = new Glyph{x=0 , y=43, width=4, height=7, xoffset=0, yoffset=1, xadvance=5,};
glyphs[61 ] = new Glyph{x=103, y=47, width=4, height=3, xoffset=0, yoffset=4, xadvance=5,};
glyphs[62 ] = new Glyph{x=10 , y=43, width=4, height=7, xoffset=0, yoffset=1, xadvance=5,};
glyphs[63 ] = new Glyph{x=12 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[64 ] = new Glyph{x=63 , y=9 , width=6, height=7, xoffset=0, yoffset=2, xadvance=7,};
glyphs[65 ] = new Glyph{x=18 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[66 ] = new Glyph{x=24 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[67 ] = new Glyph{x=30 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[68 ] = new Glyph{x=36 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[69 ] = new Glyph{x=42 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[70 ] = new Glyph{x=48 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[71 ] = new Glyph{x=54 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[72 ] = new Glyph{x=0 , y=35, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[73 ] = new Glyph{x=70 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[74 ] = new Glyph{x=15 , y=41, width=4, height=7, xoffset=0, yoffset=1, xadvance=5,};
glyphs[75 ] = new Glyph{x=91 , y=8 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[76 ] = new Glyph{x=5 , y=43, width=4, height=7, xoffset=0, yoffset=1, xadvance=5,};
glyphs[77 ] = new Glyph{x=86 , y=0 , width=7, height=7, xoffset=0, yoffset=1, xadvance=8,};
glyphs[78 ] = new Glyph{x=77 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[79 ] = new Glyph{x=35 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[80 ] = new Glyph{x=78 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[81 ] = new Glyph{x=2 , y=0 , width=6, height=8, xoffset=0, yoffset=1, xadvance=7,};
glyphs[82 ] = new Glyph{x=84 , y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[83 ] = new Glyph{x=123, y=0 , width=4, height=7, xoffset=0, yoffset=1, xadvance=5,};
glyphs[84 ] = new Glyph{x=21 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[85 ] = new Glyph{x=90 , y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[86 ] = new Glyph{x=109, y=0 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[87 ] = new Glyph{x=78 , y=0 , width=7, height=7, xoffset=0, yoffset=1, xadvance=8,};
glyphs[88 ] = new Glyph{x=0 , y=11, width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[89 ] = new Glyph{x=7 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[90 ] = new Glyph{x=96 , y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[91 ] = new Glyph{x=60 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[92 ] = new Glyph{x=28 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[93 ] = new Glyph{x=64 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[94 ] = new Glyph{x=112, y=47, width=3, height=3, xoffset=0, yoffset=1, xadvance=4,};
glyphs[95 ] = new Glyph{x=7 , y=57, width=5, height=1, xoffset=0, yoffset=7, xadvance=6,};
glyphs[96 ] = new Glyph{x=4 , y=57, width=2, height=2, xoffset=0, yoffset=1, xadvance=3,};
glyphs[97 ] = new Glyph{x=73 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[98 ] = new Glyph{x=102, y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[99 ] = new Glyph{x=90 , y=47, width=4, height=5, xoffset=0, yoffset=3, xadvance=5,};
glyphs[100] = new Glyph{x=108, y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[101] = new Glyph{x=55 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[102] = new Glyph{x=32 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[103] = new Glyph{x=86 , y=40, width=5, height=6, xoffset=0, yoffset=3, xadvance=6,};
glyphs[104] = new Glyph{x=114, y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[105] = new Glyph{x=61 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[106] = new Glyph{x=44 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[107] = new Glyph{x=120, y=24, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[108] = new Glyph{x=55 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[109] = new Glyph{x=0 , y=51, width=8, height=5, xoffset=0, yoffset=3, xadvance=9,};
glyphs[110] = new Glyph{x=43 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[111] = new Glyph{x=49 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[112] = new Glyph{x=110, y=40, width=5, height=6, xoffset=0, yoffset=3, xadvance=6,};
glyphs[113] = new Glyph{x=104, y=40, width=5, height=6, xoffset=0, yoffset=3, xadvance=6,};
glyphs[114] = new Glyph{x=85 , y=48, width=4, height=5, xoffset=0, yoffset=3, xadvance=5,};
glyphs[115] = new Glyph{x=95 , y=47, width=4, height=5, xoffset=0, yoffset=3, xadvance=5,};
glyphs[116] = new Glyph{x=20 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[117] = new Glyph{x=67 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[118] = new Glyph{x=61 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[119] = new Glyph{x=9 , y=51, width=7, height=5, xoffset=0, yoffset=3, xadvance=8,};
glyphs[120] = new Glyph{x=37 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[121] = new Glyph{x=92 , y=40, width=5, height=6, xoffset=0, yoffset=3, xadvance=6,};
glyphs[122] = new Glyph{x=31 , y=49, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[123] = new Glyph{x=68 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[124] = new Glyph{x=72 , y=0 , width=2, height=8, xoffset=0, yoffset=1, xadvance=3,};
glyphs[125] = new Glyph{x=48 , y=0 , width=3, height=8, xoffset=0, yoffset=1, xadvance=4,};
glyphs[126] = new Glyph{x=119, y=47, width=5, height=2, xoffset=0, yoffset=1, xadvance=6,};
glyphs[128] = new Glyph{x=79 , y=41, width=6, height=6, xoffset=0, yoffset=2, xadvance=7,};
glyphs[136] = new Glyph{x=108, y=47, width=3, height=3, xoffset=0, yoffset=1, xadvance=4,};
glyphs[146] = new Glyph{x=126, y=16, width=1, height=2, xoffset=0, yoffset=1, xadvance=2,};
glyphs[154] = new Glyph{x=0 , y=0 , width=1, height=1, xoffset=0, yoffset=0, xadvance=4,};
glyphs[159] = new Glyph{x=14 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[160] = new Glyph{x=7 , y=17, width=1, height=1, xoffset=0, yoffset=0, xadvance=3,};
glyphs[161] = new Glyph{x=64 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[163] = new Glyph{x=6 , y=35, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[164] = new Glyph{x=98 , y=40, width=5, height=6, xoffset=0, yoffset=2, xadvance=6,};
glyphs[165] = new Glyph{x=105, y=8 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[166] = new Glyph{x=75 , y=0 , width=2, height=8, xoffset=0, yoffset=1, xadvance=3,};
glyphs[167] = new Glyph{x=39 , y=0 , width=4, height=8, xoffset=0, yoffset=1, xadvance=5,};
glyphs[186] = new Glyph{x=124, y=40, width=3, height=5, xoffset=0, yoffset=1, xadvance=4,};
glyphs[191] = new Glyph{x=12 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[192] = new Glyph{x=18 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[193] = new Glyph{x=24 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[194] = new Glyph{x=30 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[195] = new Glyph{x=36 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[196] = new Glyph{x=42 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[197] = new Glyph{x=48 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[198] = new Glyph{x=94 , y=0 , width=7, height=7, xoffset=0, yoffset=1, xadvance=8,};
glyphs[199] = new Glyph{x=9 , y=0 , width=5, height=8, xoffset=0, yoffset=1, xadvance=6,};
glyphs[200] = new Glyph{x=54 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[201] = new Glyph{x=60 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[202] = new Glyph{x=66 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[203] = new Glyph{x=72 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[204] = new Glyph{x=73 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[205] = new Glyph{x=76 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[206] = new Glyph{x=36 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[207] = new Glyph{x=40 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[209] = new Glyph{x=78 , y=33, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[210] = new Glyph{x=116, y=0 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[211] = new Glyph{x=84 , y=8 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[212] = new Glyph{x=70 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[213] = new Glyph{x=56 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[214] = new Glyph{x=49 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[216] = new Glyph{x=42 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[217] = new Glyph{x=84 , y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[218] = new Glyph{x=90 , y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[219] = new Glyph{x=96 , y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[220] = new Glyph{x=102, y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[221] = new Glyph{x=28 , y=9 , width=6, height=7, xoffset=0, yoffset=1, xadvance=7,};
glyphs[223] = new Glyph{x=21 , y=0 , width=5, height=8, xoffset=0, yoffset=1, xadvance=6,};
glyphs[224] = new Glyph{x=108, y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[225] = new Glyph{x=114, y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[226] = new Glyph{x=120, y=32, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[227] = new Glyph{x=118, y=8 , width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[228] = new Glyph{x=0 , y=19, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[229] = new Glyph{x=12 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[230] = new Glyph{x=17 , y=49, width=7, height=5, xoffset=0, yoffset=3, xadvance=8,};
glyphs[231] = new Glyph{x=116, y=40, width=4, height=6, xoffset=0, yoffset=3, xadvance=5,};
glyphs[232] = new Glyph{x=72 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[233] = new Glyph{x=24 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[234] = new Glyph{x=30 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[235] = new Glyph{x=36 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[236] = new Glyph{x=58 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[237] = new Glyph{x=52 , y=41, width=2, height=7, xoffset=0, yoffset=1, xadvance=3,};
glyphs[238] = new Glyph{x=48 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[239] = new Glyph{x=44 , y=41, width=3, height=7, xoffset=0, yoffset=1, xadvance=4,};
glyphs[241] = new Glyph{x=42 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[242] = new Glyph{x=48 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[243] = new Glyph{x=60 , y=17, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[244] = new Glyph{x=108, y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[245] = new Glyph{x=114, y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[246] = new Glyph{x=120, y=16, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[248] = new Glyph{x=79 , y=48, width=5, height=5, xoffset=0, yoffset=3, xadvance=6,};
glyphs[249] = new Glyph{x=0 , y=27, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[250] = new Glyph{x=6 , y=27, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[251] = new Glyph{x=60 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[252] = new Glyph{x=66 , y=25, width=5, height=7, xoffset=0, yoffset=1, xadvance=6,};
glyphs[253] = new Glyph{x=33 , y=0 , width=5, height=8, xoffset=0, yoffset=1, xadvance=6,};
glyphs[255] = new Glyph{x=27 , y=0 , width=5, height=8, xoffset=0, yoffset=1, xadvance=6,};
}
// Image magick command to convert grayscale png to this:
// convert nokia_font_0.png -define h:format=gray -depth 8 -channel RGBA out_rgb.h
static readonly byte [] bitmap = new byte[NOKIA_IMG_W * NOKIA_IMG_H] {
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#if HAS_UNITY
static Texture2D _texture;
public static Texture2D GetTexture() {
if ( _texture ) {
return _texture;
}
_texture = new Texture2D( NOKIA_IMG_W, NOKIA_IMG_H, textureFormat: TextureFormat.RGBA32,
mipChain: false, linear: false );
_texture.filterMode = FilterMode.Point;
for ( int y = 0; y < NOKIA_IMG_H; y++ ) {
for ( int x = 0; x < NOKIA_IMG_W; x++ ) {
int alpha = bitmap[x + y * NOKIA_IMG_W];
Color32 c = new Color32( 0xff, 0xff, 0xff, ( byte )alpha );
//_texture.SetPixel( x, NOKIA_IMG_H - y - 1, c );
_texture.SetPixel( x, y, c );
}
}
_texture.Apply();
return _texture;
}
#endif
}
} namespace QON {
}
@zloedi
Copy link
Author

zloedi commented Oct 19, 2023

Features:

. Persistent history, browse previously issued commands (in previous app runs) using up/down arrows.
Tries to match previous commands by the string on the prompt.
. Persistent variables stored in config file in the app config directory.
. Versioned config files -- changing the config version resets all vars to defaults.
. Works in the Editor (Scene) window too, if the game is paused or not running, setup vars before running the game.
. No dependencies in the code that uses it, no need of attributes, code using it compiles without Qonsole.
. Can modify persistent console variables from within code.
. Doesn't need any Unity assets; drawn using GL calls and font bytes are part of the source code.
. Supports custom config files by command line param: [ff9000]--cfg=zloedi.cfg[-].
Custom config files don't get erased/reset on config version change (the defaults do).
. Separate configs in Build and inside Unity Editor: qon_default.cfg vs qon_default_ed.cfg
. Autocompletes partial commands, not only start-of-command.
. Supports multiple commands chained together; example:
[ff9000]] open_all_doors ; kill_all_enemies ; spawn_monster living Ally 9 12 ; spawn_monster cityguard 8 10 ; teleport player 6 6[-]
. Repeat commands by prepending a number i.e. [ff9000]] 3clear[-].
. Colorized output.
. Config file supports arbitrary commands.
. Variable descriptions stored as comments in the config file.
. Hook on different events (Start, Update, Done) by defining Qonsole commands with no dependencies.
and more...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment