Merge pull request #51 from Ed94/dev

This commit is contained in:
Edward R. Gonzalez 2023-10-25 23:47:29 -04:00 committed by GitHub
commit 9bd6dac783
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 13151 additions and 358 deletions

22
.gitignore vendored
View File

@ -16,25 +16,15 @@
gencpp.hpp gencpp.hpp
gencpp.cpp gencpp.cpp
# Build results **/*.lib
[Dd]ebug/ **/*.pdb
[Dd]ebugPublic/ **/*.exe
[Rr]elease/ **/*.dll
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
vc140.pdb
release/**
# Unreal # Unreal
**/Unreal/*.h **/Unreal/*.h
**/Unreal/*.cpp **/Unreal/*.cpp
! **/Unreal/validate.unreal.cpp ! **/Unreal/validate.unreal.cpp
project/auxillary/vis_ast/dependencies/temp

View File

@ -12,7 +12,8 @@
"GEN_TIME", "GEN_TIME",
"GEN_IMPLEMENTATION", "GEN_IMPLEMENTATION",
// "GEN_DONT_USE_NAMESPACE" // "GEN_DONT_USE_NAMESPACE"
"GEN_INTELLISENSE_DIRECTIVES" "GEN_INTELLISENSE_DIRECTIVES",
"INTELLISENSE_DIRECTIVES"
], ],
"windowsSdkVersion": "10.0.19041.0", "windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe", "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe",
@ -31,7 +32,8 @@
"GEN_TIME", "GEN_TIME",
"GEN_IMPLEMENTATION", "GEN_IMPLEMENTATION",
// "GEN_DONT_USE_NAMESPACE" // "GEN_DONT_USE_NAMESPACE"
"GEN_INTELLISENSE_DIRECTIVES" "GEN_INTELLISENSE_DIRECTIVES",
"INTELLISENSE_DIRECTIVES"
], ],
"windowsSdkVersion": "10.0.19041.0", "windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe", "compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe",

9
.vscode/launch.json vendored
View File

@ -40,6 +40,15 @@
"args": [], "args": [],
"cwd": "${workspaceFolder}/singleheader/", "cwd": "${workspaceFolder}/singleheader/",
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
},
{
"type": "cppvsdbg",
"request": "launch",
"name": "Debug raylib refactor vsdbg",
"program": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/raylib/build/raylib_refactor.exe",
"args": [],
"cwd": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/temp/raylib-master/src/",
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
} }
] ]
} }

View File

@ -28,7 +28,9 @@
"functional": "cpp", "functional": "cpp",
"vector": "cpp", "vector": "cpp",
"list": "cpp", "list": "cpp",
"xhash": "cpp" "xhash": "cpp",
"glfw3.h": "c",
"stdbool.h": "c"
}, },
"C_Cpp.intelliSenseEngineFallback": "disabled", "C_Cpp.intelliSenseEngineFallback": "disabled",
"mesonbuild.configureOnOpen": true, "mesonbuild.configureOnOpen": true,

View File

@ -0,0 +1,106 @@
Clear-Host
$path_root = git rev-parse --show-toplevel
$path_scripts = Join-Path $path_root 'scripts'
$target_arch = Join-Path $path_scripts 'helpers/target_arch.psm1'
$devshell = Join-Path $path_scripts 'helpers/devshell.ps1'
$format_cpp = Join-Path $path_scripts 'helpers/format_cpp.psm1'
$incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1'
$vendor_toolchain = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1'
$path_project = Join-Path $path_root 'project'
$path_aux = Join-Path $path_project 'auxillary'
$path_vis_root = Join-Path $path_aux 'vis_ast'
$path_binaries = Join-Path $path_vis_root 'binaries'
$path_build = Join-Path $path_vis_root 'build'
$path_code = Join-Path $path_vis_root 'code'
$path_win32 = Join-Path $path_code 'win32'
Import-Module $target_arch
Import-Module $format_cpp
#region Arguments
$vendor = $null
$optimize = $null
$debug = $null
$analysis = $false
$dev = $false
$verbose = $null
$platform = $null
$module_specified = $false
[array] $vendors = @( "clang", "msvc" )
# This is a really lazy way of parsing the args, could use actual params down the line...
if ( $args ) { $args | ForEach-Object {
switch ($_){
{ $_ -in $vendors } { $vendor = $_; break }
"optimize" { $optimize = $true }
"debug" { $debug = $true }
"analysis" { $analysis = $true }
"dev" { $dev = $true }
"verbose" { $verbose = $true }
"platform" { $platform = $true; $module_specified = $true }
}
}}
#endregion Argument
if ( -not $module_specified )
{
$platform = $true
}
# Load up toolchain configuraion
. $vendor_toolchain
. $incremental_checks
write-host "Building Vis AST with $vendor"
if ( (Test-Path $path_build) -eq $false ) {
New-Item $path_build -ItemType Directory
}
if ( (Test-Path $path_binaries) -eq $false ) {
New-Item $path_binaries -ItemType Directory
}
$includes = @(
$paht_code
)
# Microsoft
$lib_gdi32 = 'Gdi32.lib'
$lib_xinput = 'Xinput.lib'
$lib_user32 = 'User32.lib'
$lib_winmm = 'Winmm.lib'
$stack_size = 1024 * 1024 * 4
$compiler_args = @(
($flag_define + 'UNICODE'),
($flag_define + '_UNICODE')
( $flag_define + 'INTELLISENSE_DIRECTIVES=0'),
# ($flag_set_stack_size + $stack_size)
$flag_wall
$flag_warnings_as_errors
$flag_optimize_intrinsics
)
if ( $dev ) {
$compiler_args += ( $flag_define + 'Build_Development=1' )
}
else {
$compiler_args += ( $flag_define + 'Build_Development=0' )
}
$linker_args = @(
$flag_link_win_subsystem_windows,
$flag_link_optiiize_references
)
$unit = join-path $path_code 'vis_ast_windows.cpp'
$executable = join-path $path_binaries 'vis_ast.exe'
$build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable

View File

View File

@ -0,0 +1,24 @@
#if INTELLISENSE_DIRECTIVES
#include "vendor/compiler.hpp"
#endif
#define global static // Global variables
#define internal static // Internal linkage
#define local_persist static // Local Persisting variables
#define api_c extern "C"
#define ccast( type, value ) ( const_cast< type >( (value) ) )
#define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) )
#define rcast( type, value ) reinterpret_cast< type >( value )
#define scast( type, value ) static_cast< type >( value )
#define do_once() for ( local_persist b32 once = true; once; once = false )
#define stmt( ... ) do { __VA_ARGS__; } while ( 0 )
#define array_count( array ) ( sizeof( array ) / sizeof( ( array )[0] ) )
#define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) )
#define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) )
#define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) )
#define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) )

View File

@ -0,0 +1,9 @@
// Platform architecture
#if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ )
# ifndef ARCH_64_BIT
# define ARCH_64_BIT 1
# endif
#else
# error A 32-bit architecture is not supported
#endif

View File

@ -0,0 +1,21 @@
// Platform compiler
#if defined( _MSC_VER )
# define Compiler_MSVC 1
#elif defined( __clang__ )
# define Compiler_Clang 1
#else
# error "Unknown compiler"
#endif
#if defined( __has_attribute )
# define HAS_ATTRIBUTE( attribute ) __has_attribute( attribute )
#else
# define HAS_ATTRIBUTE( attribute ) ( 0 )
#endif
#ifdef Compiler_Clang
# define compiler_decorated_func_name __PRETTY_NAME__
#elif defined(Compiler_MSVC)
# define compiler_decorated_func_name __FUNCDNAME__
#endif

View File

@ -0,0 +1,34 @@
#pragma once
#if INTELLISENSE_DIRECTIVES
#include "compiler.hpp"
#endif
#ifdef Compiler_MSVC
#pragma warning( disable: 4201 ) // Support for non-standard nameless struct or union extesnion
#pragma warning( disable: 4100 ) // Support for unreferenced formal parameters
#pragma warning( disable: 4800 ) // Support implicit conversion to bools
#pragma warning( disable: 4365 ) // Support for signed/unsigned mismatch auto-conversion
#pragma warning( disable: 4189 ) // Support for unused variables
#pragma warning( disable: 4514 ) // Support for unused inline functions
#pragma warning( disable: 4505 ) // Support for unused static functions
#pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
#pragma warning( disable: 5264 ) // Support for 'const' variables unused
#pragma warning( disable: 4820 ) // Support auto-adding padding to structs
#pragma warning( disable: 4711 ) // Support automatic inline expansion
#pragma warning( disable: 4710 ) // Support automatic inline expansion
#pragma warning( disable: 4805 ) // Support comparisons of s32 to bool.
#pragma warning( disable: 5246 ) // Support for initialization of subobject without braces.
#endif
#ifdef Compiler_Clang
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-const-variable"
#pragma clang diagnostic ignored "-Wswitch"
#pragma clang diagnostic ignored "-Wunused-variable"
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wvarargs"
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif

View File

@ -0,0 +1,21 @@
// Platform OS detection
#if defined( _WIN32 ) || defined( _WIN64 )
# ifndef System_Windows
# define System_Windows 1
# endif
#elif defined( __APPLE__ ) && defined( __MACH__ )
# ifndef System_MacOS
# define System_MacOS 1
# endif
#elif defined( __unix__ )
# if defined( __linux__ )
# ifndef System_Linux
# define System_linux 1
# endif
# else
# error This UNIX operating system is not supported
# endif
#else
# error This operating system is not supported
#endif

View File

@ -0,0 +1,8 @@
#if INTELLISENSE_DIRECTIVES
#include "win32.hpp"
#endif
int __stdcall WinMain( HINSTANCE instance, HINSTANCE prev_instance, char* commandline, int num_cmd_show)
{
return 0;
}

View File

@ -0,0 +1 @@
using HINSTANCE = void*;

View File

@ -0,0 +1,10 @@
#include "platform/vendor/arch.hpp"
#include "platform/vendor/compiler.hpp"
#include "platform/vendor/compiler_ignores.hpp"
#include "platform/vendor/os.hpp"
#include "platform/macros.hpp"
#include "platform/win32/types.hpp"
#include "platform/win32/launch.cpp"

View File

