Compare commits

...

4 Commits

Author SHA1 Message Date
Ray
9fe3f7ca14 REXM: ADDED: Automated-testing system
Elements tested:
```
TESTING_FAIL_INIT      = 1 << 0,   // Initialization (InitWindow())    -> "INFO: DISPLAY: Device initialized successfully"
            TESTING_FAIL_CLOSE     = 1 << 1,   // Closing (CloseWindow())          -> "INFO: Window closed successfully"
            TESTING_FAIL_ASSETS    = 1 << 2,   // Assets loading (WARNING: FILE:)  -> "WARNING: FILEIO:"
            TESTING_FAIL_RLGL      = 1 << 3,   // OpenGL-wrapped initialization    -> "INFO: RLGL: Default OpenGL state initialized successfully"
            TESTING_FAIL_PLATFORM  = 1 << 4,   // Platform initialization          -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
            TESTING_FAIL_FONT      = 1 << 5,   // Font default initialization      -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
            TESTING_FAIL_TIMER     = 1 << 6,   // Timer initialization             -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
```
2025-11-17 00:29:54 +01:00
Ray
d26b17f320 Some comment tweaks 2025-11-17 00:27:33 +01:00
Ray
6756e9d3d7 Update core_input_gestures_testbed.c 2025-11-17 00:16:47 +01:00
Ray
06589d3350 Update core_2d_camera_mouse_zoom.c 2025-11-17 00:14:08 +01:00
4 changed files with 300 additions and 269 deletions

View File

