|
| 1 | +# SDL3 Code Style Sheet (C to Pascal) |
| 2 | + |
| 3 | +This guide helps to quickly translate often found C constructs in the |
| 4 | +SDL3 package into Pascal according to our Code style guidelines. Its |
| 5 | +goal is to have consistent code over all files in the conversion |
| 6 | +project. |
| 7 | + |
| 8 | +## General Rules |
| 9 | + |
| 10 | +1. Names of C defines (constants) and function parameters shall not be modified or "pascalified" |
| 11 | +Ex: `SDL_INIT_VIDEO` does not change into `SDLInitVideo`. |
| 12 | + |
| 13 | +2. Names corresponding to reserved key words are kept and an underscore is added. |
| 14 | +Ex.: `type` in C function `SDL_HasEvent(Uint32 type)` changes into `type_` |
| 15 | +in Pascal function `SDL_HasEvent(type_: TSDL_EventType)`. |
| 16 | + |
| 17 | +3. Use C data types like `cuint8`, `cuint16`, `cuint32`, `cint8`, `cint16`, |
| 18 | +`cint32`, `cfloat` and so on if native C data types are used in the |
| 19 | +original code. Note: For FPC you need to add the unit `ctypes` to use these C |
| 20 | +data types. For Delphi we have a temporary solution provided. |
| 21 | + |
| 22 | +**Example:** Use `cuint32` (if `Uint32` is used in |
| 23 | +the original code) instead of `UInt32`, `Cardinal`, `LongWord` or `DWord`. |
| 24 | +Exception: Replace `*char` by `PAnsiChar`. |
| 25 | + |
| 26 | +**Hint:** Use `TSDL_Bool` to translate `SDL_bool`. For macro functions use `Boolean`. |
| 27 | + |
| 28 | +4. If an identifier or a function declaration is gone, mark them as `deprecated`. |
| 29 | + |
| 30 | +5. For convenience we encourage to add single and double pointers for any SDL type. |
| 31 | + |
| 32 | +## Defines |
| 33 | + |
| 34 | +C: |
| 35 | + |
| 36 | +```c |
| 37 | +#define SDL_HAT_CENTERED 0x00 |
| 38 | +#define SDL_HAT_UP 0x01 |
| 39 | +#define SDL_HAT_RIGHT 0x02 |
| 40 | +#define SDL_HAT_DOWN 0x04 |
| 41 | +#define SDL_HAT_LEFT 0x08 |
| 42 | +#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT|SDL_HAT_UP) |
| 43 | +#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT|SDL_HAT_DOWN) |
| 44 | +#define SDL_HAT_LEFTUP (SDL_HAT_LEFT|SDL_HAT_UP) |
| 45 | +#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT|SDL_HAT_DOWN) |
| 46 | +``` |
| 47 | +
|
| 48 | +Pascal: |
| 49 | +
|
| 50 | +```pascal |
| 51 | +const |
| 52 | + SDL_HAT_CENTERED = $00; |
| 53 | + SDL_HAT_UP = $01; |
| 54 | + SDL_HAT_RIGHT = $02; |
| 55 | + SDL_HAT_DOWN = $04; |
| 56 | + SDL_HAT_LEFT = $08; |
| 57 | + SDL_HAT_RIGHTUP = SDL_HAT_RIGHT or SDL_HAT_UP; |
| 58 | + SDL_HAT_RIGHTDOWN = SDL_HAT_RIGHT or SDL_HAT_DOWN; |
| 59 | + SDL_HAT_LEFTUP = SDL_HAT_LEFT or SDL_HAT_UP; |
| 60 | + SDL_HAT_LEFTDOWN = SDL_HAT_LEFT or SDL_HAT_DOWN; |
| 61 | +``` |
| 62 | + |
| 63 | +## Enums |
| 64 | + |
| 65 | +C: |
| 66 | + |
| 67 | +```c |
| 68 | +typedef enum |
| 69 | +{ |
| 70 | + SDL_JOYSTICK_POWER_UNKNOWN = -1, |
| 71 | + SDL_JOYSTICK_POWER_EMPTY, /* <= 5% */ |
| 72 | + SDL_JOYSTICK_POWER_LOW, /* <= 20% */ |
| 73 | + SDL_JOYSTICK_POWER_MEDIUM, /* <= 70% */ |
| 74 | + SDL_JOYSTICK_POWER_FULL, /* <= 100% */ |
| 75 | + SDL_JOYSTICK_POWER_WIRED, |
| 76 | + SDL_JOYSTICK_POWER_MAX |
| 77 | +} SDL_JoystickPowerLevel; |
| 78 | +``` |
| 79 | + |
| 80 | +Pascal: |
| 81 | + |
| 82 | +```pascal |
| 83 | +type |
| 84 | + PPSDL_JoystickPowerLevel = ^PSDL_JoystickPowerLevel; |
| 85 | + PSDL_JoystickPowerLevel = ^TSDL_JoystickPowerLevel; |
| 86 | + TSDL_JoystickPowerLevel = type Integer; |
| 87 | +
|
| 88 | +const |
| 89 | + SDL_JOYSTICK_POWER_UNKNOWN = TSDL_JoystickPowerLevel(-1); |
| 90 | + SDL_JOYSTICK_POWER_EMPTY = TSDL_JoystickPowerLevel(0); {* <= 5% *} |
| 91 | + SDL_JOYSTICK_POWER_LOW = TSDL_JoystickPowerLevel(1); {* <= 20% *} |
| 92 | + SDL_JOYSTICK_POWER_MEDIUM = TSDL_JoystickPowerLevel(2); {* <= 70% *} |
| 93 | + SDL_JOYSTICK_POWER_FULL = TSDL_JoystickPowerLevel(3); {* <= 100% *} |
| 94 | + SDL_JOYSTICK_POWER_WIRED = TSDL_JoystickPowerLevel(4); |
| 95 | + SDL_JOYSTICK_POWER_MAX = TSDL_JoystickPowerLevel(5); |
| 96 | +``` |
| 97 | + |
| 98 | +Hint 1: C enums start at 0 if no explicit value is set. |
| 99 | + |
| 100 | +Hint 2: The type should always be cint. Most C compilers have the enum elements |
| 101 | +> In C, each enumeration constant has type int and each enumeration type |
| 102 | +> is compatible with some integer type. (The integer types include all three |
| 103 | +> character types–plain, signed, and unsigned.) The choice of compatible |
| 104 | +> type is implementation-defined. The C standard grants the freedom to |
| 105 | +> use different integer types to represent different enumeration types, |
| 106 | +> but most compilers just use int to represent all enumeration types. |
| 107 | +Ref.: [https://www.embedded.com/enumerations-are-integers-except-when-theyre-not/](https://www.embedded.com/enumerations-are-integers-except-when-theyre-not/) |
| 108 | + |
| 109 | +Hint 3: Do not translate C enums to Pascal enums. C enums are handled like plain |
| 110 | +integers which will make bitwise operations (e. g. in macros) possible |
| 111 | +without typecasting. |
| 112 | + |
| 113 | +## Structs |
| 114 | + |
| 115 | +### Defined Structs |
| 116 | + |
| 117 | +C: |
| 118 | + |
| 119 | +```c |
| 120 | +typedef struct SDL_version |
| 121 | +{ |
| 122 | + Uint8 major; /**< major version */ |
| 123 | + Uint8 minor; /**< minor version */ |
| 124 | + Uint8 patch; /**< update version */ |
| 125 | +} SDL_version; |
| 126 | +``` |
| 127 | + |
| 128 | +Pascal: |
| 129 | + |
| 130 | +```pascal |
| 131 | +type |
| 132 | + PPSDL_Version = ^PSDL_Version; |
| 133 | + PSDL_Version = ^TSDL_Version; |
| 134 | + TSDL_Version = record |
| 135 | + major: cuint8 { major version } |
| 136 | + minor: cuint8 { minor version } |
| 137 | + patch: cuint8; { update version } |
| 138 | + end; |
| 139 | +``` |
| 140 | + |
| 141 | +### Opaque Structs |
| 142 | + |
| 143 | +If you have something like ```typedef struct name name```. the concrete |
| 144 | +structure is opaque, and the programmer is expected to only ever |
| 145 | +interact with pointers to the struct. |
| 146 | + |
| 147 | +C: |
| 148 | + |
| 149 | +```c |
| 150 | +typedef struct SDL_Window SDL_Window; |
| 151 | +``` |
| 152 | + |
| 153 | +Pascal: |
| 154 | + |
| 155 | +```pascal |
| 156 | +type |
| 157 | + PPSDL_Window = ^PSDL_Window; |
| 158 | + PSDL_Window = type Pointer; |
| 159 | +``` |
| 160 | + |
| 161 | +As shown above, for opaque structs, we avoid defining the base `TType` |
| 162 | +and define only the pointer `PType`. |
| 163 | +For the rationale behind this decision, read the discussion in |
| 164 | +[issue #63](https://github.com/PascalGameDevelopment/SDL2-for-Pascal/issues/63). |
| 165 | + |
| 166 | + |
| 167 | +## Unions |
| 168 | + |
| 169 | +C: |
| 170 | + |
| 171 | +```c |
| 172 | +typedef union { |
| 173 | + /** \brief A cutoff alpha value for binarization of the window shape's alpha channel. */ |
| 174 | + Uint8 binarizationCutoff; |
| 175 | + SDL_Color colorKey; |
| 176 | +} SDL_WindowShapeParams; |
| 177 | +``` |
| 178 | + |
| 179 | +Pascal: |
| 180 | + |
| 181 | +```pascal |
| 182 | +type |
| 183 | + PPSDL_WindowShapeParams = ^PSDL_WindowShapeParams; |
| 184 | + PSDL_WindowShapeParams = ^TSDL_WindowShapeParams; |
| 185 | + TSDL_WindowShapeParams = record |
| 186 | + case cint of |
| 187 | + { A cutoff alpha value for binarization of the window shape's alpha channel. } |
| 188 | + 0: (binarizationCutoff: cuint8); |
| 189 | + 1: (colorKey: TSDL_ColorKey); |
| 190 | + end; |
| 191 | +``` |
| 192 | + |
| 193 | +## Functions |
| 194 | + |
| 195 | +C: |
| 196 | + |
| 197 | +```c |
| 198 | +extern DECLSPEC void SDLCALL SDL_LockJoysticks(void); |
| 199 | + |
| 200 | +extern DECLSPEC const char *SDLCALL SDL_JoystickNameForIndex(int device_index); |
| 201 | +``` |
| 202 | +
|
| 203 | +Pascal: |
| 204 | +
|
| 205 | +```pascal |
| 206 | +procedure SDL_LockJoysticks(); cdecl; |
| 207 | + external SDL_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDL_LockJoysticks' {$ENDIF} {$ENDIF}; |
| 208 | +
|
| 209 | +function SDL_JoystickNameForIndex(device_index: cint): PAnsiChar; cdecl; |
| 210 | + external SDL_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDL_JoystickNameForIndex' {$ENDIF} {$ENDIF}; |
| 211 | +``` |
| 212 | + |
| 213 | +## C Macros |
| 214 | + |
| 215 | +Macros are pre-processed constructs in C which have no analogue in Pascal. |
| 216 | +Usually a C macro is translated as a Pascal function and implemented in SDL2.pas. |
| 217 | + |
| 218 | +C: |
| 219 | + |
| 220 | +```c |
| 221 | +#define SDL_VERSION_ATLEAST(X, Y, Z) \ |
| 222 | + (SDL_COMPILEDVERSION >= SDL_VERSIONNUM(X, Y, Z)) |
| 223 | +``` |
| 224 | +
|
| 225 | +Pascal: |
| 226 | +
|
| 227 | +_sdlversion.inc (declaration)_: |
| 228 | +```pascal |
| 229 | +function SDL_VERSION_ATLEAST(X,Y,Z: cuint8): Boolean; |
| 230 | +``` |
| 231 | + |
| 232 | +_sdl2.pas (implementation)_: |
| 233 | +```pascal |
| 234 | +function SDL_VERSION_ATLEAST(X,Y,Z: cuint8): Boolean; |
| 235 | +begin |
| 236 | + Result := SDL_COMPILEDVERSION >= SDL_VERSIONNUM(X,Y,Z); |
| 237 | +end; |
| 238 | +``` |
| 239 | +Hint: As can be seen from this example, the macro has no clearly defined |
| 240 | +argument types and return value type. The types to be used for arguments and |
| 241 | +return values depend on the context in which this macro is used. Here from the |
| 242 | +context is known that X, Y and Z stand for the major version, minor version and |
| 243 | +the patch level which are declared to be 8 bit unsigned integers. From the |
| 244 | +context it is also clear, that the macro returns true or false, hence the |
| 245 | +function should return a Boolean value. The context does not suggest to use, |
| 246 | +e. g., TSDL_Bool here, although in a different context this could be the better |
| 247 | +translation. |
| 248 | +
|
| 249 | +## When to use TSDL_Bool? |
| 250 | +
|
| 251 | +TSDL_Bool is memory compatible with C's bool (integer size, e. g. 2 or 4 bytes). |
| 252 | +Pascal's Boolean is different and typically 1 byte in size. ([FPC Ref.](https://www.freepascal.org/docs-html/current/ref/refsu4.html#x26-270003.1.1)) |
| 253 | +
|
| 254 | +* return values and paramters of original SDL functions which are of SDL_Bool type, should be translated with TSDL_Bool |
| 255 | +* DO NOT use TSDL_Bool for macro functions which evaluate to a boolean value, use Pascal's Boolean instead (exception: the value is an argument for a SDL_Bool parameter) |
| 256 | +
|
| 257 | +_Example code_ |
| 258 | +```pascal |
| 259 | +program SDLBoolTest; |
| 260 | +
|
| 261 | +uses SDL2, ctypes, SysUtils; |
| 262 | +
|
| 263 | +var |
| 264 | + a, b: Integer; |
| 265 | +
|
| 266 | +function BoolTest(a, b: Integer): TSDL_Bool; |
| 267 | +begin |
| 268 | + // works |
| 269 | + //Result := TSDL_Bool(a > b); |
| 270 | +
|
| 271 | + // works, too |
| 272 | + Result := (a > b); |
| 273 | +end; |
| 274 | +
|
| 275 | +begin |
| 276 | + writeln('Bool Test a > b'); |
| 277 | + for a:= 0 to 3 do |
| 278 | + for b := 0 to 3 do |
| 279 | + begin |
| 280 | + write('a = ' + IntToStr(a) + '; b = ' + IntToStr(b) +'; Result = '); |
| 281 | + writeln(BoolTest(a, b)); |
| 282 | + end; |
| 283 | +
|
| 284 | + readln; |
| 285 | +end. |
| 286 | +``` |
0 commit comments