{
    This file is part of Chentrah,
    Copyright (C) 2004-2008 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************}

const
  VersionMajor = 0;
  VersionMinor = 16;
  CgeStringEn = 'Chentrah';
  CgeStringRu = 'Чентра';
  CopyrightEn = '2004-2014, Anton Rzheshevski';
  CopyrightRu = '2004-2014, Антон Ржешевский';
  CopyrightLibsRu =
    'библиотеку Vampyre Imaging, © 2007-2014 Marek Mauder,';
  CopyrightLibsEn =
    'Vampyre Imaging Library, © 2007-2014 Marek Mauder';
//  SplashScreenNumVariants = 11;
//  SplashScreenPath = 'modules/cge/splash/';
  MyAppNick = 'chentrah';
  MyAppName = 'chentrah';

  Type
    float = single;
    boolean = longbool;
    {$ifndef fpc}
      //delphi
      winbool = longbool;
      dword = cardinal;
    {$endif}

    TIntegerArray = array of integer;

 Const
  Yes=True;
  No=False;

  floaterror = 1e-5;
  
//  {$ifdef chepersy_align_4}
    AlignGranularity = 4;
    BasicUnitSize = 4;
(*  {$endif}
  {$ifdef chepersy_align_8}
    {$fatal 64-bit alignment support not implemented yet!}
    //AlignGranularity = 8;
    //BasicUnitSize = 4;
  {$endif}
*)

//for Cheb's Game Engine only:
{$ifdef cge}

{$include un_keys.h}

type
  //only add new ones at the end, to avoid breaking backward compatibility
  // with the existing modules. Never remove any.
  TOsType = (ostLinux, ostWine, ostDarwine, ostWinXP, ostWin2k, ostWin9x, ostVista, ostWin7, ostMacOsX, ostWin8, ostWin9);

const
  OsMinMem: array[TOSType] of integer = ( {if you have less physical RAM than this,
                                             Chentrah will refuse to run.}
              200,      200,      200,       450,      200,      200,     900,      450,       200,       450,    450);
  OsMinMemRep: array[TOSType] of integer = ( {as it is shown to the user}
              256,      256,      256,       512,      256,      256,     1024,     512,      256,        512,    512 );

  OsReqMem: array[TOSType] of integer = ( {if you have less physical RAM than this,
                                Chentrah will whine about not having enough memory.}
              450,      450,      450,       900,      450,      450,     1800,     900,      450,        900,    900 );
  OsReqMemRep: array[TOSType] of integer = ( {as it is shown to the user}
              512,      512,      512,      1024,      512,      512,     2048,     1024,      512,      1024,    1024 );


  OsName: array[TOsType] of string = (
    'Linux', 'Wine', 'Darwine', 'Windows XP', 'Windows 2000', 'Windows 98/Me', 'Windows Vista',  'Windows 7', 'MacOS X', 'Windows 8', 'Windows 9(?)');

  //If the current OS is not in this list, give a scary warning at startup:
  SupportedOSes: set of TOSType = [{ostLinux,} ostWine, ostWinXP, ostWin7];
  {
    After the outrage of Kde 4, Gnome 3 and Ubuntu 11.10 (where pen tablet still
    glitches making it not usable) I'm *very* tempted to just drop the native
    Linux support. Wine is enough.

    The lack of a sane universal API does that to you.
    Maybe later I'll rework the framework to QT, but as of 2012,
                                                        Linux is NOT supported.
  }

  //just setting a completely transparent cursor is not enough,
  // we need to actually employ ShowCursor(False);
  OSNeedsMousePointerHack: set of TOSType = [ostVista, ostWin7, ostWin8, ostWin9];
  
  WindowsEmulators: set of TOSType = [ostWine, ostDarwine];

  WindowsShouldHaveBuiltInOpenAL: set of TOSType = [];
                         //WTF, they don't? Microsoft lied.  ostVista, ostWin7];

  UnableToDisplayRussianTextInDialogs: set of TOSType =
                                     [ostLinux, ostWine, ostDarwine, ostMacOsX];
  //I mean MessageBoxA and xmessage here. The eternal character set problem.

  CGM_PRESS = 1; //(scancode, mx, my)
  CGM_RELEASE = 2; //(scancode, mx, my)
  CGM_MOUSEMOVE = 3; //(mx, my)
  CGM_TYPE = 4; //(char, mx, my)
  CGM_PEN = 5; //x, y, pressure (all floats), reserved1, reserved2, reserved3
  CGM_JOYSTICK = 6; //type (integer), x, y, dx, dy (floats). x & y are ranged -1.0..1.0 (or 0.0..1.0 depending on the type), dx & dy measured in 1/second

  { Quality Factor is a global setting controlling the load balance
      100 is considered "average", with FBO size equaling the viewport size.

      The alghorithms controlling it consider mostly the averaged SwapBuffers
      duration, but also events of large textures being not resident as they are
      bound, and so on.
  }
  QF_MIN = 10;
  QF_MAX = 2999;

  FPS_CULL_DEFAULT = 30; //also, values of MotherState.CullFrameRate below this are ignored