@ -23,7 +23,7 @@
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main ()
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
@ -35,9 +35,9 @@ int main ()
Camera2D camera = { 0 };
camera.zoom = 1.0f;
int zoomMode = 0; // 0-Mouse Wheel, 1-Mouse Move
int zoomMode = 0; // 0-Mouse Wheel, 1-Mouse Move
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
@ -93,6 +93,7 @@ int main ()
// under the cursor to the screen space point under the cursor at any zoom
camera.target = mouseWorldPos;
}
if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
{
// Zoom increment
@ -110,7 +111,6 @@ int main ()
ClearBackground(RAYWHITE);
BeginMode2D(camera);
// Draw the 3d grid, rotated 90 degrees and centered around 0,0
// just so we have something in the XY plane
rlPushMatrix();
@ -121,7 +121,6 @@ int main ()
// Draw a reference circle
DrawCircle(GetScreenWidth()/2, GetScreenHeight()/2, 50, MAROON);
EndMode2D();
// Draw mouse reference
@ -142,5 +141,6 @@ int main ()
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -69,7 +69,6 @@ int main(void)
float angleLength = 90.0f;
float currentAngleDegrees = 0.0f;
Vector2 finalVector = { 0.0f, 0.0f };
char currentAngleStr[7] = "";
Vector2 protractorPosition = { 266.0f, 315.0f };
SetTargetFPS(60); // Set our game to run at 60 frames-per-second

View File

@ -4,15 +4,17 @@
```
Example automated testing elements validated:
- [WARN] : WARNING messages count
- [INIT] : Initialization
- [CLOSE] : Closing
- [ASSETS] : Assets loading
- [OTHER] : Other types of warnings
- [RESULT] : Ending program result (0)
- [RLGL] : OpenGL-wrapped initialization
- [PLAT] : Platform initialization
- [FONT] : Font default initialization
- [TIMER] : Timer initialization
```
| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [OTHER] | [RESULT] |
|:---------------------------------|:------:|:------:|:-------:|:--------:|:-------:|:--------:|
| core_highdpi_testbed | 2 | ✔ | ✔ | ✔ | ✔ | ✔ |
| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
| core_custom_logging | 0 | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| core_custom_frame_control | 0 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |

View File

@ -1,6 +1,6 @@
/*******************************************************************************************
*
* rexm [raylib examples manager] - A simple command-line tool to manage raylib examples
* rexm [raylib examples manager] - A simple and easy-to-use raylib examples collection manager
*
* Supported processes:
* - create <new_example_name>
@ -8,8 +8,9 @@
* - rename <old_examples_name> <new_example_name>
* - remove <example_name>
* - build <example_name>
* - validate
* - update
* - test <example_name>
* - validate // All examples
* - update // All examples
*
* Files involved in the processes:
* - raylib/examples/<category>/<category>_example_name.c
@ -86,11 +87,17 @@ typedef struct {
char author[64]; // Example author
char authorGitHub[64]; // Example author, GitHub user name
int status; // Example validation status info
int status; // Example validation status flags
int resCount; // Example resources counter
char **resPaths; // Example resources paths (MAX: 256)
} rlExampleInfo;
// Automated testing data
typedef struct {
int warnings; // Warnings counter
int status; // Testing status result flags
} rlExampleTesting;
// Validation status for a single example
typedef enum {
VALID_OK = 0, // All required files and entries are present
@ -111,6 +118,18 @@ typedef enum {
VALID_UNKNOWN_ERROR = 1 << 14 // Unknown failure case (fallback)
} rlExampleValidationStatus;
typedef enum {
TESTING_OK = 0, // All automated testing ok
TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
TESTING_FAIL_FONT = 1 << 5, // Font deefault initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
TESTING_FAIL_OTHER = 1 << 7, // Other types of warnings (WARNING:)
} rlExampleTestingStatus;
// Example management operations
typedef enum {
OP_NONE = 0, // No process to do
@ -119,9 +138,9 @@ typedef enum {
OP_RENAME = 3, // Rename existing example
OP_REMOVE = 4, // Remove existing example
OP_VALIDATE = 5, // Validate examples, using [examples_list.txt] as main source by default
OP_UPDATE = 6, // Validate and update required examples (as far as possible)
OP_BUILD = 7, // Build example for desktop and web, copy web output
OP_TEST = 8, // Test example: check output LOG WARNINGS
OP_UPDATE = 6, // Validate and update required examples (as far as possible): ALL
OP_BUILD = 7, // Build example(s) for desktop and web, copy web output - Multiple examples supported
OP_TEST = 8, // Test example(s), checking output log "WARNING" - Multiplee examples supported
} rlExampleOperation;
static const char *exCategories[REXM_MAX_EXAMPLE_CATEGORIES] = { "core", "shapes", "textures", "text", "models", "shaders", "audio", "others" };
@ -145,8 +164,8 @@ static int UpdateRequiredFiles(void);
// Load examples collection information
// NOTE 1: Load by category: "ALL", "core", "shapes", "textures", "text", "models", "shaders", others"
// NOTE 2: Sort examples list on request flag
static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount);
static void UnloadExamplesData(rlExampleInfo *exInfo);
static rlExampleInfo *LoadExampleData(const char *filter, bool sort, int *exCount);
static void UnloadExampleData(rlExampleInfo *exInfo);
// Load example info from file header
static rlExampleInfo *LoadExampleInfo(const char *exFileName);
@ -161,10 +180,10 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry);
static void SortExampleByName(rlExampleInfo *items, int count);
// Scan resource paths in example file
static char **ScanExampleResources(const char *filePath, int *resPathCount);
static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount);
// Clear resource paths scanned
static void ClearExampleResources(char **resPaths);
static void UnloadExampleResourcePaths(char **resPaths);
// Add/remove VS project (.vcxproj) tofrom existing VS solution (.sln)
static int AddVSProjectToSolution(const char *slnFile, const char *projFile, const char *category);
@ -222,7 +241,8 @@ int main(int argc, char *argv[])
char exRecategory[32] = { 0 }; // Example re-name category: shapes
char exRename[64] = { 0 }; // Example re-name, without extension
char exRebuildRequested[16] = { 0 }; // Example category/full rebuild request
char *exBuildList[256] = { 0 }; // Example build list for: ALL, <category>, single-example
int exBuildListCount = 0; // Example build list file count
int opCode = OP_NONE; // Operation code: 0-None(Help), 1-Create, 2-Add, 3-Rename, 4-Remove
bool showUsage = false; // Flag to show usage help
@ -382,80 +402,38 @@ int main(int argc, char *argv[])
opCode = OP_UPDATE;
}
else if (strcmp(argv[1], "build") == 0)
else if ((strcmp(argv[1], "build") == 0) || (strcmp(argv[1], "test") == 0))
{
// Build example for PLATFORM_DESKTOP and PLATFORM_WEB
// Build/Test example(s) for PLATFORM_DESKTOP and PLATFORM_WEB
// NOTE: Build outputs to default directory, usually where the .c file is located,
// to avoid issues with copying resources (at least on Desktop)
// Web build files (.html, .wasm, .js, .data) are copied to raylib.com/examples repo
// Check for valid upcoming argument
if (argc == 2) LOG("WARNING: No example name provided to build\n");
if (argc == 2) LOG("WARNING: No example name/category provided\n");
else if (argc > 3) LOG("WARNING: Too many arguments provided\n");
else
{
// Support building not only individual examples but categories and "ALL"
if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES))
// Support building/testing not only individual examples but multiple: ALL/<category>
rlExampleInfo *exBuildListInfo = LoadExampleData(argv[2], false, &exBuildListCount);
for (int i = 0; i < exBuildListCount; i++)
{
// Category/ALL rebuilt requested
strcpy(exRebuildRequested, argv[2]);
}
else
{
// Verify example exists in collection to be removed
char *exColInfo = LoadFileText(exCollectionFilePath);
if (TextFindIndex(exColInfo, argv[2]) != -1) // Example in the collection
{
strcpy(exName, argv[2]); // Register example name
strncpy(exCategory, exName, TextFindIndex(exName, "_"));
opCode = OP_BUILD;
}
else LOG("WARNING: BUILD: Example requested not available in the collection\n");
UnloadFileText(exColInfo);
}
}
}
else if (strcmp(argv[1], "test") == 0)
{
// Build and test example for PLATFORM_DESKTOP
// NOTE: Build outputs to default directory, usually where the .c file is located,
// to avoid issues with copying resources (at least on Desktop)
if (argc == 2) LOG("WARNING: No example name provided to test\n");
else if (argc > 3) LOG("WARNING: Too many arguments provided\n");
else
{
// Support building not only individual examples but categories and "ALL"
if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES))
{
// Category/ALL rebuilt requested
strcpy(exRebuildRequested, argv[2]);
}
else
{
// Verify example exists in collection to be removed
char *exColInfo = LoadFileText(exCollectionFilePath);
if (TextFindIndex(exColInfo, argv[2]) != -1) // Example in the collection
{
strcpy(exName, argv[2]); // Register example name
strncpy(exCategory, exName, TextFindIndex(exName, "_"));
opCode = OP_TEST;
}
else LOG("WARNING: TEST: Example requested not available in the collection\n");
UnloadFileText(exColInfo);
exBuildList[i] = (char *)RL_CALLOC(256, sizeof(char));
strcpy(exBuildList[i], exBuildListInfo[i].name);
}
UnloadExampleData(exBuildListInfo);
if (exBuildListCount == 0) LOG("WARNING: BUILD: Example requested not available in the collection\n");
else opCode = OP_TEST;
}
}
// Process command line options arguments
for (int i = 1; i < argc; i++)
{
if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0))
{
showUsage = true;
}
else if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0))
{
verbose = true;
}
if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "--help") == 0)) showUsage = true;
else if ((strcmp(argv[i], "-v") == 0) || (strcmp(argv[i], "--verbose") == 0)) verbose = true;
}
}
@ -512,7 +490,7 @@ int main(int argc, char *argv[])
// NOTE: resources path will be relative to example source file directory
int resPathCount = 0;
LOG("INFO: [%s] Scanning file for resources...\n", GetFileName(inFileName));
char **resPaths = ScanExampleResources(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount);
char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s.c", GetDirectoryPath(inFileName), exName), &resPathCount);
if (resPathCount > 0)
{
@ -570,7 +548,7 @@ int main(int argc, char *argv[])
}
}
ClearExampleResources(resPaths);
UnloadExampleResourcePaths(resPaths);
// -----------------------------------------------------------------------------------------
// Add example to the collection list, if not already there
@ -726,13 +704,13 @@ int main(int argc, char *argv[])
// Edit: Update example source code metadata
int exListCount = 0;
rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, exCategory, false, &exListCount);
rlExampleInfo *exList = LoadExampleData(exCategory, false, &exListCount);
for (int i = 0; i < exListCount; i++)
{
if (strcmp(exList[i].name, exRename) == 0)
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exRename), &exList[i]);
}
UnloadExamplesData(exList);
UnloadExampleData(exList);
// NOTE: Example resource files do not need to be changed...
// unless the example is moved from one caegory to another
@ -918,79 +896,24 @@ int main(int argc, char *argv[])
case OP_BUILD:
{
LOG("INFO: Command requested: BUILD\n");
LOG("INFO: Example to be built: %s\n", exName);
LOG("INFO: Example(s) to be built: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
if ((exRebuildRequested[0] != '\0') &&
(strcmp(exRebuildRequested, "others") != 0) &&
(strcmp(exCategory, "others") != 0)) // Skipping "others" category for rebuild: Special needs
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
for (int i = 0; i < exBuildListCount; i++)
{
// TODO: Support building full categories: exRebuildRequested
// Get example name and category
memset(exName, 0, 64);
strcpy(exName, exBuildList[i]);
memset(exCategory, 0, 32);
strncpy(exCategory, exName, TextFindIndex(exName, "_"));
int exRebuildCount = 0;
rlExampleInfo *exRebuildList = LoadExamplesData(exCollectionFilePath, exRebuildRequested, false, &exRebuildCount);
// Build: raylib.com/examples/<category>/<category>_example_name.html
// Build: raylib.com/examples/<category>/<category>_example_name.data
// Build: raylib.com/examples/<category>/<category>_example_name.wasm
// Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
for (int i = 0; i < exRebuildCount; i++)
{
// Build example for PLATFORM_DESKTOP
#if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#else
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#endif
// Build example for PLATFORM_WEB
#if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exName);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
#endif
// Update generated .html metadata
LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exRebuildList[i].name));
UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.c", exBasePath, exRebuildList[i].category, exRebuildList[i].name));
// Copy results to web side
LOG("INFO: [%s] Copy example build to raylib.com\n", exRebuildList[i].name);
FileCopy(TextFormat("%s/%s/%s.html", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.html", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
FileCopy(TextFormat("%s/%s/%s.data", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.data", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
FileCopy(TextFormat("%s/%s/%s.wasm", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.wasm", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exRebuildList[i].category, exRebuildList[i].name),
TextFormat("%s/%s/%s.js", exWebPath, exRebuildList[i].category, exRebuildList[i].name));
}
UnloadExamplesData(exRebuildList);
}
else // Build a single example
{
// Build: raylib.com/examples/<category>/<category>_example_name.html
// Build: raylib.com/examples/<category>/<category>_example_name.data
// Build: raylib.com/examples/<category>/<category>_example_name.wasm
// Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
LOG("INFO: [%i/%i] Building example: [%s]\n", i + 1, exBuildListCount, exName);
// Build example for PLATFORM_DESKTOP
#if defined(_WIN32)
@ -1002,6 +925,10 @@ int main(int argc, char *argv[])
#endif
// Build example for PLATFORM_WEB
// Build: raylib.com/examples/<category>/<category>_example_name.html
// Build: raylib.com/examples/<category>/<category>_example_name.data
// Build: raylib.com/examples/<category>/<category>_example_name.wasm
// Build: raylib.com/examples/<category>/<category>_example_name.js
#if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName));
@ -1024,8 +951,10 @@ int main(int argc, char *argv[])
TextFormat("%s/%s/%s.wasm", exWebPath, exCategory, exName));
FileCopy(TextFormat("%s/%s/%s.js", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.js", exWebPath, exCategory, exName));
// Once example processed, free memory from list
RL_FREE(exBuildList[i]);
}
//LOG("WARNING: [others] category examples should be build manually, they could have specific build requirements\n");
} break;
case OP_VALIDATE: // Validate: report and actions
@ -1128,7 +1057,7 @@ int main(int argc, char *argv[])
// Check all examples in collection [examples_list.txt] -> Source of truth!
LOG("INFO: Validating examples in collection...\n");
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData("ALL", false, &exCollectionCount);
// Set status information for all examples, using "status" field in the struct
for (int i = 0; i < exCollectionCount; i++)
@ -1173,7 +1102,7 @@ int main(int argc, char *argv[])
// Validate: raylib/examples/<category>/resources/.. -> Example resources available?
// Scan resources used in example to check for missing resource files
// WARNING: Some paths could be for files to save, not files to load, verify it
char **resPaths = ScanExampleResources(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), &exInfo->resCount);
char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s/%s.c", exBasePath, exInfo->category, exInfo->name), &exInfo->resCount);
if (exInfo->resCount > 0)
{
for (int r = 0; r < exInfo->resCount; r++)
@ -1206,7 +1135,7 @@ int main(int argc, char *argv[])
}
}
}
ClearExampleResources(resPaths);
UnloadExampleResourcePaths(resPaths);
// Validate: raylib.com/examples/<category>/<category>_example_name.html -> File exists?
// Validate: raylib.com/examples/<category>/<category>_example_name.data -> File exists?
@ -1336,8 +1265,8 @@ int main(int argc, char *argv[])
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
system(TextFormat("mingw32-make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
#else
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->name);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->name));
LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", exInfo->filter);
system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exInfo->category, exInfo->filter));
#endif
// Update generated .html metadata
@ -1410,7 +1339,7 @@ int main(int argc, char *argv[])
| shapes_colors_palette | | | | | | | | | | | | | | |
| text_format_text | | | | | | | | | | | | | | |
*/
LOG("INFO: [examples_report.md] Generating examples validation report...\n");
LOG("INFO: [examples_validation.md] Generating examples validation report...\n");
char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
@ -1456,13 +1385,13 @@ int main(int argc, char *argv[])
(exCollection[i].status & VALID_MISSING_WEB_METADATA)? "" : "");
}
SaveFileText(TextFormat("%s/../tools/rexm/%s", exBasePath, "examples_report.md"), report);
SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_validation.md"), report);
RL_FREE(report);
//-----------------------------------------------------------------------------------------------------
// Generate a report with only the examples missing some elements
//-----------------------------------------------------------------------------------------------------
LOG("INFO: [examples_report_issues.md] Generating examples issues report...\n");
LOG("INFO: [examples_issues.md] Generating examples issues report...\n");
char *reportIssues = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
@ -1511,100 +1440,193 @@ int main(int argc, char *argv[])
}
}
SaveFileText(TextFormat("%s/../tools/rexm/%s", exBasePath, "examples_report_issues.md"), reportIssues);
SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_issues.md"), reportIssues);
RL_FREE(reportIssues);
//-----------------------------------------------------------------------------------------------------
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
//------------------------------------------------------------------------------------------------
} break;
case OP_TEST:
{
LOG("INFO: Command requested: TEST\n");
LOG("INFO: Example to be built and tested: %s\n", exName);
LOG("INFO: Example(s) to be build and tested: %i [%s]\n", exBuildListCount, (exBuildListCount == 1)? exBuildList[0] : argv[2]);
// Steps to follow
// STEP 1: Load example.c and replace required code to inject basic testing code: frames to run
// OPTION 1: Code injection required multiple changes for testing but it does not require raylib changes!
// OPTION 2: Support testing on raylib side: Args processing and events injection: SUPPORT_AUTOMATD_TESTING_SYSTEM, EVENTS_TESTING_MODE
// STEP 2: Build example (PLATFORM_DESKTOP)
// STEP 3: Run example with arguments: --frames 2 > <example>.out.log
// STEP 4: Load <example>.out.log and check "WARNING:" messages -> Some could maybe be ignored
// STEP 5: Generate report with results
rlExampleTesting *testing = (rlExampleTesting *)RL_CALLOC(exBuildListCount, sizeof(rlExampleTesting));
// STEP 1: Load example and inject required code
// PROBLEM: As we need to modify the example source code for building, we need to keep a copy or something
// WARNING: If we make a copy and something fails, it could not be restored at the end
// PROBLEM: Trying to build a copy won't work because Makefile is setup to look for specific example on specific path -> No output dir config
// IDEA: Create directory for testing data -> It implies moving files and set working dir...
// SOLUTION: Make a copy of original file -> Modify original -> Build -> Rename to <example>.test.exe
FileCopy(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
char *srcText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
static const char *mainReplaceText =
"#include <string.h>\n"
"#include <stdlib.h>\n"
"int main(int argc, char *argv[])\n{\n"
" int requestedTestFrames = 0;\n"
" int testFramesCount = 0;\n"
" if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
char *srcTextUpdated[3] = { 0 };
srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
UnloadFileText(srcText);
SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[2]);
for (int i = 0; i < 3; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
// STEP 2: Build example for DESKTOP platform
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
// Build example for PLATFORM_DESKTOP
#if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
#else
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
#endif
// Restore original source code before continue
FileCopy(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
// STEP 3: Run example with required arguments
ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory));
system(TextFormat("%s --frames 2 > %s.log", exName, exName));
// STEP 4: Load and validate log -> WARNINGS
char *exTestLog = LoadFileText(TextFormat("%s/%s/%s.log", exBasePath, exCategory, exName));
int exTestLogLinesCount = 0;
char **exTestLogLines = LoadTextLines(exTestLog, &exTestLogLinesCount);
UnloadFileText(exTestLog);
int issueCounter = false;
for (int i = 0; i < exTestLogLinesCount; i++)
for (int i = 0; i < exBuildListCount; i++)
{
if (TextFindIndex(exTestLogLines[i], "WARNING") >= 0)
// Get example name and category
memset(exName, 0, 64);
strcpy(exName, exBuildList[i]);
memset(exCategory, 0, 32);
strncpy(exCategory, exName, TextFindIndex(exName, "_"));
LOG("INFO: [%i/%i] Testing example: [%s]\n", i + 1, exBuildListCount, exName);
// Steps to follow
// STEP 1: Load example.c and replace required code to inject basic testing code: frames to run
// OPTION 1: Code injection required multiple changes for testing but it does not require raylib changes!
// OPTION 2: Support testing on raylib side: Args processing and events injection: SUPPORT_AUTOMATD_TESTING_SYSTEM, EVENTS_TESTING_MODE
// STEP 2: Build example (PLATFORM_DESKTOP)
// STEP 3: Run example with arguments: --frames 2 > <example>.out.log
// STEP 4: Load <example>.out.log and check "WARNING:" messages -> Some could maybe be ignored
// STEP 5: Generate report with results
// STEP 1: Load example and inject required code
// PROBLEM: As we need to modify the example source code for building, we need to keep a copy or something
// WARNING: If we make a copy and something fails, it could not be restored at the end
// PROBLEM: Trying to build a copy won't work because Makefile is setup to look for specific example on specific path -> No output dir config
// IDEA: Create directory for testing data -> It implies moving files and set working dir...
// SOLUTION: Make a copy of original file -> Modify original -> Build -> Rename to <example>.test.exe
FileCopy(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
char *srcText = LoadFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
static const char *mainReplaceText =
"#include <string.h>\n"
"#include <stdlib.h>\n"
"int main(int argc, char *argv[])\n{\n"
" int requestedTestFrames = 0;\n"
" int testFramesCount = 0;\n"
" if ((argc > 1) && (argc == 3) && (strcmp(argv[1], \"--frames\") != 0)) requestedTestFrames = atoi(argv[2]);\n";
char *srcTextUpdated[3] = { 0 };
srcTextUpdated[0] = TextReplace(srcText, "int main(void)\n{", mainReplaceText);
srcTextUpdated[1] = TextReplace(srcTextUpdated[0], "WindowShouldClose()", "WindowShouldClose() && (testFramesCount < requestedTestFrames)");
srcTextUpdated[2] = TextReplace(srcTextUpdated[1], "EndDrawing();", "EndDrawing(); testFramesCount++;");
UnloadFileText(srcText);
SaveFileText(TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName), srcTextUpdated[2]);
for (int i = 0; i < 3; i++) { MemFree(srcTextUpdated[i]); srcTextUpdated[i] = NULL; }
// STEP 2: Build example for DESKTOP platform
#if defined(_WIN32)
// Set required environment variables
//putenv(TextFormat("RAYLIB_DIR=%s\\..", exBasePath));
_putenv("PATH=%PATH%;C:\\raylib\\w64devkit\\bin");
//putenv("MAKE=mingw32-make");
//ChangeDirectory(exBasePath);
#endif
// Build example for PLATFORM_DESKTOP
#if defined(_WIN32)
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: Win32)\n", exName);
system(TextFormat("mingw32-make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
#else
LOG("INFO: [%s] Building example for PLATFORM_DESKTOP (Host: POSIX)\n", exName);
system(TextFormat("make -C %s %s/%s PLATFORM=PLATFORM_DESKTOP -B", exBasePath, exCategory, exName));
#endif
// Restore original source code before continue
FileCopy(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName),
TextFormat("%s/%s/%s.c", exBasePath, exCategory, exName));
FileRemove(TextFormat("%s/%s/%s.original.c", exBasePath, exCategory, exName));
// STEP 3: Run example with required arguments
// NOTE: Not easy to retrieve process return value from system(), it's platform dependant
ChangeDirectory(TextFormat("%s/%s", exBasePath, exCategory));
system(TextFormat("%s --frames 2 > %s.log", exName, exName));
// STEP 4: Load and validate log info
char *exTestLog = LoadFileText(TextFormat("%s/%s/%s.log", exBasePath, exCategory, exName));
int exTestLogLinesCount = 0;
char **exTestLogLines = LoadTextLines(exTestLog, &exTestLogLinesCount);
/*
TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
TESTING_FAIL_FONT = 1 << 5, // Font default initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
*/
if (TextFindIndex(exTestLog, "INFO: DISPLAY: Device initialized successfully") == -1) testing[i].status |= TESTING_FAIL_INIT;
if (TextFindIndex(exTestLog, "INFO: Window closed successfully") == -1) testing[i].status |= TESTING_FAIL_CLOSE;
if (TextFindIndex(exTestLog, "WARNING: FILEIO:") >= 0) testing[i].status |= TESTING_FAIL_ASSETS;
if (TextFindIndex(exTestLog, "INFO: RLGL: Default OpenGL state initialized successfully") == -1) testing[i].status |= TESTING_FAIL_RLGL;
if (TextFindIndex(exTestLog, "INFO: PLATFORM:") == -1) testing[i].status |= TESTING_FAIL_PLATFORM;
if (TextFindIndex(exTestLog, "INFO: FONT: Default font loaded successfully") == -1) testing[i].status |= TESTING_FAIL_FONT;
if (TextFindIndex(exTestLog, "INFO: TIMER: Target time per frame:") == -1) testing[i].status |= TESTING_FAIL_TIMER;
for (int k = 0, index = 0; k < exTestLogLinesCount; k++)
{
LOG("TEST: [%s] %s\n", exName, exTestLogLines[i]);
issueCounter++;
if (TextFindIndex(exTestLogLines[k], "WARNING") >= 0) testing[i].warnings++;
}
UnloadTextLines(exTestLogLines, exTestLogLinesCount);
UnloadFileText(exTestLog);
}
// STEP 5: Generate testing report/table with results (.md)
//-----------------------------------------------------------------------------------------------------
/*
Columns:
- [WARN] : WARNING messages count
- [INIT] : Initialization
- [CLOSE] : Closing
- [ASSETS] : Assets loading
- [RLGL] : OpenGL-wrapped initialization
- [PLAT] : Platform initialization
- [FONT] : Font default initialization
- [TIMER] : Timer initialization
| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |
|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|
| core_basic window | 0 | | | | | | | |
*/
LOG("INFO: [examples_testing.md] Generating examples testing report...\n");
char *report = (char *)RL_CALLOC(REXM_MAX_BUFFER_SIZE, 1);
int repIndex = 0;
repIndex += sprintf(report + repIndex, "# EXAMPLES COLLECTION - TESTING REPORT\n\n");
repIndex += sprintf(report + repIndex, "## Tested Platform: Windows\n\n");
repIndex += sprintf(report + repIndex, "```\nExample automated testing elements validated:\n");
repIndex += sprintf(report + repIndex, " - [WARN] : WARNING messages count\n");
repIndex += sprintf(report + repIndex, " - [INIT] : Initialization\n");
repIndex += sprintf(report + repIndex, " - [CLOSE] : Closing\n");
repIndex += sprintf(report + repIndex, " - [ASSETS] : Assets loading\n");
repIndex += sprintf(report + repIndex, " - [RLGL] : OpenGL-wrapped initialization\n");
repIndex += sprintf(report + repIndex, " - [PLAT] : Platform initialization\n");
repIndex += sprintf(report + repIndex, " - [FONT] : Font default initialization\n");
repIndex += sprintf(report + repIndex, " - [TIMER] : Timer initialization\n```\n");
repIndex += sprintf(report + repIndex, "| **EXAMPLE NAME** | [WARN] | [INIT] | [CLOSE] | [ASSETS] | [RLGL] | [PLAT] | [FONT] | [TIMER] |\n");
repIndex += sprintf(report + repIndex, "|:---------------------------------|:------:|:------:|:-------:|:--------:|:------:|:------:|:------:|:-------:|\n");
/*
TESTING_FAIL_INIT = 1 << 0, // Initialization (InitWindow()) -> "INFO: DISPLAY: Device initialized successfully"
TESTING_FAIL_CLOSE = 1 << 1, // Closing (CloseWindow()) -> "INFO: Window closed successfully"
TESTING_FAIL_ASSETS = 1 << 2, // Assets loading (WARNING: FILE:) -> "WARNING: FILEIO:"
TESTING_FAIL_RLGL = 1 << 3, // OpenGL-wrapped initialization -> "INFO: RLGL: Default OpenGL state initialized successfully"
TESTING_FAIL_PLATFORM = 1 << 4, // Platform initialization -> "INFO: PLATFORM: DESKTOP (GLFW - Win32): Initialized successfully"
TESTING_FAIL_FONT = 1 << 5, // Font default initialization -> "INFO: FONT: Default font loaded successfully (224 glyphs)"
TESTING_FAIL_TIMER = 1 << 6, // Timer initialization -> "INFO: TIMER: Target time per frame: 16.667 milliseconds"
*/
for (int i = 0; i < exBuildListCount; i++)
{
if (testing[i].status > 0)
{
repIndex += sprintf(report + repIndex, "| %-32s | %i | %s | %s | %s | %s | %s | %s | %s |\n",
exBuildList[i], testing[i].warnings,
(testing[i].status & TESTING_FAIL_INIT)? "" : "",
(testing[i].status & TESTING_FAIL_CLOSE)? "" : "",
(testing[i].status & TESTING_FAIL_ASSETS)? "" : "",
(testing[i].status & TESTING_FAIL_RLGL)? "" : "",
(testing[i].status & TESTING_FAIL_PLATFORM)? "" : "",
(testing[i].status & TESTING_FAIL_FONT)? "" : "",
(testing[i].status & TESTING_FAIL_TIMER)? "" : "");
}
}
UnloadTextLines(exTestLogLines, exTestLogLinesCount);
repIndex += sprintf(report + repIndex, "\n");
// STEP 5: Generate auto-test report
//if (issueCounter > 0)
SaveFileText(TextFormat("%s/../tools/rexm/reports/%s", exBasePath, "examples_testing_windows.md"), report);
RL_FREE(report);
//-----------------------------------------------------------------------------------------------------
} break;
default: // Help
@ -1667,13 +1689,13 @@ static int UpdateRequiredFiles(void)
//------------------------------------------------------------------------------------------------
LOG("INFO: Updating all examples metadata...\n");
int exListCount = 0;
rlExampleInfo *exList = LoadExamplesData(exCollectionFilePath, "ALL", true, &exListCount);
rlExampleInfo *exList = LoadExampleData("ALL", true, &exListCount);
for (int i = 0; i < exListCount; i++)
{
rlExampleInfo *info = &exList[i];
UpdateSourceMetadata(TextFormat("%s/%s/%s.c", exBasePath, info->category, info->name), info);
}
UnloadExamplesData(exList);
UnloadExampleData(exList);
//------------------------------------------------------------------------------------------------
// Edit: raylib/examples/Makefile --> Update from collection
@ -1694,12 +1716,12 @@ static int UpdateRequiredFiles(void)
mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat("%s = \\\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount - 1; x++) mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat(" %s/%s \\\n", exCollection[x].category, exCollection[x].name));
mkIndex += sprintf(mkTextUpdated + mkListStartIndex + mkIndex, TextFormat(" %s/%s\n\n", exCollection[exCollectionCount - 1].category, exCollection[exCollectionCount - 1].name));
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@ -1731,12 +1753,12 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("%s = \\\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount - 1; x++) mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat(" %s/%s \\\n", exCollection[x].category, exCollection[x].name));
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat(" %s/%s\n\n", exCollection[exCollectionCount - 1].category, exCollection[exCollectionCount - 1].name));
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
}
// Add examples individual targets, considering every example resources
@ -1757,13 +1779,13 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, TextFormat("# Compile %s examples\n", TextToUpper(exCategories[i])));
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], true, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData(exCategories[i], true, &exCollectionCount);
for (int x = 0; x < exCollectionCount; x++)
{
// Scan resources used in example to list
int resPathCount = 0;
char **resPaths = ScanExampleResources(TextFormat("%s/%s/%s.c", exBasePath, exCollection[x].category, exCollection[x].name), &resPathCount);
char **resPaths = LoadExampleResourcePaths(TextFormat("%s/%s/%s.c", exBasePath, exCollection[x].category, exCollection[x].name), &resPathCount);
if (resPathCount > 0)
{
@ -1816,10 +1838,10 @@ static int UpdateRequiredFiles(void)
mkwIndex += sprintf(mkwTextUpdated + mkwListStartIndex + mkwIndex, " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)\n\n");
}
ClearExampleResources(resPaths);
UnloadExampleResourcePaths(resPaths);
}
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@ -1845,8 +1867,8 @@ static int UpdateRequiredFiles(void)
memcpy(mdTextUpdated, mdText, mdListStartIndex);
int exCollectionFullCount = 0;
rlExampleInfo *exCollectionFull = LoadExamplesData(exCollectionFilePath, "ALL", false, &exCollectionFullCount);
UnloadExamplesData(exCollectionFull);
rlExampleInfo *exCollectionFull = LoadExampleData("ALL", false, &exCollectionFullCount);
UnloadExampleData(exCollectionFull);
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex, TextFormat("## EXAMPLES COLLECTION [TOTAL: %i]\n", exCollectionFullCount));
@ -1854,7 +1876,7 @@ static int UpdateRequiredFiles(void)
for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES; i++)
{
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData(exCategories[i], false, &exCollectionCount);
// Every category includes some introductory text, as it is quite short, just copying it here
if (i == 0) // "core"
@ -1925,7 +1947,7 @@ static int UpdateRequiredFiles(void)
starsText, exCollection[x].verCreated, exCollection[x].verUpdated, exCollection[x].author, exCollection[x].authorGitHub));
}
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
}
mdIndex += sprintf(mdTextUpdated + mdListStartIndex + mdIndex,
@ -1971,7 +1993,7 @@ static int UpdateRequiredFiles(void)
for (int i = 0; i < REXM_MAX_EXAMPLE_CATEGORIES - 1; i++)
{
int exCollectionCount = 0;
rlExampleInfo *exCollection = LoadExamplesData(exCollectionFilePath, exCategories[i], false, &exCollectionCount);
rlExampleInfo *exCollection = LoadExampleData(exCategories[i], false, &exCollectionCount);
for (int x = 0; x < exCollectionCount; x++)
{
for (int s = 0; s < 4; s++)
@ -1993,7 +2015,7 @@ static int UpdateRequiredFiles(void)
}
}
UnloadExamplesData(exCollection);
UnloadExampleData(exCollection);
}
// Add the remaining part of the original file
@ -2010,8 +2032,8 @@ static int UpdateRequiredFiles(void)
return result;
}
// Load examples collection information
static rlExampleInfo *LoadExamplesData(const char *fileName, const char *category, bool sort, int *exCount)
// Load examples information from collection data
static rlExampleInfo *LoadExampleData(const char *filter, bool sort, int *exCount)
{
#define MAX_EXAMPLES_INFO 256
@ -2019,7 +2041,8 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
int exCounter = 0;
*exCount = 0;
char *text = LoadFileText(fileName);
// Load main collection list file: "raylib/examples/examples_list.txt"
char *text = LoadFileText(exCollectionFilePath);
if (text != NULL)
{
@ -2041,18 +2064,25 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
int result = ParseExampleInfoLine(lines[i], &info);
if (result == 1) // Success on parsing
{
if (strcmp(category, "ALL") == 0)
if (strcmp(filter, "ALL") == 0)
{
// Add all examples to the list
memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
exCounter++;
}
else if (strcmp(info.category, category) == 0)
else if (strcmp(info.category, filter) == 0)
{
// Get only specific category examples
memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
exCounter++;
}
else if (strcmp(info.name, filter) == 0)
{
// Get only requested example
memcpy(&exInfo[exCounter], &info, sizeof(rlExampleInfo));
exCounter++;
break;
}
}
}
}
@ -2069,7 +2099,7 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
}
// Unload examples collection data
static void UnloadExamplesData(rlExampleInfo *exInfo)
static void UnloadExampleData(rlExampleInfo *exInfo)
{
RL_FREE(exInfo);
}
@ -2159,7 +2189,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
UnloadFileText(exText);
exInfo->resPaths = ScanExampleResources(exFileName, &exInfo->resCount);
exInfo->resPaths = LoadExampleResourcePaths(exFileName, &exInfo->resCount);
}
return exInfo;
@ -2168,7 +2198,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName)
// Unload example information
static void UnloadExampleInfo(rlExampleInfo *exInfo)
{
ClearExampleResources(exInfo->resPaths);
UnloadExampleResourcePaths(exInfo->resPaths);
RL_FREE(exInfo);
}
@ -2244,7 +2274,7 @@ static void SortExampleByName(rlExampleInfo *items, int count)
// but new examples could require other file extensions to be added,
// maybe it should look for '.xxx")' patterns instead
// TODO: WARNING: Some resources could require linked resources: .fnt --> .png, .mtl --> .png, .gltf --> .png, ...
static char **ScanExampleResources(const char *filePath, int *resPathCount)
static char **LoadExampleResourcePaths(const char *filePath, int *resPathCount)
{
#define REXM_MAX_RESOURCE_PATH_LEN 256
@ -2326,7 +2356,7 @@ static char **ScanExampleResources(const char *filePath, int *resPathCount)
}
// Clear resource paths scanned
static void ClearExampleResources(char **resPaths)
static void UnloadExampleResourcePaths(char **resPaths)
{
for (int i = 0; i < REXM_MAX_RESOURCE_PATHS; i++) RL_FREE(resPaths[i]);