Skip to content

raylib syntax analysis

Ray edited this page Jun 14, 2021 · 19 revisions

raylib is a simple and easy-to-use library to enjoy videogames programing... but, what makes the library simple and easy-to-use? For many users the first approach to the library is through its API, so, here it is a small analysis of the API from a syntactic point of view.

How are the functions structured? Which words are used? How many parameters are exposed? How intuitive is it to understand or even guess every function/structure/enum when required? Syntax is the set of rules, principles, and processes that govern the structure of sentences in a given language and defines how we understand it.

To do this analysis a raylib.h parser has been created. That parser dissects API into small pieces to automatize some parts of the analysis; actually, this parser can also be useful for automatic docs and bindings generation!

The analysis is organized in 3 parts, one for each API element analyzed:

  • Functions: Instructions called by the users to make things happen
  • Structures (struct): Data types to organize information packages
  • Enumerators (enum): Sequence of named values used for convenience

Functions

Latest raylib version (3.8-dev) exposes a total of 470 functions, a relatively small API for a gamedev library.

All raylib functions try to follow this syntactic structure:

    <Verb><Subject><Complement>();

More specifically, every syntactic element implies:

    <Action><Object><Attribute/State>();  // Do an Action over some Object Attribute/State

Following this syntactic structure is what make the API comprehensive, intuitive, easy-to-remember and easy-to-use.

Checking the available functions with more detail, they can be divided into 3 groups:

  1. Functions following a common pattern
  2. Functions operating over specific type of data
  3. Functions with unique pattern

1. Functions following a common pattern

Most of the functions of the library go into this first group (359 functions), there is some common <Action> that prepends the name of most of the functions:

pattern function format API count examples
01 void Init*() 2 InitWindow(), InitAudioDevice()
02 void Close*() 2 CloseWindow(), CloseAudioDevice()
03 void Begin*() 8 BeginDrawing(), BeginBlendMode()
04 void End*() 8 EndDrawing(), EndBlendMode()
05 TYPE Get*() 79 GetKeyPressed(), GetMouseX(), GetRayCollision*()
06 void Set*() 46 SetWindowTitle(), SetTargetFPS(), SetMouseScale()
07 bool Is*() 33 IsKeyPressed(), IsGamepadAvailable(), IsSoundPlaying()
08 TYPE Gen<TYPE>*() 20 GenImage*(), GenMesh*()
09 TYPE Load<TYPE>*() 34 LoadImage*(), LoadTexture*(), LoadSound*()
10 void Unload<TYPE>*(<TYPE>) 22 UnloadImage(), UnloadTexture(), UnloadSound()
11 void Update<TYPE>*(<TYPE>, *) 8 UpdateTexture(), UpdateCamera()
12 bool Save*() 3 SaveFileData(), SaveFileText(), SaveStorageValue()
13 bool Export*() 5 ExportImage(), ExportImageAsCode(), ExportMesh(), ExportWave(), ExportWaveAsCode()
14 void Draw*() 79 DrawRectangle(), DrawTexture*(), DrawModel*()
15 bool Check*() 10 CheckCollisionRecs(), CheckCollisionCircles(), CheckCollisionBoxSphere()

2. Functions operating over specific type of data

Those functions (68 in total) operate over a specific data type, so, it was decided to prepend the DataType to the function name, they are an exception over the main syntax rule followed by the API:

pattern function format API count examples
01 TYPE Color*() 7 ColorAlpha(), ColorFromHSV(), ColorToHSV()
02 Image Image*()
void Image*()
40 ImageFormat(), ImageCrop(), ImageResize(), ImageFlipVertical()
03 TYPE Text*() 16 TextFormat(), TextReplace(), TextSplit(), TextToLower()
04 Mesh*() 2 MeshTangents(), MeshBinormals()
05 Wave Wave*()
void Wave*()
3 WaveFormat(), WaveCopy(), WaveCrop()

NOTE: Maybe some of them are renamed in the future for consistency.

3. Functions with unique pattern

Remaining functions (43 in total) follow a unique pattern, still, most of them follow the standard syntax pattern of <Verb><Subject><Complement>.