type

  TModuleState = (ms_NotInitialized, ms_Loading, ms_Unloading, ms_Exiting, ms_Loaded, ms_Crashed, ms_WaitingForThreadsToTerminate, ms_DoNothing);

  //displays them bottom to top in this order.
  TFpsCounterParam = (fcp_QualityFactor, fcp_FramesPerSecond, fcp_RdtscFrequency, fcp_SwapBuffersTime);
  TFpsCounterParams = set of TFpsCounterParam;

  TJoystickType = (JoytypePrimary, JoytypeRightThumb, JoytypeLeftTrigger, JoytypeRightTrigger);
  PInputEvent = ^TInputEvent;
  TInputEvent = packed record
    case EventType: dword of
    0: (
      Stub: array[1..9] of dword;
    );
    CGM_PRESS {also CGM_RELEASE and CGM_MOUSEMOVE} : (
      key: TKey;
      mx, my: float; //formerly integer. Must allow for subpixel precision if necessary.
    );
    CGM_TYPE: (
       character: WideChar; //also mx and my from the previous part. Must not overlap.
    );
    CGM_PEN: (
      PenX, PenY, PenPressure, PenReserved1, PenReserved2, PenReserved3: float;
    );
    CGM_JOYSTICK: (
      JoyType: TJoystickType;
      JoyX, JoyY, JoydX, JoydY: float;
    );
  end;

  TOglQuirks = (glqScissorFailed); //only add new ones at the end! Is saved as a raw  hex value
  TOglQuirksSet = set of TOglQuirks;

  PMotherState = ^TMotherState;
  TMotherState = packed record {an absolutely unsystematic heap of interface
     variables: you can only add new ones at the end, to avoid breaking the
     backward compatibility!}
    dwSize: dword;
    ExportHostProc: procedure (i: integer; var p: pointer); cdecl;
    OS: TOSType;
    PhysMemory, //in megabytes. Note: it often reports not all of it, e.g. 1010 when you have 1024
    CPUCount: integer; //uses heuristics to guesstimate a real core count instead of cores*hyperthreading multiplier
    IsRussian, //if the currently selected language is Russian.
    VerboseLog,
    NowDying,
    DebugMode, //wtf is this if "debug mode" in the config really means VerboseLog ?
    DeveloperMode,
    InFullScreenMode,
    WindowExists,
    WindowVisible,
    TextInput: boolean;
    DisplayWidth,
    DisplayHeight: integer; //gets updated every frame in the windowed mode
    ModuleFileName,
    ModulePureName, //oops. Must NOT be used in cl_module for internal workings
    HomePath,
    InstallPath,
    CacheDir,
    SessionDir:
      {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif}; //System 8-bit code page. Important!
    FPS,
    QF: single;
    SSE2Available: boolean;
    MouseIsBeyondOurWindow,
    UseHardware1bitCursor: boolean; //is set automatically each frame if fps is below certain limit
    FadeIn: float; //for menu/startup transition effects
    DriveZIsRoot: boolean; //in wine and darwine. It means "filesystem root" aka "/".
                           //This is used by Windows executable to determine Linux version
                           //  when running in Wine (by parsing the file Z:\etc\issue )
    ModuleState: TModuleState;
    DyingAfterTrueException: boolean; {if the exception handling chain was set off
            by a real exception like an AV and not by a controlled call to Die() }
    DebugInfoPath:
      {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif};
    StartupDateTime: TDateTime;
    RdtscFrequency, //gets updated dynamically, a few times per second. Thus, it's somehow noisy.
    LastSwapBuffersDuration: double; //seconds
    FpsCounterParams: TFpsCounterParams;
    AverageSwapBuffersDuration: double;
    UserName,
   {$ifdef windows}
    CSIDL_AppDataDir,
   {$endif}
    StdHomepath,
    OstID: {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif}; //text representation of the OS enum value
    UserNameUCS16: {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    ProgramDirIsWriteable: boolean;
    RollBackTheSessionOnNextLoad: boolean;
    LegacyWindowslacksFunctions: boolean; //there is no SHGetFolderPathA in the vanilla Windows 98. Needs a workaround.
    ExePath: {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif};
    ProgramInitialized: boolean;
    ModuleNameW: {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    CallStackLogged: boolean;
   {$ifdef windows}
    Win98LacksUnicodeSupport: boolean;
   {$endif}
    ModuleRequestToChooseModule: boolean;
    RestartRequested: boolean;
    QF_ManualOverride: boolean;
    FixedFontQuality: integer; //read-only, autoregulated! 0 = hq font, 1 = built-in lq font
    FixedFontEmergencyDownsample: boolean;
    BlackoutStart: TDateTime; //fade to black is instaneous, then fade in for about one second.
    LogoAnimationPlaying: boolean;
    LogoAnimationStart: TDateTime;
    SuddenShutdownReason: // this one is filled in the call to LogGoDownXX().
      {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    CpuName: {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif};
    SoundBufferAhead: longint; //in samples (44100/second).
   {$ifndef buildmein}
    //not needed (?) in Linux, keeping it for compatibility sake.
    sehh_ExceptionCode, //true exception codes in Windows, custom codes in Linux (see cl_seh_hack.inc)
    sehh_ExceptionAddress: dword;
   {$endif}
    NeedToKeepModuleResources: function (): boolean; cdecl;
    PenTabletPresent: boolean;
    PenTabletName,
    PenTabletAbsenceReason: {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    WindowOriginX, //TODO: add support for Linux! Currently it's always zero.
    WindowOriginY,
    ScreenWidth, //again, gets updated each frame in both in Linux and Windows, via system call.
    ScreenHeight: integer;
    FontsHash: TMd5Digest;
    OSName: {$ifdef cgekernel} WideString {$else} PWideChar {$endif}; //
    PenActivityDetected: boolean;
    PenTabletPressureResolution: integer;
    FloatToFixedAssignmentsDisabled: boolean;//if an attempt made to assign a floating-point
    // value to a fixed-point variable, assertion exception happens. This is to avoid leaking
    // non-deterministic data into deterministic data
    ModuleRequiresOpenGL2: boolean; //this is set according the parameter in the corresponding .module file.
      //The module itself checks this value and when false it just skips loading
      //all OGL2-related functions so corresponding procedure variables stay NIL.
    OGLVersionHi,
    OGLVersionMed: integer;
    OGLVersionString,
    OGLRenderer,
    OGLVendor,
    OGLSummary:  {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    IsPortable: boolean; //this is a "portable" version of the program (see the main *.ini file)
    CullFrameRate: integer; {
      This field gets set to 30 before each call to the module pulse function
        (or to 60 if a mouse movement event was received).
      Unless the module sets it back to a higher value, there will be Sleep() called
        by the mother module after return from the module pulse function, to cull
        frame rate at the value determined here. (implemented in cl_window)
      This way only performance 3d rendering modules would hog all the video card & cpu
        resources, and only when they specifically request it.
      Setting it higher than 300 disables culling.
    }
    GamepadPresent: boolean;
    GamepadName,
    GamepadAbsenceReason: {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    GamepadRumble: array[0..3] of float; {
      This array is usually filled by the module. It is monitored by the gamepad polling thread.
      0 - left (low-frequency) vibrator amplitude (0.0..1.0)
      1 - left vibrator activity duration, seconds
      2 - right (high-frequency) vibrator amplitude
      3 - right vibrator activity duration
      The gamepad polling thread has its own duration counters that are reset by changes
        in the requested amplitudes (array entries 0 and 2). Durations cannot exceed
        limit set by the GAMEPAD_RUMBLE_DURATION_LIMIT constant (default 5.0 seconds)
      Setting the same amplitude won't reset the internal counters, so the vibrators will stop if there's no change.
    }
    Criticalsection: TRTLCriticalSection;
    InputEvents: {$ifdef cgekernel} array of TInputEvent {$else} PInputEvent {$endif};
    CPUTSCInvariance: boolean; { if the Time Stamp Counter runs on a fixed frequency,
      independed of the real currlen CPU clock frequency. See more in Intel or AMD manuals for CPUID 80000007h
      Note: you need to find a *really* rare CPU for this to matter. Most
      older ones either don't support clock scaling, or do support this feature.
    }
    CPUL2CacheSize: integer; //in kilobytes. May be 0, meaning "unknown"
                             //This is a *guesstimated* value: if it is < 512 on Intel processors,
                             //then cpu count gets divided by 2 while this value gets multiplied by 2.
    CPUL2CacheLineSize: integer; //in bytes. May be 0.
    ExeHandle: {$ifdef windows} THandle {$else} pointer {$endif}; //is filled by InitSehHack() in cl_seh_hack.pp
    ProcessID: SizeUint; //pid for linux
    StateTrashedRestartRequired: boolean; //is set to signal that any attempt to load a module should cause program restart
    ModuleHasThreadsRunning: boolean; {it's the module's responsibility to set and clear it.
      if true, then ms_Unloading leads to ms_WaitingForThreadsToTerminate instead of ms_Loading }
    WaitingForModuleThreadsToTerminateTimeoutMoment: TDateTime; //to manage timeout and force restart on waiting for too long.
    MainThreadId: TThreadId; //is filled by InitSehHack()
    ModuleThreadStackSize: PtrUInt; //Is filled by the mother module at module loading, according its INI file
    Terminated: boolean; //To curb broblems with various hacks that keep executing even after the call to TerminateProcess() (W.T.F.?)
    ExitRequested: boolean; //is used to initiate program shutdown

    {
      Xbox 360 game controller's right thumb emulating mouse
      There's no dead zone. Around the center position, thumb movement
      maps linearly to cursor movement. Further away, acceleration gets added.}
    GCToMouseSpeedMultiplier, //pixels per second for maximum position, clipped to 100..3000
    GCToMouseAccelThreshold, //percent of the maximum position, clipped to 10..90
    GCToMouseAccelMultiplier //in pixels per second^2 for maximum, clipped to 0..3000 (when thumb is pushed to the edge)
      : longint;

    OGLExtensions: {$ifdef cgekernel} WideString {$else} PWideChar {$endif};
    OGLNpotSupported: boolean; //I have some real museum pieces that do not support NPOT textures. I love testing Chentrah on them :)
    OGLTextureMax,
    OGL3dTextureMax,
    OGLFboMax: ptrint;
    RunSessionHash: packed array[0..15] of byte; {some module resources (e.g.
       FBOs and textures) shpuld not be kept between different program runs.}

    SuspendSwbMeasurement: boolean; { Must suspend measurement
      during operations like creating FBOs to avaoid a feedback loop}
    OGLMaxTextureCoords,
    OGLMaxTextureUnits : ptrint;
    Fatality: boolean; {if set, the following Die bubbling up from the module
      causes to write the error  details to a file, restart self and display
      a dialog box}
    BatteryRemaining: integer; //Windows only. 0..100 or 255 when on AC/unknown
    WindowHasFocus: boolean;
    OGLQuirks: {$ifdef cgekernel} dword {$else} TOglQuirksSet {$endif}; //
    RendererAlias: {$ifdef cgekernel} AnsiString {$else} PAnsiChar {$endif};//suitable for using in file names and INI section names
    OGLMaxAnisotropy: float;
  end;


const
  
  {$ifdef cgekernel}
   {$typeinfo off}
  {$endif}

 {$ifdef fpc}
  CompileDate = {$I %DATE%};
  CompileTime = {$I %TIME%};
  CompilerVersion = 'Free Pascal ' + {$I %FPCVERSION%};
  CompileTarget = {$I %FPCTARGETOS%}+'-'+{$I %FPCTARGETCPU%};
 {$else}
  {$fatal Chentrah source code is no longer compatible with Delphi!}
  <<<<<
  CompileDate = 'n/a';
  CompileTime = 'n/a';
  CompilerVersion = 'Delphi';
  CompileTarget = 'n/a';
 {$endif}

 {$ifdef unix}
  {$ifdef darwin}
   {$fatal Chentrah is not ported to MacOS X yet!}
   DS = '/';
   PathSlash = '/';
   SystemSuffix = 'macosx';
   DllExtension = '.dylib';
   DllPrefix = 'lib';
  {$else}
   {fatal Linux support is temporarily dropped as of Jan 2012!}
   DS = '/';
   PathSlash = '/';
   SystemSuffix = 'linux';
   DllExtension = '.so';
   DllPrefix = 'lib';
  {$endif}
 {$else}
  DS = '\';
  PathSlash = '\';
  SystemSuffix = 'win32';
  DllExtension = '.dll';
  DllPrefix = '';
 {$endif}



  Slash = PathSlash;

  type
    TCbMessage = (Re_OnDestroy, Re_OnCycle, Re_OnUnload, //the module knows only these three
                         Re_OnGetFocus, Re_OnLoseFocus, Re_Stub);

  type
    PMd5Digest = ^TMd5Digest;
    PResourceHash = ^TResourceHash;
    TResourceHash = packed record
      case integer of
        0: (
          Stamp: QWord;
          DateTime: TDateTime);
        1: (
          Md5Hash: TMD5Digest);
    end;
    PRes = ^TRes;
    TRes = packed record
      Hash: TResourceHash;
      Handle,
      owner,
      kind //required for deleting the lost resources,
           // to know a vertex buffer from a vampyre image record
        : DWORD;
      Unclaimed: longbool;
    end;
    
    PStringFitRec = ^TStringFitRec;
    TStringFitRec = record
      face,
      ActualWidth,
      ActualHeight: integer;
      zoomX,
      zoomY: float;
    end;
    

  {$ifdef fpc}
    //it is assumed that Delphi supports only win32 on i386
    {$ifndef ENDIAN_LITTLE}
      {$fatal POWERPC ARCHITECTURE NOT SUPPORTED DUE TO THE BINARY FORMAT INCOMPATIBILITIES}
    {$endif}

    {$ifndef CPU32}
      { fatal ONLY 32-BIT PLATFORMS ARE SUPPORTED YET!}
    {$endif}
  {$endif}

  Const
    SecondsPerDay = 86424.0;
{$endif}