@ -0,0 +1,226 @@
/**********************************************************************************************
*
* raylib configuration flags
*
* This file defines all the configuration flags for the different raylib modules
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2018-2023 Ahmad Fatoum & Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef CONFIG_H
#define RL_CONFIG_H
//------------------------------------------------------------------------------------
// Module selection - Some modules could be avoided
// Mandatory modules: rcore, rlgl, utils
//------------------------------------------------------------------------------------
#define RL_SUPPORT_MODULE_RSHAPES 1
#define RL_SUPPORT_MODULE_RTEXTURES 1
#define RL_SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
#define RL_SUPPORT_MODULE_RMODELS 1
#define RL_SUPPORT_MODULE_RAUDIO 1
//------------------------------------------------------------------------------------
// Module: rcore - Configuration Flags
//------------------------------------------------------------------------------------
// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
#define RL_SUPPORT_CAMERA_SYSTEM 1
// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag
#define RL_SUPPORT_GESTURES_SYSTEM 1
// Mouse gestures are directly mapped like touches and processed by gestures system
#define RL_SUPPORT_MOUSE_GESTURES 1
// Reconfigure standard input to receive key inputs, works with SSH connection.
#define RL_SUPPORT_SSH_KEYBOARD_RPI 1
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
#define RL_SUPPORT_WINMM_HIGHRES_TIMER 1
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
// #define SUPPORT_BUSY_WAIT_LOOP 1
// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
#define RL_SUPPORT_PARTIALBUSY_WAIT_LOOP 1
// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback()
#define RL_SUPPORT_SCREEN_CAPTURE 1
// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback()
#define RL_SUPPORT_GIF_RECORDING 1
// Support CompressData() and DecompressData() functions
#define RL_SUPPORT_COMPRESSION_API 1
// Support automatic generated events, loading and recording of those events when required
// #define SUPPORT_EVENTS_AUTOMATION 1
// Support custom frame control, only for advance users
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
// Enabling this flag allows manual control of the frame processes, use at your own risk
// #define SUPPORT_CUSTOM_FRAME_CONTROL 1
// rcore: Configuration values
//------------------------------------------------------------------------------------
#define RL_MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
#define RL_MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#define RL_MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
#define RL_MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
#define RL_MAX_GAMEPADS 4 // Maximum number of gamepads supported
#define RL_MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
#define RL_MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#define RL_MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#define RL_MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
#define RL_MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
#define RL_MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB
//------------------------------------------------------------------------------------
// Module: rlgl - Configuration values
//------------------------------------------------------------------------------------
// Enable OpenGL Debug Context (only available on OpenGL 4.3)
// #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 1
// Show OpenGL extensions and capabilities detailed logs on init
// #define RLGL_SHOW_GL_DETAILS_INFO 1
// #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // Default internal render batch elements limits
// Default shader vertex attribute names to set location points
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
//------------------------------------------------------------------------------------
// Module: rshapes - Configuration Flags
//------------------------------------------------------------------------------------
// Use QUADS instead of TRIANGLES for drawing when possible
// Some lines-based shapes could still use lines
#define RL_SUPPORT_QUADS_DRAW_MODE 1
//------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------
// Selecte desired fileformats to be supported for image data loading
#define RL_SUPPORT_FILEFORMAT_PNG 1
// #define SUPPORT_FILEFORMAT_BMP 1
// #define SUPPORT_FILEFORMAT_TGA 1
// #define SUPPORT_FILEFORMAT_JPG 1
#define RL_SUPPORT_FILEFORMAT_GIF 1
#define RL_SUPPORT_FILEFORMAT_QOI 1
// #define SUPPORT_FILEFORMAT_PSD 1
#define RL_SUPPORT_FILEFORMAT_DDS 1
// #define SUPPORT_FILEFORMAT_HDR 1
// #define SUPPORT_FILEFORMAT_PIC 1
// #define SUPPORT_FILEFORMAT_KTX 1
// #define SUPPORT_FILEFORMAT_ASTC 1
// #define SUPPORT_FILEFORMAT_PKM 1
// #define SUPPORT_FILEFORMAT_PVR 1
// #define SUPPORT_FILEFORMAT_SVG 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define RL_SUPPORT_IMAGE_EXPORT 1
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define RL_SUPPORT_IMAGE_GENERATION 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
#define RL_SUPPORT_IMAGE_MANIPULATION 1
//------------------------------------------------------------------------------------
// Module: rtext - Configuration Flags
//------------------------------------------------------------------------------------
// Default font is loaded on window initialization to be available for the user to render simple text
// NOTE: If enabled, uses external module functions to load default raylib font
#define RL_SUPPORT_DEFAULT_FONT 1
// Selected desired font fileformats to be supported for loading
#define RL_SUPPORT_FILEFORMAT_FNT 1
#define RL_SUPPORT_FILEFORMAT_TTF 1
// Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat()
#define RL_SUPPORT_TEXT_MANIPULATION 1
// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle
// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow
// drawing text and shapes with a single draw call [SetShapesTexture()].
#define RL_SUPPORT_FONT_ATLAS_WHITE_REC 1
// rtext: Configuration values
//------------------------------------------------------------------------------------
#define RL_MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#define RL_MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
//------------------------------------------------------------------------------------
// Module: rmodels - Configuration Flags
//------------------------------------------------------------------------------------
// Selected desired model fileformats to be supported for loading
#define RL_SUPPORT_FILEFORMAT_OBJ 1
#define RL_SUPPORT_FILEFORMAT_MTL 1
#define RL_SUPPORT_FILEFORMAT_IQM 1
#define RL_SUPPORT_FILEFORMAT_GLTF 1
#define RL_SUPPORT_FILEFORMAT_VOX 1
#define RL_SUPPORT_FILEFORMAT_M3D 1
// Support procedural mesh generation functions, uses external par_shapes.h library
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define RL_SUPPORT_MESH_GENERATION 1
// rmodels: Configuration values
//------------------------------------------------------------------------------------
#define RL_MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
#define RL_MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
//------------------------------------------------------------------------------------
// Module: raudio - Configuration Flags
//------------------------------------------------------------------------------------
// Desired audio fileformats to be supported for loading
#define RL_SUPPORT_FILEFORMAT_WAV 1
#define RL_SUPPORT_FILEFORMAT_OGG 1
#define RL_SUPPORT_FILEFORMAT_MP3 1
#define RL_SUPPORT_FILEFORMAT_QOA 1
// #define SUPPORT_FILEFORMAT_FLAC 1
#define RL_SUPPORT_FILEFORMAT_XM 1
#define RL_SUPPORT_FILEFORMAT_MOD 1
// raudio: Configuration values
//------------------------------------------------------------------------------------
#define RL_AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
#define RL_AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
#define RL_AUDIO_DEVICE_SAMPLE_RATE 0 // Device sample rate (device default)
#define RL_MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels
//------------------------------------------------------------------------------------
// Module: utils - Configuration Flags
//------------------------------------------------------------------------------------
// Standard file io library (stdio.h) included
#define RL_SUPPORT_STANDARD_FILEIO 1
// Show TRACELOG() output messages
// NOTE: By default LOG_DEBUG traces not shown
#define RL_SUPPORT_TRACELOG 1
// #define SUPPORT_TRACELOG_DEBUG 1
// utils: Configuration values
//------------------------------------------------------------------------------------
#define RL_MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
#endif
// CONFIG_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
/*******************************************************************************************
*
* rcamera - Basic camera system with support for multiple camera modes
*
* CONFIGURATION:
* #define RCAMERA_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define RCAMERA_STANDALONE
* If defined, the library can be used as standalone as a camera system but some
* functions must be redefined to manage inputs accordingly.
*
* CONTRIBUTORS:
* Ramon Santamaria: Supervision, review, update and maintenance
* Christoph Wagner: Complete redesign, using raymath (2022)
* Marc Palau: Initial implementation (2014)
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RCAMERA_H
#define RL_RCAMERA_H
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Function specifiers definition
// Function specifiers in case library is build/used as a shared library (Windows)
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
#if defined( _WIN32 )
#if defined( BUILD_LIBTYPE_SHARED )
#if defined( __TINYC__ )
#define RL___declspec( x ) __attribute__( ( x ) )
#endif
#elif defined( USE_LIBTYPE_SHARED )
#endif
#endif
#ifndef RLAPI
#endif
#if defined( RCAMERA_STANDALONE )
#define RL_CAMERA_CULL_DISTANCE_NEAR 0.01
#define RL_CAMERA_CULL_DISTANCE_FAR 1000.0
#else
#define RL_CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR
#define RL_CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Below types are required for standalone usage
//----------------------------------------------------------------------------------
#if defined( RCAMERA_STANDALONE )
// Vector2, 2 components
typedef struct Vector2
{
f32 x; // Vector x component
f32 y; // Vector y component
} Vector2;
// Vector3, 3 components
typedef struct Vector3
{
f32 x; // Vector x component
f32 y; // Vector y component
f32 z; // Vector z component
} Vector3;
// Matrix, 4x4 components, column major, OpenGL style, right-handed
typedef struct Matrix
{
f32 m0, m4, m8, m12; // Matrix first row (4 components)
f32 m1, m5, m9, m13; // Matrix second row (4 components)
f32 m2, m6, m10, m14; // Matrix third row (4 components)
f32 m3, m7, m11, m15; // Matrix fourth row (4 components)
} Matrix;
// Camera type, defines a camera position/orientation in 3d space
typedef struct Camera3D
{
Vector3 position; // Camera position
Vector3 target; // Camera target it looks-at
Vector3 up; // Camera up vector (rotation over its axis)
f32 fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
s32 projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
} Camera3D;
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
// Camera projection
typedef enum
{
Camera_Perspective = 0, // Perspective projection
Camera_Orthographic // orthographic projection
} CameraProjection;
// Camera system modes
typedef enum
{
Camera_Custom = 0, // Camera custom, controlled by user (UpdateCamera() does nothing)
Camera_Free, // Camera free mode
Camera_Orbital, // Camera orbital, around target, zoom supported
Camera_First_Person, // Camera first person
Camera_Third_Person // camera third person
} CameraMode;
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
#if defined( __cplusplus )
namespace raylib
{
extern "C"
{
// Prevents name mangling of functions
#endif
RLAPI Vector3 get_camera_forward( Camera* camera );
RLAPI Vector3 get_camera_up( Camera* camera );
RLAPI Vector3 get_camera_right( Camera* camera );
// Camera movement
RLAPI void camera_move_forward( Camera* camera, f32 distance, bool moveInWorldPlane );
RLAPI void camera_move_up( Camera* camera, f32 distance );
RLAPI void camera_move_right( Camera* camera, f32 distance, bool moveInWorldPlane );
RLAPI void camera_move_to_target( Camera* camera, f32 delta );
// Camera rotation
RLAPI void camera_yaw( Camera* camera, f32 angle, bool rotateAroundTarget );
RLAPI void camera_pitch( Camera* camera, f32 angle, bool lockView, bool rotateAroundTarget, bool rotateUp );
RLAPI void camera_roll( Camera* camera, f32 angle );
RLAPI Matrix get_camera_view_matrix( Camera* camera );
RLAPI Matrix get_camera_projection_matrix( Camera* camera, f32 aspect );
#if defined( __cplusplus )
}
}
#endif
#endif
// RCAMERA_H
/***********************************************************************************
*
* CAMERA IMPLEMENTATION
*
************************************************************************************/
#if defined( RCAMERA_IMPLEMENTATION )
#include "raymath.h"
// Required for vector maths:
// Vector3Add()
// Vector3Subtract()
// Vector3Scale()
// Vector3Normalize()
// Vector3Distance()
// Vector3CrossProduct()
// Vector3RotateByAxisAngle()
// Vector3Angle()
// Vector3Negate()
// MatrixLookAt()
// MatrixPerspective()
// MatrixOrtho()
// MatrixIdentity()
// raylib required functionality:
// GetMouseDelta()
// GetMouseWheelMove()
// IsKeyDown()
// IsKeyPressed()
// GetFrameTime()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define RL_CAMERA_MOVE_SPEED 0.09f
#define RL_CAMERA_ROTATION_SPEED 0.03f
#define RL_CAMERA_PAN_SPEED 0.2f
// Camera mouse movement sensitivity
#define RL_CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate
#define RL_CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
#define RL_CAMERA_ORBITAL_SPEED 0.5f // Radians per second
#define RL_CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f
#define RL_CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
#define RL_CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
// PLAYER (used by camera)
#define RL_PLAYER_MOVEMENT_SENSITIVITY 20.0f
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Returns the cameras forward vector (normalized)
Vector3 get_camera_forward( Camera* camera )
{
return Vector3Normalize( Vector3Subtract( camera->target, camera->position ) );
}
// Returns the cameras up vector (normalized)
// Note: The up vector might not be perpendicular to the forward vector
Vector3 get_camera_up( Camera* camera )
{
return Vector3Normalize( camera->up );
}
// Returns the cameras right vector (normalized)
Vector3 get_camera_right( Camera* camera )
{
Vector3 forward = GetCameraForward( camera );
Vector3 up = GetCameraUp( camera );
return Vector3CrossProduct( forward, up );
}
// Moves the camera in its forward direction
void camera_move_forward( Camera* camera, f32 distance, bool moveInWorldPlane )
{
Vector3 forward = GetCameraForward( camera );
if ( moveInWorldPlane )
{
// Project vector onto world plane
forward.y = 0;
forward = Vector3Normalize( forward );
}
// Scale by distance
forward = Vector3Scale( forward, distance );
// Move position and target
camera->position = Vector3Add( camera->position, forward );
camera->target = Vector3Add( camera->target, forward );
}
// Moves the camera in its up direction
void camera_move_up( Camera* camera, f32 distance )
{
Vector3 up = GetCameraUp( camera );
// Scale by distance
up = Vector3Scale( up, distance );
// Move position and target
camera->position = Vector3Add( camera->position, up );
camera->target = Vector3Add( camera->target, up );
}
// Moves the camera target in its current right direction
void camera_move_right( Camera* camera, f32 distance, bool moveInWorldPlane )
{
Vector3 right = GetCameraRight( camera );
if ( moveInWorldPlane )
{
// Project vector onto world plane
right.y = 0;
right = Vector3Normalize( right );
}
// Scale by distance
right = Vector3Scale( right, distance );
// Move position and target
camera->position = Vector3Add( camera->position, right );
camera->target = Vector3Add( camera->target, right );
}
// Moves the camera position closer/farther to/from the camera target
void camera_move_to_target( Camera* camera, f32 delta )
{
float distance = Vector3Distance( camera->position, camera->target );
// Apply delta
distance += delta;
// Distance must be greater than 0
if ( distance <= 0 )
distance = 0.001f;
// Set new distance by moving the position along the forward vector
Vector3 forward = GetCameraForward( camera );
camera->position = Vector3Add( camera->target, Vector3Scale( forward, -distance ) );
}
// Rotates the camera around its up vector
// Yaw is "looking left and right"
// If rotateAroundTarget is false, the camera rotates around its position
// Note: angle must be provided in radians
void camera_yaw( Camera* camera, f32 angle, bool rotateAroundTarget )
{
Vector3 up = GetCameraUp( camera );
// View vector
Vector3 targetPosition = Vector3Subtract( camera->target, camera->position );
// Rotate view vector around up axis
targetPosition = Vector3RotateByAxisAngle( targetPosition, up, angle );
if ( rotateAroundTarget )
{
// Move position relative to target
camera->position = Vector3Subtract( camera->target, targetPosition );
}
else // rotate around camera.position
{
// Move target relative to position
camera->target = Vector3Add( camera->position, targetPosition );
}
}
// Rotates the camera around its right vector, pitch is "looking up and down"
// - lockView prevents camera overrotation (aka "somersaults")
// - rotateAroundTarget defines if rotation is around target or around its position
// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
// NOTE: angle must be provided in radians
void camera_pitch( Camera* camera, f32 angle, bool lockView, bool rotateAroundTarget, bool rotateUp )
{
Vector3 up = GetCameraUp( camera );
// View vector
Vector3 targetPosition = Vector3Subtract( camera->target, camera->position );
if ( lockView )
{
// In these camera modes we clamp the Pitch angle
// to allow only viewing straight up or down.
// Clamp view up
float maxAngleUp = Vector3Angle( up, targetPosition );
maxAngleUp -= 0.001f; // avoid numerical errors
if ( angle > maxAngleUp )
angle = maxAngleUp;
// Clamp view down
float maxAngleDown = Vector3Angle( Vector3Negate( up ), targetPosition );
maxAngleDown *= -1.0f; // downwards angle is negative
maxAngleDown += 0.001f; // avoid numerical errors
if ( angle < maxAngleDown )
angle = maxAngleDown;
}
// Rotation axis
Vector3 right = GetCameraRight( camera );
// Rotate view vector around right axis
targetPosition = Vector3RotateByAxisAngle( targetPosition, right, angle );
if ( rotateAroundTarget )
{
// Move position relative to target
camera->position = Vector3Subtract( camera->target, targetPosition );
}
else // rotate around camera.position
{
// Move target relative to position
camera->target = Vector3Add( camera->position, targetPosition );
}
if ( rotateUp )
{
// Rotate up direction around right axis
camera->up = Vector3RotateByAxisAngle( camera->up, right, angle );
}
}
// Rotates the camera around its forward vector
// Roll is "turning your head sideways to the left or right"
// Note: angle must be provided in radians
void camera_roll( Camera* camera, f32 angle )
{
Vector3 forward = GetCameraForward( camera );
// Rotate up direction around forward axis
camera->up = Vector3RotateByAxisAngle( camera->up, forward, angle );
}
// Returns the camera view matrix
Matrix get_camera_view_matrix( Camera* camera )
{
return MatrixLookAt( camera->position, camera->target, camera->up );
}
// Returns the camera projection matrix
Matrix get_camera_projection_matrix( Camera* camera, f32 aspect )
{
if ( camera->projection == CAMERA_PERSPECTIVE )
{
return MatrixPerspective( camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR );
}
else if ( camera->projection == CAMERA_ORTHOGRAPHIC )
{
double top = camera->fovy / 2.0;
double right = top * aspect;
return MatrixOrtho( -right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR );
}
return MatrixIdentity();
}
#if ! defined( RCAMERA_STANDALONE )
// Update camera position for selected mode
// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
void update_camera( Camera* camera, s32 mode )
{
Vector2 mousePositionDelta = GetMouseDelta();
bool moveInWorldPlane = ( ( mode == CAMERA_FIRST_PERSON ) || ( mode == CAMERA_THIRD_PERSON ) );
bool rotateAroundTarget = ( ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) );
bool lockView = ( ( mode == CAMERA_FIRST_PERSON ) || ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) );
bool rotateUp = false;
if ( mode == CAMERA_ORBITAL )
{
// Orbital can just orbit
Matrix rotation = MatrixRotate( GetCameraUp( camera ), CAMERA_ORBITAL_SPEED * GetFrameTime() );
Vector3 view = Vector3Subtract( camera->position, camera->target );
view = Vector3Transform( view, rotation );
camera->position = Vector3Add( camera->target, view );
}
else
{
// Camera rotation
if ( IsKeyDown( KEY_DOWN ) )
CameraPitch( camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp );
if ( IsKeyDown( KEY_UP ) )
CameraPitch( camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp );
if ( IsKeyDown( KEY_RIGHT ) )
CameraYaw( camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget );
if ( IsKeyDown( KEY_LEFT ) )
CameraYaw( camera, CAMERA_ROTATION_SPEED, rotateAroundTarget );
if ( IsKeyDown( KEY_Q ) )
CameraRoll( camera, -CAMERA_ROTATION_SPEED );
if ( IsKeyDown( KEY_E ) )
CameraRoll( camera, CAMERA_ROTATION_SPEED );
// Camera movement
if ( ! IsGamepadAvailable( 0 ) )
{
// Camera pan (for CAMERA_FREE)
if ( ( mode == CAMERA_FREE ) && ( IsMouseButtonDown( MOUSE_BUTTON_MIDDLE ) ) )
{
const Vector2 mouseDelta = GetMouseDelta();
if ( mouseDelta.x > 0.0f )
CameraMoveRight( camera, CAMERA_PAN_SPEED, moveInWorldPlane );
if ( mouseDelta.x < 0.0f )
CameraMoveRight( camera, -CAMERA_PAN_SPEED, moveInWorldPlane );
if ( mouseDelta.y > 0.0f )
CameraMoveUp( camera, -CAMERA_PAN_SPEED );
if ( mouseDelta.y < 0.0f )
CameraMoveUp( camera, CAMERA_PAN_SPEED );
}
else
{
// Mouse support
CameraYaw( camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget );
CameraPitch( camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp );
}
// Keyboard support
if ( IsKeyDown( KEY_W ) )
CameraMoveForward( camera, CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( IsKeyDown( KEY_A ) )
CameraMoveRight( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( IsKeyDown( KEY_S ) )
CameraMoveForward( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( IsKeyDown( KEY_D ) )
CameraMoveRight( camera, CAMERA_MOVE_SPEED, moveInWorldPlane );
}
else
{
// Gamepad controller support
CameraYaw( camera, -( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_RIGHT_X ) * 2 ) * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget );
CameraPitch(
camera,
-( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_RIGHT_Y ) * 2 ) * CAMERA_MOUSE_MOVE_SENSITIVITY,
lockView,
rotateAroundTarget,
rotateUp
);
if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_Y ) <= -0.25f )
CameraMoveForward( camera, CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_X ) <= -0.25f )
CameraMoveRight( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_Y ) >= 0.25f )
CameraMoveForward( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane );
if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_X ) >= 0.25f )
CameraMoveRight( camera, CAMERA_MOVE_SPEED, moveInWorldPlane );
}
if ( mode == CAMERA_FREE )
{
if ( IsKeyDown( KEY_SPACE ) )
CameraMoveUp( camera, CAMERA_MOVE_SPEED );
if ( IsKeyDown( KEY_LEFT_CONTROL ) )
CameraMoveUp( camera, -CAMERA_MOVE_SPEED );
}
}
if ( ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) || ( mode == CAMERA_FREE ) )
{
// Zoom target distance
CameraMoveToTarget( camera, -GetMouseWheelMove() );
if ( IsKeyPressed( KEY_KP_SUBTRACT ) )
CameraMoveToTarget( camera, 2.0f );
if ( IsKeyPressed( KEY_KP_ADD ) )
CameraMoveToTarget( camera, -2.0f );
}
}
#endif
// !RCAMERA_STANDALONE
// Update camera movement, movement/rotation values should be provided by user
void update_camera_pro( Camera* camera, Vector3 movement, Vector3 rotation, f32 zoom )
{
bool lockView = true;
bool rotateAroundTarget = false;
bool rotateUp = false;
bool moveInWorldPlane = true;
// Camera rotation
CameraPitch( camera, -rotation.y * DEG2RAD, lockView, rotateAroundTarget, rotateUp );
CameraYaw( camera, -rotation.x * DEG2RAD, rotateAroundTarget );
CameraRoll( camera, rotation.z * DEG2RAD );
// Camera movement
CameraMoveForward( camera, movement.x, moveInWorldPlane );
CameraMoveRight( camera, movement.y, moveInWorldPlane );
CameraMoveUp( camera, movement.z );
// Zoom target distance
CameraMoveToTarget( camera, zoom );
}
#endif
// RCAMERA_IMPLEMENTATION