// core.c
WindowShouldClose();   // Not following pattern
ClearWindowState();
ToggleFullscreen();
MaximizeWindow();
MinimizeWindow();
RestoreWindow();
ShowCursor();
HideCursor();
EnableCursor();
DisableCursor();
ClearBackground();
TakeScreenshot();
TraceLog();            // Not following pattern
MemAlloc();            // Data-type pattern?
MemRealloc();          // Data-type pattern?
MemFree();             // Data-type pattern?
FileExists();          // Not following pattern -> IsFileAvailable()?
DirectoryExists();     // Not following pattern -> IsDirectoryAvailable()?
ClearDirectoryFiles();
ChangeDirectory();
ClearDroppedFiles();
CompressData();
DecompressData();
OpenURL();

// textures.c
Fade();                // Superseded by ColorAlpha()

// text.c
MeasureText();
MeasureTextEx();
CodepointToUtf8();     // Not following pattern -> EncodeCodepointAsUtf8()?

// models.c
UploadMesh();

// raudio.c
PlaySound();
StopSound();
PauseSound();
ResumeSound();
PlaySoundMulti();
StopSoundMulti();
PlayMusicStream();
StopMusicStream();
PauseMusicStream();
ResumeMusicStream();
PlayAudioStream();
StopAudioStream();
PauseAudioStream();
ResumeAudioStream();

Functions suffixes

A part from the function prefixes that we can find in many functions names (1. common patterns), we can also find some common suffixes used by several functions:

// Suffix: *Ex() -> Used for "Extended" versions of same name functions
Vector2 GetWorldToScreenEx();
void DrawLineEx();
void DrawRectangleGradientEx();
void DrawRectangleLinesEx();
void DrawPolyLinesEx();
Image ImageTextEx();
void ImageDrawTextEx();
void DrawTextureEx();
Font LoadFontEx();
void DrawTextEx();
void DrawTextRecEx();
Vector2 MeasureTextEx();
void DrawSphereEx();
void DrawModelEx();
void DrawModelWiresEx();

// Suffix: *Pro() -> Used for "Professional" versions of same name functions, more advanced than "Ex"
void DrawRectanglePro();
void DrawTexturePro();
void DrawBillboardPro();

// Suffix: *Rec() -> Used for functions requiring a "Rectangle" as one main input parameter
void DrawRectangleRec();
bool CheckCollisionCircleRec();
bool CheckCollisionPointRec();
Rectangle GetCollisionRec();
void ImageDrawRectangleRec();
void UpdateTextureRec();
void DrawTextureRec();
void DrawTextRec();
void DrawBillboardRec();

// Suffix: *FromMemory() -> Used for functions loading data "from memory" instead of from files
Shader LoadShaderFromMemory();
Image LoadImageFromMemory();
Font LoadFontFromMemory();
Wave LoadWaveFromMemory();
Music LoadMusicStreamFromMemory();

// Suffix: *Callback() -> Used for functions setting a callback function
void SetTraceLogCallback();
void SetLoadFileDataCallback();
void SetSaveFileDataCallback();
void SetLoadFileTextCallback();
void SetSaveFileTextCallback();

Functions naming

Most functions in raylib use a maximum of 4 words on its name. I think that's a good trade-off to remember the name of the function. Still, there is a small set of functions that go beyond that limit:

count function words comments
001 GetWindowScaleDPI() 4 Acronym used
002 GetWorldToScreenEx() 5
003 GetWorldToScreen2D() 5
004 GetScreenToWorld2D() 5
005 SetTargetFPS() 5 Acronym used
006 SetLoadFileDataCallback() 5 Callback function
007 SetSaveFileDataCallback() 5 Callback function
008 SetLoadFileTextCallback() 5 Callback function
009 SetSaveFileTextCallback() 5 Callback function
010 GetFileNameWithoutExt() 5
011 SetCameraSmoothZoomControl() 5 TODO: Review!!!
012 ImageToPOT() 3 Acronym used
013 ImageRotateCCW() 3 Acronym used
014 ColorToHSV() 3 Acronym used
015 ColorFromHSV() 3 Acronym used
016 LoadMusicStreamFromMemory() 5 *FromMemory() set of functions
017 SetAudioStreamBufferSizeDefault() 6 TODO: Review!!!

Functions parameters

