@ -58,6 +58,10 @@
# define LOG(...)
# endif
# define REXM_MAX_BUFFER_SIZE (2*1024*1024) / / 2MB
# define REXM_MAX_RESOURCE_PATHS 256
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Types and Structures Definition
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -92,7 +96,10 @@ static const char *exBasePath = "C:/GitHub/raylib/examples";
static const char * exWebPath = " C:/GitHub/raylib.com/examples " ;
static const char * exTemplateFilePath = " C:/GitHub/raylib/examples/examples_template.c " ;
static const char * exTemplateScreenshot = " C:/GitHub/raylib/examples/examples_template.png " ;
static const char * exCollectionListPath = " C:/GitHub/raylib/examples/examples_list.txt " ;
static const char * exCollectionFilePath = " C:/GitHub/raylib/examples/examples_list.txt " ;
/ / const char * exBasePath = getenv ( " REXM_EXAMPLES_PATH " ) ;
/ / if ( ! exBasePath ) exBasePath = " default/path " ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Module specific functions declaration
@ -101,6 +108,7 @@ static int FileTextReplace(const char *fileName, const char *textLookUp, const c
static int FileCopy ( const char * srcPath , const char * dstPath ) ;
static int FileRename ( const char * fileName , const char * fileRename ) ;
static int FileRemove ( const char * fileName ) ;
static int FileMove ( const char * srcPath , const char * dstPath ) ;
/ / Update required files from examples collection
/ / UPDATES : Makefile , Makefile . Web , README . md , examples . js
@ -125,6 +133,12 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry);
/ / WARNING : items [ ] pointers are reorganized
static void SortExampleByName ( rlExampleInfo * items , int count ) ;
/ / Scan resource paths in example file
static char * * ScanExampleResources ( const char * filePath , int * resPathCount ) ;
/ / Clear resource paths scanned
static void ClearExampleResources ( char * * resPaths ) ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Program main entry point
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -226,7 +240,7 @@ int main(int argc, char *argv[])
else
{
/ / Verify example exists in collection to be removed
char * exColInfo = LoadFileText ( exCollectionList Path ) ;
char * exColInfo = LoadFileText ( exCollectionFile Path ) ;
if ( TextFindIndex ( exColInfo , argv [ 2 ] ) ! = - 1 ) / / Example in the collection
{
strcpy ( exName , argv [ 2 ] ) ; / / Register example name
@ -247,7 +261,7 @@ int main(int argc, char *argv[])
else
{
/ / Verify example exists in collection to be removed
char * exColInfo = LoadFileText ( exCollectionList Path ) ;
char * exColInfo = LoadFileText ( exCollectionFile Path ) ;
if ( TextFindIndex ( exColInfo , argv [ 2 ] ) ! = - 1 ) / / Example in the collection
{
strcpy ( exName , argv [ 2 ] ) ; / / Register filename for removal
@ -296,22 +310,73 @@ int main(int argc, char *argv[])
/ / Create : raylib / examples / < category > / < category > _example_name . png
FileCopy ( exTemplateScreenshot , TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exName ) ) ; / / WARNING : To be updated manually !
/ / Copy : raylib / examples / < category > / resources / . . . / / WARNING : To be updated manually !
/ / IDEA : Example to be added could be provided as a . zip , containing resources !
/ / TODO : Copy provided resources to respective directories
/ / Possible strategy :
/ / 1. Scan code file for resources paths - > Resources list
/ / Look for specific text : ' . png " '
/ / Look for full path , previous ' " '
/ / Be careful with shaders : ' . vs " ', '.fs " ' - > Reconstruct path manually ?
/ / 2. Verify paths : resource files exist
/ / 3. Copy files to required resource dir
/ / Copy : raylib / examples / < category > / resources / . . .
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Scan resources used in example to copy
int resPathCount = 0 ;
char * * resPaths = ScanExampleResources ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) , & resPathCount ) ;
if ( resPathCount > 0 )
{
for ( int r = 0 ; r < resPathCount ; r + + )
{
/ / WARNING : Special case to consider : shaders , resource paths could use conditions : " glsl%i "
/ / In this case , multiple resources are required : glsl100 , glsl120 , glsl330
if ( TextFindIndex ( resPaths [ r ] , " glsl%i " ) > - 1 )
{
int glslVer [ 3 ] = { 100 , 120 , 330 } ;
for ( int v = 0 ; v < 3 ; v + + )
{
char * resPathUpdated = TextReplace ( resPaths [ r ] , " glsl%i " , TextFormat ( " glsl%i " , glslVer [ v ] ) ) ;
LOG ( " INFO: Example resource required: %s \n " , resPathUpdated ) ;
if ( FileExists ( TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPathUpdated ) ) )
{
/ / Verify the resources are placed in " resources " directory
if ( TextFindIndex ( resPathUpdated , " resources/ " ) > 0 )
{
/ / NOTE : Look for resources in the path of the provided . c to be added
/ / To be copied to < category > / resources directory , extra dirs are automatically created if required
FileCopy ( TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPathUpdated ) ,
TextFormat ( " %s/%s/%s " , exBasePath , exCategory , resPathUpdated ) ) ;
}
else LOG ( " WARNING: Example resource must be placed in 'resources' directory next to .c file \n " ) ;
}
else LOG ( " WARNING: Example resource can not be found in: %s \n " , TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPathUpdated ) ) ;
RL_FREE ( resPathUpdated ) ;
}
}
else
{
LOG ( " INFO: Example resource required: %s \n " , resPaths [ r ] ) ;
if ( FileExists ( TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPaths [ r ] ) ) )
{
/ / Verify the resources are placed in " resources " directory
if ( TextFindIndex ( resPaths [ r ] , " resources/ " ) > 0 )
{
/ / NOTE : Look for resources in the path of the provided . c to be added
/ / To be copied to < category > / resources directory , extra dirs are automatically created if required
FileCopy ( TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPaths [ r ] ) ,
TextFormat ( " %s/%s/%s " , exBasePath , exCategory , resPaths [ r ] ) ) ;
}
else LOG ( " WARNING: Example resource must be placed in 'resources' directory next to .c file \n " ) ;
}
else LOG ( " WARNING: Example resource can not be found in: %s \n " , TextFormat ( " %s/%s " , GetDirectoryPath ( inFileName ) , resPaths [ r ] ) ) ;
}
}
}
ClearExampleResources ( resPaths ) ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Add example to the collection list , if not already there
/ / NOTE : Required format : shapes ; shapes_basic_shapes ; ⭐ ️ ☆ ☆ ☆ ; 1.0 ; 4.2 ; " Ray " ; @ raysan5
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
char * exColInfo = LoadFileText ( exCollectionListPath ) ;
char * exColInfo = LoadFileText ( exCollectionFile Path ) ;
if ( TextFindIndex ( exColInfo , exName ) = = - 1 ) / / Example not found
{
char * exColInfoUpdated = ( char * ) RL_CALLOC ( 2 * 1024 * 1024 , 1 ) ; / / Updated list copy , 2 MB
@ -348,7 +413,7 @@ int main(int argc, char *argv[])
memcpy ( exColInfoUpdated + catIndex + textWritenSize , exColInfo + catIndex , strlen ( exColInfo ) - catIndex ) ;
}
SaveFileText ( exCollectionList Path , exColInfoUpdated ) ;
SaveFileText ( exCollectionFile Path , exColInfoUpdated ) ;
RL_FREE ( exColInfoUpdated ) ;
}
else LOG ( " WARNING: ADD: Example is already on the collection \n " ) ;
@ -403,42 +468,49 @@ int main(int argc, char *argv[])
if ( strcmp ( exCategory , exRecategory ) = = 0 )
{
/ / Rename example on collection
FileTextReplace ( exCollectionList Path , TextFormat ( " %s;%s " , exCategory , exName ) ,
FileTextReplace ( exCollectionFile Path , TextFormat ( " %s;%s " , exCategory , exName ) ,
TextFormat ( " %s;%s " , exRecategory , exRename ) ) ;
/ / ">Rename all required files
/ / l">Edit : Rename example code and screenshot files . c and . png
rename ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) ,
TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exRename ) ) ;
rename ( TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exName ) ,
TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exRename ) ) ;
/ / Rename example on required files
/ / NOTE : Example resource files do not need to be changed . . .
/ / unless the example is moved from one caegory to another
/ / Edit : Rename example on required files
FileTextReplace ( TextFormat ( " %s/Makefile " , exBasePath ) , exName , exRename ) ;
FileTextReplace ( TextFormat ( " %s/Makefile.Web " , exBasePath ) , exName , exRename ) ;
FileTextReplace ( TextFormat ( " %s/README.md " , exBasePath ) , exName , exRename ) ;
FileTextReplace ( TextFormat ( " %s/../common/examples.js " , exWebPath ) , exName , exRename ) ;
/ / Rename example project and solution
/ / l">Edit : Rename example project and solution
rename ( TextFormat ( " %s/../projects/VS2022/examples/%s.vcxproj " , exBasePath , exName ) ,
TextFormat ( " %s/../projects/VS2022/examples/%s.vcxproj " , exBasePath , exRename ) ) ;
FileTextReplace ( TextFormat ( " %s/../projects/VS2022/raylib.sln " , exBasePath ) , exName , exRename ) ;
}
else
{
/ / Rename with change of category
/ / TODO : Reorder collection as required
FileTextReplace ( exCollectionList Path , TextFormat ( " %s;%s " , exCategory , exName ) ,
/ / l">WARNING : Rename with change of category
/ / TODO : Reorder collection to place renamed example at the end of category
FileTextReplace ( exCollectionFile Path , TextFormat ( " %s;%s " , exCategory , exName ) ,
TextFormat ( " %s;%s " , exRecategory , exRename ) ) ;
/ / Rename all required files
/ / TODO : Move example resources from < src_category > / resources to < dst_category > / resources
/ / WARNING : Resources can be shared with other examples in the category
/ / Edit : Rename example code file ( copy and remove )
FileCopy ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) ,
TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exRename ) ) ;
remove ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) ) ;
/ / Edit : Rename example screenshot file ( copy and remove )
FileCopy ( TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exName ) ,
TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exRename ) ) ;
remove ( TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exName ) ) ;
/ / Edit : Update required files : Makefile , Makefile . Web , README . md , examples . js
UpdateRequiredFiles ( ) ;
}
@ -468,7 +540,7 @@ int main(int argc, char *argv[])
{
/ / Remove example from collection for files update
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
char * exColInfo = LoadFileText ( exCollectionList Path ) ;
char * exColInfo = LoadFileText ( exCollectionFile Path ) ;
int exIndex = TextFindIndex ( exColInfo , TextFormat ( " %s;%s " , exCategory , exName ) ) ;
if ( exIndex > 0 ) / / Example found
{
@ -480,21 +552,53 @@ int main(int argc, char *argv[])
/ / Remove line and copy the rest next
memcpy ( exColInfoUpdated + exIndex , exColInfo + exIndex + lineLen + 1 , strlen ( exColInfo ) - exIndex - lineLen ) ;
SaveFileText ( exCollectionList Path , exColInfoUpdated ) ;
SaveFileText ( exCollectionFile Path , exColInfoUpdated ) ;
RL_FREE ( exColInfoUpdated ) ;
}
else LOG ( " WARNING: REMOVE: Example not found in the collection \n " ) ;
UnloadFileText ( exColInfo ) ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Remove : raylib / examples / < category > / resources / . .
/ / WARNING : Some of those resources could be used by other examples ,
/ / just leave this process to manual update for now !
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*
/ / Scan resources used in example to be removed
int resPathCount = 0 ;
char * * resPaths = ScanExampleResources ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) , & resPathCount ) ;
if ( resPathCount > 0 )
{
for ( int r = 0 ; r < resPathCount ; r + + )
{
/ / WARNING : Special case to consider : shaders , resource paths could use conditions : " glsl%i "
/ / In this case , multiple resources are required : glsl100 , glsl120 , glsl330
if ( TextFindIndex ( resPaths [ r ] , " glsl%i " ) > - 1 )
{
int glslVer [ 3 ] = { 100 , 120 , 330 } ;
for ( int v = 0 ; v < 3 ; v + + )
{
char * resPathUpdated = TextReplace ( resPaths [ r ] , " glsl%i " , TextFormat ( " glsl%i " , glslVer [ v ] ) ) ;
remove ( TextFormat ( " %s/%s/%s " , exBasePath , exCategory , resPathUpdated ) ) ;
RL_FREE ( resPathUpdated ) ;
}
}
else remove ( TextFormat ( " %s/%s/%s " , exBasePath , exCategory , resPaths [ r ] ) ) ;
}
}
ClearExampleResources ( resPaths ) ;
*/
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Remove : raylib / examples / < category > / < category > _example_name . c
/ / Remove : raylib / examples / < category > / < category > _example_name . png
remove ( TextFormat ( " %s/%s/%s.c " , exBasePath , exCategory , exName ) ) ;
remove ( TextFormat ( " %s/%s/%s.png " , exBasePath , exCategory , exName ) ) ;
/ / TODO : Remove : raylib / examples / < category > / resources / . .
/ / Get list of resources from Makefile . Web or examples ResourcesScan ( )
/ / Edit : Update required files : Makefile , Makefile . Web , README . md , examples . js
UpdateRequiredFiles ( ) ;
/ / Remove : raylib / projects / VS2022 / examples / < category > _example_name . vcxproj
@ -518,21 +622,29 @@ int main(int argc, char *argv[])
} break ;
case 5 : / / Validate
{
/ / TODO : Validate examples collection against [ examples_list . txt ]
/ / Validate : raylib / examples / < category > / < category > _example_name . c
/ / Validate : raylib / examples / < category > / < category > _example_name . png
/ / Validate : raylib / examples / < category > / resources / . . - > Not possible for now . . .
/ / Validate : raylib / examples / Makefile
/ / Validate : raylib / examples / Makefile . Web
/ / Validate : raylib / examples / README . md
/ / Validate : raylib / projects / VS2022 / examples / < category > _example_name . vcxproj
/ / Validate : raylib / projects / VS2022 / raylib . sln
/ / Validate : raylib . com / common / examples . js
/ / Validate : raylib . com / examples / < category > / < category > _example_name . html
/ / Validate : raylib . com / examples / < category > / < category > _example_name . data
/ / Validate : raylib . com / examples / < category > / < category > _example_name . wasm
/ / Validate : raylib . com / examples / < category > / < category > _example_name . js
/ / TODO : Validate examples in collection list [ examples_list . txt ] - > Source of truth !
/ / Validate : raylib / examples / < category > / < category > _example_name . c - > File exists ?
/ / Validate : raylib / examples / < category > / < category > _example_name . png - > File exists ?
/ / Validate : raylib / examples / < category > / resources / . . - > Example resources available ?
/ / Validate : raylib / examples / Makefile - > Example listed ?
/ / Validate : raylib / examples / Makefile . Web - > Example listed ?
/ / Validate : raylib / examples / README . md - > Example listed ?
/ / Validate : raylib / projects / VS2022 / examples / < category > _example_name . vcxproj - > File exists ?
/ / Validate : raylib / projects / VS2022 / raylib . sln - > Example listed ?
/ / Validate : raylib . com / common / examples . js - > Example listed ?
/ / Validate : raylib . com / examples / < category > / < category > _example_name . html - > File exists ?
/ / Validate : raylib . com / examples / < category > / < category > _example_name . data - > File exists ?
/ / Validate : raylib . com / examples / < category > / < category > _example_name . wasm - > File exists ?
/ / Validate : raylib . com / examples / < category > / < category > _example_name . js - > File exists ?
/ / Additional validation elements
/ / Validate : Example naming conventions : < category > / < category > _example_name
/ / Validate : Duplicate entries in collection list
/ / Validate : Example info ( stars , author , github ) missmatches with example content
/ / After validation , update required files for consistency
/ / Update files : Makefile , Makefile . Web , README . md , examples . js
UpdateRequiredFiles ( ) ;
} break ;
default : / / Help
@ -599,13 +711,13 @@ static int UpdateRequiredFiles(void)
{
mkIndex + = sprintf ( mkTextUpdated + mkListStartIndex + mkIndex , TextFormat ( " %s = \\ \n " , TextToUpper ( exCategories [ i ] ) ) ) ;
int exCount = 0 ;
rlExampleInfo * exCatList = LoadExamplesData ( exCollectionList Path , exCategories [ i ] , true , & exCount ) ;
int exCollectionCo unt = 0 ;
rlExampleInfo * exCollection = LoadExamplesData ( exCollectionFile Path , exCategories [ i ] , true , & exCollection Count ) ;
for ( int x = 0 ; x < exCount - 1 ; x + + ) mkIndex + = sprintf ( mkTextUpdated + mkListStartIndex + mkIndex , TextFormat ( " %s/%s \\ \n " , exCatList [ x ] . category , exCatList [ x ] . name ) ) ;
mkIndex + = sprintf ( mkTextUpdated + mkListStartIndex + mkIndex , TextFormat ( " %s/%s \n \n " , exCatList [ ex Count - 1 ] . category , exCatList [ ex Count - 1 ] . name ) ) ;
for ( int x = 0 ; x < exCollectionCo unt - 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 [ exCollection Count - 1 ] . category , exCollection [ exCollection Count - 1 ] . name ) ) ;
UnloadExamplesData ( exCatList ) ;
UnloadExamplesData ( exCollection ) ;
}
/ / Add the remaining part of the original file
@ -618,6 +730,7 @@ static int UpdateRequiredFiles(void)
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / Edit : raylib / examples / Makefile . Web - - > Update from collection
/ / NOTE : We avoid the " others " category on web building
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
char * mkwText = LoadFileText ( TextFormat ( " %s/Makefile.Web " , exBasePath ) ) ;
char * mkwTextUpdated = ( char * ) RL_CALLOC ( 2 * 1024 * 1024 , 1 ) ; / / Updated Makefile copy , 2 MB
@ -629,24 +742,106 @@ static int UpdateRequiredFiles(void)
memcpy ( mkwTextUpdated , mkwText , mkwListStartIndex ) ;
mkwIndex = sprintf ( mkwTextUpdated + mkwListStartIndex , " #EXAMPLES_LIST_START \n " ) ;
for ( int i = 0 ; i < MAX_EXAMPLE_CATEGORIES ; i + + )
/ / NOTE : We avoid the " others " category on web building
for ( int i = 0 ; i < MAX_EXAMPLE_CATEGORIES - 1 ; i + + )
{
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , TextFormat ( " %s = \\ \n " , TextToUpper ( exCategories [ i ] ) ) ) ;
int exCount = 0 ;
rlExampleInfo * exCatList = LoadExamplesData ( exCollectionList Path , exCategories [ i ] , true , & exCount ) ;
int exCollectionCo unt = 0 ;
rlExampleInfo * exCollection = LoadExamplesData ( exCollectionFile Path , exCategories [ i ] , true , & exCollection Count ) ;
for ( int x = 0 ; x < exCount - 1 ; x + + ) mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , TextFormat ( " %s/%s \\ \n " , exCatList [ x ] . category , exCatList [ x ] . name ) ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , TextFormat ( " %s/%s \n \n " , exCatList [ ex Count - 1 ] . category , exCatList [ ex Count - 1 ] . name ) ) ;
for ( int x = 0 ; x < exCollectionCo unt - 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 [ exCollection Count - 1 ] . category , exCollection [ exCollection Count - 1 ] . name ) ) ;
UnloadExamplesData ( exCatList ) ;
UnloadExamplesData ( exCollection ) ;
}
/ / Add examples individual targets , considering every example resources
/ / Some required makefile code . . .
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " # Default target entry \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " all: $(CORE) $(SHAPES) $(TEXT) $(TEXTURES) $(MODELS) $(SHADERS) $(AUDIO) \n \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " core: $(CORE) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " shapes: $(SHAPES) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " textures: $(TEXTURES) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " text: $(TEXT) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " models: $(MODELS) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " shaders: $(SHADERS) \n " ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " audio: $(AUDIO) \n \n " ) ;
/ / NOTE : We avoid the " others " category on web building
for ( int i = 0 ; i < MAX_EXAMPLE_CATEGORIES - 1 ; i + + )
{
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , TextFormat ( " # Compile %s examples \n " , TextToUpper ( exCategories [ i ] ) ) ) ;
int exCollectionCount = 0 ;
rlExampleInfo * exCollection = LoadExamplesData ( exCollectionFilePath , 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 ) ;
if ( resPathCount > 0 )
{
/*
/ / WARNING : Compilation line starts with [ TAB ]
shaders / shaders_vertex_displacement : shaders / shaders_vertex_displacement . c
$ ( CC ) - o $ @ $ ( EXT ) $ < $ ( CFLAGS ) $ ( INCLUDE_PATHS ) $ ( LDFLAGS ) $ ( LDLIBS ) - D $ ( PLATFORM ) \
- - preload - file shaders / resources / shaders / glsl100 / vertex_displacement . vs @ resources / shaders / glsl100 / vertex_displacement . vs \
- - preload - file shaders / resources / shaders / glsl330 / vertex_displacement . vs @ resources / shaders / glsl330 / vertex_displacement . vs \
- - preload - file shaders / resources / shaders / glsl100 / vertex_displacement . fs @ resources / shaders / glsl100 / vertex_displacement . fs \
- - preload - file shaders / resources / shaders / glsl330 / vertex_displacement . fs @ resources / shaders / glsl330 / vertex_displacement . fs
*/
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex ,
TextFormat ( " %s/%s: %s/%s.c \n " , exCollection [ x ] . category , exCollection [ x ] . name , exCollection [ x ] . category , exCollection [ x ] . name ) ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \\ \n " ) ;
for ( int r = 0 ; r < resPathCount ; r + + )
{
/ / WARNING : Special case to consider : shaders , resource paths could use conditions : " glsl%i "
/ / In this case , we focus on web building for : glsl100
if ( TextFindIndex ( resPaths [ r ] , " glsl%i " ) > - 1 )
{
char * resPathUpdated = TextReplace ( resPaths [ r ] , " glsl%i " , " glsl100 " ) ;
memset ( resPaths [ r ] , 0 , 256 ) ;
strcpy ( resPaths [ r ] , resPathUpdated ) ;
RL_FREE ( resPathUpdated ) ;
}
if ( r < ( resPathCount - 1 ) )
{
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex ,
TextFormat ( " --preload-file %s/%s@%s \\ \n " , exCollection [ x ] . category , resPaths [ r ] , resPaths [ r ] ) ) ;
}
else
{
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex ,
TextFormat ( " --preload-file %s/%s@%s \n \n " , exCollection [ x ] . category , resPaths [ r ] , resPaths [ r ] ) ) ;
}
}
}
else / / Example does not require resources
{
/*
/ / WARNING : Compilation line starts with [ TAB ]
core / core_2d_camera : core / core_2d_camera . c
$ ( CC ) - o $ @ $ ( EXT ) $ < $ ( CFLAGS ) $ ( INCLUDE_PATHS ) $ ( LDFLAGS ) $ ( LDLIBS ) - D $ ( PLATFORM )
*/
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex ,
TextFormat ( " %s/%s: %s/%s.c \n " , exCollection [ x ] . category , exCollection [ x ] . name , exCollection [ x ] . category , exCollection [ x ] . name ) ) ;
mkwIndex + = sprintf ( mkwTextUpdated + mkwListStartIndex + mkwIndex , " $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \n \n " ) ;
}
ClearExampleResources ( resPaths ) ;
}
UnloadExamplesData ( exCollection ) ;
}
/ / Add the remaining part of the original file
memcpy ( mkwTextUpdated + mkwListStartIndex + mkwIndex - 1 , mkwText + mkwListEndIndex , strlen ( mkwText ) - mkwListEndIndex ) ;
/ / TODO : Add new example target , considering resources
/ / Save updated file
SaveFileText ( TextFormat ( " %s/Makefile.Web " , exBasePath ) , mkwTextUpdated ) ;
UnloadFileText ( mkwText ) ;
@ -660,87 +855,100 @@ static int UpdateRequiredFiles(void)
char * mdText = LoadFileText ( TextFormat ( " %s/README.md " , exBasePath ) ) ;
char * mdTextUpdated = ( char * ) RL_CALLOC ( 2 * 1024 * 1024 , 1 ) ; / / Updated examples . js copy , 2 MB
int mdListStartIndex = TextFindIndex ( mdText , " | 01 | " ) ;
int mdListStartIndex = TextFindIndex ( mdText , " ## EXAMPLES COLLECTION " ) ;
int mdIndex = 0 ;
memcpy ( mdTextUpdated , mdText , mdListStartIndex ) ;
int exCollectionFullCount = 0 ;
rlExampleInfo * exCollectionFull = LoadExamplesData ( exCollectionFilePath , " ALL " , false , & exCollectionFullCount ) ;
UnloadExamplesData ( exCollectionFull ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , TextFormat ( " ## EXAMPLES COLLECTION [TOTAL: %i] \n \n " , exCollectionFullCount ) ) ;
/ / NOTE : We keep a global examples counter
for ( int i = 0 , catCount = 0 , gCount = 0 ; i < MAX_EXAMPLE_CATEGORIES ; i + + )
for ( int i = 0 ; i < MAX_EXAMPLE_CATEGORIES ; i + + )
{
int exCollectionCount = 0 ;
rlExampleInfo * exCollection = LoadExamplesData ( exCollectionFilePath , exCategories [ i ] , false , & exCollectionCount ) ;
/ / Every category includes some introductory text , as it is quite short , just copying it here
/ / NOTE : " core " text already placed in the file
if ( i = = 1 ) / / " shapes "
if ( i = = 0 ) / / " core "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , TextFormat ( " \n ### category: core [%i] \n \n " , exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality. \n \n " ) ;
}
else if ( i = = 1 ) / / " shapes "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: shapes \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: shapes [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib shapes drawing functionality, provided by raylib [shapes](../src/rshapes.c) module. \n \n " ) ;
}
else if ( i = = 2 ) / / " textures "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: textures \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: textures [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib textures functionality, including image/textures loading/generation and drawing, provided by raylib [textures](../src/rtextures.c) module. \n \n " ) ;
}
else if ( i = = 3 ) / / " text "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: text \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: text [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib text functionality, including sprite fonts loading/generation and text drawing, provided by raylib [text](../src/rtext.c) module. \n \n " ) ;
}
else if ( i = = 4 ) / / " models "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: models \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: models [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib models functionality, including models loading/generation and drawing, provided by raylib [models](../src/rmodels.c) module. \n \n " ) ;
}
else if ( i = = 5 ) / / " shaders "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: shaders \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: shaders [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module. \n \n " ) ;
}
else if ( i = = 6 ) / / " audio "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: audio \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: audio [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples using raylib audio functionality, including sound/music loading and playing. This functionality is provided by raylib [raudio](../src/raudio.c) module. Note this module can be used standalone independently of raylib. \n \n " ) ;
}
else if ( i = = 7 ) / / " others "
{
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " \n ### category: others \n \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , n">TextFormat ( " \n ### category: others [%i] \n \n ", exCollectionCount ) ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Examples showing raylib misc functionality that does not fit in other categories, like standalone modules usage or examples integrating external libraries. \n \n " ) ;
}
if ( i > 0 )
{
/ / Table header required
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " | ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer | \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " |----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| \n " ) ;
}
/ / Table header required
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer | \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex , " |-----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------| \n " ) ;
rlExampleInfo * exCatList = LoadExamplesData ( exCollectionListPath , exCategories [ i ] , false , & catCount ) ;
for ( int x = 0 ; x < catCount ; x + + )
for ( int x = 0 ; x < exCollectionCount ; x + + )
{
char stars [ 16 ] = { 0 } ;
for ( int s = 0 ; s < 4 ; s + + )
{
if ( s < exCatList [ x ] . stars ) strcpy ( stars + 3 * s , " ⭐️ " ) ;
if ( s < exCollection [ x ] . stars ) strcpy ( stars + 3 * s , " ⭐️ " ) ;
else strcpy ( stars + 3 * s , " ☆ " ) ;
}
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
TextFormat ( " | %02i | [%s](%s/%s.c) | <img src= \" %s/%s.png \" alt= \" %s \" width= \" 80 \" > | %s | %.1f | %.1f | [%s](https://github.com/%s) | \n " ,
gCount + 1 , exCatList [ x ] . name , exCatList [ x ] . category , exCatList [ x ] . name , exCatList [ x ] . category , exCatList [ x ] . name , exCatList [ x ] . name ,
stars , exCatList [ x ] . verCreated , exCatList [ x ] . verUpdated , exCatList [ x ] . author , exCatList [ x ] . authorGitHub + 1 ) ) ;
gCount + + ;
TextFormat ( " | [%s](%s/%s.c) | <img src= \" %s/%s.png \" alt= \" %s \" width= \" 80 \" > | %s | %.1f | %.1f | [%s](https://github.com/%s) | \n " ,
exCollection [ x ] . name , exCollection [ x ] . category , exCollection [ x ] . name , exCollection [ x ] . category , exCollection [ x ] . name , exCollection [ x ] . name ,
stars , exCollection [ x ] . verCreated , exCollection [ x ] . verUpdated , exCollection [ x ] . author , exCollection [ x ] . authorGitHub + 1 ) ) ;
}
UnloadExamplesData ( exCatList ) ;
UnloadExamplesData ( exCollection ) ;
}
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" \n Some example missing? As always, contributions are welcome, feel free to send new examples! \n " ) ;
mdIndex + = sprintf ( mdTextUpdated + mdListStartIndex + mdIndex ,
" Here is an[examples template](examples_template.c) with instructions to start with! \n " ) ;
/ / Save updated file
SaveFileText ( TextFormat ( " %s/README.md " , exBasePath ) , mdTextUpdated ) ;
UnloadFileText ( mdText ) ;
@ -762,32 +970,33 @@ static int UpdateRequiredFiles(void)
jsIndex + = sprintf ( jsTextUpdated + jsListStartIndex + jsIndex , " var exampleData = [ \n " ) ;
/ / NOTE : We avoid " others " category
for ( int i = 0 , exCount = 0 ; i < MAX_EXAMPLE_CATEGORIES - 1 ; i + + )
for ( int i = 0 ; i < MAX_EXAMPLE_CATEGORIES - 1 ; i + + )
{
rlExampleInfo * exCatList = LoadExamplesData ( exCollectionListPath , exCategories [ i ] , false , & exCount ) ;
for ( int x = 0 ; x < exCount ; x + + )
int exCollectionCount = 0 ;
rlExampleInfo * exCollection = LoadExamplesData ( exCollectionFilePath , exCategories [ i ] , false , & exCollectionCount ) ;
for ( int x = 0 ; x < exCollectionCount ; x + + )
{
char stars [ 16 ] = { 0 } ;
for ( int s = 0 ; s < 4 ; s + + )
{
if ( s < exCatList [ x ] . stars ) strcpy ( stars + 3 * s , " ⭐️ " ) ;
if ( s < exCollection [ x ] . stars ) strcpy ( stars + 3 * s , " ⭐️ " ) ;
else strcpy ( stars + 3 * s , " ☆ " ) ;
}
if ( ( i = = 6 ) & & ( x = = ( exCount - 1 ) ) )
if ( ( i = = 6 ) & & ( x = = ( exCollectionCo unt - 1 ) ) )
{
/ / NOTE : Last line to add , special case to consider
jsIndex + = sprintf ( jsTextUpdated + jsListStartIndex + jsIndex ,
TextFormat ( " exampleEntry('%s', '%s', '%s')]; \n " , stars , exCatList [ x ] . category , exCatList [ x ] . name + strlen ( exCatList [ x ] . category ) + 1 ) ) ;
TextFormat ( " exampleEntry('%s', '%s', '%s')]; \n " , stars , exCollection [ x ] . category , exCollection [ x ] . name + strlen ( exCollection [ x ] . category ) + 1 ) ) ;
}
else
{
jsIndex + = sprintf ( jsTextUpdated + jsListStartIndex + jsIndex ,
TextFormat ( " exampleEntry('%s', '%s', '%s'), \n " , stars , exCatList [ x ] . category , exCatList [ x ] . name + strlen ( exCatList [ x ] . category ) + 1 ) ) ;
TextFormat ( " exampleEntry('%s', '%s', '%s'), \n " , stars , exCollection [ x ] . category , exCollection [ x ] . name + strlen ( exCollection [ x ] . category ) + 1 ) ) ;
}
}
UnloadExamplesData ( exCatList ) ;
UnloadExamplesData ( exCollection ) ;
}
/ / Add the remaining part of the original file
@ -816,7 +1025,7 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
if ( text ! = NULL )
{
int lineCount = 0 ;
">const char * * lines = LoadTextLines ( text , & lineCount ) ;
char * * lines = LoadTextLines ( text , & lineCount ) ;
for ( int i = 0 ; i < lineCount ; i + + )
{
@ -849,6 +1058,7 @@ static rlExampleInfo *LoadExamplesData(const char *fileName, const char *categor
}
}
UnloadTextLines ( lines ) ;
UnloadFileText ( text ) ;
}
@ -925,6 +1135,21 @@ static int FileRemove(const char *fileName)
return result ;
}
/ / Move file from one directory to another
/ / NOTE : If dst directories do not exists they are created
static int FileMove ( const char * srcPath , const char * dstPath )
{
int result = 0 ;
if ( FileExists ( srcPath ) )
{
FileCopy ( srcPath , dstPath ) ;
remove ( srcPath ) ;
}
return result ;
}
/ / Load text lines
static char * * LoadTextLines ( const char * text , int * count )
{
@ -1018,3 +1243,78 @@ static void SortExampleByName(rlExampleInfo *items, int count)
{
qsort ( items , count , sizeof ( rlExampleInfo ) , rlExampleInfoCompare ) ;
}
/ / Scan resource paths in example file
/ / WARNING : Supported resource file extensions is hardcoded by used file types
/ / but new examples could require other file extensions to be added ,
/ / maybe it should look for ' . xxx " )' patterns instead
static char * * ScanExampleResources ( const char * filePath , int * resPathCount )
{
# define REXM_MAX_RESOURCE_PATH_LEN 256
char * * paths = ( char * * ) RL_CALLOC ( REXM_MAX_RESOURCE_PATHS , sizeof ( char * * ) ) ;
for ( int i = 0 ; i < REXM_MAX_RESOURCE_PATHS ; i + + ) paths [ i ] = ( char * ) RL_CALLOC ( REXM_MAX_RESOURCE_PATH_LEN , sizeof ( char ) ) ;
int resCounter = 0 ;
char * code = LoadFileText ( filePath ) ;
if ( code ! = NULL )
{
/ / Resources extensions to check
const char * exts [ ] = { " .png " , " .bmp " , " .jpg " , " .qoi " , " .gif " , " .raw " , " .hdr " , " .ttf " , " .fnt " , " .wav " , " .ogg " , " .mp3 " , " .flac " , " .mod " , " .qoa " , " .qoa " , " .obj " , " .iqm " , " .glb " , " .m3d " , " .vox " , " .vs " , " .fs " , " .txt " } ;
const int extCount = sizeof ( exts ) / sizeof ( char * ) ;
char * ptr = code ;
while ( ( ptr = strchr ( ptr , ' " ' ) ) ! = NULL )
{
char * start = ptr + 1 ;
char * end = strchr ( start , ' " ' ) ;
if ( ! end ) break ;
int len = end - start ;
if ( ( len > 0 ) & & ( len < REXM_MAX_RESOURCE_PATH_LEN ) )
{
char buffer [ REXM_MAX_RESOURCE_PATH_LEN ] = { 0 } ;
strncpy ( buffer , start , len ) ;
buffer [ len ] = ' \0 ' ;
/ / Check for known extensions
for ( int i = 0 ; i < extCount ; i + + )
{
if ( IsFileExtension ( buffer , exts [ i ] ) )
{
/ / Avoid duplicates
bool found = false ;
for ( int j = 0 ; j < resCounter ; j + + )
{
if ( TextIsEqual ( paths [ j ] , buffer ) ) { found = true ; break ; }
}
if ( ! found & & ( resCounter < REXM_MAX_RESOURCE_PATHS ) )
{
strcpy ( paths [ resCounter ] , buffer ) ;
resCounter + + ;
}
break ;
}
}
}
ptr = end + 1 ;
}
UnloadFileText ( code ) ;
}
* resPathCount = resCounter ;
return paths ;
}
/ / Clear resource paths scanned
static void ClearExampleResources ( char * * resPaths )
{
for ( int i = 0 ; i < REXM_MAX_RESOURCE_PATHS ; i + + ) RL_FREE ( resPaths [ i ] ) ;
RL_FREE ( resPaths ) ;
}