View File

@ -0,0 +1,233 @@
/**********************************************************************************************
*
* rcore - Common types and globals (all platforms)
*
* LIMITATIONS:
* - Limitation 01
* - Limitation 02
*
* POSSIBLE IMPROVEMENTS:
* - Improvement 01
* - Improvement 02
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) and contributors
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RCORE_H
#define RCORE_H
#include "raylib.h"
#include "utils.h" // Required for: TRACELOG() macros
#include "rlgl.h" // Required for: graphics layer functionality
#define RAYMATH_IMPLEMENTATION
#include "raymath.h" // Required for: Vector2/Vector3/Matrix functionality
#include <stdlib.h> // Required for: srand(), rand(), atexit()
#include <stdio.h> // Required for: sprintf() [Used in OpenURL()]
#include <string.h> // Required for: strrchr(), strcmp(), strlen(), memset()
#include <time.h> // Required for: time() [Used in InitTimer()]
#include <math.h> // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()]
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef MAX_FILEPATH_CAPACITY
#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath
#endif
#ifndef MAX_FILEPATH_LENGTH
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#endif
#ifndef MAX_KEYBOARD_KEYS
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
#endif
#ifndef MAX_MOUSE_BUTTONS
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
#endif
#ifndef MAX_GAMEPADS
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
#endif
#ifndef MAX_GAMEPAD_AXIS
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
#endif
#ifndef MAX_GAMEPAD_BUTTONS
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
#endif
#ifndef MAX_TOUCH_POINTS
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#endif
#ifndef MAX_KEY_PRESSED_QUEUE
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
#endif
#ifndef MAX_CHAR_PRESSED_QUEUE
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
#endif
#ifndef MAX_DECOMPRESSION_SIZE
#define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB
#endif
// Flags operation macros
#define FLAG_SET( n, f ) ( ( n ) |= ( f ) )
#define FLAG_CLEAR( n, f ) ( ( n ) &= ~( f ) )
#define FLAG_TOGGLE( n, f ) ( ( n ) ^= ( f ) )
#define FLAG_CHECK( n, f ) ( ( n ) & ( f ) )
#if ( defined( __linux__ ) || defined( PLATFORM_WEB ) ) && ( _POSIX_C_SOURCE < 199309L )
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef struct
{
int x;
int y;
} Point;
typedef struct
{
unsigned int width;
unsigned int height;
} Size;
// Core global state context data
typedef struct CoreData
{
struct
{
const char* title; // Window text title const pointer
unsigned int flags; // Configuration flags (bit based), keeps window state
bool ready; // Check if window has been initialized successfully
bool fullscreen; // Check if fullscreen mode is enabled
bool shouldClose; // Check if window set for closing
bool resizedLastFrame; // Check if window has been resized last frame
bool eventWaiting; // Wait for events before ending frame
Point position; // Window position (required on fullscreen toggle)
Point previousPosition; // Window previous position (required on borderless windowed toggle)
Size display; // Display width and height (monitor, device-screen, LCD, ...)
Size screen; // Screen width and height (used render area)
Size previousScreen; // Screen previous width and height (required on borderless windowed toggle)
Size currentFbo; // Current render width and height (depends on active fbo)
Size render; // Framebuffer width and height (render area, including black bars if required)
Point renderOffset; // Offset from render area (must be divided by 2)
Size screenMin; // Screen minimum width and height (for resizable window)
Size screenMax; // Screen maximum width and height (for resizable window)
Matrix screenScale; // Matrix to scale screen (framebuffer rendering)
char** dropFilepaths; // Store dropped files paths pointers (provided by GLFW)
unsigned int dropFileCount; // Count dropped files strings
} Window;
struct
{
const char* basePath; // Base path for data storage
} Storage;
struct
{
struct
{
int exitKey; // Default exit key
char currentKeyState[ MAX_KEYBOARD_KEYS ]; // Registers current frame key state
char previousKeyState[ MAX_KEYBOARD_KEYS ]; // Registers previous frame key state
// NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially
char keyRepeatInFrame[ MAX_KEYBOARD_KEYS ]; // Registers key repeats for current frame.
int keyPressedQueue[ MAX_KEY_PRESSED_QUEUE ]; // Input keys queue
int keyPressedQueueCount; // Input keys queue count
int charPressedQueue[ MAX_CHAR_PRESSED_QUEUE ]; // Input characters queue (unicode)
int charPressedQueueCount; // Input characters queue count
} Keyboard;
struct
{
Vector2 offset; // Mouse offset
Vector2 scale; // Mouse scaling
Vector2 currentPosition; // Mouse position on screen
Vector2 previousPosition; // Previous mouse position
int cursor; // Tracks current mouse cursor
bool cursorHidden; // Track if cursor is hidden
bool cursorOnScreen; // Tracks if cursor is inside client area
char currentButtonState[ MAX_MOUSE_BUTTONS ]; // Registers current mouse button state
char previousButtonState[ MAX_MOUSE_BUTTONS ]; // Registers previous mouse button state
Vector2 currentWheelMove; // Registers current mouse wheel variation
Vector2 previousWheelMove; // Registers previous mouse wheel variation
} Mouse;
struct
{
int pointCount; // Number of touch points active
int pointId[ MAX_TOUCH_POINTS ]; // Point identifiers
Vector2 position[ MAX_TOUCH_POINTS ]; // Touch position on screen
char currentTouchState[ MAX_TOUCH_POINTS ]; // Registers current touch state
char previousTouchState[ MAX_TOUCH_POINTS ]; // Registers previous touch state
} Touch;
struct
{
int lastButtonPressed; // Register last gamepad button pressed
int axisCount[ MAX_GAMEPADS ]; // Register number of available gamepad axis
bool ready[ MAX_GAMEPADS ]; // Flag to know if gamepad is ready
char name[ MAX_GAMEPADS ][ 64 ]; // Gamepad name holder
char currentButtonState[ MAX_GAMEPADS ][ MAX_GAMEPAD_BUTTONS ]; // Current gamepad buttons state
char previousButtonState[ MAX_GAMEPADS ][ MAX_GAMEPAD_BUTTONS ]; // Previous gamepad buttons state
float axisState[ MAX_GAMEPADS ][ MAX_GAMEPAD_AXIS ]; // Gamepad axis state
} Gamepad;
} Input;
struct
{
double current; // Current time measure
double previous; // Previous time measure
double update; // Time measure for frame update
double draw; // Time measure for frame draw
double frame; // Time measure for one frame
double target; // Desired time for one frame, if 0 not applied
unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM)
unsigned int frameCounter; // Frame counter
} Time;
} CoreData;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
extern CoreData CORE;
#endif

View File

@ -0,0 +1,594 @@
/**********************************************************************************************
*
* rgestures - Gestures system, gestures processing based on input events (touch/mouse)
*
* CONFIGURATION:
* #define RGESTURES_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define RGESTURES_STANDALONE
* If defined, the library can be used as standalone to process gesture events with
* no external dependencies.
*
* CONTRIBUTORS:
* Marc Palau: Initial implementation (2014)
* Albert Martos: Complete redesign and testing (2015)
* Ian Eito: Complete redesign and testing (2015)
* Ramon Santamaria: Supervision, review, update and maintenance
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RGESTURES_H
#define RGESTURES_H
#ifndef PI
#define PI 3.14159265358979323846
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef MAX_TOUCH_POINTS
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Below types are required for standalone usage
//----------------------------------------------------------------------------------
// Boolean type
#if ( defined( __STDC__ ) && __STDC_VERSION__ >= 199901L ) || ( defined( _MSC_VER ) && _MSC_VER >= 1800 )
#include <stdbool.h>
#elif ! defined( __cplusplus ) && ! defined( bool ) && ! defined( RL_BOOL_TYPE )
typedef enum bool
{
false = 0,
true = ! false
} bool;
#endif
#if ! defined( RL_VECTOR2_TYPE )
// Vector2 type
typedef struct Vector2
{
float x;
float y;
} Vector2;
#endif
#if defined( RGESTURES_STANDALONE )
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum
{
GESTURE_NONE = 0,
GESTURE_TAP = 1,
GESTURE_DOUBLETAP = 2,
GESTURE_HOLD = 4,
GESTURE_DRAG = 8,
GESTURE_SWIPE_RIGHT = 16,
GESTURE_SWIPE_LEFT = 32,
GESTURE_SWIPE_UP = 64,
GESTURE_SWIPE_DOWN = 128,
GESTURE_PINCH_IN = 256,
GESTURE_PINCH_OUT = 512
} Gesture;
#endif
typedef enum
{
TOUCH_ACTION_UP = 0,
TOUCH_ACTION_DOWN,
TOUCH_ACTION_MOVE,
TOUCH_ACTION_CANCEL
} TouchAction;
// Gesture event
typedef struct
{
int touchAction;
int pointCount;
int pointId[ MAX_TOUCH_POINTS ];
Vector2 position[ MAX_TOUCH_POINTS ];
} GestureEvent;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
#if defined( __cplusplus )
extern "C"
{ // Prevents name mangling of functions
#endif
void ProcessGestureEvent( GestureEvent event ); // Process gesture event and translate it into gestures
void UpdateGestures( void ); // Update gestures detected (must be called every frame)
#if defined( RGESTURES_STANDALONE )
void SetGesturesEnabled( unsigned int flags ); // Enable a set of gestures using flags
bool IsGestureDetected( int gesture ); // Check if a gesture have been detected
int GetGestureDetected( void ); // Get latest detected gesture
float GetGestureHoldDuration( void ); // Get gesture hold time in seconds
Vector2 GetGestureDragVector( void ); // Get gesture drag vector
float GetGestureDragAngle( void ); // Get gesture drag angle
Vector2 GetGesturePinchVector( void ); // Get gesture pinch delta
float GetGesturePinchAngle( void ); // Get gesture pinch angle
#endif
#if defined( __cplusplus )
}
#endif
#endif // RGESTURES_H
/***********************************************************************************
*
* RGESTURES IMPLEMENTATION
*
************************************************************************************/
#if defined( RGESTURES_IMPLEMENTATION )
#if defined( RGESTURES_STANDALONE )
#if defined( _WIN32 )
#if defined( __cplusplus )
extern "C"
{ // Prevents name mangling of functions
#endif
// Functions required to query time on Windows
int __stdcall QueryPerformanceCounter( unsigned long long int* lpPerformanceCount );
int __stdcall QueryPerformanceFrequency( unsigned long long int* lpFrequency );
#if defined( __cplusplus )
}
#endif
#elif defined( __linux__ )
#if _POSIX_C_SOURCE < 199309L
#undef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#endif
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
#include <math.h> // Required for: sqrtf(), atan2f()
#endif
#if defined( __APPLE__ ) // macOS also defines __MACH__
#include <mach/clock.h> // Required for: clock_get_time()
#include <mach/mach.h> // Required for: mach_timespec_t
#endif
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 0.2f // Swipe force, measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
#define DRAG_TIMEOUT 0.3f // Drag minimum time for web, measured in seconds
#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds
#define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds
#define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Gestures module state context [136 bytes]
typedef struct
{
unsigned int current; // Current detected gesture
unsigned int enabledFlags; // Enabled gestures flags
struct
{
int firstId; // Touch id for first touch point
int pointCount; // Touch points counter
double eventTime; // Time stamp when an event happened
Vector2 upPosition; // Touch up position
Vector2 downPositionA; // First touch down position
Vector2 downPositionB; // Second touch down position
Vector2 downDragPosition; // Touch drag position
Vector2 moveDownPositionA; // First touch down position on move
Vector2 moveDownPositionB; // Second touch down position on move
Vector2 previousPositionA; // Previous position A to compare for pinch gestures
Vector2 previousPositionB; // Previous position B to compare for pinch gestures
int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions)
} Touch;
struct
{
bool resetRequired; // HOLD reset to get first touch point again
double timeDuration; // HOLD duration in seconds
} Hold;
struct
{
Vector2 vector; // DRAG vector (between initial and current position)
float angle; // DRAG angle (relative to x-axis)
float distance; // DRAG distance (from initial touch point to final) (normalized [0..1])
float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame)
} Drag;
struct
{
double startTime; // SWIPE start time to calculate drag intensity
} Swipe;
struct
{
Vector2 vector; // PINCH vector (between first and second touch points)
float angle; // PINCH angle (relative to x-axis)
float distance; // PINCH displacement distance (normalized [0..1])
} Pinch;
} GesturesData;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static GesturesData GESTURES = {
.Touch.firstId = -1,
.current = GESTURE_NONE, // No current gesture detected
.enabledFlags = 0b0000001111111111 // All gestures supported by default
};
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static float rgVector2Angle( Vector2 initialPosition, Vector2 finalPosition );
static float rgVector2Distance( Vector2 v1, Vector2 v2 );
static double rgGetCurrentTime( void );
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Enable only desired gestures to be detected
void SetGesturesEnabled( unsigned int flags )
{
GESTURES.enabledFlags = flags;
}
// Check if a gesture have been detected
bool IsGestureDetected( unsigned int gesture )
{
if ( ( GESTURES.enabledFlags & GESTURES.current ) == gesture )
return true;
else
return false;
}
// Process gesture event and translate it into gestures
void ProcessGestureEvent( GestureEvent event )
{
// Reset required variables
GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures()
if ( GESTURES.Touch.pointCount == 1 ) // One touch point
{
if ( event.touchAction == TOUCH_ACTION_DOWN )
{
GESTURES.Touch.tapCounter++; // Tap counter
// Detect GESTURE_DOUBLE_TAP
if ( ( GESTURES.current == GESTURE_NONE ) && ( GESTURES.Touch.tapCounter >= 2 )
&& ( ( rgGetCurrentTime() - GESTURES.Touch.eventTime ) < TAP_TIMEOUT )
&& ( rgVector2Distance( GESTURES.Touch.downPositionA, event.position[ 0 ] ) < DOUBLETAP_RANGE ) )
{
GESTURES.current = GESTURE_DOUBLETAP;
GESTURES.Touch.tapCounter = 0;
}
else // Detect GESTURE_TAP
{
GESTURES.Touch.tapCounter = 1;
GESTURES.current = GESTURE_TAP;
}
GESTURES.Touch.downPositionA = event.position[ 0 ];
GESTURES.Touch.downDragPosition = event.position[ 0 ];
GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA;
GESTURES.Touch.eventTime = rgGetCurrentTime();
GESTURES.Swipe.startTime = rgGetCurrentTime();
GESTURES.Drag.vector = ( Vector2 ) { 0.0f, 0.0f };
}
else if ( event.touchAction == TOUCH_ACTION_UP )
{
// A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases
if ( GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD )
GESTURES.Touch.upPosition = event.position[ 0 ];
// NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
GESTURES.Drag.distance = rgVector2Distance( GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition );
GESTURES.Drag.intensity = GESTURES.Drag.distance / ( float )( ( rgGetCurrentTime() - GESTURES.Swipe.startTime ) );
// Detect GESTURE_SWIPE
if ( ( GESTURES.Drag.intensity > FORCE_TO_SWIPE ) && ( GESTURES.current != GESTURE_DRAG ) )
{
// NOTE: Angle should be inverted in Y
GESTURES.Drag.angle = 360.0f - rgVector2Angle( GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition );
if ( ( GESTURES.Drag.angle < 30 ) || ( GESTURES.Drag.angle > 330 ) )
GESTURES.current = GESTURE_SWIPE_RIGHT; // Right
else if ( ( GESTURES.Drag.angle >= 30 ) && ( GESTURES.Drag.angle <= 150 ) )
GESTURES.current = GESTURE_SWIPE_UP; // Up
else if ( ( GESTURES.Drag.angle > 150 ) && ( GESTURES.Drag.angle < 210 ) )
GESTURES.current = GESTURE_SWIPE_LEFT; // Left
else if ( ( GESTURES.Drag.angle >= 210 ) && ( GESTURES.Drag.angle <= 330 ) )
GESTURES.current = GESTURE_SWIPE_DOWN; // Down
else
GESTURES.current = GESTURE_NONE;
}
else
{
GESTURES.Drag.distance = 0.0f;
GESTURES.Drag.intensity = 0.0f;
GESTURES.Drag.angle = 0.0f;
GESTURES.current = GESTURE_NONE;
}
GESTURES.Touch.downDragPosition = ( Vector2 ) { 0.0f, 0.0f };
GESTURES.Touch.pointCount = 0;
}
else if ( event.touchAction == TOUCH_ACTION_MOVE )
{
GESTURES.Touch.moveDownPositionA = event.position[ 0 ];
if ( GESTURES.current == GESTURE_HOLD )
{
if ( GESTURES.Hold.resetRequired )
GESTURES.Touch.downPositionA = event.position[ 0 ];
GESTURES.Hold.resetRequired = false;
// Detect GESTURE_DRAG
if ( ( rgGetCurrentTime() - GESTURES.Touch.eventTime ) > DRAG_TIMEOUT )
{
GESTURES.Touch.eventTime = rgGetCurrentTime();
GESTURES.current = GESTURE_DRAG;
}
}
GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x;
GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y;
}
}
else if ( GESTURES.Touch.pointCount == 2 ) // Two touch points
{
if ( event.touchAction == TOUCH_ACTION_DOWN )
{
GESTURES.Touch.downPositionA = event.position[ 0 ];
GESTURES.Touch.downPositionB = event.position[ 1 ];
GESTURES.Touch.previousPositionA = GESTURES.Touch.downPositionA;
GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB;
// GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB);
GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y;
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = rgGetCurrentTime();
}
else if ( event.touchAction == TOUCH_ACTION_MOVE )
{
GESTURES.Pinch.distance = rgVector2Distance( GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB );
GESTURES.Touch.moveDownPositionA = event.position[ 0 ];
GESTURES.Touch.moveDownPositionB = event.position[ 1 ];
GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x;
GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y;
if ( ( rgVector2Distance( GESTURES.Touch.previousPositionA, GESTURES.Touch.moveDownPositionA ) >= MINIMUM_PINCH )
|| ( rgVector2Distance( GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB ) >= MINIMUM_PINCH ) )
{
if ( rgVector2Distance( GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB )
> rgVector2Distance( GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB ) )
GESTURES.current = GESTURE_PINCH_IN;
else
GESTURES.current = GESTURE_PINCH_OUT;
}
else
{
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = rgGetCurrentTime();
}
// NOTE: Angle should be inverted in Y
GESTURES.Pinch.angle = 360.0f - rgVector2Angle( GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB );
}
else if ( event.touchAction == TOUCH_ACTION_UP )
{
GESTURES.Pinch.distance = 0.0f;
GESTURES.Pinch.angle = 0.0f;
GESTURES.Pinch.vector = ( Vector2 ) { 0.0f, 0.0f };
GESTURES.Touch.pointCount = 0;
GESTURES.current = GESTURE_NONE;
}
}
else if ( GESTURES.Touch.pointCount > 2 ) // More than two touch points
{
// TODO: Process gesture events for more than two points
}
}
// Update gestures detected (must be called every frame)
void UpdateGestures( void )
{
// NOTE: Gestures are processed through system callbacks on touch events
// Detect GESTURE_HOLD
if ( ( ( GESTURES.current == GESTURE_TAP ) || ( GESTURES.current == GESTURE_DOUBLETAP ) ) && ( GESTURES.Touch.pointCount < 2 ) )
{
GESTURES.current = GESTURE_HOLD;
GESTURES.Hold.timeDuration = rgGetCurrentTime();
}
// Detect GESTURE_NONE
if ( ( GESTURES.current == GESTURE_SWIPE_RIGHT ) || ( GESTURES.current == GESTURE_SWIPE_UP ) || ( GESTURES.current == GESTURE_SWIPE_LEFT )
|| ( GESTURES.current == GESTURE_SWIPE_DOWN ) )
{
GESTURES.current = GESTURE_NONE;
}
}
// Get latest detected gesture
int GetGestureDetected( void )
{
// Get current gesture only if enabled
return ( GESTURES.enabledFlags & GESTURES.current );
}
// Hold time measured in ms
float GetGestureHoldDuration( void )
{
// NOTE: time is calculated on current gesture HOLD
double time = 0.0;
if ( GESTURES.current == GESTURE_HOLD )
time = rgGetCurrentTime() - GESTURES.Hold.timeDuration;
return ( float )time;
}
// Get drag vector (between initial touch point to current)
Vector2 GetGestureDragVector( void )
{
// NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE
return GESTURES.Drag.vector;
}
// Get drag angle
// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
float GetGestureDragAngle( void )
{
// NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP
return GESTURES.Drag.angle;
}
// Get distance between two pinch points
Vector2 GetGesturePinchVector( void )
{
// NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE
return GESTURES.Pinch.vector;
}
// Get angle between two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
float GetGesturePinchAngle( void )
{
// NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE
return GESTURES.Pinch.angle;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Get angle from two-points vector with X-axis
static float rgVector2Angle( Vector2 v1, Vector2 v2 )
{
float angle = atan2f( v2.y - v1.y, v2.x - v1.x ) * ( 180.0f / PI );
if ( angle < 0 )
angle += 360.0f;
return angle;
}
// Calculate distance between two Vector2
static float rgVector2Distance( Vector2 v1, Vector2 v2 )
{
float result;
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
result = ( float )sqrt( dx * dx + dy * dy );
return result;
}
// Time measure returned are seconds
static double rgGetCurrentTime( void )
{
double time = 0;
#if ! defined( RGESTURES_STANDALONE )
time = GetTime();
#else
#if defined( _WIN32 )
unsigned long long int clockFrequency, currentTime;
QueryPerformanceFrequency( &clockFrequency ); // BE CAREFUL: Costly operation!
QueryPerformanceCounter( &currentTime );
time = ( double )currentTime / clockFrequency; // Time in seconds
#endif
#if defined( __linux__ )
// NOTE: Only for Linux-based systems
struct timespec now;
clock_gettime( CLOCK_MONOTONIC, &now );
unsigned long long int nowTime = ( unsigned long long int )now.tv_sec * 1000000000LLU + ( unsigned long long int )now.tv_nsec; // Time in nanoseconds
time = ( ( double )nowTime * 1e-9 ); // Time in seconds
#endif
#if defined( __APPLE__ )
// #define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01
// #define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time
clock_serv_t cclock;
mach_timespec_t now;
host_get_clock_service( mach_host_self(), SYSTEM_CLOCK, &cclock );
// NOTE: OS X does not have clock_gettime(), using clock_get_time()
clock_get_time( cclock, &now );
mach_port_deallocate( mach_task_self(), cclock );
unsigned long long int nowTime = ( unsigned long long int )now.tv_sec * 1000000000LLU + ( unsigned long long int )now.tv_nsec; // Time in nanoseconds
time = ( ( double )nowTime * 1e-9 ); // Time in seconds
#endif
#endif
return time;
}
#endif // RGESTURES_IMPLEMENTATION

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
/**********************************************************************************************
*
* raylib.utils - Some common utility functions
*
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef UTILS_H
#define UTILS_H
#if defined( PLATFORM_ANDROID )
#include <stdio.h> // Required for: FILE
#include <android/asset_manager.h> // Required for: AAssetManager
#endif
#if defined( SUPPORT_TRACELOG )
#define TRACELOG( level, ... ) TraceLog( level, __VA_ARGS__ )
#if defined( SUPPORT_TRACELOG_DEBUG )
#define TRACELOGD( ... ) TraceLog( LOG_DEBUG, __VA_ARGS__ )
#else
#define TRACELOGD( ... ) ( void )0
#endif
#else
#define TRACELOG( level, ... ) ( void )0
#define TRACELOGD( ... ) ( void )0
#endif
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
#if defined( PLATFORM_ANDROID )
#define fopen( name, mode ) android_fopen( name, mode )
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// Nop...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
#if defined( __cplusplus )
extern "C"
{ // Prevents name mangling of functions
#endif
#if defined( PLATFORM_ANDROID )
void InitAssetManager( AAssetManager* manager, const char* dataPath ); // Initialize asset manager from android app
FILE* android_fopen( const char* fileName, const char* mode ); // Replacement for fopen() -> Read-only!
#endif
#if defined( __cplusplus )
}
#endif
#endif // UTILS_H

View File

@ -0,0 +1,8 @@
#include "raudio.c"
#include "rcore.c"
#include "rglfw.c"
#include "rmodels.c"
#include "rshapes.c"
#include "rtext.c"
#include "rtextures.c"
#include "rutils.c"

View File

@ -0,0 +1,9 @@
__VERSION 1
word SUPPORT_MODULE_RSHAPES, RL_SUPPORT_MODULE_RSHAPES
word SUPPORT_MODULE_RTEXTURES, RL_SUPPORT_MODULE_RTEXTURES
word SUPPORT_MODULE_RTEXT, RL_SUPPORT_MODULE_RTEXT
word SUPPORT_MODULE_RMODELS, RL_SUPPORT_MODULE_RMODELS
word SUPPORT_MODULE_RAUDIO, RL_SUPPORT_MODULE_RAUDIO

View File

@ -0,0 +1,290 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_BENCHMARK
#define GEN_ENFORCE_STRONG_CODE_TYPES
// #define GEN_IMPLEMENTATION
#include "gen.cpp"
#include "gen.builder.cpp"
constexpr char const* path_config = "config.h";
constexpr char const* path_raylib = "raylib.h";
constexpr char const* path_raymath = "raymath.h";
constexpr char const* path_rcamera = "rcamera.h";
constexpr char const* path_rcore = "rcore.h";
constexpr char const* path_rgestures = "rgestures.h";
constexpr char const* path_rgl = "rgl.h";
constexpr char const* path_rtext = "rtext.h";
using namespace gen;
StringCached upper_snake_to_mixed_snake(StringCached str)
{
local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1));
scratch.clear();
bool capitalizeNext = true;
for (s32 index = 0; index < str.length(); ++index)
{
char c = str[index];
if (c == '_')
{
scratch.append(c);
capitalizeNext = true;
}
else if (capitalizeNext)
{
if (c >= 'a' && c <= 'z')
{
scratch.append(c - 32); // Convert to uppercase
}
else
{
scratch.append(c);
}
capitalizeNext = false;
}
else
{
if (c >= 'A' && c <= 'Z')
{
scratch.append(c + 32); // Convert to lowercase
}
else
{
scratch.append(c);
}
}
}
StringCached result = get_cached_string(scratch);
return result;
}
StringCached pascal_to_lower_snake(StringCached str)
{
local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1));
scratch.clear();
for (s32 index = 0; index < str.length(); ++index)
{
char c = str[index];
char next = (index + 1 < str.length()) ? str[index + 1] : '\0'; // Ensure we don't go out of bounds
// Whitelist check for "2D" and "3D"
if ((c == '2' || c == '3' | c == '4') && (next == 'D' || next == 'd'))
{
if (index > 0) // If it's not the start of the string, append an underscore
{
char* prev = str.Data + index - 1;
if (*prev != '_') // Avoid double underscores
{
scratch.append('_');
}
}
scratch.append(c);
scratch.append('d'); // Convert to lowercase
index++; // Skip the next character since we've already processed it
continue;
}
if (c >= 'A' && c <= 'Z')
{
char* prev = (index > 0) ? str.Data + index - 1 : nullptr;
if ((index > 0 && prev && *prev >= 'a' && *prev <= 'z') ||
(prev && char_is_digit(*prev) && (next >= 'A' && next <= 'Z')))
{
scratch.append('_');
}
scratch.append(c + 32);
}
else if (char_is_digit(c) && (next >= 'A' && next <= 'Z')) // Check for a number followed by an uppercase letter
{
scratch.append(c);
scratch.append('_');
}
else
{
scratch.append(c);
}
}
StringCached result = get_cached_string(scratch);
return result;
}
void refactor_enum( CodeEnum& code )
{
for ( Code elem : code->Body )
{
if ( elem->Type == ECode::Untyped )
{
elem->Content = upper_snake_to_mixed_snake( elem->Content );
}
}
}
void refactor_typename( CodeType& type )
{
local_persist CodeType t_unsigned_char = parse_type( code(unsigned char) );
local_persist CodeType t_unsigned_char_ptr = parse_type( code(unsigned char*) );
local_persist CodeType t_unsigned_short_ptr = parse_type( code(unsigned short*) );
local_persist CodeType t_int = parse_type( code(int) );
local_persist CodeType t_int_ptr = parse_type( code(int*) );
local_persist CodeType t_unsigned_int = parse_type( code(unsigned int) );
local_persist CodeType t_float = parse_type( code(float) );
local_persist CodeType t_float_ptr = parse_type( code(float*) );
local_persist CodeType t_f32_ptr = parse_type( code(f32*) );
local_persist CodeType t_u8_ptr = parse_type( code(u8*) );
local_persist CodeType t_s32_ptr = parse_type( code(s32*) );
String type_str = type.to_string();
if ( str_compare( type_str, t_unsigned_char.to_string() ) == 0 )
{
type.ast = t_u8.ast;
}
if ( str_compare( type_str, t_unsigned_char_ptr.to_string() ) == 0 )
{
type.ast = t_u8_ptr.ast;
}
if ( str_compare( type_str, t_unsigned_short_ptr.to_string() ) == 0 )
{
type.ast = t_u8_ptr.ast;
}
if ( str_compare( type_str, t_int.to_string() ) == 0 )
{
type.ast = t_s32.ast;
}
if ( str_compare( type_str, t_int_ptr.to_string() ) == 0 )
{
type.ast = t_s32_ptr.ast;
}
if ( str_compare( type_str, t_unsigned_int.to_string() ) == 0 )
{
type.ast = t_u32.ast;
}
if ( str_compare( type_str, t_float.to_string() ) == 0 )
{
type.ast = t_f32.ast;
}
if ( str_compare( type_str, t_float_ptr.to_string() ) == 0 )
{
type.ast = t_f32_ptr.ast;
}
}
void refactor_fn( CodeFn& fn )
{
fn->Name = pascal_to_lower_snake( fn->Name );
for ( CodeParam param : fn->Params )
{
refactor_typename( param->ValueType );
}
}
void refactor_struct( CodeStruct& code )
{
for ( Code field : code->Body )
{
if ( field->Type == ECode::Variable )
{
CodeVar var = field.cast<CodeVar>();
refactor_typename( var->ValueType );
}
}
}
void refactor_file( char const* path )
{
FileContents contents = file_read_contents( GlobalAllocator, true, path );
CodeBody code = parse_global_body( { contents.size, rcast(char const*, contents.data) } );
String name_scratch = String::make_reserve( GlobalAllocator, kilobytes(1) );
// CodeBody includes
// CodeBody nspace_body = def_body( ECode::Namespace );
CodeBody new_code = def_body( ECode::Global_Body );
for ( Code elem : code )
{
if ( elem->Type == ECode::Preprocess_Define )
{
if ( str_compare( elem->Name, txt("RL"), 2 ) == 0 || str_compare( elem->Name, txt("RAYLIB"), 6 ) == 0 )
continue;
name_scratch.append_fmt( "%RL_%S", elem->Name );
elem->Name = get_cached_string( name_scratch );
name_scratch.clear();
}
if ( elem->Type == ECode::Enum )
{
refactor_enum( elem.cast<CodeEnum>() );
}
if ( elem->Type == ECode::Typedef )
{
CodeTypedef td = elem.cast<CodeTypedef>();
if ( td->UnderlyingType->Type == ECode::Enum )
{
CodeEnum code = td->UnderlyingType.cast<CodeEnum>();
refactor_enum( code );
}
if ( td->UnderlyingType->Type == ECode::Struct )
{
CodeStruct code = td->UnderlyingType.cast<CodeStruct>();
refactor_struct( code );
}
}
if ( elem->Type == ECode::Struct )
{
refactor_struct( elem.cast<CodeStruct>() );
}
if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd )
{
refactor_fn( elem.cast<CodeFn>() );
}
if ( elem->Type == ECode::Extern_Linkage )
{
CodeBody body = elem.cast<CodeExtern>()->Body;
for ( Code elem : body )
{
if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd )
{
refactor_fn( elem.cast<CodeFn>() );
}
}
Code nspace = def_namespace( txt("raylib"), def_namespace_body( args(elem) ) );
elem = nspace;
}
new_code.append( elem );
}
Builder builder = Builder::open( path );
builder.print( new_code );
builder.write();
}
int gen_main()
{
gen::init();
refactor_file( path_config );
refactor_file( path_raylib );
refactor_file( path_raymath );
refactor_file( path_rcamera );
return 0;
}

View File

@ -0,0 +1,10 @@
# Vis AST
AST visualizer for gencpp
This is a early start to creating frontend tooling for c/c++ using gencpp as a core component.
I'll be exploring creating an AST explorer for this library with raylib as the graphical & general platform vendor for dependencies that go beyond the scope of gencpp.
For now I'll have its build script in this file, however it will heavily rely on gencpp's helper scripts.
Whatever sort of UX tooling I setup for this will be reused for the other tools I'll be creating for gencpp.

View File

View File

@ -0,0 +1,178 @@
Clear-Host
$path_root = git rev-parse --show-toplevel
$path_scripts = Join-Path $path_root 'scripts'
$target_arch = Join-Path $path_scripts 'helpers/target_arch.psm1'
$devshell = Join-Path $path_scripts 'helpers/devshell.ps1'
$format_cpp = Join-Path $path_scripts 'helpers/format_cpp.psm1'
$incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1'
$vendor_toolchain = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1'
$path_project = Join-Path $path_root 'project'
$path_aux = Join-Path $path_project 'auxillary'
$path_vis_root = Join-Path $path_aux 'vis_ast'
$path_binaries = Join-Path $path_vis_root 'binaries'
$path_deps = Join-Path $path_vis_root 'dependencies'
$path_temp = Join-Path $path_deps 'temp'
Import-Module $target_arch
Import-Module $format_cpp
#region Arguments
$vendor = $null
$optimize = $null
$debug = $null
$analysis = $false
$dev = $false
$verbose = $null
[array] $vendors = @( "clang", "msvc" )
# This is a really lazy way of parsing the args, could use actual params down the line...
if ( $args ) { $args | ForEach-Object {
switch ($_){
{ $_ -in $vendors } { $vendor = $_; break }
"optimize" { $optimize = $true }
"debug" { $debug = $true }
"analysis" { $analysis = $true }
"dev" { $dev = $true }
"verbose" { $verbose = $true }
}
}}
#endregion Argument
# Load up toolchain configuraion
. $vendor_toolchain
. $incremental_checks
# Clear out the current content first
# remove-item $path_temp -Recurse
# New-Item -ItemType Directory -Path $path_temp
if ( -not (Test-Path $path_binaries) ) {
New-Item -ItemType Directory -Path $path_binaries
}
function setup-raylib {
$path_raylib = join-path $path_deps 'raylib'
$path_raylib_inc = join-path $path_raylib 'include'
$path_raylib_lib = join-path $path_raylib 'lib'
if ( test-path $path_raylib_inc ) {
remove-item $path_raylib_inc -recurse
remove-item $path_raylib_lib -recurse
}
new-item -path $path_raylib_inc -ItemType Directory
new-item -path $path_raylib_lib -ItemType Directory
$url_raylib_zip = 'https://github.com/raysan5/raylib/archive/refs/heads/master.zip'
$path_raylib_zip = join-path $path_temp 'raylib.zip'
$path_raylib_master = join-path $path_temp 'raylib-master'
$path_raylib_src = join-path $path_raylib_master 'src'
$path_raylib_glfw_inc = join-path $path_raylib_src 'external/glfw/include'
remove-item $path_raylib_master -Recurse
# invoke-webrequest -uri $url_raylib_zip -outfile $path_raylib_zip
expand-archive -path $path_raylib_zip -destinationpath $path_temp
write-host "Building raylib with $vendor"
$path_build = Join-Path $path_raylib 'build'
if ( (Test-Path $path_build) -eq $false ) {
New-Item $path_build -ItemType Directory
}
$raylib_headers = Get-ChildItem -Path $path_raylib_src -Filter "*.h" -File
$raylib_modules = get-childitem -path $path_raylib_src -filter "*.c" -file
# Refactor raylib
if ( $true ) {
# if ( $false ) {
$path_gencpp = join-path $path_root 'project/gen'
$includes = @(
$path_gencpp
)
$compiler_args = @(
($flag_define + 'GEN_TIME')
)
$linker_args = @(
)
$unit = join-path $path_raylib 'raylib_refactor.cpp'
$executable = join-path $path_build 'raylib_refactor.exe'
$build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_raylib_src
if ( Test-Path( $executable ) ) {
Measure-Command { & $executable
| ForEach-Object {
write-host `t $_ -ForegroundColor Green
}
}
}
Pop-Location
push-location $path_scripts
# Time to format
$fmt_includes = @()
foreach ( $header in $raylib_headers ) {
$fmt_includes += split-path $header -leaf
}
foreach ( $module in $raylib_modules ) {
$fmt_includes += split-path $module -leaf
}
format-cpp $path_raylib_src $fmt_includes $null
pop-location
}
# Build raylib
if ( $false ) {
# Microsoft
$lib_gdi32 = 'Gdi32.lib'
$lib_shell32 = 'Shell32.lib'
$lib_xinput = 'Xinput.lib'
$lib_user32 = 'User32.lib'
$lib_winmm = 'Winmm.lib'
$includes = @(
$path_raylib_src,
$path_raylib_glfw_inc
)
foreach ($include in $includes) {
write-host $include
}
$compiler_args = @(
($flag_define + 'PLATFORM_DESKTOP'),
($flag_define + 'BUILD_LIBTYPE_SHARED')
)
$linker_args = @(
$flag_link_dll,
# $lib_xinput,
$lib_gdi32,
$lib_shell32,
$lib_user32,
$lib_winmm
)
# $unit = join-path $path_raylib 'raylib.c'
$dll = join-path $path_raylib_lib 'raylib.dll'
# $build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $dll
$build_result = build $path_build $includes $compiler_args $linker_args $raylib_modules $dll
}
# Move headers to used include
foreach ($header in $raylib_headers) {
Copy-Item -Path $header -Destination (join-path $path_raylib_inc (split-path $header -Leaf))
}
}
setup-raylib

View File

@ -1317,6 +1317,8 @@ String AST::to_string()
// Keep the chain going... // Keep the chain going...
if ( NextVar ) if ( NextVar )
result.append_fmt( ", %S", NextVar->to_string() ); result.append_fmt( ", %S", NextVar->to_string() );
break;
} }
if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export )) if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export ))

View File

@ -475,7 +475,8 @@ struct CodeParam
} }
CodeParam end() CodeParam end()
{ {
return { (AST_Param*) rcast( AST*, ast)->Last }; // return { (AST_Param*) rcast( AST*, ast)->Last };
return { nullptr };
} }
CodeParam& operator++(); CodeParam& operator++();
CodeParam operator*() CodeParam operator*()

View File

@ -7,7 +7,7 @@
#pragma region Constants #pragma region Constants
#ifndef GEN_GLOBAL_BUCKET_SIZE #ifndef GEN_GLOBAL_BUCKET_SIZE
# define GEN_GLOBAL_BUCKET_SIZE megabytes(4) # define GEN_GLOBAL_BUCKET_SIZE megabytes(8)
#endif #endif
#ifndef GEN_CODEPOOL_NUM_BLOCKS #ifndef GEN_CODEPOOL_NUM_BLOCKS
# define GEN_CODEPOOL_NUM_BLOCKS kilobytes(16) # define GEN_CODEPOOL_NUM_BLOCKS kilobytes(16)
@ -31,7 +31,7 @@
# define GEN_LEX_ALLOCATOR_SIZE megabytes(4) # define GEN_LEX_ALLOCATOR_SIZE megabytes(4)
#endif #endif
#ifndef GEN_BUILDER_STR_BUFFER_RESERVE #ifndef GEN_BUILDER_STR_BUFFER_RESERVE
# define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(1) # define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(2)
#endif #endif
// These constexprs are used for allocation behavior of data structures // These constexprs are used for allocation behavior of data structures

View File

@ -1294,7 +1294,7 @@ internal Code parse_compilcated_definition ();
internal CodeBody parse_class_struct_body ( Parser::TokType which, Parser::Token name = Parser::NullToken ); internal CodeBody parse_class_struct_body ( Parser::TokType which, Parser::Token name = Parser::NullToken );
internal Code parse_class_struct ( Parser::TokType which, bool inplace_def ); internal Code parse_class_struct ( Parser::TokType which, bool inplace_def );
internal CodeDefine parse_define (); internal CodeDefine parse_define ();
internal Code parse_foward_or_definition ( Parser::TokType which, bool is_inplace ); internal Code parse_forward_or_definition ( Parser::TokType which, bool is_inplace );
internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Parser::Token name ); internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Parser::Token name );
internal Code parse_function_body (); internal Code parse_function_body ();
internal Code parse_global_nspace (); internal Code parse_global_nspace ();
@ -1309,6 +1309,7 @@ internal Code parse_simple_preprocess ( Parser::TokType
internal Code parse_static_assert (); internal Code parse_static_assert ();
internal void parse_template_args ( Parser::Token& token ); internal void parse_template_args ( Parser::Token& token );
internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType type, StrC name ); internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType type, StrC name );
internal CodeVar parse_variable_declaration_list ();
internal CodeClass parse_class ( bool inplace_def = false ); internal CodeClass parse_class ( bool inplace_def = false );
internal CodeConstructor parse_constructor (); internal CodeConstructor parse_constructor ();
@ -1316,7 +1317,7 @@ internal CodeDestructor parse_destructor ( CodeSpecifiers specifiers = NoC
internal CodeEnum parse_enum ( bool inplace_def = false ); internal CodeEnum parse_enum ( bool inplace_def = false );
internal CodeBody parse_export_body (); internal CodeBody parse_export_body ();
internal CodeBody parse_extern_link_body(); internal CodeBody parse_extern_link_body();
internal CodeExtern parse_exten_link (); internal CodeExtern parse_extern_link ();
internal CodeFriend parse_friend (); internal CodeFriend parse_friend ();
internal CodeFn parse_function (); internal CodeFn parse_function ();
internal CodeNS parse_namespace (); internal CodeNS parse_namespace ();
@ -1783,7 +1784,9 @@ Code parse_complicated_definition( Parser::TokType which )
if ( (idx - 2 ) == tokens.Idx ) if ( (idx - 2 ) == tokens.Idx )
{ {
// Its a forward declaration only // Its a forward declaration only
return parse_foward_or_definition( which, is_inplace ); Code result = parse_forward_or_definition( which, is_inplace );
Context.pop();
return result;
} }
Token tok = tokens[ idx - 1 ]; Token tok = tokens[ idx - 1 ];
@ -1831,7 +1834,9 @@ Code parse_complicated_definition( Parser::TokType which )
{ {
// Its a definition // Its a definition
// <which> { ... }; // <which> { ... };
return parse_foward_or_definition( which, is_inplace ); Code result = parse_forward_or_definition( which, is_inplace );
Context.pop();
return result;
} }
else if ( tok.Type == TokType::BraceSquare_Close) else if ( tok.Type == TokType::BraceSquare_Close)
{ {
@ -2262,7 +2267,7 @@ CodeDefine parse_define()
} }
internal inline internal inline
Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ) Code parse_forward_or_definition( Parser::TokType which, bool is_inplace )
{ {
using namespace Parser; using namespace Parser;
@ -2272,22 +2277,18 @@ Code parse_foward_or_definition( Parser::TokType which, bool is_inplace )
{ {
case TokType::Decl_Class: case TokType::Decl_Class:
result = parse_class( is_inplace ); result = parse_class( is_inplace );
Context.pop();
return result; return result;
case TokType::Decl_Enum: case TokType::Decl_Enum:
result = parse_enum( is_inplace ); result = parse_enum( is_inplace );
Context.pop();
return result; return result;
case TokType::Decl_Struct: case TokType::Decl_Struct:
result = parse_struct( is_inplace ); result = parse_struct( is_inplace );
Context.pop();
return result; return result;
case TokType::Decl_Union: case TokType::Decl_Union:
result = parse_union( is_inplace ); result = parse_union( is_inplace );
Context.pop();
return result; return result;
default: default:
@ -2295,7 +2296,6 @@ Code parse_foward_or_definition( Parser::TokType which, bool is_inplace )
"(only supports class, enum, struct, union) \n%s" "(only supports class, enum, struct, union) \n%s"
, Context.to_string() ); , Context.to_string() );
Context.pop();
return CodeInvalid; return CodeInvalid;
} }
@ -2499,7 +2499,7 @@ CodeBody parse_global_nspace( CodeT which )
if ( which == Extern_Linkage_Body ) if ( which == Extern_Linkage_Body )
log_failure( "Nested extern linkage\n%s", Context.to_string() ); log_failure( "Nested extern linkage\n%s", Context.to_string() );
member = parse_extern_link_body(); member = parse_extern_link();
break; break;
case TokType::Decl_Namespace: case TokType::Decl_Namespace:
@ -3636,17 +3636,30 @@ CodeVar parse_variable_after_name(
bitfield_expr = untyped_str( expr_tok ); bitfield_expr = untyped_str( expr_tok );
} }
CodeVar next_var = NoCode;
Token stmt_end = NullToken;
CodeComment inline_cmt = NoCode;
if ( type )
{
if ( currtok.Type == TokType::Comma )
{
// Were dealing with a statement with more than one declaration
// This is only handled this way if its the first declaration
// Otherwise its looped through in parse_variable_declaration_list
next_var = parse_variable_declaration_list();
}
// If we're dealing with a "comma-procedding then we cannot expect a statement end or inline comment
// Any comma procedding variable will not have a type provided so it can act as a indicator to skip this
Token stmt_end = currtok; Token stmt_end = currtok;
eat( TokType::Statement_End ); eat( TokType::Statement_End );
// Check for inline comment : <type> <identifier> = <expression>; // <inline comment> // Check for inline comment : <type> <identifier> = <expression>; // <inline comment>
CodeComment inline_cmt = NoCode; if ( left && ( currtok_noskip.Type == TokType::Comment ) && currtok_noskip.Line == stmt_end.Line )
if ( left
&& ( currtok_noskip.Type == TokType::Comment )
&& currtok_noskip.Line == stmt_end.Line )
{ {
inline_cmt = parse_comment(); inline_cmt = parse_comment();
} }
}
using namespace ECode; using namespace ECode;
@ -3656,6 +3669,8 @@ CodeVar parse_variable_after_name(
result->Name = get_cached_string( name ); result->Name = get_cached_string( name );
result->ModuleFlags = mflags; result->ModuleFlags = mflags;
// Type can be null if we're dealing with a declaration from a variable declaration-list
if ( type )
result->ValueType = type; result->ValueType = type;
if (array_expr ) if (array_expr )
@ -3676,6 +3691,90 @@ CodeVar parse_variable_after_name(
if ( inline_cmt ) if ( inline_cmt )
result->InlineCmt = inline_cmt; result->InlineCmt = inline_cmt;
if ( next_var )
{
result->NextVar = next_var;
result->NextVar->Parent = result;
}
Context.pop();
return result;
}
/*
Note(Ed): This does not support the following:
* Function Pointers
*/
internal CodeVar parse_variable_declaration_list()
{
using namespace Parser;
push_scope();
CodeVar result = NoCode;
CodeVar last_var = NoCode;
while ( check( TokType::Comma ) )
{
eat( TokType::Comma );
CodeSpecifiers specifiers = NoCode;
while ( left && currtok.is_specifier() )
{
SpecifierT spec = ESpecifier::to_type( currtok );
switch ( spec )
{
case ESpecifier::Const:
if ( specifiers->NumEntries && specifiers->ArrSpecs[ specifiers->NumEntries - 1 ] != ESpecifier::Ptr )
{
log_failure( "Error, const specifier must come after pointer specifier for variable declaration proceeding comma\n"
"(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s"
, Context.to_string() );
specifiers.append( spec );
}
break;
case ESpecifier::Ptr:
case ESpecifier::Ref:
case ESpecifier::RValue:
break;
default:
{
log_failure( "Error, invalid specifier '%s' proceeding comma\n"
"(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s"
, currtok.Text, Context.to_string() );
continue;
}
break;
}
if ( specifiers )
specifiers.append( spec );
else
specifiers = def_specifier( spec );
}
StrC name = currtok;
eat( TokType::Identifier );
CodeVar var = parse_variable_after_name( ModuleFlag::None, NoCode, specifiers, NoCode, name );
// TODO(Ed) : CodeVar is going to need a procedure to append comma-defined vars to itself.
if ( ! result )
{
result.ast = var.ast;
last_var.ast = var.ast;
}
else
{
last_var->NextVar.ast = var.ast;
last_var->NextVar->Parent.ast = rcast(AST*, var.ast);
last_var.ast = var.ast;
}
}
Context.pop(); Context.pop();
return result; return result;
} }
@ -4837,16 +4936,16 @@ CodeType parse_type( bool* typedef_is_function )
// Check if native type keywords are used, eat them for the signature. // Check if native type keywords are used, eat them for the signature.
else if ( currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 ) else if ( currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 )
{ {
// TODO(Ed) : Review this... Its necessary for parsing however the algo's path to this is lost...
name = currtok; name = currtok;
eat( currtok.Type ); eat( currtok.Type );
while (currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 ) while ( left && currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 )
{ {
eat( currtok.Type ); eat( currtok.Type );
} }
name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text;
Context.Scope->Name = name;
} }
// The usual Identifier type signature that may have namespace qualifiers // The usual Identifier type signature that may have namespace qualifiers
@ -4925,7 +5024,8 @@ CodeType parse_type( bool* typedef_is_function )
last_capture = scanner; last_capture = scanner;
} }
bool is_for_opcast = str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0; bool has_context = Context.Scope && Context.Scope->Prev;
bool is_for_opcast = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0;
if ( is_for_opcast && is_function_typename && last_capture ) if ( is_for_opcast && is_function_typename && last_capture )
{ {
// If we're parsing for an operator cast, having one capture start is not enough // If we're parsing for an operator cast, having one capture start is not enough
@ -5203,6 +5303,7 @@ CodeTypedef parse_typedef()
|| currtok.Type == TokType::Decl_Struct || currtok.Type == TokType::Decl_Struct
|| currtok.Type == TokType::Decl_Union; || currtok.Type == TokType::Decl_Union;
// This code is highly correlated with parse_compilcated_definition
if ( is_complicated ) if ( is_complicated )
{ {
TokArray tokens = Context.Tokens; TokArray tokens = Context.Tokens;
@ -5224,7 +5325,7 @@ CodeTypedef parse_typedef()
if ( (idx - 2 ) == tokens.Idx ) if ( (idx - 2 ) == tokens.Idx )
{ {
// Its a forward declaration only // Its a forward declaration only
type = parse_foward_or_definition( currtok.Type, from_typedef ); type = parse_forward_or_definition( currtok.Type, from_typedef );
} }
Token tok = tokens[ idx - 1 ]; Token tok = tokens[ idx - 1 ];
@ -5263,13 +5364,15 @@ CodeTypedef parse_typedef()
return CodeInvalid; return CodeInvalid;
} }
type = parse_type(); // TODO(Ed) : I'm not sure if I have to use parse_type here, I'd rather not as that would complicate parse_type.
// type = parse_type();
type = parse_forward_or_definition( currtok.Type, from_typedef );
} }
else if ( tok.Type == TokType::BraceCurly_Close ) else if ( tok.Type == TokType::BraceCurly_Close )
{ {
// Its a definition // Its a definition
// <which> { ... }; // <which> { ... };
type = parse_foward_or_definition( currtok.Type, from_typedef ); type = parse_forward_or_definition( currtok.Type, from_typedef );
} }
else if ( tok.Type == TokType::BraceSquare_Close) else if ( tok.Type == TokType::BraceSquare_Close)
{ {
@ -5327,7 +5430,12 @@ CodeTypedef parse_typedef()
result->IsFunction = false; result->IsFunction = false;
} }
if ( type )
{
result->UnderlyingType = type; result->UnderlyingType = type;
result->UnderlyingType->Parent = rcast(AST*, result.ast);
}
// Type needs to be aware of its parent so that it can be serialized properly.
if ( type->Type == Typename && array_expr && array_expr->Type != Invalid ) if ( type->Type == Typename && array_expr && array_expr->Type != Invalid )
type.cast<CodeType>()->ArrExpr = array_expr; type.cast<CodeType>()->ArrExpr = array_expr;