Most functions are limited to 5 or less input parameters. I think 5 or less parameters is a good number to keep the function simple and rememberable, more than 5 usually requires the user to use some kind of intellisense system. The number of parameters is a key point for raylib simplicity, still, there are some functions requiring 6 or more parameters:

count function param count comments
001 SetCameraMoveControls() 6
002 DrawCircleSector() 6
003 DrawCircleSectorLines() 6
004 DrawRing() 7 WARNING: >6 parameters
005 DrawRingLines() 7 WARNING: >6 parameters
006 DrawRectangleGradientV() 6
007 DrawRectangleGradientH() 6
008 DrawPolyLinesEx() 6
009 GenImageChecked() 6
010 ImageResizeCanvas() 6
011 ImageDrawLine() 6
012 ImageDrawRectangle() 6
013 ImageDrawText() 6
014 ImageDrawTextEx() 7 WARNING: >6 parameters
015 DrawTextureTiled() 7 WARNING: >6 parameters
016 DrawTexturePro() 6
017 DrawTextureNPatch() 6
018 DrawTexturePoly() 6
019 LoadFontFromMemory() 6
020 LoadFontData() 6
021 GenImageFontAtlas() 6
022 DrawTextEx() 6
023 DrawTextRec() 7 WARNING: >6 parameters
024 DrawTextRecEx() 11 TODO: Review!!!
025 DrawCubeTexture() 6
026 DrawCylinder() 6
027 DrawCylinderWires() 6
028 DrawModelEx() 6
029 DrawModelWiresEx() 6
030 DrawBillboardRec() 6
031 DrawBillboardPro() 8 WARNING: >6 parameters

Note that only 7 function out of 470 require more than 6 parameters. This is what makes raylib so special.

Structures

raylib defines a total of 31 struct data types, most of those structs use a single word to define the type and some of them use two words.

raylib tries to provide generic data types for most common use scenarios, only some of those structs are required for specific examples: NPatchInfo, VrDeviceInfo, VrStereoConfig.

About the fields contained in every struct, it was tried to just include the minimum required but when moving into 3d Mesh and Model, the amount of required data grows fast. For a more detailed analysis on data structures (not purely syntactic), check Wiki entry: raylib data structures.

count struct name fields count comments
01 Vector2 2
02 Vector3 3
03 Vector4 4
04 Matrix 4
05 Color 4
06 Rectangle 4
07 Image 5
08 Texture 5
09 RenderTexture 3 2 words name
10 NPatchInfo 6 2 words name
11 CharInfo 5
12 Font 6
13 Camera3D 5
14 Camera2D 4
15 Mesh 15
16 Shader 2
17 MaterialMap 3 2 words name
18 Material 3
19 Transform 3
20 BoneInfo 2
21 Model 9
22 ModelAnimation 4 2 words name
23 Ray 2
24 RayCollision 4 2 words name
25 BoundingBox 2 2 words name
26 Wave 5
27 AudioStream 4 2 words name
28 Sound 2
29 Music 5
30 VrDeviceInfo 10 3 words name
31 VrStereoConfig 8 3 words name

Enumerations

raylib defines 20 enumerations for convenience. Enum names and contained value names are kept simple and clear. Most of those values are only required to be used by some very specific functions, for a detailed list check Wiki entry: raylib enumerated types.

Personally, I tried to avoid enum values requirement as much as possible within the library, actually, only 35 function in raylib could require using some enum value on some of its input parameters.

count enum name values count comments
01 ConfigFlags 14
02 TraceLogLevel 8 3 words name
03 KeyboardKey 110
04 MouseButton 8
05 MouseCursor 11
06 GamepadButton 18
07 GamepadAxis 6
08 MaterialMapIndex 11 3 words name
09 ShaderLocationIndex 26 3 words name
10 ShaderUniformDataType 9 4 words name
11 PixelFormat 21
12 TextureFilter 6
13 TextureWrap 4
14 CubemapLayout 6
15 FontType 3
16 BlendMode 6
17 Gesture 11
18 CameraMode 5
19 CameraProjection 2
20 NPatchLayout 3 3 words name

Conclusion

One of the goals of raylib is being simple and easy-to-use and many hours have been put into the API design; thinking about the best name for every function, the minimum number of parameters required, the right name of each parameter, the data types structure and more.

I think this syntax analysis is useful to see what worked for raylib library and also help to improved it.

Clone this wiki locally