View File

@ -3,14 +3,23 @@
# That or just rewrite it in an sh script and call it a day. # That or just rewrite it in an sh script and call it a day.
Import-Module ./helpers/target_arch.psm1 Import-Module ./helpers/target_arch.psm1
$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1'
$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' $devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1'
$format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1'
$incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1'
$vendor_toolchain = Join-Path $PSScriptRoot 'helpers/vendor_toolchain.ps1'
$path_root = git rev-parse --show-toplevel $path_root = git rev-parse --show-toplevel
Import-Module $target_arch
Import-Module $format_cpp
Push-Location $path_root Push-Location $path_root
#region Arguments #region Arguments
$vendor = $null $vendor = $null
$release = $null $release = $null
$verbose = $false
[bool] $bootstrap = $false [bool] $bootstrap = $false
[bool] $singleheader = $false [bool] $singleheader = $false
[bool] $test = $false [bool] $test = $false
@ -22,6 +31,7 @@ Push-Location $path_root
if ( $args ) { $args | ForEach-Object { if ( $args ) { $args | ForEach-Object {
switch ($_){ switch ($_){
{ $_ -in $vendors } { $vendor = $_; break } { $_ -in $vendors } { $vendor = $_; break }
"verbose" { $verbose = $true }
"release" { $release = $true } "release" { $release = $true }
"debug" { $release = $false } "debug" { $release = $false }
"bootstrap" { $bootstrap = $true } "bootstrap" { $bootstrap = $true }
@ -47,295 +57,24 @@ if ( $release -eq $null ) {
write-host "No build type specified, assuming debug" write-host "No build type specified, assuming debug"
$release = $false $release = $false
} }
elseif ( $release -eq $false ) {
$debug = $true
}
else {
$optimize = treu
}
if ( $bootstrap -eq $false -and $singleheader -eq $false -and $test -eq $false ) { if ( $bootstrap -eq $false -and $singleheader -eq $false -and $test -eq $false ) {
throw "No build target specified. One must be specified, this script will not assume one" throw "No build target specified. One must be specified, this script will not assume one"
} }
. $vendor_toolchain
. $incremental_checks
write-host "Building gencpp with $vendor" write-host "Building gencpp with $vendor"
write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )"
function run-compiler
{
param( $compiler, $unit, $compiler_args )
write-host "`Compiling $unit"
write-host "Compiler config:"
$compiler_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
$time_taken = Measure-Command {
& $compiler $compiler_args 2>&1 | ForEach-Object {
$color = 'White'
switch ($_){
{ $_ -match "error" } { $color = 'Red' ; break }
{ $_ -match "warning" } { $color = 'Yellow'; break }
}
write-host `t $_ -ForegroundColor $color
}
}
if ( Test-Path($unit) ) {
write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms"
}
else {
write-host "Compile failed for $unit" -ForegroundColor Red
}
}
function run-linker
{
param( $linker, $binary, $linker_args )
write-host "`Linking $binary"
write-host "Linker config:"
$linker_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
$time_taken = Measure-Command {
& $linker $linker_args 2>&1 | ForEach-Object {
$color = 'White'
switch ($_){
{ $_ -match "error" } { $color = 'Red' ; break }
{ $_ -match "warning" } { $color = 'Yellow'; break }
}
write-host `t $_ -ForegroundColor $color
}
}
if ( Test-Path($binary) ) {
write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms"
}
else {
write-host "Linking failed for $binary" -ForegroundColor Red
}
}
function run-compile-and-link
{
param( $vendor, $unit, $compiler_args, $linker_args )
write-host "`Compiling & Linking $unit"
write-host "Compiler config:"
$compiler_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
write-host "Linker config:"
$linker_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
$time_taken = Measure-Command {
& $vendor $compiler_args $linker_args 2>&1 | ForEach-Object {
$color = 'White'
switch ($_){
{ $_ -match "error" } { $color = 'Red' ; break }
{ $_ -match "warning" } { $color = 'Yellow'; break }
}
write-host `t $_ -ForegroundColor $color
}
}
# if ( Test-Path($binary) ) {
# write-host "$binary compile & link finished in $($time_taken.TotalMilliseconds) ms"
# }
# else {
# write-host "Compile & Link failed for $binary" -ForegroundColor Red
# }
}
if ( $vendor -match "clang" )
{
# https://clang.llvm.org/docs/ClangCommandLineReference.html
$flag_compile = '-c'
$flag_color_diagnostics = '-fcolor-diagnostics'
$flag_no_color_diagnostics = '-fno-color-diagnostics'
$flag_debug = '-g'
$flag_debug_codeview = '-gcodeview'
$flag_define = '-D'
$flag_preprocess = '-E'
$flag_include = '-I'
$flag_library = '-l'
$flag_library_path = '-L'
$flag_link_win = '-Wl,'
$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
$flag_link_win_machine_32 = '/MACHINE:X86'
$flag_link_win_machine_64 = '/MACHINE:X64'
$flag_link_win_debug = '/DEBUG'
$flag_link_win_pdb = '/PDB:'
$flag_link_win_path_output = '/OUT:'
$flag_no_optimization = '-O0'
$flag_path_output = '-o'
$flag_preprocess_non_intergrated = '-no-integrated-cpp'
$flag_profiling_debug = '-fdebug-info-for-profiling'
$flag_target_arch = '-target'
$flag_wall = '-Wall'
$flag_warning = '-W'
$flag_warning_as_error = '-Werror'
$flag_win_nologo = '/nologo'
$ignore_warning_ms_include = 'no-microsoft-include'
$target_arch = Get-TargetArchClang
$warning_ignores = @(
$ignore_warning_ms_include
)
# https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170
$libraries = @(
'Kernel32' # For Windows API
# 'msvcrt', # For the C Runtime (Dynamically Linked)
# 'libucrt',
'libcmt' # For the C Runtime (Static Linkage)
)
function build-simple
{
param( $includes, $unit, $executable )
Write-Host "build-simple: clang"
$object = $executable -replace '\.exe', '.obj'
$pdb = $executable -replace '\.exe', '.pdb'
$compiler_args = @(
$flag_no_color_diagnostics,
$flag_target_arch, $target_arch,
$flag_wall,
$flag_preprocess_non_intergrated,
( $flag_define + 'GEN_TIME' ),
# ( $flag_path_output + $object ),
( $flag_path_output + $executable )
( $flag_include + $includes )
)
if ( $release -eq $false ) {
$compiler_args += ( $flag_define + 'Build_Debug' )
$compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug
$compiler_args += $flag_no_optimization
}
$warning_ignores | ForEach-Object {
$compiler_args += $flag_warning + $_
}
# $compiler_args += $flag_preprocess
# $compiler_args += $flag_compile, $unit
# run-compiler $compiler $unit $compiler_args
$linker_args = @(
$flag_link_win_subsystem_console,
$flag_link_win_machine_64,
$( $flag_link_win_path_output + $executable )
)
if ( $release -eq $false ) {
$linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb
}
else {
}
$libraries | ForEach-Object {
$linker_args += $_ + '.lib'
}
# $linker_args += $object
# run-linker $linker $executable $linker_args
$compiler_args += $unit
# $linker_args += $object
run-compile-and-link $compiler $unit $compiler_args
}
$compiler = 'clang++'
$linker = 'lld-link'
}
if ( $vendor -match "msvc" )
{
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
$flag_compile = '/c'
$flag_debug = '/Zi'
$flag_define = '/D'
$flag_include = '/I'
$flag_full_src_path = '/FC'
$flag_nologo = '/nologo'
$flag_dll = '/LD'
$flag_dll_debug = '/LDd'
$flag_linker = '/link'
$flag_link_debug = '/DEBUG'
$flag_link_pdb = '/PDB:'
$flag_link_machine_32 = '/MACHINE:X86'
$flag_link_machine_64 = '/MACHINE:X64'
$flag_link_path_output = '/OUT:'
$flag_link_rt_dll = '/MD'
$flag_link_rt_dll_debug = '/MDd'
$flag_link_rt_static = '/MT'
$flag_link_rt_static_debug = '/MTd'
$flag_link_subsystem_console = '/SUBSYSTEM:CONSOLE'
$flag_link_subsystem_windows = '/SUBSYSTEM:WINDOWS'
$flag_no_optimization = '/Od'
$flag_out_name = '/OUT:'
$flag_path_interm = '/Fo'
$flag_path_debug = '/Fd'
$flag_path_output = '/Fe'
$flag_preprocess_conform = '/Zc:preprocessor'
# This works because this project uses a single unit to build
function build-simple
{
param( $includes, $unit, $executable )
Write-Host "build-simple: msvc"
$object = $executable -replace '\.exe', '.obj'
$pdb = $executable -replace '\.exe', '.pdb'
$compiler_args = @(
$flag_nologo,
$flag_preprocess_conform,
$flag_debug,
( $flag_define + 'GEN_TIME' ),
$flag_full_src_path,
( $flag_path_interm + $path_build + '\' ),
( $flag_path_output + $path_build + '\' )
)
if ( $release -eq $false ) {
$compiler_args += ( $flag_define + 'Build_Debug' )
$compiler_args += ( $flag_path_debug + $path_build + '\' )
$compiler_args += $flag_link_rt_static_debug
$compiler_args += $flag_no_optimization
}
else {
$compiler_args += $flag_link_rt_static
}
$compiler_args += $includes | ForEach-Object { $flag_include + $_ }
$compiler_args += $flag_compile, $unit
run-compiler $compiler $unit $compiler_args
$linker_args = @(
$flag_nologo,
$flag_link_machine_64,
$flag_link_subsystem_console,
( $flag_link_path_output + $executable )
)
if ( $release -eq $false ) {
$linker_args += $flag_link_debug
$linker_args += $flag_link_pdb + $pdb
}
else {
}
$linker_args += $object
run-linker $linker $executable $linker_args
}
$compiler = 'cl'
$linker = 'link'
}
#endregion Configuration
#region Building #region Building
$path_build = Join-Path $path_root build $path_build = Join-Path $path_root build
$path_project = Join-Path $path_root project $path_project = Join-Path $path_root project
@ -359,11 +98,18 @@ if ( $bootstrap )
New-Item -ItemType Directory -Path $path_comp_gen New-Item -ItemType Directory -Path $path_comp_gen
} }
$compiler_args = @()
$compiler_args += ( $flag_define + 'GEN_TIME' )
$linker_args = @(
$flag_link_win_subsystem_console
)
$includes = @( $path_project) $includes = @( $path_project)
$unit = join-path $path_project "bootstrap.cpp" $unit = join-path $path_project "bootstrap.cpp"
$executable = join-path $path_build "bootstrap.exe" $executable = join-path $path_build "bootstrap.exe"
build-simple $includes $unit $executable build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_project Push-Location $path_project
if ( Test-Path( $executable ) ) { if ( Test-Path( $executable ) ) {
@ -394,7 +140,14 @@ if ( $singleheader )
$unit = join-path $path_singleheader "singleheader.cpp" $unit = join-path $path_singleheader "singleheader.cpp"
$executable = join-path $path_build "singleheader.exe" $executable = join-path $path_build "singleheader.exe"
build-simple $includes $unit $executable $compiler_args = @()
$compiler_args += ( $flag_define + 'GEN_TIME' )
$linker_args = @(
$flag_link_win_subsystem_console
)
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_singleheader Push-Location $path_singleheader
if ( Test-Path( $executable ) ) { if ( Test-Path( $executable ) ) {
@ -431,7 +184,14 @@ if ( $test )
$unit = join-path $path_test "test.cpp" $unit = join-path $path_test "test.cpp"
$executable = join-path $path_build "test.exe" $executable = join-path $path_build "test.exe"
build-simple $includes $unit $executable $compiler_args = @()
$compiler_args += ( $flag_define + 'GEN_TIME' )
$linker_args = @(
$flag_link_win_subsystem_console
)
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
Push-Location $path_test Push-Location $path_test
Write-Host $path_test Write-Host $path_test
@ -449,29 +209,7 @@ if ( $test )
#endregion Building #endregion Building
#region Formatting #region Formatting
function format-cpp push-location $path_scripts
{
param( $path, $include, $exclude )
# Format generated gencpp
Write-Host "`nBeginning format"
$formatParams = @(
'-i' # In-place
'-style=file:./scripts/.clang-format'
'-verbose'
)
$targetFiles = @(
Get-ChildItem -Recurse -Path $path -Include $include -Exclude $exclude
| Select-Object -ExpandProperty FullName
)
$time_taken = Measure-Command {
clang-format $formatParams $targetFiles
}
Write-Host "`nFormatting complete in $($time_taken.TotalMilliseconds) ms"
}
if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) ) if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) )
{ {
$path_gen = join-path $path_project gen $path_gen = join-path $path_project gen
@ -485,6 +223,7 @@ if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) )
$exclude = $null $exclude = $null
format-cpp $path_gen $include $exclude format-cpp $path_gen $include $exclude
format-cpp $path_comp_gen @( 'ast_inlines.hpp', 'ecode.hpp', 'especifier.hpp', 'eoperator.hpp', 'etoktype.cpp' ) $null format-cpp $path_comp_gen @( 'ast_inlines.hpp', 'ecode.hpp', 'especifier.hpp', 'eoperator.hpp', 'etoktype.cpp' ) $null
} }
if ( $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp")) ) if ( $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp")) )
@ -506,6 +245,7 @@ if ( $test -and $false )
$exclude = $null $exclude = $null
format-cpp $path_gen $include $exclude format-cpp $path_gen $include $exclude
} }
pop-location
#endregion Formatting #endregion Formatting
Pop-Location # $path_root Pop-Location # $path_root

View File

@ -23,5 +23,6 @@ if ( -not (Test-Path $vs_devshell) ) {
# Launch the Visual Studio Developer Shell # Launch the Visual Studio Developer Shell
Push-Location Push-Location
write-host @args
& $vs_devshell @args & $vs_devshell @args
Pop-Location Pop-Location

View File

@ -0,0 +1,26 @@
# format_cpp.psm1
function format-cpp
{
param( $path, $include, $exclude )
# Format generated gencpp
Write-Host "Beginning format"
$formatParams = @(
'-i' # In-place
'-style=file:.clang-format'
'-verbose'
)
$targetFiles = @(
Get-ChildItem -Recurse -Path $path -Include $include -Exclude $exclude
| Select-Object -ExpandProperty FullName
)
$time_taken = Measure-Command {
clang-format $formatParams $targetFiles
}
Write-Host "Formatting complete in $($time_taken.TotalMilliseconds) ms`n"
}
Export-ModuleMember -Function format-cpp

View File

@ -0,0 +1,73 @@
# This is meant to be used with build.ps1, and is not a standalone script.
function check-FileForChanges
{
param(
[Parameter(Mandatory=$true)]
[string]$path_file
)
if (-not (Test-Path $path_file -PathType Leaf)) {
Write-Error "The provided path is not a valid file: $path_file"
return $false
}
$file_name = Split-Path $path_file -Leaf
$path_csv = Join-Path $path_build ($file_name + "_file_hash.csv")
$csv_file_hash = $null
if (Test-Path $path_csv) {
$csv_file_hash = Import-Csv $path_csv | Select-Object -ExpandProperty value
}
$current_hash_info = Get-FileHash -Path $path_file -Algorithm MD5
$current_file_hash = $current_hash_info.Hash
# Save the current hash to the CSV
[PSCustomObject]@{
name = $path_file
value = $current_file_hash
} | Export-Csv $path_csv -NoTypeInformation
if ($csv_file_hash -and $csv_file_hash -eq $current_file_hash) {
return $false
} else {
return $true
}
}
# Check to see if the module has changed files since the last build
function check-ModuleForChanges
{
param( [string]$path_module, [array]$excludes )
$module_name = split-path $path_module -leaf
$path_csv = Join-Path $path_build ($module_name + "_module_hashes.csv")
$csv_file_hashes = $null
if ( test-path $path_csv ) {
$csv_file_hashes = @{}
import-csv $path_csv | foreach-object {
$csv_file_hashes[ $_.name ] = $_.value
}
}
$file_hashes = @{}
get-childitem -path $path_module -recurse -file -Exclude $excludes | foreach-object {
$id = $_.fullname
$hash_info = get-filehash -path $id -Algorithm MD5
$file_hashes[ $id ] = $hash_info.Hash
}
$file_hashes.GetEnumerator() | foreach-object { [PSCustomObject]$_ } |
export-csv $path_csv -NoTypeInformation
if ( -not $csv_file_hashes ) { return $true }
if ( $csv_file_hashes.Count -ne $file_hashes.Count ) { return $true }
foreach ( $key in $csv_file_hashes.Keys ) {
if ( $csv_file_hashes[ $key ] -ne $file_hashes[ $key ] ) {
return $true
}
}
return $false
}

View File

@ -0,0 +1,525 @@
# This is meant to be used with build.ps1, and is not a standalone script.
if ($IsWindows) {
# This HandmadeHero implementation is only designed for 64-bit systems
& $devshell -arch amd64
}
if ( $vendor -eq $null ) {
write-host "No vendor specified, assuming clang available"
$vendor = "clang"
}
if ( $dev ) {
if ( $debug -eq $null ) {
$debug = $true
}
if ( $optimize -eq $null ) {
$optimize = $false
}
}
function run-compiler
{
param( $compiler, $unit, $compiler_args )
if ( $analysis ) {
$compiler_args += $flag_syntax_only
}
write-host "`Compiling $unit"
if ( $verbose ) {
write-host "Compiler config:"
$compiler_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
}
$time_taken = Measure-Command {
& $compiler $compiler_args 2>&1 | ForEach-Object {
$color = 'White'
switch ($_){
{ $_ -match "error" } { $color = 'Red' ; break }
{ $_ -match "warning" } { $color = 'Yellow'; break }
}
write-host `t $_ -ForegroundColor $color
}
}
if ( $LASTEXITCODE -eq 0 ) {
write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms`n"
return $true
}
else {
write-host "Compile failed for $unit`n" -ForegroundColor Red
return $false
}
}
function run-linker
{
param( $linker, $binary, $linker_args )
write-host "`Linking $binary"
if ( $verbose ) {
write-host "Linker config:"
$linker_args | ForEach-Object {
write-host $_ -ForegroundColor Cyan
}
}
$time_taken = Measure-Command {
& $linker $linker_args 2>&1 | ForEach-Object {
$color = 'White'
switch ($_){
{ $_ -match "error" } { $color = 'Red' ; break }
{ $_ -match "warning" } { $color = 'Yellow'; break }
}
write-host `t $_ -ForegroundColor $color
}
}
if ( $LASTEXITCODE -eq 0 ) {
write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms`n"
return $true
}
else {
write-host "Linking failed for $binary`n" -ForegroundColor Red
return $false
}
}
if ( $vendor -match "clang" )
{
# https://clang.llvm.org/docs/ClangCommandLineReference.html
$flag_all_c = '/TC'
$flag_all_cpp = '/TP'
$flag_compile = '-c'
$flag_color_diagnostics = '-fcolor-diagnostics'
$flag_no_color_diagnostics = '-fno-color-diagnostics'
$flag_debug = '-g'
$flag_debug_codeview = '-gcodeview'
$flag_define = '-D'
$flag_exceptions_disabled = '-fno-exceptions'
$flag_preprocess = '-E'
$flag_include = '-I'
$flag_section_data = '-fdata-sections'
$flag_section_functions = '-ffunction-sections'
$flag_library = '-l'
$flag_library_path = '-L'
$flag_linker = '-Wl,'
if ( $IsWindows ) {
$flag_link_dll = '/DLL'
$flag_link_mapfile = '/MAP:'
$flag_link_optimize_references = '/OPT:REF'
}
if ( $IsLinux ) {
$flag_link_mapfile = '--Map='
$flag_link_optimize_references = '--gc-sections'
}
$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
$flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
$flag_link_win_machine_32 = '/MACHINE:X86'
$flag_link_win_machine_64 = '/MACHINE:X64'
$flag_link_win_debug = '/DEBUG'
$flag_link_win_pdb = '/PDB:'
$flag_link_win_path_output = '/OUT:'
$flag_no_optimization = '-O0'
$flag_optimize_fast = '-O2'
$flag_optimize_size = '-O1'
$flag_optimize_intrinsics = '-Oi'
$flag_path_output = '-o'
$flag_preprocess_non_intergrated = '-no-integrated-cpp'
$flag_profiling_debug = '-fdebug-info-for-profiling'
$flag_set_stack_size = '-stack='
$flag_syntax_only = '-fsyntax-only'
$flag_target_arch = '-target'
$flag_time_trace = '-ftime-trace'
$flag_verbose = '-v'
$flag_wall = '-Wall'
$flag_warning = '-W'
$flag_warnings_as_errors = '-Werror'
$flag_win_nologo = '/nologo'
$ignore_warning_ms_include = 'no-microsoft-include'
$ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage'
$target_arch = Get-TargetArchClang
$warning_ignores = @(
$ignore_warning_ms_include,
$ignore_warning_return_type_c_linkage
)
# https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170
if ( $IsWindows ) {
$libraries = @(
'Kernel32' # For Windows API
# 'msvcrt', # For the C Runtime (Dynamically Linked)
# 'libucrt',
'libcmt' # For the C Runtime (Static Linkage)
)
}
function build
{
param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [array]$units, [string]$binary )
$result = $false
#Write-Host "build: clang"
$map = $binary -replace '\.(exe|dll)$', '.map'
$map = join-path $path_output (split-path $map -Leaf)
# This allows dll reloads at runtime to work (jankily, use below if not interested)
$pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb"
# $pdb = $binary -replace '\.(exe|dll)$', ".pdb"
$compiler_args += @(
$flag_no_color_diagnostics,
$flag_exceptions_disabled,
$flag_target_arch, $target_arch,
$flag_wall,
$flag_preprocess_non_intergrated
# $flag_section_data,
# $flag_section_functions,
)
if ( $verbose ) {
# $compiler_args += $flag_verbose
# $compiler_args += $flag_time_trace
}
if ( $optimize ) {
$compiler_args += $flag_optimize_fast
}
else {
$compiler_args += $flag_no_optimization
}
if ( $debug ) {
$compiler_args += ( $flag_define + 'Build_Debug=1' )
$compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug
}
else {
$compiler_args += ( $flag_define + 'Build_Debug=0' )
}
$warning_ignores | ForEach-Object {
$compiler_args += $flag_warning + $_
}
$compiler_args += $includes | ForEach-Object { $flag_include + $_ }
$objects = @()
foreach ( $unit in $units )
{
$object = $unit -replace '\.(cpp|c)$', '.obj'
$object = join-path $path_output (split-path $object -Leaf)
$objects += $object
$unit_compiler_args = $compiler_args
$unit_compiler_args += ( $flag_path_output + $object )
$unit_compiler_args += $flag_compile, $unit
run-compiler $compiler $unit $unit_compiler_args
}
$linker_args += @(
$flag_link_win_machine_64,
$( $flag_link_win_path_output + $binary )
)
if ( $debug ) {
$linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map
}
$libraries | ForEach-Object {
$linker_args += $_ + '.lib'
}
$linker_args += $objects
return run-linker $linker $binary $linker_args
}
function build-simple
{
param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary )
$result = $false
#Write-Host "build-simple: clang"
$object = $unit -replace '\.(cpp|c)$', '.obj'
$map = $unit -replace '\.(cpp|c)$', '.map'
$object = join-path $path_output (split-path $object -Leaf)
$map = join-path $path_output (split-path $map -Leaf)
# This allows dll reloads at runtime to work (jankily, use below if not interested)
$pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb"
# $pdb = $binary -replace '\.(exe|dll)$', ".pdb"
$compiler_args += @(
$flag_no_color_diagnostics,
$flag_exceptions_disabled,
$flag_target_arch, $target_arch,
$flag_wall,
$flag_preprocess_non_intergrated,
# $flag_section_data,
# $flag_section_functions,
( $flag_path_output + $object )
)
if ( $verbose ) {
# $compiler_args += $flag_verbose
# $compiler_args += $flag_time_trace
}
if ( $optimize ) {
$compiler_args += $flag_optimize_fast
}
else {
$compiler_args += $flag_no_optimization
}
if ( $debug ) {
$compiler_args += ( $flag_define + 'Build_Debug=1' )
$compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug
}
else {
$compiler_args += ( $flag_define + 'Build_Debug=0' )
}
$warning_ignores | ForEach-Object {
$compiler_args += $flag_warning + $_
}
$compiler_args += $includes | ForEach-Object { $flag_include + $_ }
$compiler_args += $flag_compile, $unit
if ( (run-compiler $compiler $unit $compiler_args) -eq $false ) {
return $false
}
$linker_args += @(
$flag_link_win_machine_64,
$( $flag_link_win_path_output + $binary )
)
if ( $debug ) {
$linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map
}
$libraries | ForEach-Object {
$linker_args += $_ + '.lib'
}
$linker_args += $object
return run-linker $linker $binary $linker_args
}
$compiler = 'clang++'
$linker = 'lld-link'
}
if ( $vendor -match "msvc" )
{
# https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170
$flag_all_c = '/TC'
$flag_all_cpp = '/TP'
$flag_compile = '/c'
$flag_debug = '/Zi'
$flag_define = '/D'
$flag_exceptions_disabled = '/EHsc-'
$flag_RTTI_disabled = '/GR-'
$flag_include = '/I'
$flag_full_src_path = '/FC'
$flag_nologo = '/nologo'
$flag_dll = '/LD'
$flag_dll_debug = '/LDd'
$flag_linker = '/link'
$flag_link_dll = '/DLL'
$flag_link_no_incremental = '/INCREMENTAL:NO'
$flag_link_mapfile = '/MAP:'
$flag_link_optimize_references = '/OPT:REF'
$flag_link_win_debug = '/DEBUG'
$flag_link_win_pdb = '/PDB:'
$flag_link_win_machine_32 = '/MACHINE:X86'
$flag_link_win_machine_64 = '/MACHINE:X64'
$flag_link_win_path_output = '/OUT:'
$flag_link_win_rt_dll = '/MD'
$flag_link_win_rt_dll_debug = '/MDd'
$flag_link_win_rt_static = '/MT'
$flag_link_win_rt_static_debug = '/MTd'
$flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE'
$flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS'
$flag_no_optimization = '/Od'
$flag_optimize_fast = '/O2'
$flag_optimize_size = '/O1'
$flag_optimize_intrinsics = '/Oi'
$flag_optimized_debug = '/Zo'
$flag_out_name = '/OUT:'
$flag_path_interm = '/Fo'
$flag_path_debug = '/Fd'
$flag_path_output = '/Fe'
$flag_preprocess_conform = '/Zc:preprocessor'
$flag_set_stack_size = '/F'
$flag_syntax_only = '/Zs'
$flag_wall = '/Wall'
$flag_warnings_as_errors = '/WX'
function build
{
param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [array]$units, [string]$binary )
$result = $false
#Write-Host "build-simple: msvc"
$map = $binary -replace '\.(exe|dll)$', '.map'
$map = join-path $path_output (split-path $map -Leaf)
# This allows dll reloads at runtime to work (jankily, use below if not interested)
$pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb"
# $pdb = $binary -replace '\.(exe|dll)$', ".pdb"
$compiler_args += @(
$flag_nologo,
# $flag_all_cpp,
$flag_exceptions_disabled,
( $flag_define + '_HAS_EXCEPTIONS=0' ),
$flag_RTTI_disabled,
$flag_preprocess_conform,
$flag_full_src_path,
( $flag_path_interm + $path_output + '\' ),
( $flag_path_output + $path_output + '\' )
)
if ( $verbose ) {
}
if ( $optimize ) {
$compiler_args += $flag_optimize_fast
}
else {
$compiler_args += $flag_no_optimization
}
if ( $debug )
{
$compiler_args += $flag_debug
$compiler_args += ( $flag_define + 'Build_Debug=1' )
$compiler_args += ( $flag_path_debug + $path_output + '\' )
$compiler_args += $flag_link_win_rt_static_debug
if ( $optimize ) {
$compiler_args += $flag_optimized_debug
}
}
else {
$compiler_args += ( $flag_define + 'Build_Debug=0' )
$compiler_args += $flag_link_win_rt_static
}
$compiler_args += $includes | ForEach-Object { $flag_include + $_ }
$objects = @()
foreach ( $unit in $units )
{
$object = $unit -replace '\.(cpp|c)$', '.obj'
$object = join-path $path_output (split-path $object -Leaf)
$objects += $object
$unit_compiler_args = $compiler_args
# $unit_compiler_args += ( $flag_path_output + $object )
$unit_compiler_args += $flag_compile, $unit
run-compiler $compiler $unit $unit_compiler_args
}
$linker_args += @(
$flag_nologo,
$flag_link_win_machine_64,
$flag_link_no_incremental,
( $flag_link_win_path_output + $binary )
)
if ( $debug ) {
$linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map
}
else {
}
$linker_args += $objects
return run-linker $linker $binary $linker_args
}
function build-simple
{
param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary )
$result = $false
#Write-Host "build-simple: msvc"
$object = $unit -replace '\.(cpp|c)$', '.obj'
$map = $unit -replace '\.(cpp|c)$', '.map'
$object = join-path $path_output (split-path $object -Leaf)
$map = join-path $path_output (split-path $map -Leaf)
# This allows dll reloads at runtime to work (jankily, use below if not interested)
$pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb"
# $pdb = $binary -replace '\.(exe|dll)$', ".pdb"
$compiler_args += @(
$flag_nologo,
# $flag_all_cpp,
$flag_exceptions_disabled,
( $flag_define + '_HAS_EXCEPTIONS=0' ),
$flag_RTTI_disabled,
$flag_preprocess_conform,
$flag_full_src_path,
( $flag_path_interm + $path_output + '\' ),
( $flag_path_output + $path_output + '\' )
)
if ( $verbose ) {
}
if ( $optimize ) {
$compiler_args += $flag_optimize_fast
}
else {
$compiler_args += $flag_no_optimization
}
if ( $debug )
{
$compiler_args += $flag_debug
$compiler_args += ( $flag_define + 'Build_Debug=1' )
$compiler_args += ( $flag_path_debug + $path_output + '\' )
$compiler_args += $flag_link_win_rt_static_debug
if ( $optimize ) {
$compiler_args += $flag_optimized_debug
}
}
else {
$compiler_args += ( $flag_define + 'Build_Debug=0' )
$compiler_args += $flag_link_win_rt_static
}
$compiler_args += $includes | ForEach-Object { $flag_include + $_ }
$compiler_args += $flag_compile, $unit
if ( (run-compiler $compiler $unit $compiler_args) -eq $false ) {
return $false;
}
$linker_args += @(
$flag_nologo,
$flag_link_win_machine_64,
$flag_link_no_incremental,
( $flag_link_win_path_output + $binary )
)
if ( $debug ) {
$linker_args += $flag_link_win_debug
$linker_args += $flag_link_win_pdb + $pdb
$linker_args += $flag_link_mapfile + $map
}
else {
}
$linker_args += $object
return run-linker $linker $binary $linker_args
}
$compiler = 'cl'
$linker = 'link'
}