├── .editorconfig ├── .gitattributes ├── .gitignore ├── .gitmodules ├── .gitpod.yml ├── android-ext └── native_app_glue │ ├── NOTICE │ ├── android_native_app_glue.c │ └── android_native_app_glue.h ├── build.maple ├── emscripten ├── libraylib.web.a └── raylib.h ├── examples ├── breakout.v └── hello.v ├── license-mit.txt ├── license-unlicense.txt ├── raygui ├── raygui-license ├── raygui.c.v ├── raygui.h ├── raygui_ext.c.v └── raygui_test.v ├── raylib.c.v ├── raylib_ext.c.v ├── raylib_test.v ├── raymath ├── raymath-license ├── raymath.c.v ├── raymath.h └── raymath_ext.c.v ├── readme.md ├── scripts ├── gitpod-init.sh ├── jsongen.py └── raygen.py └── v.mod /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | end_of_line = lf 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | 7 | [*.v] 8 | indent_style = tab 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.bat eol=crlf 3 | 4 | *.v linguist-language=V 5 | *.vv linguist-language=V 6 | *.vsh linguist-language=V 7 | v.mod linguist-language=V 8 | .vdocignore linguist-language=ignore 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | main 3 | raygen 4 | *.exe 5 | *.exe~ 6 | *.so 7 | *.dylib 8 | *.dll 9 | 10 | # Ignore binary output folders 11 | bin/ 12 | 13 | # Ignore common editor/system specific metadata 14 | .DS_Store 15 | .idea/ 16 | .vscode/ 17 | *.iml 18 | 19 | # ENV 20 | .env 21 | 22 | # vweb and database 23 | *.db 24 | *.js 25 | 26 | # Local installs 27 | /v/ 28 | /clockwork/ 29 | /raylib/ 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "raylib"] 2 | path = external/raylib 3 | url = https://github.com/raysan5/raylib 4 | [submodule "raygui"] 5 | path = external/raygui 6 | url = https://github.com/raysan5/raygui 7 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - name: "Init" 3 | command: ./scripts/init.sh 4 | -------------------------------------------------------------------------------- /android-ext/native_app_glue/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2016 The Android Open Source Project 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /android-ext/native_app_glue/android_native_app_glue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "android_native_app_glue.h" 27 | #include 28 | 29 | #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) 30 | #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) 31 | 32 | /* For debug builds, always enable the debug traces in this library */ 33 | #ifndef NDEBUG 34 | # define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) 35 | #else 36 | # define LOGV(...) ((void)0) 37 | #endif 38 | 39 | static void free_saved_state(struct android_app* android_app) { 40 | pthread_mutex_lock(&android_app->mutex); 41 | if (android_app->savedState != NULL) { 42 | free(android_app->savedState); 43 | android_app->savedState = NULL; 44 | android_app->savedStateSize = 0; 45 | } 46 | pthread_mutex_unlock(&android_app->mutex); 47 | } 48 | 49 | int8_t android_app_read_cmd(struct android_app* android_app) { 50 | int8_t cmd; 51 | if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { 52 | switch (cmd) { 53 | case APP_CMD_SAVE_STATE: 54 | free_saved_state(android_app); 55 | break; 56 | } 57 | return cmd; 58 | } else { 59 | LOGE("No data on command pipe!"); 60 | } 61 | return -1; 62 | } 63 | 64 | static void print_cur_config(struct android_app* android_app) { 65 | char lang[2], country[2]; 66 | AConfiguration_getLanguage(android_app->config, lang); 67 | AConfiguration_getCountry(android_app->config, country); 68 | 69 | LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " 70 | "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " 71 | "modetype=%d modenight=%d", 72 | AConfiguration_getMcc(android_app->config), 73 | AConfiguration_getMnc(android_app->config), 74 | lang[0], lang[1], country[0], country[1], 75 | AConfiguration_getOrientation(android_app->config), 76 | AConfiguration_getTouchscreen(android_app->config), 77 | AConfiguration_getDensity(android_app->config), 78 | AConfiguration_getKeyboard(android_app->config), 79 | AConfiguration_getNavigation(android_app->config), 80 | AConfiguration_getKeysHidden(android_app->config), 81 | AConfiguration_getNavHidden(android_app->config), 82 | AConfiguration_getSdkVersion(android_app->config), 83 | AConfiguration_getScreenSize(android_app->config), 84 | AConfiguration_getScreenLong(android_app->config), 85 | AConfiguration_getUiModeType(android_app->config), 86 | AConfiguration_getUiModeNight(android_app->config)); 87 | } 88 | 89 | void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { 90 | switch (cmd) { 91 | case APP_CMD_INPUT_CHANGED: 92 | LOGV("APP_CMD_INPUT_CHANGED\n"); 93 | pthread_mutex_lock(&android_app->mutex); 94 | if (android_app->inputQueue != NULL) { 95 | AInputQueue_detachLooper(android_app->inputQueue); 96 | } 97 | android_app->inputQueue = android_app->pendingInputQueue; 98 | if (android_app->inputQueue != NULL) { 99 | LOGV("Attaching input queue to looper"); 100 | AInputQueue_attachLooper(android_app->inputQueue, 101 | android_app->looper, LOOPER_ID_INPUT, NULL, 102 | &android_app->inputPollSource); 103 | } 104 | pthread_cond_broadcast(&android_app->cond); 105 | pthread_mutex_unlock(&android_app->mutex); 106 | break; 107 | 108 | case APP_CMD_INIT_WINDOW: 109 | LOGV("APP_CMD_INIT_WINDOW\n"); 110 | pthread_mutex_lock(&android_app->mutex); 111 | android_app->window = android_app->pendingWindow; 112 | pthread_cond_broadcast(&android_app->cond); 113 | pthread_mutex_unlock(&android_app->mutex); 114 | break; 115 | 116 | case APP_CMD_TERM_WINDOW: 117 | LOGV("APP_CMD_TERM_WINDOW\n"); 118 | pthread_cond_broadcast(&android_app->cond); 119 | break; 120 | 121 | case APP_CMD_RESUME: 122 | case APP_CMD_START: 123 | case APP_CMD_PAUSE: 124 | case APP_CMD_STOP: 125 | LOGV("activityState=%d\n", cmd); 126 | pthread_mutex_lock(&android_app->mutex); 127 | android_app->activityState = cmd; 128 | pthread_cond_broadcast(&android_app->cond); 129 | pthread_mutex_unlock(&android_app->mutex); 130 | break; 131 | 132 | case APP_CMD_CONFIG_CHANGED: 133 | LOGV("APP_CMD_CONFIG_CHANGED\n"); 134 | AConfiguration_fromAssetManager(android_app->config, 135 | android_app->activity->assetManager); 136 | print_cur_config(android_app); 137 | break; 138 | 139 | case APP_CMD_DESTROY: 140 | LOGV("APP_CMD_DESTROY\n"); 141 | android_app->destroyRequested = 1; 142 | break; 143 | } 144 | } 145 | 146 | void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { 147 | switch (cmd) { 148 | case APP_CMD_TERM_WINDOW: 149 | LOGV("APP_CMD_TERM_WINDOW\n"); 150 | pthread_mutex_lock(&android_app->mutex); 151 | android_app->window = NULL; 152 | pthread_cond_broadcast(&android_app->cond); 153 | pthread_mutex_unlock(&android_app->mutex); 154 | break; 155 | 156 | case APP_CMD_SAVE_STATE: 157 | LOGV("APP_CMD_SAVE_STATE\n"); 158 | pthread_mutex_lock(&android_app->mutex); 159 | android_app->stateSaved = 1; 160 | pthread_cond_broadcast(&android_app->cond); 161 | pthread_mutex_unlock(&android_app->mutex); 162 | break; 163 | 164 | case APP_CMD_RESUME: 165 | free_saved_state(android_app); 166 | break; 167 | } 168 | } 169 | 170 | void app_dummy() { 171 | 172 | } 173 | 174 | static void android_app_destroy(struct android_app* android_app) { 175 | LOGV("android_app_destroy!"); 176 | free_saved_state(android_app); 177 | pthread_mutex_lock(&android_app->mutex); 178 | if (android_app->inputQueue != NULL) { 179 | AInputQueue_detachLooper(android_app->inputQueue); 180 | } 181 | AConfiguration_delete(android_app->config); 182 | android_app->destroyed = 1; 183 | pthread_cond_broadcast(&android_app->cond); 184 | pthread_mutex_unlock(&android_app->mutex); 185 | // Can't touch android_app object after this. 186 | } 187 | 188 | static void process_input(struct android_app* app, struct android_poll_source* source) { 189 | AInputEvent* event = NULL; 190 | while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { 191 | LOGV("New input event: type=%d\n", AInputEvent_getType(event)); 192 | if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { 193 | continue; 194 | } 195 | int32_t handled = 0; 196 | if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); 197 | AInputQueue_finishEvent(app->inputQueue, event, handled); 198 | } 199 | } 200 | 201 | static void process_cmd(struct android_app* app, struct android_poll_source* source) { 202 | int8_t cmd = android_app_read_cmd(app); 203 | android_app_pre_exec_cmd(app, cmd); 204 | if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); 205 | android_app_post_exec_cmd(app, cmd); 206 | } 207 | 208 | static void* android_app_entry(void* param) { 209 | struct android_app* android_app = (struct android_app*)param; 210 | 211 | android_app->config = AConfiguration_new(); 212 | AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); 213 | 214 | print_cur_config(android_app); 215 | 216 | android_app->cmdPollSource.id = LOOPER_ID_MAIN; 217 | android_app->cmdPollSource.app = android_app; 218 | android_app->cmdPollSource.process = process_cmd; 219 | android_app->inputPollSource.id = LOOPER_ID_INPUT; 220 | android_app->inputPollSource.app = android_app; 221 | android_app->inputPollSource.process = process_input; 222 | 223 | ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); 224 | ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, 225 | &android_app->cmdPollSource); 226 | android_app->looper = looper; 227 | 228 | pthread_mutex_lock(&android_app->mutex); 229 | android_app->running = 1; 230 | pthread_cond_broadcast(&android_app->cond); 231 | pthread_mutex_unlock(&android_app->mutex); 232 | 233 | android_main(android_app); 234 | 235 | android_app_destroy(android_app); 236 | return NULL; 237 | } 238 | 239 | // -------------------------------------------------------------------- 240 | // Native activity interaction (called from main thread) 241 | // -------------------------------------------------------------------- 242 | 243 | static struct android_app* android_app_create(ANativeActivity* activity, 244 | void* savedState, size_t savedStateSize) { 245 | struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); 246 | memset(android_app, 0, sizeof(struct android_app)); 247 | android_app->activity = activity; 248 | 249 | pthread_mutex_init(&android_app->mutex, NULL); 250 | pthread_cond_init(&android_app->cond, NULL); 251 | 252 | if (savedState != NULL) { 253 | android_app->savedState = malloc(savedStateSize); 254 | android_app->savedStateSize = savedStateSize; 255 | memcpy(android_app->savedState, savedState, savedStateSize); 256 | } 257 | 258 | int msgpipe[2]; 259 | if (pipe(msgpipe)) { 260 | LOGE("could not create pipe: %s", strerror(errno)); 261 | return NULL; 262 | } 263 | android_app->msgread = msgpipe[0]; 264 | android_app->msgwrite = msgpipe[1]; 265 | 266 | pthread_attr_t attr; 267 | pthread_attr_init(&attr); 268 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 269 | pthread_create(&android_app->thread, &attr, android_app_entry, android_app); 270 | 271 | // Wait for thread to start. 272 | pthread_mutex_lock(&android_app->mutex); 273 | while (!android_app->running) { 274 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 275 | } 276 | pthread_mutex_unlock(&android_app->mutex); 277 | 278 | return android_app; 279 | } 280 | 281 | static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { 282 | if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { 283 | LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); 284 | } 285 | } 286 | 287 | static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { 288 | pthread_mutex_lock(&android_app->mutex); 289 | android_app->pendingInputQueue = inputQueue; 290 | android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); 291 | while (android_app->inputQueue != android_app->pendingInputQueue) { 292 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 293 | } 294 | pthread_mutex_unlock(&android_app->mutex); 295 | } 296 | 297 | static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { 298 | pthread_mutex_lock(&android_app->mutex); 299 | if (android_app->pendingWindow != NULL) { 300 | android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); 301 | } 302 | android_app->pendingWindow = window; 303 | if (window != NULL) { 304 | android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); 305 | } 306 | while (android_app->window != android_app->pendingWindow) { 307 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 308 | } 309 | pthread_mutex_unlock(&android_app->mutex); 310 | } 311 | 312 | static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { 313 | pthread_mutex_lock(&android_app->mutex); 314 | android_app_write_cmd(android_app, cmd); 315 | while (android_app->activityState != cmd) { 316 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 317 | } 318 | pthread_mutex_unlock(&android_app->mutex); 319 | } 320 | 321 | static void android_app_free(struct android_app* android_app) { 322 | pthread_mutex_lock(&android_app->mutex); 323 | android_app_write_cmd(android_app, APP_CMD_DESTROY); 324 | while (!android_app->destroyed) { 325 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 326 | } 327 | pthread_mutex_unlock(&android_app->mutex); 328 | 329 | close(android_app->msgread); 330 | close(android_app->msgwrite); 331 | pthread_cond_destroy(&android_app->cond); 332 | pthread_mutex_destroy(&android_app->mutex); 333 | free(android_app); 334 | } 335 | 336 | static void onDestroy(ANativeActivity* activity) { 337 | LOGV("Destroy: %p\n", activity); 338 | android_app_free((struct android_app*)activity->instance); 339 | } 340 | 341 | static void onStart(ANativeActivity* activity) { 342 | LOGV("Start: %p\n", activity); 343 | android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); 344 | } 345 | 346 | static void onResume(ANativeActivity* activity) { 347 | LOGV("Resume: %p\n", activity); 348 | android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); 349 | } 350 | 351 | static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { 352 | struct android_app* android_app = (struct android_app*)activity->instance; 353 | void* savedState = NULL; 354 | 355 | LOGV("SaveInstanceState: %p\n", activity); 356 | pthread_mutex_lock(&android_app->mutex); 357 | android_app->stateSaved = 0; 358 | android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); 359 | while (!android_app->stateSaved) { 360 | pthread_cond_wait(&android_app->cond, &android_app->mutex); 361 | } 362 | 363 | if (android_app->savedState != NULL) { 364 | savedState = android_app->savedState; 365 | *outLen = android_app->savedStateSize; 366 | android_app->savedState = NULL; 367 | android_app->savedStateSize = 0; 368 | } 369 | 370 | pthread_mutex_unlock(&android_app->mutex); 371 | 372 | return savedState; 373 | } 374 | 375 | static void onPause(ANativeActivity* activity) { 376 | LOGV("Pause: %p\n", activity); 377 | android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); 378 | } 379 | 380 | static void onStop(ANativeActivity* activity) { 381 | LOGV("Stop: %p\n", activity); 382 | android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); 383 | } 384 | 385 | static void onConfigurationChanged(ANativeActivity* activity) { 386 | struct android_app* android_app = (struct android_app*)activity->instance; 387 | LOGV("ConfigurationChanged: %p\n", activity); 388 | android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); 389 | } 390 | 391 | static void onLowMemory(ANativeActivity* activity) { 392 | struct android_app* android_app = (struct android_app*)activity->instance; 393 | LOGV("LowMemory: %p\n", activity); 394 | android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); 395 | } 396 | 397 | static void onWindowFocusChanged(ANativeActivity* activity, int focused) { 398 | LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); 399 | android_app_write_cmd((struct android_app*)activity->instance, 400 | focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); 401 | } 402 | 403 | static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { 404 | LOGV("NativeWindowCreated: %p -- %p\n", activity, window); 405 | android_app_set_window((struct android_app*)activity->instance, window); 406 | } 407 | 408 | static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { 409 | LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); 410 | android_app_set_window((struct android_app*)activity->instance, NULL); 411 | } 412 | 413 | static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { 414 | LOGV("InputQueueCreated: %p -- %p\n", activity, queue); 415 | android_app_set_input((struct android_app*)activity->instance, queue); 416 | } 417 | 418 | static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { 419 | LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); 420 | android_app_set_input((struct android_app*)activity->instance, NULL); 421 | } 422 | 423 | JNIEXPORT 424 | void ANativeActivity_onCreate(ANativeActivity* activity, void* savedState, 425 | size_t savedStateSize) { 426 | LOGV("Creating: %p\n", activity); 427 | activity->callbacks->onDestroy = onDestroy; 428 | activity->callbacks->onStart = onStart; 429 | activity->callbacks->onResume = onResume; 430 | activity->callbacks->onSaveInstanceState = onSaveInstanceState; 431 | activity->callbacks->onPause = onPause; 432 | activity->callbacks->onStop = onStop; 433 | activity->callbacks->onConfigurationChanged = onConfigurationChanged; 434 | activity->callbacks->onLowMemory = onLowMemory; 435 | activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; 436 | activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; 437 | activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; 438 | activity->callbacks->onInputQueueCreated = onInputQueueCreated; 439 | activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; 440 | 441 | activity->instance = android_app_create(activity, savedState, savedStateSize); 442 | } 443 | -------------------------------------------------------------------------------- /android-ext/native_app_glue/android_native_app_glue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | #ifndef _ANDROID_NATIVE_APP_GLUE_H 19 | #define _ANDROID_NATIVE_APP_GLUE_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | /** 34 | * The native activity interface provided by 35 | * is based on a set of application-provided callbacks that will be called 36 | * by the Activity's main thread when certain events occur. 37 | * 38 | * This means that each one of this callbacks _should_ _not_ block, or they 39 | * risk having the system force-close the application. This programming 40 | * model is direct, lightweight, but constraining. 41 | * 42 | * The 'android_native_app_glue' static library is used to provide a different 43 | * execution model where the application can implement its own main event 44 | * loop in a different thread instead. Here's how it works: 45 | * 46 | * 1/ The application must provide a function named "android_main()" that 47 | * will be called when the activity is created, in a new thread that is 48 | * distinct from the activity's main thread. 49 | * 50 | * 2/ android_main() receives a pointer to a valid "android_app" structure 51 | * that contains references to other important objects, e.g. the 52 | * ANativeActivity obejct instance the application is running in. 53 | * 54 | * 3/ the "android_app" object holds an ALooper instance that already 55 | * listens to two important things: 56 | * 57 | * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX 58 | * declarations below. 59 | * 60 | * - input events coming from the AInputQueue attached to the activity. 61 | * 62 | * Each of these correspond to an ALooper identifier returned by 63 | * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, 64 | * respectively. 65 | * 66 | * Your application can use the same ALooper to listen to additional 67 | * file-descriptors. They can either be callback based, or with return 68 | * identifiers starting with LOOPER_ID_USER. 69 | * 70 | * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event, 71 | * the returned data will point to an android_poll_source structure. You 72 | * can call the process() function on it, and fill in android_app->onAppCmd 73 | * and android_app->onInputEvent to be called for your own processing 74 | * of the event. 75 | * 76 | * Alternatively, you can call the low-level functions to read and process 77 | * the data directly... look at the process_cmd() and process_input() 78 | * implementations in the glue to see how to do this. 79 | * 80 | * See the sample named "native-activity" that comes with the NDK with a 81 | * full usage example. Also look at the JavaDoc of NativeActivity. 82 | */ 83 | 84 | struct android_app; 85 | 86 | /** 87 | * Data associated with an ALooper fd that will be returned as the "outData" 88 | * when that source has data ready. 89 | */ 90 | struct android_poll_source { 91 | // The identifier of this source. May be LOOPER_ID_MAIN or 92 | // LOOPER_ID_INPUT. 93 | int32_t id; 94 | 95 | // The android_app this ident is associated with. 96 | struct android_app* app; 97 | 98 | // Function to call to perform the standard processing of data from 99 | // this source. 100 | void (*process)(struct android_app* app, struct android_poll_source* source); 101 | }; 102 | 103 | /** 104 | * This is the interface for the standard glue code of a threaded 105 | * application. In this model, the application's code is running 106 | * in its own thread separate from the main thread of the process. 107 | * It is not required that this thread be associated with the Java 108 | * VM, although it will need to be in order to make JNI calls any 109 | * Java objects. 110 | */ 111 | struct android_app { 112 | // The application can place a pointer to its own state object 113 | // here if it likes. 114 | void* userData; 115 | 116 | // Fill this in with the function to process main app commands (APP_CMD_*) 117 | void (*onAppCmd)(struct android_app* app, int32_t cmd); 118 | 119 | // Fill this in with the function to process input events. At this point 120 | // the event has already been pre-dispatched, and it will be finished upon 121 | // return. Return 1 if you have handled the event, 0 for any default 122 | // dispatching. 123 | int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); 124 | 125 | // The ANativeActivity object instance that this app is running in. 126 | ANativeActivity* activity; 127 | 128 | // The current configuration the app is running in. 129 | AConfiguration* config; 130 | 131 | // This is the last instance's saved state, as provided at creation time. 132 | // It is NULL if there was no state. You can use this as you need; the 133 | // memory will remain around until you call android_app_exec_cmd() for 134 | // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. 135 | // These variables should only be changed when processing a APP_CMD_SAVE_STATE, 136 | // at which point they will be initialized to NULL and you can malloc your 137 | // state and place the information here. In that case the memory will be 138 | // freed for you later. 139 | void* savedState; 140 | size_t savedStateSize; 141 | 142 | // The ALooper associated with the app's thread. 143 | ALooper* looper; 144 | 145 | // When non-NULL, this is the input queue from which the app will 146 | // receive user input events. 147 | AInputQueue* inputQueue; 148 | 149 | // When non-NULL, this is the window surface that the app can draw in. 150 | ANativeWindow* window; 151 | 152 | // Current content rectangle of the window; this is the area where the 153 | // window's content should be placed to be seen by the user. 154 | ARect contentRect; 155 | 156 | // Current state of the app's activity. May be either APP_CMD_START, 157 | // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. 158 | int activityState; 159 | 160 | // This is non-zero when the application's NativeActivity is being 161 | // destroyed and waiting for the app thread to complete. 162 | int destroyRequested; 163 | 164 | // ------------------------------------------------- 165 | // Below are "private" implementation of the glue code. 166 | 167 | pthread_mutex_t mutex; 168 | pthread_cond_t cond; 169 | 170 | int msgread; 171 | int msgwrite; 172 | 173 | pthread_t thread; 174 | 175 | struct android_poll_source cmdPollSource; 176 | struct android_poll_source inputPollSource; 177 | 178 | int running; 179 | int stateSaved; 180 | int destroyed; 181 | int redrawNeeded; 182 | AInputQueue* pendingInputQueue; 183 | ANativeWindow* pendingWindow; 184 | ARect pendingContentRect; 185 | }; 186 | 187 | enum { 188 | /** 189 | * Looper data ID of commands coming from the app's main thread, which 190 | * is returned as an identifier from ALooper_pollOnce(). The data for this 191 | * identifier is a pointer to an android_poll_source structure. 192 | * These can be retrieved and processed with android_app_read_cmd() 193 | * and android_app_exec_cmd(). 194 | */ 195 | LOOPER_ID_MAIN = 1, 196 | 197 | /** 198 | * Looper data ID of events coming from the AInputQueue of the 199 | * application's window, which is returned as an identifier from 200 | * ALooper_pollOnce(). The data for this identifier is a pointer to an 201 | * android_poll_source structure. These can be read via the inputQueue 202 | * object of android_app. 203 | */ 204 | LOOPER_ID_INPUT = 2, 205 | 206 | /** 207 | * Start of user-defined ALooper identifiers. 208 | */ 209 | LOOPER_ID_USER = 3, 210 | }; 211 | 212 | enum { 213 | /** 214 | * Command from main thread: the AInputQueue has changed. Upon processing 215 | * this command, android_app->inputQueue will be updated to the new queue 216 | * (or NULL). 217 | */ 218 | APP_CMD_INPUT_CHANGED, 219 | 220 | /** 221 | * Command from main thread: a new ANativeWindow is ready for use. Upon 222 | * receiving this command, android_app->window will contain the new window 223 | * surface. 224 | */ 225 | APP_CMD_INIT_WINDOW, 226 | 227 | /** 228 | * Command from main thread: the existing ANativeWindow needs to be 229 | * terminated. Upon receiving this command, android_app->window still 230 | * contains the existing window; after calling android_app_exec_cmd 231 | * it will be set to NULL. 232 | */ 233 | APP_CMD_TERM_WINDOW, 234 | 235 | /** 236 | * Command from main thread: the current ANativeWindow has been resized. 237 | * Please redraw with its new size. 238 | */ 239 | APP_CMD_WINDOW_RESIZED, 240 | 241 | /** 242 | * Command from main thread: the system needs that the current ANativeWindow 243 | * be redrawn. You should redraw the window before handing this to 244 | * android_app_exec_cmd() in order to avoid transient drawing glitches. 245 | */ 246 | APP_CMD_WINDOW_REDRAW_NEEDED, 247 | 248 | /** 249 | * Command from main thread: the content area of the window has changed, 250 | * such as from the soft input window being shown or hidden. You can 251 | * find the new content rect in android_app::contentRect. 252 | */ 253 | APP_CMD_CONTENT_RECT_CHANGED, 254 | 255 | /** 256 | * Command from main thread: the app's activity window has gained 257 | * input focus. 258 | */ 259 | APP_CMD_GAINED_FOCUS, 260 | 261 | /** 262 | * Command from main thread: the app's activity window has lost 263 | * input focus. 264 | */ 265 | APP_CMD_LOST_FOCUS, 266 | 267 | /** 268 | * Command from main thread: the current device configuration has changed. 269 | */ 270 | APP_CMD_CONFIG_CHANGED, 271 | 272 | /** 273 | * Command from main thread: the system is running low on memory. 274 | * Try to reduce your memory use. 275 | */ 276 | APP_CMD_LOW_MEMORY, 277 | 278 | /** 279 | * Command from main thread: the app's activity has been started. 280 | */ 281 | APP_CMD_START, 282 | 283 | /** 284 | * Command from main thread: the app's activity has been resumed. 285 | */ 286 | APP_CMD_RESUME, 287 | 288 | /** 289 | * Command from main thread: the app should generate a new saved state 290 | * for itself, to restore from later if needed. If you have saved state, 291 | * allocate it with malloc and place it in android_app.savedState with 292 | * the size in android_app.savedStateSize. The will be freed for you 293 | * later. 294 | */ 295 | APP_CMD_SAVE_STATE, 296 | 297 | /** 298 | * Command from main thread: the app's activity has been paused. 299 | */ 300 | APP_CMD_PAUSE, 301 | 302 | /** 303 | * Command from main thread: the app's activity has been stopped. 304 | */ 305 | APP_CMD_STOP, 306 | 307 | /** 308 | * Command from main thread: the app's activity is being destroyed, 309 | * and waiting for the app thread to clean up and exit before proceeding. 310 | */ 311 | APP_CMD_DESTROY, 312 | }; 313 | 314 | /** 315 | * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next 316 | * app command message. 317 | */ 318 | int8_t android_app_read_cmd(struct android_app* android_app); 319 | 320 | /** 321 | * Call with the command returned by android_app_read_cmd() to do the 322 | * initial pre-processing of the given command. You can perform your own 323 | * actions for the command after calling this function. 324 | */ 325 | void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); 326 | 327 | /** 328 | * Call with the command returned by android_app_read_cmd() to do the 329 | * final post-processing of the given command. You must have done your own 330 | * actions for the command before calling this function. 331 | */ 332 | void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); 333 | 334 | /** 335 | * Dummy function that used to be used to prevent the linker from stripping app 336 | * glue code. No longer necessary, since __attribute__((visibility("default"))) 337 | * does this for us. 338 | */ 339 | __attribute__(( 340 | deprecated("Calls to app_dummy are no longer necessary. See " 341 | "https://github.com/android-ndk/ndk/issues/381."))) void 342 | app_dummy(); 343 | 344 | /** 345 | * This is the function that application code must implement, representing 346 | * the main entry to the app. 347 | */ 348 | extern void android_main(struct android_app* app); 349 | 350 | #ifdef __cplusplus 351 | } 352 | #endif 353 | 354 | #endif /* _ANDROID_NATIVE_APP_GLUE_H */ 355 | -------------------------------------------------------------------------------- /build.maple: -------------------------------------------------------------------------------- 1 | plugins = [ 'v' ] 2 | 3 | config:v_main = 'raylib_test.v' 4 | 5 | task:clean = { 6 | run = 'rm -rf ${build_dir} && rm -rf raylib' 7 | } 8 | 9 | task:gen = { 10 | run = 'python3 scripts/jsongen.py && python3 scripts/raygen.py' 11 | } 12 | 13 | task:deps = { 14 | run = '${v} install' 15 | } 16 | -------------------------------------------------------------------------------- /emscripten/libraylib.web.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vlang/raylib/6b2125101db13225d02c6658d80352ee55c6b90e/emscripten/libraylib.web.a -------------------------------------------------------------------------------- /examples/breakout.v: -------------------------------------------------------------------------------- 1 | @[has_globals] 2 | module main 3 | 4 | import raylib 5 | import raylib.raymath 6 | 7 | const screen_width = 800 8 | const screen_height = 600 9 | 10 | const ball_radius = 10 11 | const ball_speed = 5 12 | 13 | const paddle_width = 100 14 | const paddle_height = 20 15 | const paddle_speed = 7 16 | 17 | const brick_width = 60 18 | const brick_height = 20 19 | const brick_rows = 5 20 | const brick_cols = screen_width / brick_width - 1 21 | const brick_gap = 5 22 | 23 | // Game state 24 | __global ball = raylib.Vector2{screen_width / 2, screen_height / 2} 25 | __global ball_direction = raylib.Vector2{1, 1} 26 | __global paddle = raylib.Rectangle{screen_width / 2 - paddle_width / 2, screen_height - paddle_height - 10, paddle_width, paddle_height} 27 | __global bricks = []raylib.Rectangle{} 28 | __global score = 0 29 | __global game_over = false 30 | 31 | fn init_bricks() []raylib.Rectangle { 32 | bricks = [] 33 | bstart := (screen_width + brick_gap - (brick_width + brick_gap) * brick_cols) / 2 34 | for row := 0; row < brick_rows; row++ { 35 | for col := 0; col < brick_cols; col++ { 36 | x := bstart + col * (brick_width + brick_gap) 37 | y := 80 + row * (brick_height + brick_gap) 38 | bricks << raylib.Rectangle{x, y, brick_width, brick_height} 39 | } 40 | } 41 | return bricks 42 | } 43 | 44 | fn reset_game() { 45 | ball = raylib.Vector2{screen_width / 2, screen_height / 2} 46 | ball_direction = raylib.Vector2{1, 1} 47 | paddle = raylib.Rectangle{screen_width / 2 - paddle_width / 2, screen_height - paddle_height - 10, paddle_width, paddle_height} 48 | init_bricks() 49 | score = 0 50 | game_over = false 51 | } 52 | 53 | fn update_game() { 54 | if game_over { 55 | if raylib.is_key_pressed(int(raylib.KeyboardKey.key_r)) { 56 | reset_game() 57 | } 58 | return 59 | } 60 | // move the paddle: 61 | if raylib.is_key_down(int(raylib.KeyboardKey.key_left)) && paddle.x > 0 { 62 | paddle.x -= paddle_speed 63 | } 64 | if raylib.is_key_down(int(raylib.KeyboardKey.key_right)) 65 | && paddle.x < screen_width - paddle.width { 66 | paddle.x += paddle_speed 67 | } 68 | // move the ball: 69 | ball.x += ball_direction.x * ball_speed 70 | ball.y += ball_direction.y * ball_speed 71 | // ball collision with walls 72 | if ball.x < ball_radius || ball.x > screen_width - ball_radius { 73 | ball_direction.x *= -1 74 | } 75 | if ball.y < ball_radius { 76 | ball_direction.y *= -1 77 | } 78 | // ball collision with paddle: 79 | if raylib.check_collision_circle_rec(ball, ball_radius, paddle) { 80 | ball_direction.y *= -1 81 | // calculate the relative position of the ball hit on the paddle 82 | hit_position := (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2) 83 | // adjust the ball's horizontal direction based on the hit position 84 | ball_direction.x = hit_position * 2 85 | // avoid excessive angles 86 | ball_direction.x = raymath.clamp(ball_direction.x, -1, 1) 87 | ball_direction = raymath.vector2_normalize(ball_direction) 88 | } 89 | // ball collision with bricks: 90 | for i := 0; i < bricks.len; i++ { 91 | if raylib.check_collision_circle_rec(ball, ball_radius, bricks[i]) { 92 | ball_direction.y *= -1 93 | bricks.delete(i) 94 | score++ 95 | break 96 | } 97 | } 98 | if ball.y > screen_height - ball_radius { 99 | game_over = true 100 | } 101 | } 102 | 103 | fn draw_game() { 104 | raylib.begin_drawing() 105 | raylib.clear_background(raylib.raywhite) 106 | raylib.draw_circle_v(ball, ball_radius, raylib.red) 107 | raylib.draw_rectangle_rec(paddle, raylib.black) 108 | for brick in bricks { 109 | raylib.draw_rectangle_rec(brick, raylib.blue) 110 | } 111 | raylib.draw_text('Score: ${score}', 10, 10, 20, raylib.gray) 112 | if game_over { 113 | raylib.draw_text('Game Over! Press R to restart.', screen_width / 2 - 250, screen_height / 2 - 20, 114 | 30, raylib.red) 115 | } 116 | raylib.end_drawing() 117 | } 118 | 119 | fn main() { 120 | raylib.set_config_flags(.flag_vsync_hint | .flag_msaa_4x_hint) 121 | raylib.set_trace_log_level(int(raylib.TraceLogLevel.log_error)) 122 | raylib.init_window(screen_width, screen_height, 'Breakout Game') 123 | defer { raylib.close_window() } 124 | raylib.set_target_fps(60) 125 | init_bricks() 126 | for !raylib.window_should_close() { 127 | update_game() 128 | draw_game() 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /examples/hello.v: -------------------------------------------------------------------------------- 1 | import raylib { Color, begin_drawing, clear_background, close_window, draw_text, end_drawing, init_window, set_target_fps, window_should_close } 2 | 3 | const screen_width = 800 4 | const screen_height = 600 5 | const white = Color{255, 255, 255, 255} 6 | const blue = Color{0, 0, 200, 255} 7 | 8 | @[export: 'android_run'] 9 | fn run(){ 10 | init_window(screen_width, screen_height, 'Example of using V and Raylib together') 11 | set_target_fps(60) 12 | for !window_should_close() { 13 | begin_drawing() 14 | clear_background(white) 15 | draw_text('Hello from V and Raylib.', 160, 270, 40, blue) 16 | end_drawing() 17 | } 18 | close_window() 19 | } 20 | 21 | fn main(){ 22 | run() 23 | } 24 | -------------------------------------------------------------------------------- /license-mit.txt: -------------------------------------------------------------------------------- 1 | Copyright 2024 EmmaTheMartian 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /license-unlicense.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /raygui/raygui-license: -------------------------------------------------------------------------------- 1 | zlib License 2 | 3 | Copyright (c) 2014-2024 Ramon Santamaria (@raysan5) 4 | 5 | This software is provided "as-is", without any express or implied warranty. In no event 6 | will the authors be held liable for any damages arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, including commercial 9 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not claim that you 12 | wrote the original software. If you use this software in a product, an acknowledgment 13 | in the product documentation would be appreciated but is not required. 14 | 15 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 16 | as being the original software. 17 | 18 | 3. This notice may not be removed or altered from any source distribution. 19 | -------------------------------------------------------------------------------- /raygui/raygui.c.v: -------------------------------------------------------------------------------- 1 | module raygui 2 | 3 | import raylib { Color, Font, Rectangle, Vector2, Vector3 } 4 | 5 | pub type GuiStyleProp = C.GuiStyleProp 6 | 7 | // NOTE: Used when exporting style as code for convenience 8 | pub struct C.GuiStyleProp { 9 | // Control identifier 10 | control_id u16 11 | // Property identifier 12 | property_id u16 13 | // Property value 14 | property_value int 15 | } 16 | 17 | pub type GuiTextStyle = C.GuiTextStyle 18 | 19 | // NOTE: Text style is defined by control 20 | pub struct C.GuiTextStyle { 21 | size u32 22 | char_spacing int 23 | line_spacing int 24 | alignment_h int 25 | alignment_v int 26 | padding int 27 | } 28 | 29 | // Gui control state 30 | pub enum GuiState { 31 | state_normal = 0 32 | state_focused = 1 33 | state_pressed = 2 34 | state_disabled = 3 35 | } 36 | 37 | // Gui control text alignment 38 | pub enum GuiTextAlignment { 39 | text_align_left = 0 40 | text_align_center = 1 41 | text_align_right = 2 42 | } 43 | 44 | // Gui control text alignment vertical 45 | pub enum GuiTextAlignmentVertical { 46 | text_align_top = 0 47 | text_align_middle = 1 48 | text_align_bottom = 2 49 | } 50 | 51 | // Gui control text wrap mode 52 | pub enum GuiTextWrapMode { 53 | text_wrap_none = 0 54 | text_wrap_char = 1 55 | text_wrap_word = 2 56 | } 57 | 58 | // Gui controls 59 | pub enum GuiControl { 60 | default = 0 61 | label = 1 // Used also for: LABELBUTTON 62 | button = 2 63 | toggle = 3 // Used also for: TOGGLEGROUP 64 | slider = 4 // Used also for: SLIDERBAR, TOGGLESLIDER 65 | progressbar = 5 66 | checkbox = 6 67 | combobox = 7 68 | dropdownbox = 8 69 | textbox = 9 // Used also for: TEXTBOXMULTI 70 | valuebox = 10 71 | spinner = 11 // Uses: BUTTON, VALUEBOX 72 | listview = 12 73 | colorpicker = 13 74 | scrollbar = 14 75 | statusbar = 15 76 | } 77 | 78 | // Gui base properties for every control 79 | pub enum GuiControlProperty { 80 | border_color_normal = 0 // Control border color in STATE_NORMAL 81 | base_color_normal = 1 // Control base color in STATE_NORMAL 82 | text_color_normal = 2 // Control text color in STATE_NORMAL 83 | border_color_focused = 3 // Control border color in STATE_FOCUSED 84 | base_color_focused = 4 // Control base color in STATE_FOCUSED 85 | text_color_focused = 5 // Control text color in STATE_FOCUSED 86 | border_color_pressed = 6 // Control border color in STATE_PRESSED 87 | base_color_pressed = 7 // Control base color in STATE_PRESSED 88 | text_color_pressed = 8 // Control text color in STATE_PRESSED 89 | border_color_disabled = 9 // Control border color in STATE_DISABLED 90 | base_color_disabled = 10 // Control base color in STATE_DISABLED 91 | text_color_disabled = 11 // Control text color in STATE_DISABLED 92 | border_width = 12 // Control border size, 0 for no border 93 | text_padding = 13 // Control text padding, not considering border 94 | text_alignment = 14 // Control text horizontal alignment inside control text bound (after border and padding) 95 | } 96 | 97 | // DEFAULT extended properties 98 | pub enum GuiDefaultProperty { 99 | text_size = 16 // Text size (glyphs max height) 100 | text_spacing = 17 // Text spacing between glyphs 101 | line_color = 18 // Line control color 102 | background_color = 19 // Background color 103 | text_line_spacing = 20 // Text spacing between lines 104 | text_alignment_vertical = 21 // Text vertical alignment inside text bounds (after border and padding) 105 | text_wrap_mode = 22 // Text wrap-mode inside text bounds 106 | } 107 | 108 | // Toggle/ToggleGroup 109 | pub enum GuiToggleProperty { 110 | group_padding = 16 // ToggleGroup separation between toggles 111 | } 112 | 113 | // Slider/SliderBar 114 | pub enum GuiSliderProperty { 115 | slider_width = 16 // Slider size of internal bar 116 | slider_padding = 17 // Slider/SliderBar internal bar padding 117 | } 118 | 119 | // ProgressBar 120 | pub enum GuiProgressBarProperty { 121 | progress_padding = 16 // ProgressBar internal padding 122 | } 123 | 124 | // ScrollBar 125 | pub enum GuiScrollBarProperty { 126 | arrows_size = 16 // ScrollBar arrows size 127 | arrows_visible = 17 // ScrollBar arrows visible 128 | scroll_slider_padding = 18 // ScrollBar slider internal padding 129 | scroll_slider_size = 19 // ScrollBar slider size 130 | scroll_padding = 20 // ScrollBar scroll padding from arrows 131 | scroll_speed = 21 // ScrollBar scrolling speed 132 | } 133 | 134 | // CheckBox 135 | pub enum GuiCheckBoxProperty { 136 | check_padding = 16 // CheckBox internal check padding 137 | } 138 | 139 | // ComboBox 140 | pub enum GuiComboBoxProperty { 141 | combo_button_width = 16 // ComboBox right button width 142 | combo_button_spacing = 17 // ComboBox button separation 143 | } 144 | 145 | // DropdownBox 146 | pub enum GuiDropdownBoxProperty { 147 | arrow_padding = 16 // DropdownBox arrow separation from border and items 148 | dropdown_items_spacing = 17 // DropdownBox items separation 149 | dropdown_arrow_hidden = 18 // DropdownBox arrow hidden 150 | dropdown_roll_up = 19 // DropdownBox roll up flag (default rolls down) 151 | } 152 | 153 | // TextBox/TextBoxMulti/ValueBox/Spinner 154 | pub enum GuiTextBoxProperty { 155 | text_readonly = 16 // TextBox in read-only mode: 0-text editable, 1-text no-editable 156 | } 157 | 158 | // Spinner 159 | pub enum GuiSpinnerProperty { 160 | spin_button_width = 16 // Spinner left/right buttons width 161 | spin_button_spacing = 17 // Spinner buttons separation 162 | } 163 | 164 | // ListView 165 | pub enum GuiListViewProperty { 166 | list_items_height = 16 // ListView items height 167 | list_items_spacing = 17 // ListView items separation 168 | scrollbar_width = 18 // ListView scrollbar size (usually width) 169 | scrollbar_side = 19 // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) 170 | list_items_border_width = 20 // ListView items border width 171 | } 172 | 173 | // ColorPicker 174 | pub enum GuiColorPickerProperty { 175 | color_selector_size = 16 176 | huebar_width = 17 // ColorPicker right hue bar width 177 | huebar_padding = 18 // ColorPicker right hue bar separation from panel 178 | huebar_selector_height = 19 // ColorPicker right hue bar selector height 179 | huebar_selector_overflow = 20 // ColorPicker right hue bar selector overflow 180 | } 181 | 182 | pub enum GuiIconName { 183 | icon_none = 0 184 | icon_folder_file_open = 1 185 | icon_file_save_classic = 2 186 | icon_folder_open = 3 187 | icon_folder_save = 4 188 | icon_file_open = 5 189 | icon_file_save = 6 190 | icon_file_export = 7 191 | icon_file_add = 8 192 | icon_file_delete = 9 193 | icon_filetype_text = 10 194 | icon_filetype_audio = 11 195 | icon_filetype_image = 12 196 | icon_filetype_play = 13 197 | icon_filetype_video = 14 198 | icon_filetype_info = 15 199 | icon_file_copy = 16 200 | icon_file_cut = 17 201 | icon_file_paste = 18 202 | icon_cursor_hand = 19 203 | icon_cursor_pointer = 20 204 | icon_cursor_classic = 21 205 | icon_pencil = 22 206 | icon_pencil_big = 23 207 | icon_brush_classic = 24 208 | icon_brush_painter = 25 209 | icon_water_drop = 26 210 | icon_color_picker = 27 211 | icon_rubber = 28 212 | icon_color_bucket = 29 213 | icon_text_t = 30 214 | icon_text_a = 31 215 | icon_scale = 32 216 | icon_resize = 33 217 | icon_filter_point = 34 218 | icon_filter_bilinear = 35 219 | icon_crop = 36 220 | icon_crop_alpha = 37 221 | icon_square_toggle = 38 222 | icon_symmetry = 39 223 | icon_symmetry_horizontal = 40 224 | icon_symmetry_vertical = 41 225 | icon_lens = 42 226 | icon_lens_big = 43 227 | icon_eye_on = 44 228 | icon_eye_off = 45 229 | icon_filter_top = 46 230 | icon_filter = 47 231 | icon_target_point = 48 232 | icon_target_small = 49 233 | icon_target_big = 50 234 | icon_target_move = 51 235 | icon_cursor_move = 52 236 | icon_cursor_scale = 53 237 | icon_cursor_scale_right = 54 238 | icon_cursor_scale_left = 55 239 | icon_undo = 56 240 | icon_redo = 57 241 | icon_reredo = 58 242 | icon_mutate = 59 243 | icon_rotate = 60 244 | icon_repeat = 61 245 | icon_shuffle = 62 246 | icon_emptybox = 63 247 | icon_target = 64 248 | icon_target_small_fill = 65 249 | icon_target_big_fill = 66 250 | icon_target_move_fill = 67 251 | icon_cursor_move_fill = 68 252 | icon_cursor_scale_fill = 69 253 | icon_cursor_scale_right_fill = 70 254 | icon_cursor_scale_left_fill = 71 255 | icon_undo_fill = 72 256 | icon_redo_fill = 73 257 | icon_reredo_fill = 74 258 | icon_mutate_fill = 75 259 | icon_rotate_fill = 76 260 | icon_repeat_fill = 77 261 | icon_shuffle_fill = 78 262 | icon_emptybox_small = 79 263 | icon_box = 80 264 | icon_box_top = 81 265 | icon_box_top_right = 82 266 | icon_box_right = 83 267 | icon_box_bottom_right = 84 268 | icon_box_bottom = 85 269 | icon_box_bottom_left = 86 270 | icon_box_left = 87 271 | icon_box_top_left = 88 272 | icon_box_center = 89 273 | icon_box_circle_mask = 90 274 | icon_pot = 91 275 | icon_alpha_multiply = 92 276 | icon_alpha_clear = 93 277 | icon_dithering = 94 278 | icon_mipmaps = 95 279 | icon_box_grid = 96 280 | icon_grid = 97 281 | icon_box_corners_small = 98 282 | icon_box_corners_big = 99 283 | icon_four_boxes = 100 284 | icon_grid_fill = 101 285 | icon_box_multisize = 102 286 | icon_zoom_small = 103 287 | icon_zoom_medium = 104 288 | icon_zoom_big = 105 289 | icon_zoom_all = 106 290 | icon_zoom_center = 107 291 | icon_box_dots_small = 108 292 | icon_box_dots_big = 109 293 | icon_box_concentric = 110 294 | icon_box_grid_big = 111 295 | icon_ok_tick = 112 296 | icon_cross = 113 297 | icon_arrow_left = 114 298 | icon_arrow_right = 115 299 | icon_arrow_down = 116 300 | icon_arrow_up = 117 301 | icon_arrow_left_fill = 118 302 | icon_arrow_right_fill = 119 303 | icon_arrow_down_fill = 120 304 | icon_arrow_up_fill = 121 305 | icon_audio = 122 306 | icon_fx = 123 307 | icon_wave = 124 308 | icon_wave_sinus = 125 309 | icon_wave_square = 126 310 | icon_wave_triangular = 127 311 | icon_cross_small = 128 312 | icon_player_previous = 129 313 | icon_player_play_back = 130 314 | icon_player_play = 131 315 | icon_player_pause = 132 316 | icon_player_stop = 133 317 | icon_player_next = 134 318 | icon_player_record = 135 319 | icon_magnet = 136 320 | icon_lock_close = 137 321 | icon_lock_open = 138 322 | icon_clock = 139 323 | icon_tools = 140 324 | icon_gear = 141 325 | icon_gear_big = 142 326 | icon_bin = 143 327 | icon_hand_pointer = 144 328 | icon_laser = 145 329 | icon_coin = 146 330 | icon_explosion = 147 331 | icon_1up = 148 332 | icon_player = 149 333 | icon_player_jump = 150 334 | icon_key = 151 335 | icon_demon = 152 336 | icon_text_popup = 153 337 | icon_gear_ex = 154 338 | icon_crack = 155 339 | icon_crack_points = 156 340 | icon_star = 157 341 | icon_door = 158 342 | icon_exit = 159 343 | icon_mode_2d = 160 344 | icon_mode_3d = 161 345 | icon_cube = 162 346 | icon_cube_face_top = 163 347 | icon_cube_face_left = 164 348 | icon_cube_face_front = 165 349 | icon_cube_face_bottom = 166 350 | icon_cube_face_right = 167 351 | icon_cube_face_back = 168 352 | icon_camera = 169 353 | icon_special = 170 354 | icon_link_net = 171 355 | icon_link_boxes = 172 356 | icon_link_multi = 173 357 | icon_link = 174 358 | icon_link_broke = 175 359 | icon_text_notes = 176 360 | icon_notebook = 177 361 | icon_suitcase = 178 362 | icon_suitcase_zip = 179 363 | icon_mailbox = 180 364 | icon_monitor = 181 365 | icon_printer = 182 366 | icon_photo_camera = 183 367 | icon_photo_camera_flash = 184 368 | icon_house = 185 369 | icon_heart = 186 370 | icon_corner = 187 371 | icon_vertical_bars = 188 372 | icon_vertical_bars_fill = 189 373 | icon_life_bars = 190 374 | icon_info = 191 375 | icon_crossline = 192 376 | icon_help = 193 377 | icon_filetype_alpha = 194 378 | icon_filetype_home = 195 379 | icon_layers_visible = 196 380 | icon_layers = 197 381 | icon_window = 198 382 | icon_hidpi = 199 383 | icon_filetype_binary = 200 384 | icon_hex = 201 385 | icon_shield = 202 386 | icon_file_new = 203 387 | icon_folder_add = 204 388 | icon_alarm = 205 389 | icon_cpu = 206 390 | icon_rom = 207 391 | icon_step_over = 208 392 | icon_step_into = 209 393 | icon_step_out = 210 394 | icon_restart = 211 395 | icon_breakpoint_on = 212 396 | icon_breakpoint_off = 213 397 | icon_burger_menu = 214 398 | icon_case_sensitive = 215 399 | icon_reg_exp = 216 400 | icon_folder = 217 401 | icon_file = 218 402 | icon_sand_timer = 219 403 | icon_warning = 220 404 | icon_help_box = 221 405 | icon_info_box = 222 406 | icon_priority = 223 407 | icon_layers_iso = 224 408 | icon_layers2 = 225 409 | icon_mlayers = 226 410 | icon_maps = 227 411 | icon_hot = 228 412 | icon_229 = 229 413 | icon_230 = 230 414 | icon_231 = 231 415 | icon_232 = 232 416 | icon_233 = 233 417 | icon_234 = 234 418 | icon_235 = 235 419 | icon_236 = 236 420 | icon_237 = 237 421 | icon_238 = 238 422 | icon_239 = 239 423 | icon_240 = 240 424 | icon_241 = 241 425 | icon_242 = 242 426 | icon_243 = 243 427 | icon_244 = 244 428 | icon_245 = 245 429 | icon_246 = 246 430 | icon_247 = 247 431 | icon_248 = 248 432 | icon_249 = 249 433 | icon_250 = 250 434 | icon_251 = 251 435 | icon_252 = 252 436 | icon_253 = 253 437 | icon_254 = 254 438 | icon_255 = 255 439 | } 440 | 441 | fn C.GuiEnable() 442 | 443 | // Enable gui controls (global state) 444 | @[inline] 445 | pub fn gui_enable() { 446 | C.GuiEnable() 447 | } 448 | 449 | fn C.GuiDisable() 450 | 451 | // Disable gui controls (global state) 452 | @[inline] 453 | pub fn gui_disable() { 454 | C.GuiDisable() 455 | } 456 | 457 | fn C.GuiLock() 458 | 459 | // Lock gui controls (global state) 460 | @[inline] 461 | pub fn gui_lock() { 462 | C.GuiLock() 463 | } 464 | 465 | fn C.GuiUnlock() 466 | 467 | // Unlock gui controls (global state) 468 | @[inline] 469 | pub fn gui_unlock() { 470 | C.GuiUnlock() 471 | } 472 | 473 | fn C.GuiIsLocked() bool 474 | 475 | // Check if gui is locked (global state) 476 | @[inline] 477 | pub fn gui_is_locked() bool { 478 | return C.GuiIsLocked() 479 | } 480 | 481 | fn C.GuiSetAlpha(f32) 482 | 483 | // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f 484 | @[inline] 485 | pub fn gui_set_alpha(alpha f32) { 486 | C.GuiSetAlpha(alpha) 487 | } 488 | 489 | fn C.GuiSetState(int) 490 | 491 | // Set gui state (global state) 492 | @[inline] 493 | pub fn gui_set_state(state int) { 494 | C.GuiSetState(state) 495 | } 496 | 497 | fn C.GuiGetState() int 498 | 499 | // Get gui state (global state) 500 | @[inline] 501 | pub fn gui_get_state() int { 502 | return C.GuiGetState() 503 | } 504 | 505 | fn C.GuiSetFont(Font) 506 | 507 | // Set gui custom font (global state) 508 | @[inline] 509 | pub fn gui_set_font(font Font) { 510 | C.GuiSetFont(font) 511 | } 512 | 513 | fn C.GuiGetFont() Font 514 | 515 | // Get gui custom font (global state) 516 | @[inline] 517 | pub fn gui_get_font() Font { 518 | return C.GuiGetFont() 519 | } 520 | 521 | fn C.GuiSetStyle(int, int, int) 522 | 523 | // Set one style property 524 | @[inline] 525 | pub fn gui_set_style(control int, property int, value int) { 526 | C.GuiSetStyle(control, property, value) 527 | } 528 | 529 | fn C.GuiGetStyle(int, int) int 530 | 531 | // Get one style property 532 | @[inline] 533 | pub fn gui_get_style(control int, property int) int { 534 | return C.GuiGetStyle(control, property) 535 | } 536 | 537 | fn C.GuiLoadStyle(&char) 538 | 539 | // Load style file over global style variable (.rgs) 540 | @[inline] 541 | pub fn gui_load_style(file_name string) { 542 | C.GuiLoadStyle(file_name.str) 543 | } 544 | 545 | fn C.GuiLoadStyleDefault() 546 | 547 | // Load style default over global style 548 | @[inline] 549 | pub fn gui_load_style_default() { 550 | C.GuiLoadStyleDefault() 551 | } 552 | 553 | fn C.GuiEnableTooltip() 554 | 555 | // Enable gui tooltips (global state) 556 | @[inline] 557 | pub fn gui_enable_tooltip() { 558 | C.GuiEnableTooltip() 559 | } 560 | 561 | fn C.GuiDisableTooltip() 562 | 563 | // Disable gui tooltips (global state) 564 | @[inline] 565 | pub fn gui_disable_tooltip() { 566 | C.GuiDisableTooltip() 567 | } 568 | 569 | fn C.GuiSetTooltip(&char) 570 | 571 | // Set tooltip string 572 | @[inline] 573 | pub fn gui_set_tooltip(tooltip string) { 574 | C.GuiSetTooltip(tooltip.str) 575 | } 576 | 577 | fn C.GuiIconText(int, &char) &char 578 | 579 | // Get text with icon id prepended (if supported) 580 | @[inline] 581 | pub fn gui_icon_text(icon_id int, text string) string { 582 | unsafe { 583 | return C.GuiIconText(icon_id, text.str).vstring() 584 | } 585 | } 586 | 587 | fn C.GuiSetIconScale(int) 588 | 589 | // Set default icon drawing size 590 | @[inline] 591 | pub fn gui_set_icon_scale(scale int) { 592 | C.GuiSetIconScale(scale) 593 | } 594 | 595 | fn C.GuiGetIcons() &u32 596 | 597 | // Get raygui icons data pointer 598 | @[inline] 599 | pub fn gui_get_icons() &u32 { 600 | return C.GuiGetIcons() 601 | } 602 | 603 | fn C.GuiLoadIcons(&char, bool) &&char 604 | 605 | // Load raygui icons file (.rgi) into internal icons data 606 | @[inline] 607 | pub fn gui_load_icons(file_name string, load_icons_name bool) &&char { 608 | return C.GuiLoadIcons(file_name.str, load_icons_name) 609 | } 610 | 611 | fn C.GuiDrawIcon(int, int, int, int, Color) 612 | 613 | // Draw icon using pixel size at specified position 614 | @[inline] 615 | pub fn gui_draw_icon(icon_id int, pos_x int, pos_y int, pixel_size int, color Color) { 616 | C.GuiDrawIcon(icon_id, pos_x, pos_y, pixel_size, color) 617 | } 618 | 619 | fn C.GuiWindowBox(Rectangle, &char) int 620 | 621 | // Window Box control, shows a window that can be closed 622 | @[inline] 623 | pub fn gui_window_box(bounds Rectangle, title string) int { 624 | return C.GuiWindowBox(bounds, title.str) 625 | } 626 | 627 | fn C.GuiGroupBox(Rectangle, &char) int 628 | 629 | // Group Box control with text name 630 | @[inline] 631 | pub fn gui_group_box(bounds Rectangle, text string) int { 632 | return C.GuiGroupBox(bounds, text.str) 633 | } 634 | 635 | fn C.GuiLine(Rectangle, &char) int 636 | 637 | // Line separator control, could contain text 638 | @[inline] 639 | pub fn gui_line(bounds Rectangle, text string) int { 640 | return C.GuiLine(bounds, text.str) 641 | } 642 | 643 | fn C.GuiPanel(Rectangle, &char) int 644 | 645 | // Panel control, useful to group controls 646 | @[inline] 647 | pub fn gui_panel(bounds Rectangle, text string) int { 648 | return C.GuiPanel(bounds, text.str) 649 | } 650 | 651 | fn C.GuiTabBar(Rectangle, &&char, int, &int) int 652 | 653 | // Tab Bar control, returns TAB to be closed or -1 654 | @[inline] 655 | pub fn gui_tab_bar(bounds Rectangle, text &&char, count int, active &int) int { 656 | return C.GuiTabBar(bounds, text, count, active) 657 | } 658 | 659 | fn C.GuiScrollPanel(Rectangle, &char, Rectangle, &Vector2, &Rectangle) int 660 | 661 | // Scroll Panel control 662 | @[inline] 663 | pub fn gui_scroll_panel(bounds Rectangle, text string, content Rectangle, scroll &Vector2, view &Rectangle) int { 664 | return C.GuiScrollPanel(bounds, text.str, content, scroll, view) 665 | } 666 | 667 | fn C.GuiLabel(Rectangle, &char) int 668 | 669 | // Label control 670 | @[inline] 671 | pub fn gui_label(bounds Rectangle, text string) int { 672 | return C.GuiLabel(bounds, text.str) 673 | } 674 | 675 | fn C.GuiButton(Rectangle, &char) int 676 | 677 | // Button control, returns true when clicked 678 | @[inline] 679 | pub fn gui_button(bounds Rectangle, text string) int { 680 | return C.GuiButton(bounds, text.str) 681 | } 682 | 683 | fn C.GuiLabelButton(Rectangle, &char) int 684 | 685 | // Label button control, returns true when clicked 686 | @[inline] 687 | pub fn gui_label_button(bounds Rectangle, text string) int { 688 | return C.GuiLabelButton(bounds, text.str) 689 | } 690 | 691 | fn C.GuiToggle(Rectangle, &char, &bool) int 692 | 693 | // Toggle Button control 694 | @[inline] 695 | pub fn gui_toggle(bounds Rectangle, text string, active &bool) int { 696 | return C.GuiToggle(bounds, text.str, active) 697 | } 698 | 699 | fn C.GuiToggleGroup(Rectangle, &char, &int) int 700 | 701 | // Toggle Group control 702 | @[inline] 703 | pub fn gui_toggle_group(bounds Rectangle, text string, active &int) int { 704 | return C.GuiToggleGroup(bounds, text.str, active) 705 | } 706 | 707 | fn C.GuiToggleSlider(Rectangle, &char, &int) int 708 | 709 | // Toggle Slider control 710 | @[inline] 711 | pub fn gui_toggle_slider(bounds Rectangle, text string, active &int) int { 712 | return C.GuiToggleSlider(bounds, text.str, active) 713 | } 714 | 715 | fn C.GuiCheckBox(Rectangle, &char, &bool) int 716 | 717 | // Check Box control, returns true when active 718 | @[inline] 719 | pub fn gui_check_box(bounds Rectangle, text string, checked &bool) int { 720 | return C.GuiCheckBox(bounds, text.str, checked) 721 | } 722 | 723 | fn C.GuiComboBox(Rectangle, &char, &int) int 724 | 725 | // Combo Box control 726 | @[inline] 727 | pub fn gui_combo_box(bounds Rectangle, text string, active &int) int { 728 | return C.GuiComboBox(bounds, text.str, active) 729 | } 730 | 731 | fn C.GuiDropdownBox(Rectangle, &char, &int, bool) int 732 | 733 | // Dropdown Box control 734 | @[inline] 735 | pub fn gui_dropdown_box(bounds Rectangle, text string, active &int, edit_mode bool) int { 736 | return C.GuiDropdownBox(bounds, text.str, active, edit_mode) 737 | } 738 | 739 | fn C.GuiSpinner(Rectangle, &char, &int, int, int, bool) int 740 | 741 | // Spinner control 742 | @[inline] 743 | pub fn gui_spinner(bounds Rectangle, text string, value &int, min_value int, max_value int, edit_mode bool) int { 744 | return C.GuiSpinner(bounds, text.str, value, min_value, max_value, edit_mode) 745 | } 746 | 747 | fn C.GuiValueBox(Rectangle, &char, &int, int, int, bool) int 748 | 749 | // Value Box control, updates input text with numbers 750 | @[inline] 751 | pub fn gui_value_box(bounds Rectangle, text string, value &int, min_value int, max_value int, edit_mode bool) int { 752 | return C.GuiValueBox(bounds, text.str, value, min_value, max_value, edit_mode) 753 | } 754 | 755 | fn C.GuiValueBoxFloat(Rectangle, &char, &char, &f32, bool) int 756 | 757 | // Value box control for float values 758 | @[inline] 759 | pub fn gui_value_box_float(bounds Rectangle, text string, text_value string, value &f32, edit_mode bool) int { 760 | return C.GuiValueBoxFloat(bounds, text.str, text_value.str, value, edit_mode) 761 | } 762 | 763 | fn C.GuiTextBox(Rectangle, &char, int, bool) int 764 | 765 | // Text Box control, updates input text 766 | @[inline] 767 | pub fn gui_text_box(bounds Rectangle, text string, text_size int, edit_mode bool) int { 768 | return C.GuiTextBox(bounds, text.str, text_size, edit_mode) 769 | } 770 | 771 | fn C.GuiSlider(Rectangle, &char, &char, &f32, f32, f32) int 772 | 773 | // Slider control 774 | @[inline] 775 | pub fn gui_slider(bounds Rectangle, text_left string, text_right string, value &f32, min_value f32, max_value f32) int { 776 | return C.GuiSlider(bounds, text_left.str, text_right.str, value, min_value, max_value) 777 | } 778 | 779 | fn C.GuiSliderBar(Rectangle, &char, &char, &f32, f32, f32) int 780 | 781 | // Slider Bar control 782 | @[inline] 783 | pub fn gui_slider_bar(bounds Rectangle, text_left string, text_right string, value &f32, min_value f32, max_value f32) int { 784 | return C.GuiSliderBar(bounds, text_left.str, text_right.str, value, min_value, max_value) 785 | } 786 | 787 | fn C.GuiProgressBar(Rectangle, &char, &char, &f32, f32, f32) int 788 | 789 | // Progress Bar control 790 | @[inline] 791 | pub fn gui_progress_bar(bounds Rectangle, text_left string, text_right string, value &f32, min_value f32, max_value f32) int { 792 | return C.GuiProgressBar(bounds, text_left.str, text_right.str, value, min_value, max_value) 793 | } 794 | 795 | fn C.GuiStatusBar(Rectangle, &char) int 796 | 797 | // Status Bar control, shows info text 798 | @[inline] 799 | pub fn gui_status_bar(bounds Rectangle, text string) int { 800 | return C.GuiStatusBar(bounds, text.str) 801 | } 802 | 803 | fn C.GuiDummyRec(Rectangle, &char) int 804 | 805 | // Dummy control for placeholders 806 | @[inline] 807 | pub fn gui_dummy_rec(bounds Rectangle, text string) int { 808 | return C.GuiDummyRec(bounds, text.str) 809 | } 810 | 811 | fn C.GuiGrid(Rectangle, &char, f32, int, &Vector2) int 812 | 813 | // Grid control 814 | @[inline] 815 | pub fn gui_grid(bounds Rectangle, text string, spacing f32, subdivs int, mouse_cell &Vector2) int { 816 | return C.GuiGrid(bounds, text.str, spacing, subdivs, mouse_cell) 817 | } 818 | 819 | fn C.GuiListView(Rectangle, &char, &int, &int) int 820 | 821 | // List View control 822 | @[inline] 823 | pub fn gui_list_view(bounds Rectangle, text string, scroll_index &int, active &int) int { 824 | return C.GuiListView(bounds, text.str, scroll_index, active) 825 | } 826 | 827 | fn C.GuiListViewEx(Rectangle, &&char, int, &int, &int, &int) int 828 | 829 | // List View with extended parameters 830 | @[inline] 831 | pub fn gui_list_view_ex(bounds Rectangle, text &&char, count int, scroll_index &int, active &int, focus &int) int { 832 | return C.GuiListViewEx(bounds, text, count, scroll_index, active, focus) 833 | } 834 | 835 | fn C.GuiMessageBox(Rectangle, &char, &char, &char) int 836 | 837 | // Message Box control, displays a message 838 | @[inline] 839 | pub fn gui_message_box(bounds Rectangle, title string, message string, buttons string) int { 840 | return C.GuiMessageBox(bounds, title.str, message.str, buttons.str) 841 | } 842 | 843 | fn C.GuiTextInputBox(Rectangle, &char, &char, &char, &char, int, &bool) int 844 | 845 | // Text Input Box control, ask for text, supports secret 846 | @[inline] 847 | pub fn gui_text_input_box(bounds Rectangle, title string, message string, buttons string, text string, text_max_size int, secret_view_active &bool) int { 848 | return C.GuiTextInputBox(bounds, title.str, message.str, buttons.str, text.str, text_max_size, 849 | secret_view_active) 850 | } 851 | 852 | fn C.GuiColorPicker(Rectangle, &char, &Color) int 853 | 854 | // Color Picker control (multiple color controls) 855 | @[inline] 856 | pub fn gui_color_picker(bounds Rectangle, text string, color &Color) int { 857 | return C.GuiColorPicker(bounds, text.str, color) 858 | } 859 | 860 | fn C.GuiColorPanel(Rectangle, &char, &Color) int 861 | 862 | // Color Panel control 863 | @[inline] 864 | pub fn gui_color_panel(bounds Rectangle, text string, color &Color) int { 865 | return C.GuiColorPanel(bounds, text.str, color) 866 | } 867 | 868 | fn C.GuiColorBarAlpha(Rectangle, &char, &f32) int 869 | 870 | // Color Bar Alpha control 871 | @[inline] 872 | pub fn gui_color_bar_alpha(bounds Rectangle, text string, alpha &f32) int { 873 | return C.GuiColorBarAlpha(bounds, text.str, alpha) 874 | } 875 | 876 | fn C.GuiColorBarHue(Rectangle, &char, &f32) int 877 | 878 | // Color Bar Hue control 879 | @[inline] 880 | pub fn gui_color_bar_hue(bounds Rectangle, text string, value &f32) int { 881 | return C.GuiColorBarHue(bounds, text.str, value) 882 | } 883 | 884 | fn C.GuiColorPickerHSV(Rectangle, &char, &Vector3) int 885 | 886 | // Color Picker control that avoids conversion to RGB on each call (multiple color controls) 887 | @[inline] 888 | pub fn gui_color_picker_hsv(bounds Rectangle, text string, color_hsv &Vector3) int { 889 | return C.GuiColorPickerHSV(bounds, text.str, color_hsv) 890 | } 891 | 892 | fn C.GuiColorPanelHSV(Rectangle, &char, &Vector3) int 893 | 894 | // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() 895 | @[inline] 896 | pub fn gui_color_panel_hsv(bounds Rectangle, text string, color_hsv &Vector3) int { 897 | return C.GuiColorPanelHSV(bounds, text.str, color_hsv) 898 | } 899 | -------------------------------------------------------------------------------- /raygui/raygui_ext.c.v: -------------------------------------------------------------------------------- 1 | module raygui 2 | 3 | #flag -I @VMODROOT/raygui/ 4 | #define RAYGUI_IMPLEMENTATION 5 | #include "raygui.h" 6 | -------------------------------------------------------------------------------- /raygui/raygui_test.v: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | import raylib 4 | import raygui 5 | import raymath 6 | 7 | fn test_raygui() { 8 | raylib.init_window(800, 600, 'Raygui Example') 9 | raylib.set_target_fps(60) 10 | 11 | mut show_message_box := false 12 | mut value := 0 13 | 14 | for !raylib.window_should_close() { 15 | raylib.begin_drawing() 16 | raylib.clear_background(raylib.raywhite) 17 | 18 | if raygui.gui_button(raylib.Rectangle{24, 24, 120, 30}, '#191#Show Message') > 0 { 19 | show_message_box = true 20 | } else if raygui.gui_button(raylib.Rectangle{24, 62, 120, 30}, '++') > 0 { 21 | value = int(raymath.clamp(value + 1, 0, 10)) 22 | } else if raygui.gui_button(raylib.Rectangle{24, 92, 120, 30}, '--') > 0 { 23 | value = int(raymath.clamp(value - 1, 0, 10)) 24 | } 25 | 26 | // raygui.gui_label(raylib.Rectangle{ 24, 100, 120, 30 }, value.str()) 27 | raylib.draw_text(value.str(), 24, 130, 20, raylib.blue) 28 | 29 | if show_message_box { 30 | result := raygui.gui_message_box(raylib.Rectangle{85, 70, 250, 100}, '#191#Message Box', 31 | 'Hi! This is a message!', 'Nice;Cool') 32 | 33 | if result >= 0 { 34 | show_message_box = false 35 | } 36 | } 37 | 38 | raylib.end_drawing() 39 | } 40 | 41 | raylib.close_window() 42 | } 43 | -------------------------------------------------------------------------------- /raylib_ext.c.v: -------------------------------------------------------------------------------- 1 | // These are manually-made bindings for parts of the library that do not need 2 | // or validate custom handling for. 3 | // Functions that use strings get bindings here so that I can allow them to use 4 | // V-strings as arguments/return types instead of C-strings 5 | 6 | module raylib 7 | 8 | #flag linux -lraylib -lGL -lm -lpthread -ldl -lrt -lX11 9 | 10 | #flag darwin -lraylib -lm -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo 11 | #flag darwin -I/opt/homebrew/include 12 | #flag darwin -L/opt/homebrew/lib 13 | 14 | #flag windows -DNOUSER -DNOSHOWWINDOW -DNOGDI 15 | #flag windows -lraylib@START_LIBS 16 | #flag windows -lgdi32 -lwinmm 17 | 18 | // test 19 | #flag android -I@VMODROOT/android-ext/native_app_glue 20 | $if android { 21 | #include "android_native_app_glue.c" 22 | } 23 | 24 | 25 | 26 | // See https://github.com/raysan5/raylib/wiki/Working-for-Web-(HTML5) for instructions on how to build/compile 27 | // programs targeting browsers, using the emscripten toolchain. The options here are 28 | #flag wasm32_emscripten -sUSE_GLFW=3 29 | #flag wasm32_emscripten -sASYNCIFY 30 | #flag wasm32_emscripten -sEXPORTED_RUNTIME_METHODS=ccall 31 | #flag wasm32_emscripten -sGL_ENABLE_GET_PROC_ADDRESS=1 32 | // Allow customisation of the include/library location, by passing `-d RAYLIB_WASM_FOLDER=/some/path` 33 | // See also https://github.com/raysan5/raylib/releases/download/5.5/raylib-5.5_webassembly.zip for how to get an older version. 34 | // Note: that .zip file contains `libraylib.a`, but more recent raylib builds (5.6), 35 | // have that renamed to `libraylib.web.a`, which allows you to have a non conflicting 36 | // libraylib.a for your current platform too. 37 | #flag wasm32_emscripten -I $d('RAYLIB_WASM_FOLDER', '.') 38 | #flag wasm32_emscripten -L $d('RAYLIB_WASM_FOLDER', '.') 39 | #flag wasm32_emscripten -I $d('RAYLIB_WASM_FOLDER', '.')/include 40 | #flag wasm32_emscripten -L $d('RAYLIB_WASM_FOLDER', '.')/lib 41 | #flag wasm32_emscripten -I @VMODROOT/emscripten 42 | #flag wasm32_emscripten -L @VMODROOT/emscripten 43 | #flag wasm32_emscripten -lraylib.web 44 | 45 | #include 46 | 47 | @[typedef] 48 | pub struct C.va_list {} 49 | 50 | pub struct C.rAudioBuffer {} 51 | 52 | pub struct C.rAudioProcessor {} 53 | 54 | pub type AudioBuffer = C.rAudioBuffer 55 | pub type AudioProcessor = C.rAudioProcessor 56 | 57 | pub const lightgray = Color{200, 200, 200, 255} 58 | pub const gray = Color{130, 130, 130, 255} 59 | pub const darkgray = Color{80, 80, 80, 255} 60 | pub const yellow = Color{253, 249, 0, 255} 61 | pub const gold = Color{255, 203, 0, 255} 62 | pub const orange = Color{255, 161, 0, 255} 63 | pub const pink = Color{255, 109, 194, 255} 64 | pub const red = Color{230, 41, 55, 255} 65 | pub const maroon = Color{190, 33, 55, 255} 66 | pub const green = Color{0, 228, 48, 255} 67 | pub const lime = Color{0, 158, 47, 255} 68 | pub const darkgreen = Color{0, 117, 44, 255} 69 | pub const skyblue = Color{102, 191, 255, 255} 70 | pub const blue = Color{0, 121, 241, 255} 71 | pub const darkblue = Color{0, 82, 172, 255} 72 | pub const purple = Color{200, 122, 255, 255} 73 | pub const violet = Color{135, 60, 190, 255} 74 | pub const darkpurple = Color{112, 31, 126, 255} 75 | pub const beige = Color{211, 176, 131, 255} 76 | pub const brown = Color{127, 106, 79, 255} 77 | pub const darkbrown = Color{76, 63, 47, 255} 78 | 79 | pub const white = Color{255, 255, 255, 255} 80 | pub const black = Color{0, 0, 0, 255} 81 | pub const blank = Color{0, 0, 0, 0} 82 | pub const magenta = Color{255, 0, 255, 255} 83 | pub const raywhite = Color{245, 245, 245, 255} 84 | 85 | pub const camera_perspective = 0 86 | pub const camera_orthographic = 1 87 | 88 | pub const camera_free = 1 89 | pub const camera_orbital = 2 90 | pub const camera_first_person = 3 91 | pub const camera_third_person = 4 92 | 93 | // Keyboard related 94 | 95 | // vis_key_pressed allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 96 | @[inline] 97 | pub fn vis_key_pressed(key KeyboardKey) bool { 98 | return is_key_pressed(int(key)) 99 | } 100 | 101 | // vis_key_pressed_repeat allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 102 | @[inline] 103 | pub fn vis_key_pressed_repeat(key KeyboardKey) bool { 104 | return is_key_pressed_repeat(int(key)) 105 | } 106 | 107 | // vis_key_down allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 108 | @[inline] 109 | pub fn vis_key_down(key KeyboardKey) bool { 110 | return is_key_down(int(key)) 111 | } 112 | 113 | // vis_key_up allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 114 | @[inline] 115 | pub fn vis_key_up(key KeyboardKey) bool { 116 | return is_key_up(int(key)) 117 | } 118 | 119 | // vis_key_released allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 120 | @[inline] 121 | pub fn vis_key_released(key KeyboardKey) bool { 122 | return is_key_released(int(key)) 123 | } 124 | 125 | // vset_exit_key allows you to pass a `KeyboardKey` enum value in your V programs, instead of a plain int. 126 | @[inline] 127 | pub fn vset_exit_key(key KeyboardKey) { 128 | set_exit_key(int(key)) 129 | } 130 | 131 | // log level 132 | 133 | // vset_trace_log_level allows you to pass a `TraceLogLevel` enum value in your V programs, instead of a plain int. 134 | @[inline] 135 | pub fn vset_trace_log_level(log_level TraceLogLevel) { 136 | set_trace_log_level(int(log_level)) 137 | } 138 | 139 | // Mouse button related 140 | 141 | // vis_mouse_button_pressed allows you to pass a `MouseButton` enum value in your V programs, instead of a plain int. 142 | @[inline] 143 | pub fn vis_mouse_button_pressed(button MouseButton) bool { 144 | return is_mouse_button_pressed(int(button)) 145 | } 146 | 147 | // vis_mouse_button_down allows you to pass a `MouseButton` enum value in your V programs, instead of a plain int. 148 | @[inline] 149 | pub fn vis_mouse_button_down(button MouseButton) bool { 150 | return is_mouse_button_down(int(button)) 151 | } 152 | 153 | // vis_mouse_button_released allows you to pass a `MouseButton` enum value in your V programs, instead of a plain int. 154 | @[inline] 155 | pub fn vis_mouse_button_released(button MouseButton) bool { 156 | return is_mouse_button_released(int(button)) 157 | } 158 | 159 | // vis_mouse_button_up allows you to pass a `MouseButton` enum value in your V programs, instead of a plain int. 160 | @[inline] 161 | pub fn vis_mouse_button_up(button MouseButton) bool { 162 | return is_mouse_button_up(int(button)) 163 | } 164 | 165 | // GamePad related 166 | 167 | // vis_gamepad_aviable allows you to pass a `GamepadButton` enum value in your V programs, instead of a plain int. 168 | @[inline] 169 | pub fn vis_gamepad_aviable(gamepad GamepadButton) bool { 170 | return is_gamepad_available(int(gamepad)) 171 | } 172 | 173 | // vis_gamepad_button_pressed allows you to pass a `GamepadButton` enum value in your V programs, instead of a plain int. 174 | @[inline] 175 | pub fn vis_gamepad_button_pressed(gamepad int, button GamepadButton) bool { 176 | return is_gamepad_button_pressed(gamepad, int(button)) 177 | } 178 | 179 | // vis_gamepad_button_down allows you to pass a `GamepadButton` enum value in your V programs, instead of a plain int. 180 | @[inline] 181 | pub fn vis_gamepad_button_down(gamepad int, button GamepadButton) bool { 182 | return is_gamepad_button_down(gamepad, int(button)) 183 | } 184 | 185 | // vis_gamepad_button_released allows you to pass a `GamepadButton` enum value in your V programs, instead of a plain int. 186 | @[inline] 187 | pub fn vis_gamepad_button_released(gamepad int, button GamepadButton) bool { 188 | return is_gamepad_button_released(gamepad, int(button)) 189 | } 190 | 191 | // vis_gamepad_button_up allows you to pass a `GamepadButton` enum value in your V programs, instead of a plain int. 192 | @[inline] 193 | pub fn vis_gamepad_button_up(gamepad int, button GamepadButton) bool { 194 | return is_gamepad_button_up(gamepad, int(button)) 195 | } 196 | 197 | // vget_gamepad_axis_movement allows you to pass a `GamepadAxis` enum value in your V programs, instead of a plain int. 198 | @[inline] 199 | pub fn vget_gamepad_axis_movement(gamepad int, axis GamepadAxis) f32 { 200 | return get_gamepad_axis_movement(gamepad, int(axis)) 201 | } 202 | 203 | // vis_gesture_detected allows you to pass a `Gesture` enum value in your V programs, instead of a plain int. 204 | @[inline] 205 | pub fn vis_gesture_detected(gesture Gesture) bool { 206 | return is_gesture_detected(u32(gesture)) 207 | } 208 | -------------------------------------------------------------------------------- /raylib_test.v: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | import raylib 4 | 5 | fn test_raylib() { 6 | raylib.set_config_flags(raylib.ConfigFlags.flag_window_resizable) 7 | raylib.init_window(800, 600, 'Hello, World!') 8 | raylib.set_target_fps(30) 9 | 10 | for !raylib.window_should_close() { 11 | raylib.begin_drawing() 12 | raylib.clear_background(raylib.white) 13 | raylib.draw_fps(raylib.get_screen_width() / 2, raylib.get_screen_height() / 2) 14 | raylib.end_drawing() 15 | } 16 | 17 | raylib.close_window() 18 | } 19 | -------------------------------------------------------------------------------- /raymath/raymath-license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2024 Ramon Santamaria (@raysan5) 2 | 3 | This software is provided "as-is", without any express or implied warranty. In no event 4 | will the authors be held liable for any damages arising from the use of this software. 5 | 6 | Permission is granted to anyone to use this software for any purpose, including commercial 7 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | 9 | 1. The origin of this software must not be misrepresented; you must not claim that you 10 | wrote the original software. If you use this software in a product, an acknowledgment 11 | in the product documentation would be appreciated but is not required. 12 | 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 14 | as being the original software. 15 | 16 | 3. This notice may not be removed or altered from any source distribution. 17 | -------------------------------------------------------------------------------- /raymath/raymath.c.v: -------------------------------------------------------------------------------- 1 | module raymath 2 | 3 | import raylib { Matrix, Vector2, Vector3, Vector4 } 4 | 5 | pub type Float3 = C.float3 6 | 7 | // NOTE: Helper types to be used instead of array return types for *ToFloat functions 8 | pub struct C.float3 { 9 | v [3]f32 10 | } 11 | 12 | pub type Float16 = C.float16 13 | 14 | pub struct C.float16 { 15 | v [16]f32 16 | } 17 | 18 | // Quaternion type 19 | pub type Quaternion = C.Vector4 20 | 21 | fn C.Clamp(f32, f32, f32) f32 22 | @[inline] 23 | pub fn clamp(value f32, min f32, max f32) f32 { 24 | return C.Clamp(value, min, max) 25 | } 26 | 27 | fn C.Lerp(f32, f32, f32) f32 28 | @[inline] 29 | pub fn lerp(start f32, end f32, amount f32) f32 { 30 | return C.Lerp(start, end, amount) 31 | } 32 | 33 | fn C.Normalize(f32, f32, f32) f32 34 | @[inline] 35 | pub fn normalize(value f32, start f32, end f32) f32 { 36 | return C.Normalize(value, start, end) 37 | } 38 | 39 | fn C.Remap(f32, f32, f32, f32, f32) f32 40 | @[inline] 41 | pub fn remap(value f32, input_start f32, input_end f32, output_start f32, output_end f32) f32 { 42 | return C.Remap(value, input_start, input_end, output_start, output_end) 43 | } 44 | 45 | fn C.Wrap(f32, f32, f32) f32 46 | @[inline] 47 | pub fn wrap(value f32, min f32, max f32) f32 { 48 | return C.Wrap(value, min, max) 49 | } 50 | 51 | fn C.FloatEquals(f32, f32) int 52 | @[inline] 53 | pub fn float_equals(x f32, y f32) int { 54 | return C.FloatEquals(x, y) 55 | } 56 | 57 | fn C.Vector2Zero() Vector2 58 | @[inline] 59 | pub fn vector2_zero() Vector2 { 60 | return C.Vector2Zero() 61 | } 62 | 63 | fn C.Vector2One() Vector2 64 | @[inline] 65 | pub fn vector2_one() Vector2 { 66 | return C.Vector2One() 67 | } 68 | 69 | fn C.Vector2Add(Vector2, Vector2) Vector2 70 | @[inline] 71 | pub fn vector2_add(v1 Vector2, v2 Vector2) Vector2 { 72 | return C.Vector2Add(v1, v2) 73 | } 74 | 75 | fn C.Vector2AddValue(Vector2, f32) Vector2 76 | @[inline] 77 | pub fn vector2_add_value(v Vector2, add f32) Vector2 { 78 | return C.Vector2AddValue(v, add) 79 | } 80 | 81 | fn C.Vector2Subtract(Vector2, Vector2) Vector2 82 | @[inline] 83 | pub fn vector2_subtract(v1 Vector2, v2 Vector2) Vector2 { 84 | return C.Vector2Subtract(v1, v2) 85 | } 86 | 87 | fn C.Vector2SubtractValue(Vector2, f32) Vector2 88 | @[inline] 89 | pub fn vector2_subtract_value(v Vector2, sub f32) Vector2 { 90 | return C.Vector2SubtractValue(v, sub) 91 | } 92 | 93 | fn C.Vector2Length(Vector2) f32 94 | @[inline] 95 | pub fn vector2_length(v Vector2) f32 { 96 | return C.Vector2Length(v) 97 | } 98 | 99 | fn C.Vector2LengthSqr(Vector2) f32 100 | @[inline] 101 | pub fn vector2_length_sqr(v Vector2) f32 { 102 | return C.Vector2LengthSqr(v) 103 | } 104 | 105 | fn C.Vector2DotProduct(Vector2, Vector2) f32 106 | @[inline] 107 | pub fn vector_2dot_product(v1 Vector2, v2 Vector2) f32 { 108 | return C.Vector2DotProduct(v1, v2) 109 | } 110 | 111 | fn C.Vector2CrossProduct(Vector2, Vector2) f32 112 | @[inline] 113 | pub fn vector2_cross_product(v1 Vector2, v2 Vector2) f32 { 114 | return C.Vector2CrossProduct(v1, v2) 115 | } 116 | 117 | fn C.Vector2Distance(Vector2, Vector2) f32 118 | @[inline] 119 | pub fn vector_2distance(v1 Vector2, v2 Vector2) f32 { 120 | return C.Vector2Distance(v1, v2) 121 | } 122 | 123 | fn C.Vector2DistanceSqr(Vector2, Vector2) f32 124 | @[inline] 125 | pub fn vector_2distance_sqr(v1 Vector2, v2 Vector2) f32 { 126 | return C.Vector2DistanceSqr(v1, v2) 127 | } 128 | 129 | fn C.Vector2Angle(Vector2, Vector2) f32 130 | @[inline] 131 | pub fn vector2_angle(v1 Vector2, v2 Vector2) f32 { 132 | return C.Vector2Angle(v1, v2) 133 | } 134 | 135 | fn C.Vector2LineAngle(Vector2, Vector2) f32 136 | @[inline] 137 | pub fn vector2_line_angle(start Vector2, end Vector2) f32 { 138 | return C.Vector2LineAngle(start, end) 139 | } 140 | 141 | fn C.Vector2Scale(Vector2, f32) Vector2 142 | @[inline] 143 | pub fn vector2_scale(v Vector2, scale f32) Vector2 { 144 | return C.Vector2Scale(v, scale) 145 | } 146 | 147 | fn C.Vector2Multiply(Vector2, Vector2) Vector2 148 | @[inline] 149 | pub fn vector2_multiply(v1 Vector2, v2 Vector2) Vector2 { 150 | return C.Vector2Multiply(v1, v2) 151 | } 152 | 153 | fn C.Vector2Negate(Vector2) Vector2 154 | @[inline] 155 | pub fn vector2_negate(v Vector2) Vector2 { 156 | return C.Vector2Negate(v) 157 | } 158 | 159 | fn C.Vector2Divide(Vector2, Vector2) Vector2 160 | @[inline] 161 | pub fn vector_2divide(v1 Vector2, v2 Vector2) Vector2 { 162 | return C.Vector2Divide(v1, v2) 163 | } 164 | 165 | fn C.Vector2Normalize(Vector2) Vector2 166 | @[inline] 167 | pub fn vector2_normalize(v Vector2) Vector2 { 168 | return C.Vector2Normalize(v) 169 | } 170 | 171 | fn C.Vector2Transform(Vector2, Matrix) Vector2 172 | @[inline] 173 | pub fn vector2_transform(v Vector2, mat Matrix) Vector2 { 174 | return C.Vector2Transform(v, mat) 175 | } 176 | 177 | fn C.Vector2Lerp(Vector2, Vector2, f32) Vector2 178 | @[inline] 179 | pub fn vector2_lerp(v1 Vector2, v2 Vector2, amount f32) Vector2 { 180 | return C.Vector2Lerp(v1, v2, amount) 181 | } 182 | 183 | fn C.Vector2Reflect(Vector2, Vector2) Vector2 184 | @[inline] 185 | pub fn vector2_reflect(v Vector2, normal Vector2) Vector2 { 186 | return C.Vector2Reflect(v, normal) 187 | } 188 | 189 | fn C.Vector2Min(Vector2, Vector2) Vector2 190 | @[inline] 191 | pub fn vector2_min(v1 Vector2, v2 Vector2) Vector2 { 192 | return C.Vector2Min(v1, v2) 193 | } 194 | 195 | fn C.Vector2Max(Vector2, Vector2) Vector2 196 | @[inline] 197 | pub fn vector2_max(v1 Vector2, v2 Vector2) Vector2 { 198 | return C.Vector2Max(v1, v2) 199 | } 200 | 201 | fn C.Vector2Rotate(Vector2, f32) Vector2 202 | @[inline] 203 | pub fn vector2_rotate(v Vector2, angle f32) Vector2 { 204 | return C.Vector2Rotate(v, angle) 205 | } 206 | 207 | fn C.Vector2MoveTowards(Vector2, Vector2, f32) Vector2 208 | @[inline] 209 | pub fn vector2_move_towards(v Vector2, target Vector2, max_distance f32) Vector2 { 210 | return C.Vector2MoveTowards(v, target, max_distance) 211 | } 212 | 213 | fn C.Vector2Invert(Vector2) Vector2 214 | @[inline] 215 | pub fn vector2_invert(v Vector2) Vector2 { 216 | return C.Vector2Invert(v) 217 | } 218 | 219 | fn C.Vector2Clamp(Vector2, Vector2, Vector2) Vector2 220 | @[inline] 221 | pub fn vector2_clamp(v Vector2, min Vector2, max Vector2) Vector2 { 222 | return C.Vector2Clamp(v, min, max) 223 | } 224 | 225 | fn C.Vector2ClampValue(Vector2, f32, f32) Vector2 226 | @[inline] 227 | pub fn vector2_clamp_value(v Vector2, min f32, max f32) Vector2 { 228 | return C.Vector2ClampValue(v, min, max) 229 | } 230 | 231 | fn C.Vector2Equals(Vector2, Vector2) int 232 | @[inline] 233 | pub fn vector2_equals(p Vector2, q Vector2) int { 234 | return C.Vector2Equals(p, q) 235 | } 236 | 237 | fn C.Vector2Refract(Vector2, Vector2, f32) Vector2 238 | @[inline] 239 | pub fn vector2_refract(v Vector2, n Vector2, r f32) Vector2 { 240 | return C.Vector2Refract(v, n, r) 241 | } 242 | 243 | fn C.Vector3Zero() Vector3 244 | @[inline] 245 | pub fn vector3_zero() Vector3 { 246 | return C.Vector3Zero() 247 | } 248 | 249 | fn C.Vector3One() Vector3 250 | @[inline] 251 | pub fn vector3_one() Vector3 { 252 | return C.Vector3One() 253 | } 254 | 255 | fn C.Vector3Add(Vector3, Vector3) Vector3 256 | @[inline] 257 | pub fn vector3_add(v1 Vector3, v2 Vector3) Vector3 { 258 | return C.Vector3Add(v1, v2) 259 | } 260 | 261 | fn C.Vector3AddValue(Vector3, f32) Vector3 262 | @[inline] 263 | pub fn vector3_add_value(v Vector3, add f32) Vector3 { 264 | return C.Vector3AddValue(v, add) 265 | } 266 | 267 | fn C.Vector3Subtract(Vector3, Vector3) Vector3 268 | @[inline] 269 | pub fn vector3_subtract(v1 Vector3, v2 Vector3) Vector3 { 270 | return C.Vector3Subtract(v1, v2) 271 | } 272 | 273 | fn C.Vector3SubtractValue(Vector3, f32) Vector3 274 | @[inline] 275 | pub fn vector3_subtract_value(v Vector3, sub f32) Vector3 { 276 | return C.Vector3SubtractValue(v, sub) 277 | } 278 | 279 | fn C.Vector3Scale(Vector3, f32) Vector3 280 | @[inline] 281 | pub fn vector3_scale(v Vector3, scalar f32) Vector3 { 282 | return C.Vector3Scale(v, scalar) 283 | } 284 | 285 | fn C.Vector3Multiply(Vector3, Vector3) Vector3 286 | @[inline] 287 | pub fn vector3_multiply(v1 Vector3, v2 Vector3) Vector3 { 288 | return C.Vector3Multiply(v1, v2) 289 | } 290 | 291 | fn C.Vector3CrossProduct(Vector3, Vector3) Vector3 292 | @[inline] 293 | pub fn vector3_cross_product(v1 Vector3, v2 Vector3) Vector3 { 294 | return C.Vector3CrossProduct(v1, v2) 295 | } 296 | 297 | fn C.Vector3Perpendicular(Vector3) Vector3 298 | @[inline] 299 | pub fn vector3_perpendicular(v Vector3) Vector3 { 300 | return C.Vector3Perpendicular(v) 301 | } 302 | 303 | fn C.Vector3Length(Vector3) f32 304 | @[inline] 305 | pub fn vector3_length(v Vector3) f32 { 306 | return C.Vector3Length(v) 307 | } 308 | 309 | fn C.Vector3LengthSqr(Vector3) f32 310 | @[inline] 311 | pub fn vector3_length_sqr(v Vector3) f32 { 312 | return C.Vector3LengthSqr(v) 313 | } 314 | 315 | fn C.Vector3DotProduct(Vector3, Vector3) f32 316 | @[inline] 317 | pub fn vector_3dot_product(v1 Vector3, v2 Vector3) f32 { 318 | return C.Vector3DotProduct(v1, v2) 319 | } 320 | 321 | fn C.Vector3Distance(Vector3, Vector3) f32 322 | @[inline] 323 | pub fn vector_3distance(v1 Vector3, v2 Vector3) f32 { 324 | return C.Vector3Distance(v1, v2) 325 | } 326 | 327 | fn C.Vector3DistanceSqr(Vector3, Vector3) f32 328 | @[inline] 329 | pub fn vector_3distance_sqr(v1 Vector3, v2 Vector3) f32 { 330 | return C.Vector3DistanceSqr(v1, v2) 331 | } 332 | 333 | fn C.Vector3Angle(Vector3, Vector3) f32 334 | @[inline] 335 | pub fn vector3_angle(v1 Vector3, v2 Vector3) f32 { 336 | return C.Vector3Angle(v1, v2) 337 | } 338 | 339 | fn C.Vector3Negate(Vector3) Vector3 340 | @[inline] 341 | pub fn vector3_negate(v Vector3) Vector3 { 342 | return C.Vector3Negate(v) 343 | } 344 | 345 | fn C.Vector3Divide(Vector3, Vector3) Vector3 346 | @[inline] 347 | pub fn vector_3divide(v1 Vector3, v2 Vector3) Vector3 { 348 | return C.Vector3Divide(v1, v2) 349 | } 350 | 351 | fn C.Vector3Normalize(Vector3) Vector3 352 | @[inline] 353 | pub fn vector3_normalize(v Vector3) Vector3 { 354 | return C.Vector3Normalize(v) 355 | } 356 | 357 | fn C.Vector3Project(Vector3, Vector3) Vector3 358 | @[inline] 359 | pub fn vector3_project(v1 Vector3, v2 Vector3) Vector3 { 360 | return C.Vector3Project(v1, v2) 361 | } 362 | 363 | fn C.Vector3Reject(Vector3, Vector3) Vector3 364 | @[inline] 365 | pub fn vector3_reject(v1 Vector3, v2 Vector3) Vector3 { 366 | return C.Vector3Reject(v1, v2) 367 | } 368 | 369 | fn C.Vector3OrthoNormalize(&Vector3, &Vector3) 370 | @[inline] 371 | pub fn vector3_ortho_normalize(v1 &Vector3, v2 &Vector3) { 372 | C.Vector3OrthoNormalize(v1, v2) 373 | } 374 | 375 | fn C.Vector3Transform(Vector3, Matrix) Vector3 376 | @[inline] 377 | pub fn vector3_transform(v Vector3, mat Matrix) Vector3 { 378 | return C.Vector3Transform(v, mat) 379 | } 380 | 381 | fn C.Vector3RotateByQuaternion(Vector3, Quaternion) Vector3 382 | @[inline] 383 | pub fn vector3_rotate_by_quaternion(v Vector3, q Quaternion) Vector3 { 384 | return C.Vector3RotateByQuaternion(v, q) 385 | } 386 | 387 | fn C.Vector3RotateByAxisAngle(Vector3, Vector3, f32) Vector3 388 | @[inline] 389 | pub fn vector3_rotate_by_axis_angle(v Vector3, axis Vector3, angle f32) Vector3 { 390 | return C.Vector3RotateByAxisAngle(v, axis, angle) 391 | } 392 | 393 | fn C.Vector3MoveTowards(Vector3, Vector3, f32) Vector3 394 | @[inline] 395 | pub fn vector3_move_towards(v Vector3, target Vector3, max_distance f32) Vector3 { 396 | return C.Vector3MoveTowards(v, target, max_distance) 397 | } 398 | 399 | fn C.Vector3Lerp(Vector3, Vector3, f32) Vector3 400 | @[inline] 401 | pub fn vector3_lerp(v1 Vector3, v2 Vector3, amount f32) Vector3 { 402 | return C.Vector3Lerp(v1, v2, amount) 403 | } 404 | 405 | fn C.Vector3CubicHermite(Vector3, Vector3, Vector3, Vector3, f32) Vector3 406 | @[inline] 407 | pub fn vector3_cubic_hermite(v1 Vector3, tangent1 Vector3, v2 Vector3, tangent2 Vector3, amount f32) Vector3 { 408 | return C.Vector3CubicHermite(v1, tangent1, v2, tangent2, amount) 409 | } 410 | 411 | fn C.Vector3Reflect(Vector3, Vector3) Vector3 412 | @[inline] 413 | pub fn vector3_reflect(v Vector3, normal Vector3) Vector3 { 414 | return C.Vector3Reflect(v, normal) 415 | } 416 | 417 | fn C.Vector3Min(Vector3, Vector3) Vector3 418 | @[inline] 419 | pub fn vector3_min(v1 Vector3, v2 Vector3) Vector3 { 420 | return C.Vector3Min(v1, v2) 421 | } 422 | 423 | fn C.Vector3Max(Vector3, Vector3) Vector3 424 | @[inline] 425 | pub fn vector3_max(v1 Vector3, v2 Vector3) Vector3 { 426 | return C.Vector3Max(v1, v2) 427 | } 428 | 429 | fn C.Vector3Barycenter(Vector3, Vector3, Vector3, Vector3) Vector3 430 | @[inline] 431 | pub fn vector3_barycenter(p Vector3, a Vector3, b Vector3, c Vector3) Vector3 { 432 | return C.Vector3Barycenter(p, a, b, c) 433 | } 434 | 435 | fn C.Vector3Unproject(Vector3, Matrix, Matrix) Vector3 436 | @[inline] 437 | pub fn vector3_unproject(source Vector3, projection Matrix, view Matrix) Vector3 { 438 | return C.Vector3Unproject(source, projection, view) 439 | } 440 | 441 | fn C.Vector3ToFloatV(Vector3) Float3 442 | @[inline] 443 | pub fn vector3_to_float_v(v Vector3) Float3 { 444 | return C.Vector3ToFloatV(v) 445 | } 446 | 447 | fn C.Vector3Invert(Vector3) Vector3 448 | @[inline] 449 | pub fn vector3_invert(v Vector3) Vector3 { 450 | return C.Vector3Invert(v) 451 | } 452 | 453 | fn C.Vector3Clamp(Vector3, Vector3, Vector3) Vector3 454 | @[inline] 455 | pub fn vector3_clamp(v Vector3, min Vector3, max Vector3) Vector3 { 456 | return C.Vector3Clamp(v, min, max) 457 | } 458 | 459 | fn C.Vector3ClampValue(Vector3, f32, f32) Vector3 460 | @[inline] 461 | pub fn vector3_clamp_value(v Vector3, min f32, max f32) Vector3 { 462 | return C.Vector3ClampValue(v, min, max) 463 | } 464 | 465 | fn C.Vector3Equals(Vector3, Vector3) int 466 | @[inline] 467 | pub fn vector3_equals(p Vector3, q Vector3) int { 468 | return C.Vector3Equals(p, q) 469 | } 470 | 471 | fn C.Vector3Refract(Vector3, Vector3, f32) Vector3 472 | @[inline] 473 | pub fn vector3_refract(v Vector3, n Vector3, r f32) Vector3 { 474 | return C.Vector3Refract(v, n, r) 475 | } 476 | 477 | fn C.Vector4Zero() Vector4 478 | @[inline] 479 | pub fn vector4_zero() Vector4 { 480 | return C.Vector4Zero() 481 | } 482 | 483 | fn C.Vector4One() Vector4 484 | @[inline] 485 | pub fn vector4_one() Vector4 { 486 | return C.Vector4One() 487 | } 488 | 489 | fn C.Vector4Add(Vector4, Vector4) Vector4 490 | @[inline] 491 | pub fn vector4_add(v1 Vector4, v2 Vector4) Vector4 { 492 | return C.Vector4Add(v1, v2) 493 | } 494 | 495 | fn C.Vector4AddValue(Vector4, f32) Vector4 496 | @[inline] 497 | pub fn vector4_add_value(v Vector4, add f32) Vector4 { 498 | return C.Vector4AddValue(v, add) 499 | } 500 | 501 | fn C.Vector4Subtract(Vector4, Vector4) Vector4 502 | @[inline] 503 | pub fn vector4_subtract(v1 Vector4, v2 Vector4) Vector4 { 504 | return C.Vector4Subtract(v1, v2) 505 | } 506 | 507 | fn C.Vector4SubtractValue(Vector4, f32) Vector4 508 | @[inline] 509 | pub fn vector4_subtract_value(v Vector4, add f32) Vector4 { 510 | return C.Vector4SubtractValue(v, add) 511 | } 512 | 513 | fn C.Vector4Length(Vector4) f32 514 | @[inline] 515 | pub fn vector4_length(v Vector4) f32 { 516 | return C.Vector4Length(v) 517 | } 518 | 519 | fn C.Vector4LengthSqr(Vector4) f32 520 | @[inline] 521 | pub fn vector4_length_sqr(v Vector4) f32 { 522 | return C.Vector4LengthSqr(v) 523 | } 524 | 525 | fn C.Vector4DotProduct(Vector4, Vector4) f32 526 | @[inline] 527 | pub fn vector4_dot_product(v1 Vector4, v2 Vector4) f32 { 528 | return C.Vector4DotProduct(v1, v2) 529 | } 530 | 531 | fn C.Vector4Distance(Vector4, Vector4) f32 532 | @[inline] 533 | pub fn vector4_distance(v1 Vector4, v2 Vector4) f32 { 534 | return C.Vector4Distance(v1, v2) 535 | } 536 | 537 | fn C.Vector4DistanceSqr(Vector4, Vector4) f32 538 | @[inline] 539 | pub fn vector4_distance_sqr(v1 Vector4, v2 Vector4) f32 { 540 | return C.Vector4DistanceSqr(v1, v2) 541 | } 542 | 543 | fn C.Vector4Scale(Vector4, f32) Vector4 544 | @[inline] 545 | pub fn vector4_scale(v Vector4, scale f32) Vector4 { 546 | return C.Vector4Scale(v, scale) 547 | } 548 | 549 | fn C.Vector4Multiply(Vector4, Vector4) Vector4 550 | @[inline] 551 | pub fn vector4_multiply(v1 Vector4, v2 Vector4) Vector4 { 552 | return C.Vector4Multiply(v1, v2) 553 | } 554 | 555 | fn C.Vector4Negate(Vector4) Vector4 556 | @[inline] 557 | pub fn vector4_negate(v Vector4) Vector4 { 558 | return C.Vector4Negate(v) 559 | } 560 | 561 | fn C.Vector4Divide(Vector4, Vector4) Vector4 562 | @[inline] 563 | pub fn vector4_divide(v1 Vector4, v2 Vector4) Vector4 { 564 | return C.Vector4Divide(v1, v2) 565 | } 566 | 567 | fn C.Vector4Normalize(Vector4) Vector4 568 | @[inline] 569 | pub fn vector4_normalize(v Vector4) Vector4 { 570 | return C.Vector4Normalize(v) 571 | } 572 | 573 | fn C.Vector4Min(Vector4, Vector4) Vector4 574 | @[inline] 575 | pub fn vector4_min(v1 Vector4, v2 Vector4) Vector4 { 576 | return C.Vector4Min(v1, v2) 577 | } 578 | 579 | fn C.Vector4Max(Vector4, Vector4) Vector4 580 | @[inline] 581 | pub fn vector4_max(v1 Vector4, v2 Vector4) Vector4 { 582 | return C.Vector4Max(v1, v2) 583 | } 584 | 585 | fn C.Vector4Lerp(Vector4, Vector4, f32) Vector4 586 | @[inline] 587 | pub fn vector4_lerp(v1 Vector4, v2 Vector4, amount f32) Vector4 { 588 | return C.Vector4Lerp(v1, v2, amount) 589 | } 590 | 591 | fn C.Vector4MoveTowards(Vector4, Vector4, f32) Vector4 592 | @[inline] 593 | pub fn vector4_move_towards(v Vector4, target Vector4, max_distance f32) Vector4 { 594 | return C.Vector4MoveTowards(v, target, max_distance) 595 | } 596 | 597 | fn C.Vector4Invert(Vector4) Vector4 598 | @[inline] 599 | pub fn vector4_invert(v Vector4) Vector4 { 600 | return C.Vector4Invert(v) 601 | } 602 | 603 | fn C.Vector4Equals(Vector4, Vector4) int 604 | @[inline] 605 | pub fn vector4_equals(p Vector4, q Vector4) int { 606 | return C.Vector4Equals(p, q) 607 | } 608 | 609 | fn C.MatrixDeterminant(Matrix) f32 610 | @[inline] 611 | pub fn matrix_determinant(mat Matrix) f32 { 612 | return C.MatrixDeterminant(mat) 613 | } 614 | 615 | fn C.MatrixTrace(Matrix) f32 616 | @[inline] 617 | pub fn matrix_trace(mat Matrix) f32 { 618 | return C.MatrixTrace(mat) 619 | } 620 | 621 | fn C.MatrixTranspose(Matrix) Matrix 622 | @[inline] 623 | pub fn matrix_transpose(mat Matrix) Matrix { 624 | return C.MatrixTranspose(mat) 625 | } 626 | 627 | fn C.MatrixInvert(Matrix) Matrix 628 | @[inline] 629 | pub fn matrix_invert(mat Matrix) Matrix { 630 | return C.MatrixInvert(mat) 631 | } 632 | 633 | fn C.MatrixIdentity() Matrix 634 | @[inline] 635 | pub fn matrix_identity() Matrix { 636 | return C.MatrixIdentity() 637 | } 638 | 639 | fn C.MatrixAdd(Matrix, Matrix) Matrix 640 | @[inline] 641 | pub fn matrix_add(left Matrix, right Matrix) Matrix { 642 | return C.MatrixAdd(left, right) 643 | } 644 | 645 | fn C.MatrixSubtract(Matrix, Matrix) Matrix 646 | @[inline] 647 | pub fn matrix_subtract(left Matrix, right Matrix) Matrix { 648 | return C.MatrixSubtract(left, right) 649 | } 650 | 651 | fn C.MatrixMultiply(Matrix, Matrix) Matrix 652 | @[inline] 653 | pub fn matrix_multiply(left Matrix, right Matrix) Matrix { 654 | return C.MatrixMultiply(left, right) 655 | } 656 | 657 | fn C.MatrixTranslate(f32, f32, f32) Matrix 658 | @[inline] 659 | pub fn matrix_translate(x f32, y f32, z f32) Matrix { 660 | return C.MatrixTranslate(x, y, z) 661 | } 662 | 663 | fn C.MatrixRotate(Vector3, f32) Matrix 664 | @[inline] 665 | pub fn matrix_rotate(axis Vector3, angle f32) Matrix { 666 | return C.MatrixRotate(axis, angle) 667 | } 668 | 669 | fn C.MatrixRotateX(f32) Matrix 670 | @[inline] 671 | pub fn matrix_rotate_x(angle f32) Matrix { 672 | return C.MatrixRotateX(angle) 673 | } 674 | 675 | fn C.MatrixRotateY(f32) Matrix 676 | @[inline] 677 | pub fn matrix_rotate_y(angle f32) Matrix { 678 | return C.MatrixRotateY(angle) 679 | } 680 | 681 | fn C.MatrixRotateZ(f32) Matrix 682 | @[inline] 683 | pub fn matrix_rotate_z(angle f32) Matrix { 684 | return C.MatrixRotateZ(angle) 685 | } 686 | 687 | fn C.MatrixRotateXYZ(Vector3) Matrix 688 | @[inline] 689 | pub fn matrix_rotate_x_y_z(angle Vector3) Matrix { 690 | return C.MatrixRotateXYZ(angle) 691 | } 692 | 693 | fn C.MatrixRotateZYX(Vector3) Matrix 694 | @[inline] 695 | pub fn matrix_rotate_z_y_x(angle Vector3) Matrix { 696 | return C.MatrixRotateZYX(angle) 697 | } 698 | 699 | fn C.MatrixScale(f32, f32, f32) Matrix 700 | @[inline] 701 | pub fn matrix_scale(x f32, y f32, z f32) Matrix { 702 | return C.MatrixScale(x, y, z) 703 | } 704 | 705 | fn C.MatrixFrustum(f64, f64, f64, f64, f64, f64) Matrix 706 | @[inline] 707 | pub fn matrix_frustum(left f64, right f64, bottom f64, top f64, near_plane f64, far_plane f64) Matrix { 708 | return C.MatrixFrustum(left, right, bottom, top, near_plane, far_plane) 709 | } 710 | 711 | fn C.MatrixPerspective(f64, f64, f64, f64) Matrix 712 | @[inline] 713 | pub fn matrix_perspective(fov_y f64, aspect f64, near_plane f64, far_plane f64) Matrix { 714 | return C.MatrixPerspective(fov_y, aspect, near_plane, far_plane) 715 | } 716 | 717 | fn C.MatrixOrtho(f64, f64, f64, f64, f64, f64) Matrix 718 | @[inline] 719 | pub fn matrix_ortho(left f64, right f64, bottom f64, top f64, near_plane f64, far_plane f64) Matrix { 720 | return C.MatrixOrtho(left, right, bottom, top, near_plane, far_plane) 721 | } 722 | 723 | fn C.MatrixLookAt(Vector3, Vector3, Vector3) Matrix 724 | @[inline] 725 | pub fn matrix_look_at(eye Vector3, target Vector3, up Vector3) Matrix { 726 | return C.MatrixLookAt(eye, target, up) 727 | } 728 | 729 | fn C.MatrixToFloatV(Matrix) Float16 730 | @[inline] 731 | pub fn matrix_to_float_v(mat Matrix) Float16 { 732 | return C.MatrixToFloatV(mat) 733 | } 734 | 735 | fn C.QuaternionAdd(Quaternion, Quaternion) Quaternion 736 | @[inline] 737 | pub fn quaternion_add(q1 Quaternion, q2 Quaternion) Quaternion { 738 | return C.QuaternionAdd(q1, q2) 739 | } 740 | 741 | fn C.QuaternionAddValue(Quaternion, f32) Quaternion 742 | @[inline] 743 | pub fn quaternion_add_value(q Quaternion, add f32) Quaternion { 744 | return C.QuaternionAddValue(q, add) 745 | } 746 | 747 | fn C.QuaternionSubtract(Quaternion, Quaternion) Quaternion 748 | @[inline] 749 | pub fn quaternion_subtract(q1 Quaternion, q2 Quaternion) Quaternion { 750 | return C.QuaternionSubtract(q1, q2) 751 | } 752 | 753 | fn C.QuaternionSubtractValue(Quaternion, f32) Quaternion 754 | @[inline] 755 | pub fn quaternion_subtract_value(q Quaternion, sub f32) Quaternion { 756 | return C.QuaternionSubtractValue(q, sub) 757 | } 758 | 759 | fn C.QuaternionIdentity() Quaternion 760 | @[inline] 761 | pub fn quaternion_identity() Quaternion { 762 | return C.QuaternionIdentity() 763 | } 764 | 765 | fn C.QuaternionLength(Quaternion) f32 766 | @[inline] 767 | pub fn quaternion_length(q Quaternion) f32 { 768 | return C.QuaternionLength(q) 769 | } 770 | 771 | fn C.QuaternionNormalize(Quaternion) Quaternion 772 | @[inline] 773 | pub fn quaternion_normalize(q Quaternion) Quaternion { 774 | return C.QuaternionNormalize(q) 775 | } 776 | 777 | fn C.QuaternionInvert(Quaternion) Quaternion 778 | @[inline] 779 | pub fn quaternion_invert(q Quaternion) Quaternion { 780 | return C.QuaternionInvert(q) 781 | } 782 | 783 | fn C.QuaternionMultiply(Quaternion, Quaternion) Quaternion 784 | @[inline] 785 | pub fn quaternion_multiply(q1 Quaternion, q2 Quaternion) Quaternion { 786 | return C.QuaternionMultiply(q1, q2) 787 | } 788 | 789 | fn C.QuaternionScale(Quaternion, f32) Quaternion 790 | @[inline] 791 | pub fn quaternion_scale(q Quaternion, mul f32) Quaternion { 792 | return C.QuaternionScale(q, mul) 793 | } 794 | 795 | fn C.QuaternionDivide(Quaternion, Quaternion) Quaternion 796 | @[inline] 797 | pub fn quaternion_divide(q1 Quaternion, q2 Quaternion) Quaternion { 798 | return C.QuaternionDivide(q1, q2) 799 | } 800 | 801 | fn C.QuaternionLerp(Quaternion, Quaternion, f32) Quaternion 802 | @[inline] 803 | pub fn quaternion_lerp(q1 Quaternion, q2 Quaternion, amount f32) Quaternion { 804 | return C.QuaternionLerp(q1, q2, amount) 805 | } 806 | 807 | fn C.QuaternionNlerp(Quaternion, Quaternion, f32) Quaternion 808 | @[inline] 809 | pub fn quaternion_nlerp(q1 Quaternion, q2 Quaternion, amount f32) Quaternion { 810 | return C.QuaternionNlerp(q1, q2, amount) 811 | } 812 | 813 | fn C.QuaternionSlerp(Quaternion, Quaternion, f32) Quaternion 814 | @[inline] 815 | pub fn quaternion_slerp(q1 Quaternion, q2 Quaternion, amount f32) Quaternion { 816 | return C.QuaternionSlerp(q1, q2, amount) 817 | } 818 | 819 | fn C.QuaternionCubicHermiteSpline(Quaternion, Quaternion, Quaternion, Quaternion, f32) Quaternion 820 | @[inline] 821 | pub fn quaternion_cubic_hermite_spline(q1 Quaternion, out_tangent1 Quaternion, q2 Quaternion, in_tangent2 Quaternion, t f32) Quaternion { 822 | return C.QuaternionCubicHermiteSpline(q1, out_tangent1, q2, in_tangent2, t) 823 | } 824 | 825 | fn C.QuaternionFromVector3ToVector3(Vector3, Vector3) Quaternion 826 | @[inline] 827 | pub fn quaternion_from_vector3_to_vector3(from Vector3, to Vector3) Quaternion { 828 | return C.QuaternionFromVector3ToVector3(from, to) 829 | } 830 | 831 | fn C.QuaternionFromMatrix(Matrix) Quaternion 832 | @[inline] 833 | pub fn quaternion_from_matrix(mat Matrix) Quaternion { 834 | return C.QuaternionFromMatrix(mat) 835 | } 836 | 837 | fn C.QuaternionToMatrix(Quaternion) Matrix 838 | @[inline] 839 | pub fn quaternion_to_matrix(q Quaternion) Matrix { 840 | return C.QuaternionToMatrix(q) 841 | } 842 | 843 | fn C.QuaternionFromAxisAngle(Vector3, f32) Quaternion 844 | @[inline] 845 | pub fn quaternion_from_axis_angle(axis Vector3, angle f32) Quaternion { 846 | return C.QuaternionFromAxisAngle(axis, angle) 847 | } 848 | 849 | fn C.QuaternionToAxisAngle(Quaternion, &Vector3, &f32) 850 | @[inline] 851 | pub fn quaternion_to_axis_angle(q Quaternion, out_axis &Vector3, out_angle &f32) { 852 | C.QuaternionToAxisAngle(q, out_axis, out_angle) 853 | } 854 | 855 | fn C.QuaternionFromEuler(f32, f32, f32) Quaternion 856 | @[inline] 857 | pub fn quaternion_from_euler(pitch f32, yaw f32, roll f32) Quaternion { 858 | return C.QuaternionFromEuler(pitch, yaw, roll) 859 | } 860 | 861 | fn C.QuaternionToEuler(Quaternion) Vector3 862 | @[inline] 863 | pub fn quaternion_to_euler(q Quaternion) Vector3 { 864 | return C.QuaternionToEuler(q) 865 | } 866 | 867 | fn C.QuaternionTransform(Quaternion, Matrix) Quaternion 868 | @[inline] 869 | pub fn quaternion_transform(q Quaternion, mat Matrix) Quaternion { 870 | return C.QuaternionTransform(q, mat) 871 | } 872 | 873 | fn C.QuaternionEquals(Quaternion, Quaternion) int 874 | @[inline] 875 | pub fn quaternion_equals(p Quaternion, q Quaternion) int { 876 | return C.QuaternionEquals(p, q) 877 | } 878 | 879 | fn C.MatrixDecompose(Matrix, &Vector3, &Quaternion, &Vector3) 880 | @[inline] 881 | pub fn matrix_decompose(mat Matrix, translation &Vector3, rotation &Quaternion, scale &Vector3) { 882 | C.MatrixDecompose(mat, translation, rotation, scale) 883 | } 884 | -------------------------------------------------------------------------------- /raymath/raymath.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************************** 2 | * 3 | * raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions 4 | * 5 | * CONVENTIONS: 6 | * - Matrix structure is defined as row-major (memory layout) but parameters naming AND all 7 | * math operations performed by the library consider the structure as it was column-major 8 | * It is like transposed versions of the matrices are used for all the maths 9 | * It benefits some functions making them cache-friendly and also avoids matrix 10 | * transpositions sometimes required by OpenGL 11 | * Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3] 12 | * - Functions are always self-contained, no function use another raymath function inside, 13 | * required code is directly re-implemented inside 14 | * - Functions input parameters are always received by value (2 unavoidable exceptions) 15 | * - Functions use always a "result" variable for return (except C++ operators) 16 | * - Functions are always defined inline 17 | * - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) 18 | * - No compound literals used to make sure libray is compatible with C++ 19 | * 20 | * CONFIGURATION: 21 | * #define RAYMATH_IMPLEMENTATION 22 | * Generates the implementation of the library into the included file. 23 | * If not defined, the library is in header only mode and can be included in other headers 24 | * or source files without problems. But only ONE file should hold the implementation. 25 | * 26 | * #define RAYMATH_STATIC_INLINE 27 | * Define static inline functions code, so #include header suffices for use. 28 | * This may use up lots of memory. 29 | * 30 | * #define RAYMATH_DISABLE_CPP_OPERATORS 31 | * Disables C++ operator overloads for raymath types. 32 | * 33 | * LICENSE: zlib/libpng 34 | * 35 | * Copyright (c) 2015-2024 Ramon Santamaria (@raysan5) 36 | * 37 | * This software is provided "as-is", without any express or implied warranty. In no event 38 | * will the authors be held liable for any damages arising from the use of this software. 39 | * 40 | * Permission is granted to anyone to use this software for any purpose, including commercial 41 | * applications, and to alter it and redistribute it freely, subject to the following restrictions: 42 | * 43 | * 1. The origin of this software must not be misrepresented; you must not claim that you 44 | * wrote the original software. If you use this software in a product, an acknowledgment 45 | * in the product documentation would be appreciated but is not required. 46 | * 47 | * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 48 | * as being the original software. 49 | * 50 | * 3. This notice may not be removed or altered from any source distribution. 51 | * 52 | **********************************************************************************************/ 53 | 54 | #ifndef RAYMATH_H 55 | #define RAYMATH_H 56 | 57 | #if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE) 58 | #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory" 59 | #endif 60 | 61 | // Function specifiers definition 62 | #if defined(RAYMATH_IMPLEMENTATION) 63 | #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) 64 | #define RMAPI __declspec(dllexport) extern inline // We are building raylib as a Win32 shared library (.dll) 65 | #elif defined(BUILD_LIBTYPE_SHARED) 66 | #define RMAPI __attribute__((visibility("default"))) // We are building raylib as a Unix shared library (.so/.dylib) 67 | #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) 68 | #define RMAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll) 69 | #else 70 | #define RMAPI extern inline // Provide external definition 71 | #endif 72 | #elif defined(RAYMATH_STATIC_INLINE) 73 | #define RMAPI static inline // Functions may be inlined, no external out-of-line definition 74 | #else 75 | #if defined(__TINYC__) 76 | #define RMAPI static inline // plain inline not supported by tinycc (See issue #435) 77 | #else 78 | #define RMAPI inline // Functions may be inlined or external definition used 79 | #endif 80 | #endif 81 | 82 | 83 | //---------------------------------------------------------------------------------- 84 | // Defines and Macros 85 | //---------------------------------------------------------------------------------- 86 | #ifndef PI 87 | #define PI 3.14159265358979323846f 88 | #endif 89 | 90 | #ifndef EPSILON 91 | #define EPSILON 0.000001f 92 | #endif 93 | 94 | #ifndef DEG2RAD 95 | #define DEG2RAD (PI/180.0f) 96 | #endif 97 | 98 | #ifndef RAD2DEG 99 | #define RAD2DEG (180.0f/PI) 100 | #endif 101 | 102 | // Get float vector for Matrix 103 | #ifndef MatrixToFloat 104 | #define MatrixToFloat(mat) (MatrixToFloatV(mat).v) 105 | #endif 106 | 107 | // Get float vector for Vector3 108 | #ifndef Vector3ToFloat 109 | #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v) 110 | #endif 111 | 112 | //---------------------------------------------------------------------------------- 113 | // Types and Structures Definition 114 | //---------------------------------------------------------------------------------- 115 | #if !defined(RL_VECTOR2_TYPE) 116 | // Vector2 type 117 | typedef struct Vector2 { 118 | float x; 119 | float y; 120 | } Vector2; 121 | #define RL_VECTOR2_TYPE 122 | #endif 123 | 124 | #if !defined(RL_VECTOR3_TYPE) 125 | // Vector3 type 126 | typedef struct Vector3 { 127 | float x; 128 | float y; 129 | float z; 130 | } Vector3; 131 | #define RL_VECTOR3_TYPE 132 | #endif 133 | 134 | #if !defined(RL_VECTOR4_TYPE) 135 | // Vector4 type 136 | typedef struct Vector4 { 137 | float x; 138 | float y; 139 | float z; 140 | float w; 141 | } Vector4; 142 | #define RL_VECTOR4_TYPE 143 | #endif 144 | 145 | #if !defined(RL_QUATERNION_TYPE) 146 | // Quaternion type 147 | typedef Vector4 Quaternion; 148 | #define RL_QUATERNION_TYPE 149 | #endif 150 | 151 | #if !defined(RL_MATRIX_TYPE) 152 | // Matrix type (OpenGL style 4x4 - right handed, column major) 153 | typedef struct Matrix { 154 | float m0, m4, m8, m12; // Matrix first row (4 components) 155 | float m1, m5, m9, m13; // Matrix second row (4 components) 156 | float m2, m6, m10, m14; // Matrix third row (4 components) 157 | float m3, m7, m11, m15; // Matrix fourth row (4 components) 158 | } Matrix; 159 | #define RL_MATRIX_TYPE 160 | #endif 161 | 162 | // NOTE: Helper types to be used instead of array return types for *ToFloat functions 163 | typedef struct float3 { 164 | float v[3]; 165 | } float3; 166 | 167 | typedef struct float16 { 168 | float v[16]; 169 | } float16; 170 | 171 | #include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf() 172 | 173 | //---------------------------------------------------------------------------------- 174 | // Module Functions Definition - Utils math 175 | //---------------------------------------------------------------------------------- 176 | 177 | // Clamp float value 178 | RMAPI float Clamp(float value, float min, float max) 179 | { 180 | float result = (value < min)? min : value; 181 | 182 | if (result > max) result = max; 183 | 184 | return result; 185 | } 186 | 187 | // Calculate linear interpolation between two floats 188 | RMAPI float Lerp(float start, float end, float amount) 189 | { 190 | float result = start + amount*(end - start); 191 | 192 | return result; 193 | } 194 | 195 | // Normalize input value within input range 196 | RMAPI float Normalize(float value, float start, float end) 197 | { 198 | float result = (value - start)/(end - start); 199 | 200 | return result; 201 | } 202 | 203 | // Remap input value within input range to output range 204 | RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) 205 | { 206 | float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart; 207 | 208 | return result; 209 | } 210 | 211 | // Wrap input value from min to max 212 | RMAPI float Wrap(float value, float min, float max) 213 | { 214 | float result = value - (max - min)*floorf((value - min)/(max - min)); 215 | 216 | return result; 217 | } 218 | 219 | // Check whether two given floats are almost equal 220 | RMAPI int FloatEquals(float x, float y) 221 | { 222 | #if !defined(EPSILON) 223 | #define EPSILON 0.000001f 224 | #endif 225 | 226 | int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y)))); 227 | 228 | return result; 229 | } 230 | 231 | //---------------------------------------------------------------------------------- 232 | // Module Functions Definition - Vector2 math 233 | //---------------------------------------------------------------------------------- 234 | 235 | // Vector with components value 0.0f 236 | RMAPI Vector2 Vector2Zero(void) 237 | { 238 | Vector2 result = { 0.0f, 0.0f }; 239 | 240 | return result; 241 | } 242 | 243 | // Vector with components value 1.0f 244 | RMAPI Vector2 Vector2One(void) 245 | { 246 | Vector2 result = { 1.0f, 1.0f }; 247 | 248 | return result; 249 | } 250 | 251 | // Add two vectors (v1 + v2) 252 | RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2) 253 | { 254 | Vector2 result = { v1.x + v2.x, v1.y + v2.y }; 255 | 256 | return result; 257 | } 258 | 259 | // Add vector and float value 260 | RMAPI Vector2 Vector2AddValue(Vector2 v, float add) 261 | { 262 | Vector2 result = { v.x + add, v.y + add }; 263 | 264 | return result; 265 | } 266 | 267 | // Subtract two vectors (v1 - v2) 268 | RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) 269 | { 270 | Vector2 result = { v1.x - v2.x, v1.y - v2.y }; 271 | 272 | return result; 273 | } 274 | 275 | // Subtract vector by float value 276 | RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub) 277 | { 278 | Vector2 result = { v.x - sub, v.y - sub }; 279 | 280 | return result; 281 | } 282 | 283 | // Calculate vector length 284 | RMAPI float Vector2Length(Vector2 v) 285 | { 286 | float result = sqrtf((v.x*v.x) + (v.y*v.y)); 287 | 288 | return result; 289 | } 290 | 291 | // Calculate vector square length 292 | RMAPI float Vector2LengthSqr(Vector2 v) 293 | { 294 | float result = (v.x*v.x) + (v.y*v.y); 295 | 296 | return result; 297 | } 298 | 299 | // Calculate two vectors dot product 300 | RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2) 301 | { 302 | float result = (v1.x*v2.x + v1.y*v2.y); 303 | 304 | return result; 305 | } 306 | 307 | // Calculate two vectors cross product 308 | RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2) 309 | { 310 | float result = (v1.x*v2.y - v1.y*v2.x); 311 | 312 | return result; 313 | } 314 | 315 | // Calculate distance between two vectors 316 | RMAPI float Vector2Distance(Vector2 v1, Vector2 v2) 317 | { 318 | float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); 319 | 320 | return result; 321 | } 322 | 323 | // Calculate square distance between two vectors 324 | RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) 325 | { 326 | float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); 327 | 328 | return result; 329 | } 330 | 331 | // Calculate angle between two vectors 332 | // NOTE: Angle is calculated from origin point (0, 0) 333 | RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) 334 | { 335 | float result = 0.0f; 336 | 337 | float dot = v1.x*v2.x + v1.y*v2.y; 338 | float det = v1.x*v2.y - v1.y*v2.x; 339 | 340 | result = atan2f(det, dot); 341 | 342 | return result; 343 | } 344 | 345 | // Calculate angle defined by a two vectors line 346 | // NOTE: Parameters need to be normalized 347 | // Current implementation should be aligned with glm::angle 348 | RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) 349 | { 350 | float result = 0.0f; 351 | 352 | // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior 353 | result = -atan2f(end.y - start.y, end.x - start.x); 354 | 355 | return result; 356 | } 357 | 358 | // Scale vector (multiply by value) 359 | RMAPI Vector2 Vector2Scale(Vector2 v, float scale) 360 | { 361 | Vector2 result = { v.x*scale, v.y*scale }; 362 | 363 | return result; 364 | } 365 | 366 | // Multiply vector by vector 367 | RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2) 368 | { 369 | Vector2 result = { v1.x*v2.x, v1.y*v2.y }; 370 | 371 | return result; 372 | } 373 | 374 | // Negate vector 375 | RMAPI Vector2 Vector2Negate(Vector2 v) 376 | { 377 | Vector2 result = { -v.x, -v.y }; 378 | 379 | return result; 380 | } 381 | 382 | // Divide vector by vector 383 | RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2) 384 | { 385 | Vector2 result = { v1.x/v2.x, v1.y/v2.y }; 386 | 387 | return result; 388 | } 389 | 390 | // Normalize provided vector 391 | RMAPI Vector2 Vector2Normalize(Vector2 v) 392 | { 393 | Vector2 result = { 0 }; 394 | float length = sqrtf((v.x*v.x) + (v.y*v.y)); 395 | 396 | if (length > 0) 397 | { 398 | float ilength = 1.0f/length; 399 | result.x = v.x*ilength; 400 | result.y = v.y*ilength; 401 | } 402 | 403 | return result; 404 | } 405 | 406 | // Transforms a Vector2 by a given Matrix 407 | RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat) 408 | { 409 | Vector2 result = { 0 }; 410 | 411 | float x = v.x; 412 | float y = v.y; 413 | float z = 0; 414 | 415 | result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; 416 | result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; 417 | 418 | return result; 419 | } 420 | 421 | // Calculate linear interpolation between two vectors 422 | RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) 423 | { 424 | Vector2 result = { 0 }; 425 | 426 | result.x = v1.x + amount*(v2.x - v1.x); 427 | result.y = v1.y + amount*(v2.y - v1.y); 428 | 429 | return result; 430 | } 431 | 432 | // Calculate reflected vector to normal 433 | RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal) 434 | { 435 | Vector2 result = { 0 }; 436 | 437 | float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product 438 | 439 | result.x = v.x - (2.0f*normal.x)*dotProduct; 440 | result.y = v.y - (2.0f*normal.y)*dotProduct; 441 | 442 | return result; 443 | } 444 | 445 | // Get min value for each pair of components 446 | RMAPI Vector2 Vector2Min(Vector2 v1, Vector2 v2) 447 | { 448 | Vector2 result = { 0 }; 449 | 450 | result.x = fminf(v1.x, v2.x); 451 | result.y = fminf(v1.y, v2.y); 452 | 453 | return result; 454 | } 455 | 456 | // Get max value for each pair of components 457 | RMAPI Vector2 Vector2Max(Vector2 v1, Vector2 v2) 458 | { 459 | Vector2 result = { 0 }; 460 | 461 | result.x = fmaxf(v1.x, v2.x); 462 | result.y = fmaxf(v1.y, v2.y); 463 | 464 | return result; 465 | } 466 | 467 | // Rotate vector by angle 468 | RMAPI Vector2 Vector2Rotate(Vector2 v, float angle) 469 | { 470 | Vector2 result = { 0 }; 471 | 472 | float cosres = cosf(angle); 473 | float sinres = sinf(angle); 474 | 475 | result.x = v.x*cosres - v.y*sinres; 476 | result.y = v.x*sinres + v.y*cosres; 477 | 478 | return result; 479 | } 480 | 481 | // Move Vector towards target 482 | RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) 483 | { 484 | Vector2 result = { 0 }; 485 | 486 | float dx = target.x - v.x; 487 | float dy = target.y - v.y; 488 | float value = (dx*dx) + (dy*dy); 489 | 490 | if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; 491 | 492 | float dist = sqrtf(value); 493 | 494 | result.x = v.x + dx/dist*maxDistance; 495 | result.y = v.y + dy/dist*maxDistance; 496 | 497 | return result; 498 | } 499 | 500 | // Invert the given vector 501 | RMAPI Vector2 Vector2Invert(Vector2 v) 502 | { 503 | Vector2 result = { 1.0f/v.x, 1.0f/v.y }; 504 | 505 | return result; 506 | } 507 | 508 | // Clamp the components of the vector between 509 | // min and max values specified by the given vectors 510 | RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max) 511 | { 512 | Vector2 result = { 0 }; 513 | 514 | result.x = fminf(max.x, fmaxf(min.x, v.x)); 515 | result.y = fminf(max.y, fmaxf(min.y, v.y)); 516 | 517 | return result; 518 | } 519 | 520 | // Clamp the magnitude of the vector between two min and max values 521 | RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max) 522 | { 523 | Vector2 result = v; 524 | 525 | float length = (v.x*v.x) + (v.y*v.y); 526 | if (length > 0.0f) 527 | { 528 | length = sqrtf(length); 529 | 530 | float scale = 1; // By default, 1 as the neutral element. 531 | if (length < min) 532 | { 533 | scale = min/length; 534 | } 535 | else if (length > max) 536 | { 537 | scale = max/length; 538 | } 539 | 540 | result.x = v.x*scale; 541 | result.y = v.y*scale; 542 | } 543 | 544 | return result; 545 | } 546 | 547 | // Check whether two given vectors are almost equal 548 | RMAPI int Vector2Equals(Vector2 p, Vector2 q) 549 | { 550 | #if !defined(EPSILON) 551 | #define EPSILON 0.000001f 552 | #endif 553 | 554 | int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && 555 | ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))); 556 | 557 | return result; 558 | } 559 | 560 | // Compute the direction of a refracted ray 561 | // v: normalized direction of the incoming ray 562 | // n: normalized normal vector of the interface of two optical media 563 | // r: ratio of the refractive index of the medium from where the ray comes 564 | // to the refractive index of the medium on the other side of the surface 565 | RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r) 566 | { 567 | Vector2 result = { 0 }; 568 | 569 | float dot = v.x*n.x + v.y*n.y; 570 | float d = 1.0f - r*r*(1.0f - dot*dot); 571 | 572 | if (d >= 0.0f) 573 | { 574 | d = sqrtf(d); 575 | v.x = r*v.x - (r*dot + d)*n.x; 576 | v.y = r*v.y - (r*dot + d)*n.y; 577 | 578 | result = v; 579 | } 580 | 581 | return result; 582 | } 583 | 584 | 585 | //---------------------------------------------------------------------------------- 586 | // Module Functions Definition - Vector3 math 587 | //---------------------------------------------------------------------------------- 588 | 589 | // Vector with components value 0.0f 590 | RMAPI Vector3 Vector3Zero(void) 591 | { 592 | Vector3 result = { 0.0f, 0.0f, 0.0f }; 593 | 594 | return result; 595 | } 596 | 597 | // Vector with components value 1.0f 598 | RMAPI Vector3 Vector3One(void) 599 | { 600 | Vector3 result = { 1.0f, 1.0f, 1.0f }; 601 | 602 | return result; 603 | } 604 | 605 | // Add two vectors 606 | RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2) 607 | { 608 | Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; 609 | 610 | return result; 611 | } 612 | 613 | // Add vector and float value 614 | RMAPI Vector3 Vector3AddValue(Vector3 v, float add) 615 | { 616 | Vector3 result = { v.x + add, v.y + add, v.z + add }; 617 | 618 | return result; 619 | } 620 | 621 | // Subtract two vectors 622 | RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) 623 | { 624 | Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; 625 | 626 | return result; 627 | } 628 | 629 | // Subtract vector by float value 630 | RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub) 631 | { 632 | Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; 633 | 634 | return result; 635 | } 636 | 637 | // Multiply vector by scalar 638 | RMAPI Vector3 Vector3Scale(Vector3 v, float scalar) 639 | { 640 | Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar }; 641 | 642 | return result; 643 | } 644 | 645 | // Multiply vector by vector 646 | RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2) 647 | { 648 | Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z }; 649 | 650 | return result; 651 | } 652 | 653 | // Calculate two vectors cross product 654 | RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) 655 | { 656 | Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; 657 | 658 | return result; 659 | } 660 | 661 | // Calculate one vector perpendicular vector 662 | RMAPI Vector3 Vector3Perpendicular(Vector3 v) 663 | { 664 | Vector3 result = { 0 }; 665 | 666 | float min = fabsf(v.x); 667 | Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f}; 668 | 669 | if (fabsf(v.y) < min) 670 | { 671 | min = fabsf(v.y); 672 | Vector3 tmp = {0.0f, 1.0f, 0.0f}; 673 | cardinalAxis = tmp; 674 | } 675 | 676 | if (fabsf(v.z) < min) 677 | { 678 | Vector3 tmp = {0.0f, 0.0f, 1.0f}; 679 | cardinalAxis = tmp; 680 | } 681 | 682 | // Cross product between vectors 683 | result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y; 684 | result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z; 685 | result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x; 686 | 687 | return result; 688 | } 689 | 690 | // Calculate vector length 691 | RMAPI float Vector3Length(const Vector3 v) 692 | { 693 | float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 694 | 695 | return result; 696 | } 697 | 698 | // Calculate vector square length 699 | RMAPI float Vector3LengthSqr(const Vector3 v) 700 | { 701 | float result = v.x*v.x + v.y*v.y + v.z*v.z; 702 | 703 | return result; 704 | } 705 | 706 | // Calculate two vectors dot product 707 | RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2) 708 | { 709 | float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); 710 | 711 | return result; 712 | } 713 | 714 | // Calculate distance between two vectors 715 | RMAPI float Vector3Distance(Vector3 v1, Vector3 v2) 716 | { 717 | float result = 0.0f; 718 | 719 | float dx = v2.x - v1.x; 720 | float dy = v2.y - v1.y; 721 | float dz = v2.z - v1.z; 722 | result = sqrtf(dx*dx + dy*dy + dz*dz); 723 | 724 | return result; 725 | } 726 | 727 | // Calculate square distance between two vectors 728 | RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2) 729 | { 730 | float result = 0.0f; 731 | 732 | float dx = v2.x - v1.x; 733 | float dy = v2.y - v1.y; 734 | float dz = v2.z - v1.z; 735 | result = dx*dx + dy*dy + dz*dz; 736 | 737 | return result; 738 | } 739 | 740 | // Calculate angle between two vectors 741 | RMAPI float Vector3Angle(Vector3 v1, Vector3 v2) 742 | { 743 | float result = 0.0f; 744 | 745 | Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; 746 | float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z); 747 | float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); 748 | result = atan2f(len, dot); 749 | 750 | return result; 751 | } 752 | 753 | // Negate provided vector (invert direction) 754 | RMAPI Vector3 Vector3Negate(Vector3 v) 755 | { 756 | Vector3 result = { -v.x, -v.y, -v.z }; 757 | 758 | return result; 759 | } 760 | 761 | // Divide vector by vector 762 | RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2) 763 | { 764 | Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; 765 | 766 | return result; 767 | } 768 | 769 | // Normalize provided vector 770 | RMAPI Vector3 Vector3Normalize(Vector3 v) 771 | { 772 | Vector3 result = v; 773 | 774 | float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 775 | if (length != 0.0f) 776 | { 777 | float ilength = 1.0f/length; 778 | 779 | result.x *= ilength; 780 | result.y *= ilength; 781 | result.z *= ilength; 782 | } 783 | 784 | return result; 785 | } 786 | 787 | //Calculate the projection of the vector v1 on to v2 788 | RMAPI Vector3 Vector3Project(Vector3 v1, Vector3 v2) 789 | { 790 | Vector3 result = { 0 }; 791 | 792 | float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); 793 | float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); 794 | 795 | float mag = v1dv2/v2dv2; 796 | 797 | result.x = v2.x*mag; 798 | result.y = v2.y*mag; 799 | result.z = v2.z*mag; 800 | 801 | return result; 802 | } 803 | 804 | //Calculate the rejection of the vector v1 on to v2 805 | RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2) 806 | { 807 | Vector3 result = { 0 }; 808 | 809 | float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); 810 | float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); 811 | 812 | float mag = v1dv2/v2dv2; 813 | 814 | result.x = v1.x - (v2.x*mag); 815 | result.y = v1.y - (v2.y*mag); 816 | result.z = v1.z - (v2.z*mag); 817 | 818 | return result; 819 | } 820 | 821 | // Orthonormalize provided vectors 822 | // Makes vectors normalized and orthogonal to each other 823 | // Gram-Schmidt function implementation 824 | RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) 825 | { 826 | float length = 0.0f; 827 | float ilength = 0.0f; 828 | 829 | // Vector3Normalize(*v1); 830 | Vector3 v = *v1; 831 | length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 832 | if (length == 0.0f) length = 1.0f; 833 | ilength = 1.0f/length; 834 | v1->x *= ilength; 835 | v1->y *= ilength; 836 | v1->z *= ilength; 837 | 838 | // Vector3CrossProduct(*v1, *v2) 839 | Vector3 vn1 = { v1->y*v2->z - v1->z*v2->y, v1->z*v2->x - v1->x*v2->z, v1->x*v2->y - v1->y*v2->x }; 840 | 841 | // Vector3Normalize(vn1); 842 | v = vn1; 843 | length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 844 | if (length == 0.0f) length = 1.0f; 845 | ilength = 1.0f/length; 846 | vn1.x *= ilength; 847 | vn1.y *= ilength; 848 | vn1.z *= ilength; 849 | 850 | // Vector3CrossProduct(vn1, *v1) 851 | Vector3 vn2 = { vn1.y*v1->z - vn1.z*v1->y, vn1.z*v1->x - vn1.x*v1->z, vn1.x*v1->y - vn1.y*v1->x }; 852 | 853 | *v2 = vn2; 854 | } 855 | 856 | // Transforms a Vector3 by a given Matrix 857 | RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat) 858 | { 859 | Vector3 result = { 0 }; 860 | 861 | float x = v.x; 862 | float y = v.y; 863 | float z = v.z; 864 | 865 | result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; 866 | result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; 867 | result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; 868 | 869 | return result; 870 | } 871 | 872 | // Transform a vector by quaternion rotation 873 | RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) 874 | { 875 | Vector3 result = { 0 }; 876 | 877 | result.x = v.x*(q.x*q.x + q.w*q.w - q.y*q.y - q.z*q.z) + v.y*(2*q.x*q.y - 2*q.w*q.z) + v.z*(2*q.x*q.z + 2*q.w*q.y); 878 | result.y = v.x*(2*q.w*q.z + 2*q.x*q.y) + v.y*(q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z) + v.z*(-2*q.w*q.x + 2*q.y*q.z); 879 | result.z = v.x*(-2*q.w*q.y + 2*q.x*q.z) + v.y*(2*q.w*q.x + 2*q.y*q.z)+ v.z*(q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z); 880 | 881 | return result; 882 | } 883 | 884 | // Rotates a vector around an axis 885 | RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle) 886 | { 887 | // Using Euler-Rodrigues Formula 888 | // Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula 889 | 890 | Vector3 result = v; 891 | 892 | // Vector3Normalize(axis); 893 | float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); 894 | if (length == 0.0f) length = 1.0f; 895 | float ilength = 1.0f/length; 896 | axis.x *= ilength; 897 | axis.y *= ilength; 898 | axis.z *= ilength; 899 | 900 | angle /= 2.0f; 901 | float a = sinf(angle); 902 | float b = axis.x*a; 903 | float c = axis.y*a; 904 | float d = axis.z*a; 905 | a = cosf(angle); 906 | Vector3 w = { b, c, d }; 907 | 908 | // Vector3CrossProduct(w, v) 909 | Vector3 wv = { w.y*v.z - w.z*v.y, w.z*v.x - w.x*v.z, w.x*v.y - w.y*v.x }; 910 | 911 | // Vector3CrossProduct(w, wv) 912 | Vector3 wwv = { w.y*wv.z - w.z*wv.y, w.z*wv.x - w.x*wv.z, w.x*wv.y - w.y*wv.x }; 913 | 914 | // Vector3Scale(wv, 2*a) 915 | a *= 2; 916 | wv.x *= a; 917 | wv.y *= a; 918 | wv.z *= a; 919 | 920 | // Vector3Scale(wwv, 2) 921 | wwv.x *= 2; 922 | wwv.y *= 2; 923 | wwv.z *= 2; 924 | 925 | result.x += wv.x; 926 | result.y += wv.y; 927 | result.z += wv.z; 928 | 929 | result.x += wwv.x; 930 | result.y += wwv.y; 931 | result.z += wwv.z; 932 | 933 | return result; 934 | } 935 | 936 | // Move Vector towards target 937 | RMAPI Vector3 Vector3MoveTowards(Vector3 v, Vector3 target, float maxDistance) 938 | { 939 | Vector3 result = { 0 }; 940 | 941 | float dx = target.x - v.x; 942 | float dy = target.y - v.y; 943 | float dz = target.z - v.z; 944 | float value = (dx*dx) + (dy*dy) + (dz*dz); 945 | 946 | if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; 947 | 948 | float dist = sqrtf(value); 949 | 950 | result.x = v.x + dx/dist*maxDistance; 951 | result.y = v.y + dy/dist*maxDistance; 952 | result.z = v.z + dz/dist*maxDistance; 953 | 954 | return result; 955 | } 956 | 957 | // Calculate linear interpolation between two vectors 958 | RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) 959 | { 960 | Vector3 result = { 0 }; 961 | 962 | result.x = v1.x + amount*(v2.x - v1.x); 963 | result.y = v1.y + amount*(v2.y - v1.y); 964 | result.z = v1.z + amount*(v2.z - v1.z); 965 | 966 | return result; 967 | } 968 | 969 | // Calculate cubic hermite interpolation between two vectors and their tangents 970 | // as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic 971 | RMAPI Vector3 Vector3CubicHermite(Vector3 v1, Vector3 tangent1, Vector3 v2, Vector3 tangent2, float amount) 972 | { 973 | Vector3 result = { 0 }; 974 | 975 | float amountPow2 = amount*amount; 976 | float amountPow3 = amount*amount*amount; 977 | 978 | result.x = (2*amountPow3 - 3*amountPow2 + 1)*v1.x + (amountPow3 - 2*amountPow2 + amount)*tangent1.x + (-2*amountPow3 + 3*amountPow2)*v2.x + (amountPow3 - amountPow2)*tangent2.x; 979 | result.y = (2*amountPow3 - 3*amountPow2 + 1)*v1.y + (amountPow3 - 2*amountPow2 + amount)*tangent1.y + (-2*amountPow3 + 3*amountPow2)*v2.y + (amountPow3 - amountPow2)*tangent2.y; 980 | result.z = (2*amountPow3 - 3*amountPow2 + 1)*v1.z + (amountPow3 - 2*amountPow2 + amount)*tangent1.z + (-2*amountPow3 + 3*amountPow2)*v2.z + (amountPow3 - amountPow2)*tangent2.z; 981 | 982 | return result; 983 | } 984 | 985 | // Calculate reflected vector to normal 986 | RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal) 987 | { 988 | Vector3 result = { 0 }; 989 | 990 | // I is the original vector 991 | // N is the normal of the incident plane 992 | // R = I - (2*N*(DotProduct[I, N])) 993 | 994 | float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z); 995 | 996 | result.x = v.x - (2.0f*normal.x)*dotProduct; 997 | result.y = v.y - (2.0f*normal.y)*dotProduct; 998 | result.z = v.z - (2.0f*normal.z)*dotProduct; 999 | 1000 | return result; 1001 | } 1002 | 1003 | // Get min value for each pair of components 1004 | RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2) 1005 | { 1006 | Vector3 result = { 0 }; 1007 | 1008 | result.x = fminf(v1.x, v2.x); 1009 | result.y = fminf(v1.y, v2.y); 1010 | result.z = fminf(v1.z, v2.z); 1011 | 1012 | return result; 1013 | } 1014 | 1015 | // Get max value for each pair of components 1016 | RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2) 1017 | { 1018 | Vector3 result = { 0 }; 1019 | 1020 | result.x = fmaxf(v1.x, v2.x); 1021 | result.y = fmaxf(v1.y, v2.y); 1022 | result.z = fmaxf(v1.z, v2.z); 1023 | 1024 | return result; 1025 | } 1026 | 1027 | // Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c) 1028 | // NOTE: Assumes P is on the plane of the triangle 1029 | RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) 1030 | { 1031 | Vector3 result = { 0 }; 1032 | 1033 | Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a) 1034 | Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a) 1035 | Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a) 1036 | float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0) 1037 | float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1) 1038 | float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1) 1039 | float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0) 1040 | float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1) 1041 | 1042 | float denom = d00*d11 - d01*d01; 1043 | 1044 | result.y = (d11*d20 - d01*d21)/denom; 1045 | result.z = (d00*d21 - d01*d20)/denom; 1046 | result.x = 1.0f - (result.z + result.y); 1047 | 1048 | return result; 1049 | } 1050 | 1051 | // Projects a Vector3 from screen space into object space 1052 | // NOTE: We are avoiding calling other raymath functions despite available 1053 | RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) 1054 | { 1055 | Vector3 result = { 0 }; 1056 | 1057 | // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it 1058 | Matrix matViewProj = { // MatrixMultiply(view, projection); 1059 | view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, 1060 | view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, 1061 | view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14, 1062 | view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15, 1063 | view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12, 1064 | view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13, 1065 | view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14, 1066 | view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15, 1067 | view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12, 1068 | view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13, 1069 | view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14, 1070 | view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15, 1071 | view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12, 1072 | view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13, 1073 | view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14, 1074 | view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 }; 1075 | 1076 | // Calculate inverted matrix -> MatrixInvert(matViewProj); 1077 | // Cache the matrix values (speed optimization) 1078 | float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3; 1079 | float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7; 1080 | float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11; 1081 | float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15; 1082 | 1083 | float b00 = a00*a11 - a01*a10; 1084 | float b01 = a00*a12 - a02*a10; 1085 | float b02 = a00*a13 - a03*a10; 1086 | float b03 = a01*a12 - a02*a11; 1087 | float b04 = a01*a13 - a03*a11; 1088 | float b05 = a02*a13 - a03*a12; 1089 | float b06 = a20*a31 - a21*a30; 1090 | float b07 = a20*a32 - a22*a30; 1091 | float b08 = a20*a33 - a23*a30; 1092 | float b09 = a21*a32 - a22*a31; 1093 | float b10 = a21*a33 - a23*a31; 1094 | float b11 = a22*a33 - a23*a32; 1095 | 1096 | // Calculate the invert determinant (inlined to avoid double-caching) 1097 | float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); 1098 | 1099 | Matrix matViewProjInv = { 1100 | (a11*b11 - a12*b10 + a13*b09)*invDet, 1101 | (-a01*b11 + a02*b10 - a03*b09)*invDet, 1102 | (a31*b05 - a32*b04 + a33*b03)*invDet, 1103 | (-a21*b05 + a22*b04 - a23*b03)*invDet, 1104 | (-a10*b11 + a12*b08 - a13*b07)*invDet, 1105 | (a00*b11 - a02*b08 + a03*b07)*invDet, 1106 | (-a30*b05 + a32*b02 - a33*b01)*invDet, 1107 | (a20*b05 - a22*b02 + a23*b01)*invDet, 1108 | (a10*b10 - a11*b08 + a13*b06)*invDet, 1109 | (-a00*b10 + a01*b08 - a03*b06)*invDet, 1110 | (a30*b04 - a31*b02 + a33*b00)*invDet, 1111 | (-a20*b04 + a21*b02 - a23*b00)*invDet, 1112 | (-a10*b09 + a11*b07 - a12*b06)*invDet, 1113 | (a00*b09 - a01*b07 + a02*b06)*invDet, 1114 | (-a30*b03 + a31*b01 - a32*b00)*invDet, 1115 | (a20*b03 - a21*b01 + a22*b00)*invDet }; 1116 | 1117 | // Create quaternion from source point 1118 | Quaternion quat = { source.x, source.y, source.z, 1.0f }; 1119 | 1120 | // Multiply quat point by unprojecte matrix 1121 | Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) 1122 | matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, 1123 | matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, 1124 | matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w, 1125 | matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w }; 1126 | 1127 | // Normalized world points in vectors 1128 | result.x = qtransformed.x/qtransformed.w; 1129 | result.y = qtransformed.y/qtransformed.w; 1130 | result.z = qtransformed.z/qtransformed.w; 1131 | 1132 | return result; 1133 | } 1134 | 1135 | // Get Vector3 as float array 1136 | RMAPI float3 Vector3ToFloatV(Vector3 v) 1137 | { 1138 | float3 buffer = { 0 }; 1139 | 1140 | buffer.v[0] = v.x; 1141 | buffer.v[1] = v.y; 1142 | buffer.v[2] = v.z; 1143 | 1144 | return buffer; 1145 | } 1146 | 1147 | // Invert the given vector 1148 | RMAPI Vector3 Vector3Invert(Vector3 v) 1149 | { 1150 | Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z }; 1151 | 1152 | return result; 1153 | } 1154 | 1155 | // Clamp the components of the vector between 1156 | // min and max values specified by the given vectors 1157 | RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max) 1158 | { 1159 | Vector3 result = { 0 }; 1160 | 1161 | result.x = fminf(max.x, fmaxf(min.x, v.x)); 1162 | result.y = fminf(max.y, fmaxf(min.y, v.y)); 1163 | result.z = fminf(max.z, fmaxf(min.z, v.z)); 1164 | 1165 | return result; 1166 | } 1167 | 1168 | // Clamp the magnitude of the vector between two values 1169 | RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max) 1170 | { 1171 | Vector3 result = v; 1172 | 1173 | float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z); 1174 | if (length > 0.0f) 1175 | { 1176 | length = sqrtf(length); 1177 | 1178 | float scale = 1; // By default, 1 as the neutral element. 1179 | if (length < min) 1180 | { 1181 | scale = min/length; 1182 | } 1183 | else if (length > max) 1184 | { 1185 | scale = max/length; 1186 | } 1187 | 1188 | result.x = v.x*scale; 1189 | result.y = v.y*scale; 1190 | result.z = v.z*scale; 1191 | } 1192 | 1193 | return result; 1194 | } 1195 | 1196 | // Check whether two given vectors are almost equal 1197 | RMAPI int Vector3Equals(Vector3 p, Vector3 q) 1198 | { 1199 | #if !defined(EPSILON) 1200 | #define EPSILON 0.000001f 1201 | #endif 1202 | 1203 | int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && 1204 | ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && 1205 | ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))); 1206 | 1207 | return result; 1208 | } 1209 | 1210 | // Compute the direction of a refracted ray 1211 | // v: normalized direction of the incoming ray 1212 | // n: normalized normal vector of the interface of two optical media 1213 | // r: ratio of the refractive index of the medium from where the ray comes 1214 | // to the refractive index of the medium on the other side of the surface 1215 | RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r) 1216 | { 1217 | Vector3 result = { 0 }; 1218 | 1219 | float dot = v.x*n.x + v.y*n.y + v.z*n.z; 1220 | float d = 1.0f - r*r*(1.0f - dot*dot); 1221 | 1222 | if (d >= 0.0f) 1223 | { 1224 | d = sqrtf(d); 1225 | v.x = r*v.x - (r*dot + d)*n.x; 1226 | v.y = r*v.y - (r*dot + d)*n.y; 1227 | v.z = r*v.z - (r*dot + d)*n.z; 1228 | 1229 | result = v; 1230 | } 1231 | 1232 | return result; 1233 | } 1234 | 1235 | 1236 | //---------------------------------------------------------------------------------- 1237 | // Module Functions Definition - Vector4 math 1238 | //---------------------------------------------------------------------------------- 1239 | 1240 | RMAPI Vector4 Vector4Zero(void) 1241 | { 1242 | Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f }; 1243 | return result; 1244 | } 1245 | 1246 | RMAPI Vector4 Vector4One(void) 1247 | { 1248 | Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f }; 1249 | return result; 1250 | } 1251 | 1252 | RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2) 1253 | { 1254 | Vector4 result = { 1255 | v1.x + v2.x, 1256 | v1.y + v2.y, 1257 | v1.z + v2.z, 1258 | v1.w + v2.w 1259 | }; 1260 | return result; 1261 | } 1262 | 1263 | RMAPI Vector4 Vector4AddValue(Vector4 v, float add) 1264 | { 1265 | Vector4 result = { 1266 | v.x + add, 1267 | v.y + add, 1268 | v.z + add, 1269 | v.w + add 1270 | }; 1271 | return result; 1272 | } 1273 | 1274 | RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2) 1275 | { 1276 | Vector4 result = { 1277 | v1.x - v2.x, 1278 | v1.y - v2.y, 1279 | v1.z - v2.z, 1280 | v1.w - v2.w 1281 | }; 1282 | return result; 1283 | } 1284 | 1285 | RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add) 1286 | { 1287 | Vector4 result = { 1288 | v.x - add, 1289 | v.y - add, 1290 | v.z - add, 1291 | v.w - add 1292 | }; 1293 | return result; 1294 | } 1295 | 1296 | RMAPI float Vector4Length(Vector4 v) 1297 | { 1298 | float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); 1299 | return result; 1300 | } 1301 | 1302 | RMAPI float Vector4LengthSqr(Vector4 v) 1303 | { 1304 | float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w); 1305 | return result; 1306 | } 1307 | 1308 | RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2) 1309 | { 1310 | float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w); 1311 | return result; 1312 | } 1313 | 1314 | // Calculate distance between two vectors 1315 | RMAPI float Vector4Distance(Vector4 v1, Vector4 v2) 1316 | { 1317 | float result = sqrtf( 1318 | (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + 1319 | (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w)); 1320 | return result; 1321 | } 1322 | 1323 | // Calculate square distance between two vectors 1324 | RMAPI float Vector4DistanceSqr(Vector4 v1, Vector4 v2) 1325 | { 1326 | float result = 1327 | (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + 1328 | (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w); 1329 | 1330 | return result; 1331 | } 1332 | 1333 | RMAPI Vector4 Vector4Scale(Vector4 v, float scale) 1334 | { 1335 | Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale }; 1336 | return result; 1337 | } 1338 | 1339 | // Multiply vector by vector 1340 | RMAPI Vector4 Vector4Multiply(Vector4 v1, Vector4 v2) 1341 | { 1342 | Vector4 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.w*v2.w }; 1343 | return result; 1344 | } 1345 | 1346 | // Negate vector 1347 | RMAPI Vector4 Vector4Negate(Vector4 v) 1348 | { 1349 | Vector4 result = { -v.x, -v.y, -v.z, -v.w }; 1350 | return result; 1351 | } 1352 | 1353 | // Divide vector by vector 1354 | RMAPI Vector4 Vector4Divide(Vector4 v1, Vector4 v2) 1355 | { 1356 | Vector4 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.w/v2.w }; 1357 | return result; 1358 | } 1359 | 1360 | // Normalize provided vector 1361 | RMAPI Vector4 Vector4Normalize(Vector4 v) 1362 | { 1363 | Vector4 result = { 0 }; 1364 | float length = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); 1365 | 1366 | if (length > 0) 1367 | { 1368 | float ilength = 1.0f/length; 1369 | result.x = v.x*ilength; 1370 | result.y = v.y*ilength; 1371 | result.z = v.z*ilength; 1372 | result.w = v.w*ilength; 1373 | } 1374 | 1375 | return result; 1376 | } 1377 | 1378 | // Get min value for each pair of components 1379 | RMAPI Vector4 Vector4Min(Vector4 v1, Vector4 v2) 1380 | { 1381 | Vector4 result = { 0 }; 1382 | 1383 | result.x = fminf(v1.x, v2.x); 1384 | result.y = fminf(v1.y, v2.y); 1385 | result.z = fminf(v1.z, v2.z); 1386 | result.w = fminf(v1.w, v2.w); 1387 | 1388 | return result; 1389 | } 1390 | 1391 | // Get max value for each pair of components 1392 | RMAPI Vector4 Vector4Max(Vector4 v1, Vector4 v2) 1393 | { 1394 | Vector4 result = { 0 }; 1395 | 1396 | result.x = fmaxf(v1.x, v2.x); 1397 | result.y = fmaxf(v1.y, v2.y); 1398 | result.z = fmaxf(v1.z, v2.z); 1399 | result.w = fmaxf(v1.w, v2.w); 1400 | 1401 | return result; 1402 | } 1403 | 1404 | // Calculate linear interpolation between two vectors 1405 | RMAPI Vector4 Vector4Lerp(Vector4 v1, Vector4 v2, float amount) 1406 | { 1407 | Vector4 result = { 0 }; 1408 | 1409 | result.x = v1.x + amount*(v2.x - v1.x); 1410 | result.y = v1.y + amount*(v2.y - v1.y); 1411 | result.z = v1.z + amount*(v2.z - v1.z); 1412 | result.w = v1.w + amount*(v2.w - v1.w); 1413 | 1414 | return result; 1415 | } 1416 | 1417 | // Move Vector towards target 1418 | RMAPI Vector4 Vector4MoveTowards(Vector4 v, Vector4 target, float maxDistance) 1419 | { 1420 | Vector4 result = { 0 }; 1421 | 1422 | float dx = target.x - v.x; 1423 | float dy = target.y - v.y; 1424 | float dz = target.z - v.z; 1425 | float dw = target.w - v.w; 1426 | float value = (dx*dx) + (dy*dy) + (dz*dz) + (dw*dw); 1427 | 1428 | if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; 1429 | 1430 | float dist = sqrtf(value); 1431 | 1432 | result.x = v.x + dx/dist*maxDistance; 1433 | result.y = v.y + dy/dist*maxDistance; 1434 | result.z = v.z + dz/dist*maxDistance; 1435 | result.w = v.w + dw/dist*maxDistance; 1436 | 1437 | return result; 1438 | } 1439 | 1440 | // Invert the given vector 1441 | RMAPI Vector4 Vector4Invert(Vector4 v) 1442 | { 1443 | Vector4 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z, 1.0f/v.w }; 1444 | return result; 1445 | } 1446 | 1447 | // Check whether two given vectors are almost equal 1448 | RMAPI int Vector4Equals(Vector4 p, Vector4 q) 1449 | { 1450 | #if !defined(EPSILON) 1451 | #define EPSILON 0.000001f 1452 | #endif 1453 | 1454 | int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && 1455 | ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && 1456 | ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && 1457 | ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w))))); 1458 | return result; 1459 | } 1460 | 1461 | 1462 | //---------------------------------------------------------------------------------- 1463 | // Module Functions Definition - Matrix math 1464 | //---------------------------------------------------------------------------------- 1465 | 1466 | // Compute matrix determinant 1467 | RMAPI float MatrixDeterminant(Matrix mat) 1468 | { 1469 | float result = 0.0f; 1470 | 1471 | // Cache the matrix values (speed optimization) 1472 | float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; 1473 | float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; 1474 | float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; 1475 | float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; 1476 | 1477 | result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + 1478 | a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + 1479 | a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + 1480 | a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + 1481 | a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + 1482 | a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; 1483 | 1484 | return result; 1485 | } 1486 | 1487 | // Get the trace of the matrix (sum of the values along the diagonal) 1488 | RMAPI float MatrixTrace(Matrix mat) 1489 | { 1490 | float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15); 1491 | 1492 | return result; 1493 | } 1494 | 1495 | // Transposes provided matrix 1496 | RMAPI Matrix MatrixTranspose(Matrix mat) 1497 | { 1498 | Matrix result = { 0 }; 1499 | 1500 | result.m0 = mat.m0; 1501 | result.m1 = mat.m4; 1502 | result.m2 = mat.m8; 1503 | result.m3 = mat.m12; 1504 | result.m4 = mat.m1; 1505 | result.m5 = mat.m5; 1506 | result.m6 = mat.m9; 1507 | result.m7 = mat.m13; 1508 | result.m8 = mat.m2; 1509 | result.m9 = mat.m6; 1510 | result.m10 = mat.m10; 1511 | result.m11 = mat.m14; 1512 | result.m12 = mat.m3; 1513 | result.m13 = mat.m7; 1514 | result.m14 = mat.m11; 1515 | result.m15 = mat.m15; 1516 | 1517 | return result; 1518 | } 1519 | 1520 | // Invert provided matrix 1521 | RMAPI Matrix MatrixInvert(Matrix mat) 1522 | { 1523 | Matrix result = { 0 }; 1524 | 1525 | // Cache the matrix values (speed optimization) 1526 | float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; 1527 | float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; 1528 | float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; 1529 | float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; 1530 | 1531 | float b00 = a00*a11 - a01*a10; 1532 | float b01 = a00*a12 - a02*a10; 1533 | float b02 = a00*a13 - a03*a10; 1534 | float b03 = a01*a12 - a02*a11; 1535 | float b04 = a01*a13 - a03*a11; 1536 | float b05 = a02*a13 - a03*a12; 1537 | float b06 = a20*a31 - a21*a30; 1538 | float b07 = a20*a32 - a22*a30; 1539 | float b08 = a20*a33 - a23*a30; 1540 | float b09 = a21*a32 - a22*a31; 1541 | float b10 = a21*a33 - a23*a31; 1542 | float b11 = a22*a33 - a23*a32; 1543 | 1544 | // Calculate the invert determinant (inlined to avoid double-caching) 1545 | float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); 1546 | 1547 | result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; 1548 | result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; 1549 | result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; 1550 | result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet; 1551 | result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet; 1552 | result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet; 1553 | result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet; 1554 | result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet; 1555 | result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet; 1556 | result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet; 1557 | result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet; 1558 | result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet; 1559 | result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet; 1560 | result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; 1561 | result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; 1562 | result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; 1563 | 1564 | return result; 1565 | } 1566 | 1567 | // Get identity matrix 1568 | RMAPI Matrix MatrixIdentity(void) 1569 | { 1570 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1571 | 0.0f, 1.0f, 0.0f, 0.0f, 1572 | 0.0f, 0.0f, 1.0f, 0.0f, 1573 | 0.0f, 0.0f, 0.0f, 1.0f }; 1574 | 1575 | return result; 1576 | } 1577 | 1578 | // Add two matrices 1579 | RMAPI Matrix MatrixAdd(Matrix left, Matrix right) 1580 | { 1581 | Matrix result = { 0 }; 1582 | 1583 | result.m0 = left.m0 + right.m0; 1584 | result.m1 = left.m1 + right.m1; 1585 | result.m2 = left.m2 + right.m2; 1586 | result.m3 = left.m3 + right.m3; 1587 | result.m4 = left.m4 + right.m4; 1588 | result.m5 = left.m5 + right.m5; 1589 | result.m6 = left.m6 + right.m6; 1590 | result.m7 = left.m7 + right.m7; 1591 | result.m8 = left.m8 + right.m8; 1592 | result.m9 = left.m9 + right.m9; 1593 | result.m10 = left.m10 + right.m10; 1594 | result.m11 = left.m11 + right.m11; 1595 | result.m12 = left.m12 + right.m12; 1596 | result.m13 = left.m13 + right.m13; 1597 | result.m14 = left.m14 + right.m14; 1598 | result.m15 = left.m15 + right.m15; 1599 | 1600 | return result; 1601 | } 1602 | 1603 | // Subtract two matrices (left - right) 1604 | RMAPI Matrix MatrixSubtract(Matrix left, Matrix right) 1605 | { 1606 | Matrix result = { 0 }; 1607 | 1608 | result.m0 = left.m0 - right.m0; 1609 | result.m1 = left.m1 - right.m1; 1610 | result.m2 = left.m2 - right.m2; 1611 | result.m3 = left.m3 - right.m3; 1612 | result.m4 = left.m4 - right.m4; 1613 | result.m5 = left.m5 - right.m5; 1614 | result.m6 = left.m6 - right.m6; 1615 | result.m7 = left.m7 - right.m7; 1616 | result.m8 = left.m8 - right.m8; 1617 | result.m9 = left.m9 - right.m9; 1618 | result.m10 = left.m10 - right.m10; 1619 | result.m11 = left.m11 - right.m11; 1620 | result.m12 = left.m12 - right.m12; 1621 | result.m13 = left.m13 - right.m13; 1622 | result.m14 = left.m14 - right.m14; 1623 | result.m15 = left.m15 - right.m15; 1624 | 1625 | return result; 1626 | } 1627 | 1628 | // Get two matrix multiplication 1629 | // NOTE: When multiplying matrices... the order matters! 1630 | RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) 1631 | { 1632 | Matrix result = { 0 }; 1633 | 1634 | result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; 1635 | result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; 1636 | result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; 1637 | result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15; 1638 | result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12; 1639 | result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13; 1640 | result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14; 1641 | result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15; 1642 | result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12; 1643 | result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13; 1644 | result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14; 1645 | result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15; 1646 | result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12; 1647 | result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; 1648 | result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; 1649 | result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; 1650 | 1651 | return result; 1652 | } 1653 | 1654 | // Get translation matrix 1655 | RMAPI Matrix MatrixTranslate(float x, float y, float z) 1656 | { 1657 | Matrix result = { 1.0f, 0.0f, 0.0f, x, 1658 | 0.0f, 1.0f, 0.0f, y, 1659 | 0.0f, 0.0f, 1.0f, z, 1660 | 0.0f, 0.0f, 0.0f, 1.0f }; 1661 | 1662 | return result; 1663 | } 1664 | 1665 | // Create rotation matrix from axis and angle 1666 | // NOTE: Angle should be provided in radians 1667 | RMAPI Matrix MatrixRotate(Vector3 axis, float angle) 1668 | { 1669 | Matrix result = { 0 }; 1670 | 1671 | float x = axis.x, y = axis.y, z = axis.z; 1672 | 1673 | float lengthSquared = x*x + y*y + z*z; 1674 | 1675 | if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) 1676 | { 1677 | float ilength = 1.0f/sqrtf(lengthSquared); 1678 | x *= ilength; 1679 | y *= ilength; 1680 | z *= ilength; 1681 | } 1682 | 1683 | float sinres = sinf(angle); 1684 | float cosres = cosf(angle); 1685 | float t = 1.0f - cosres; 1686 | 1687 | result.m0 = x*x*t + cosres; 1688 | result.m1 = y*x*t + z*sinres; 1689 | result.m2 = z*x*t - y*sinres; 1690 | result.m3 = 0.0f; 1691 | 1692 | result.m4 = x*y*t - z*sinres; 1693 | result.m5 = y*y*t + cosres; 1694 | result.m6 = z*y*t + x*sinres; 1695 | result.m7 = 0.0f; 1696 | 1697 | result.m8 = x*z*t + y*sinres; 1698 | result.m9 = y*z*t - x*sinres; 1699 | result.m10 = z*z*t + cosres; 1700 | result.m11 = 0.0f; 1701 | 1702 | result.m12 = 0.0f; 1703 | result.m13 = 0.0f; 1704 | result.m14 = 0.0f; 1705 | result.m15 = 1.0f; 1706 | 1707 | return result; 1708 | } 1709 | 1710 | // Get x-rotation matrix 1711 | // NOTE: Angle must be provided in radians 1712 | RMAPI Matrix MatrixRotateX(float angle) 1713 | { 1714 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1715 | 0.0f, 1.0f, 0.0f, 0.0f, 1716 | 0.0f, 0.0f, 1.0f, 0.0f, 1717 | 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1718 | 1719 | float cosres = cosf(angle); 1720 | float sinres = sinf(angle); 1721 | 1722 | result.m5 = cosres; 1723 | result.m6 = sinres; 1724 | result.m9 = -sinres; 1725 | result.m10 = cosres; 1726 | 1727 | return result; 1728 | } 1729 | 1730 | // Get y-rotation matrix 1731 | // NOTE: Angle must be provided in radians 1732 | RMAPI Matrix MatrixRotateY(float angle) 1733 | { 1734 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1735 | 0.0f, 1.0f, 0.0f, 0.0f, 1736 | 0.0f, 0.0f, 1.0f, 0.0f, 1737 | 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1738 | 1739 | float cosres = cosf(angle); 1740 | float sinres = sinf(angle); 1741 | 1742 | result.m0 = cosres; 1743 | result.m2 = -sinres; 1744 | result.m8 = sinres; 1745 | result.m10 = cosres; 1746 | 1747 | return result; 1748 | } 1749 | 1750 | // Get z-rotation matrix 1751 | // NOTE: Angle must be provided in radians 1752 | RMAPI Matrix MatrixRotateZ(float angle) 1753 | { 1754 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1755 | 0.0f, 1.0f, 0.0f, 0.0f, 1756 | 0.0f, 0.0f, 1.0f, 0.0f, 1757 | 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1758 | 1759 | float cosres = cosf(angle); 1760 | float sinres = sinf(angle); 1761 | 1762 | result.m0 = cosres; 1763 | result.m1 = sinres; 1764 | result.m4 = -sinres; 1765 | result.m5 = cosres; 1766 | 1767 | return result; 1768 | } 1769 | 1770 | 1771 | // Get xyz-rotation matrix 1772 | // NOTE: Angle must be provided in radians 1773 | RMAPI Matrix MatrixRotateXYZ(Vector3 angle) 1774 | { 1775 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 1776 | 0.0f, 1.0f, 0.0f, 0.0f, 1777 | 0.0f, 0.0f, 1.0f, 0.0f, 1778 | 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 1779 | 1780 | float cosz = cosf(-angle.z); 1781 | float sinz = sinf(-angle.z); 1782 | float cosy = cosf(-angle.y); 1783 | float siny = sinf(-angle.y); 1784 | float cosx = cosf(-angle.x); 1785 | float sinx = sinf(-angle.x); 1786 | 1787 | result.m0 = cosz*cosy; 1788 | result.m1 = (cosz*siny*sinx) - (sinz*cosx); 1789 | result.m2 = (cosz*siny*cosx) + (sinz*sinx); 1790 | 1791 | result.m4 = sinz*cosy; 1792 | result.m5 = (sinz*siny*sinx) + (cosz*cosx); 1793 | result.m6 = (sinz*siny*cosx) - (cosz*sinx); 1794 | 1795 | result.m8 = -siny; 1796 | result.m9 = cosy*sinx; 1797 | result.m10= cosy*cosx; 1798 | 1799 | return result; 1800 | } 1801 | 1802 | // Get zyx-rotation matrix 1803 | // NOTE: Angle must be provided in radians 1804 | RMAPI Matrix MatrixRotateZYX(Vector3 angle) 1805 | { 1806 | Matrix result = { 0 }; 1807 | 1808 | float cz = cosf(angle.z); 1809 | float sz = sinf(angle.z); 1810 | float cy = cosf(angle.y); 1811 | float sy = sinf(angle.y); 1812 | float cx = cosf(angle.x); 1813 | float sx = sinf(angle.x); 1814 | 1815 | result.m0 = cz*cy; 1816 | result.m4 = cz*sy*sx - cx*sz; 1817 | result.m8 = sz*sx + cz*cx*sy; 1818 | result.m12 = 0; 1819 | 1820 | result.m1 = cy*sz; 1821 | result.m5 = cz*cx + sz*sy*sx; 1822 | result.m9 = cx*sz*sy - cz*sx; 1823 | result.m13 = 0; 1824 | 1825 | result.m2 = -sy; 1826 | result.m6 = cy*sx; 1827 | result.m10 = cy*cx; 1828 | result.m14 = 0; 1829 | 1830 | result.m3 = 0; 1831 | result.m7 = 0; 1832 | result.m11 = 0; 1833 | result.m15 = 1; 1834 | 1835 | return result; 1836 | } 1837 | 1838 | // Get scaling matrix 1839 | RMAPI Matrix MatrixScale(float x, float y, float z) 1840 | { 1841 | Matrix result = { x, 0.0f, 0.0f, 0.0f, 1842 | 0.0f, y, 0.0f, 0.0f, 1843 | 0.0f, 0.0f, z, 0.0f, 1844 | 0.0f, 0.0f, 0.0f, 1.0f }; 1845 | 1846 | return result; 1847 | } 1848 | 1849 | // Get perspective projection matrix 1850 | RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) 1851 | { 1852 | Matrix result = { 0 }; 1853 | 1854 | float rl = (float)(right - left); 1855 | float tb = (float)(top - bottom); 1856 | float fn = (float)(farPlane - nearPlane); 1857 | 1858 | result.m0 = ((float)nearPlane*2.0f)/rl; 1859 | result.m1 = 0.0f; 1860 | result.m2 = 0.0f; 1861 | result.m3 = 0.0f; 1862 | 1863 | result.m4 = 0.0f; 1864 | result.m5 = ((float)nearPlane*2.0f)/tb; 1865 | result.m6 = 0.0f; 1866 | result.m7 = 0.0f; 1867 | 1868 | result.m8 = ((float)right + (float)left)/rl; 1869 | result.m9 = ((float)top + (float)bottom)/tb; 1870 | result.m10 = -((float)farPlane + (float)nearPlane)/fn; 1871 | result.m11 = -1.0f; 1872 | 1873 | result.m12 = 0.0f; 1874 | result.m13 = 0.0f; 1875 | result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; 1876 | result.m15 = 0.0f; 1877 | 1878 | return result; 1879 | } 1880 | 1881 | // Get perspective projection matrix 1882 | // NOTE: Fovy angle must be provided in radians 1883 | RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane) 1884 | { 1885 | Matrix result = { 0 }; 1886 | 1887 | double top = nearPlane*tan(fovY*0.5); 1888 | double bottom = -top; 1889 | double right = top*aspect; 1890 | double left = -right; 1891 | 1892 | // MatrixFrustum(-right, right, -top, top, near, far); 1893 | float rl = (float)(right - left); 1894 | float tb = (float)(top - bottom); 1895 | float fn = (float)(farPlane - nearPlane); 1896 | 1897 | result.m0 = ((float)nearPlane*2.0f)/rl; 1898 | result.m5 = ((float)nearPlane*2.0f)/tb; 1899 | result.m8 = ((float)right + (float)left)/rl; 1900 | result.m9 = ((float)top + (float)bottom)/tb; 1901 | result.m10 = -((float)farPlane + (float)nearPlane)/fn; 1902 | result.m11 = -1.0f; 1903 | result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; 1904 | 1905 | return result; 1906 | } 1907 | 1908 | // Get orthographic projection matrix 1909 | RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane) 1910 | { 1911 | Matrix result = { 0 }; 1912 | 1913 | float rl = (float)(right - left); 1914 | float tb = (float)(top - bottom); 1915 | float fn = (float)(farPlane - nearPlane); 1916 | 1917 | result.m0 = 2.0f/rl; 1918 | result.m1 = 0.0f; 1919 | result.m2 = 0.0f; 1920 | result.m3 = 0.0f; 1921 | result.m4 = 0.0f; 1922 | result.m5 = 2.0f/tb; 1923 | result.m6 = 0.0f; 1924 | result.m7 = 0.0f; 1925 | result.m8 = 0.0f; 1926 | result.m9 = 0.0f; 1927 | result.m10 = -2.0f/fn; 1928 | result.m11 = 0.0f; 1929 | result.m12 = -((float)left + (float)right)/rl; 1930 | result.m13 = -((float)top + (float)bottom)/tb; 1931 | result.m14 = -((float)farPlane + (float)nearPlane)/fn; 1932 | result.m15 = 1.0f; 1933 | 1934 | return result; 1935 | } 1936 | 1937 | // Get camera look-at matrix (view matrix) 1938 | RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) 1939 | { 1940 | Matrix result = { 0 }; 1941 | 1942 | float length = 0.0f; 1943 | float ilength = 0.0f; 1944 | 1945 | // Vector3Subtract(eye, target) 1946 | Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z }; 1947 | 1948 | // Vector3Normalize(vz) 1949 | Vector3 v = vz; 1950 | length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 1951 | if (length == 0.0f) length = 1.0f; 1952 | ilength = 1.0f/length; 1953 | vz.x *= ilength; 1954 | vz.y *= ilength; 1955 | vz.z *= ilength; 1956 | 1957 | // Vector3CrossProduct(up, vz) 1958 | Vector3 vx = { up.y*vz.z - up.z*vz.y, up.z*vz.x - up.x*vz.z, up.x*vz.y - up.y*vz.x }; 1959 | 1960 | // Vector3Normalize(x) 1961 | v = vx; 1962 | length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); 1963 | if (length == 0.0f) length = 1.0f; 1964 | ilength = 1.0f/length; 1965 | vx.x *= ilength; 1966 | vx.y *= ilength; 1967 | vx.z *= ilength; 1968 | 1969 | // Vector3CrossProduct(vz, vx) 1970 | Vector3 vy = { vz.y*vx.z - vz.z*vx.y, vz.z*vx.x - vz.x*vx.z, vz.x*vx.y - vz.y*vx.x }; 1971 | 1972 | result.m0 = vx.x; 1973 | result.m1 = vy.x; 1974 | result.m2 = vz.x; 1975 | result.m3 = 0.0f; 1976 | result.m4 = vx.y; 1977 | result.m5 = vy.y; 1978 | result.m6 = vz.y; 1979 | result.m7 = 0.0f; 1980 | result.m8 = vx.z; 1981 | result.m9 = vy.z; 1982 | result.m10 = vz.z; 1983 | result.m11 = 0.0f; 1984 | result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye) 1985 | result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye) 1986 | result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye) 1987 | result.m15 = 1.0f; 1988 | 1989 | return result; 1990 | } 1991 | 1992 | // Get float array of matrix data 1993 | RMAPI float16 MatrixToFloatV(Matrix mat) 1994 | { 1995 | float16 result = { 0 }; 1996 | 1997 | result.v[0] = mat.m0; 1998 | result.v[1] = mat.m1; 1999 | result.v[2] = mat.m2; 2000 | result.v[3] = mat.m3; 2001 | result.v[4] = mat.m4; 2002 | result.v[5] = mat.m5; 2003 | result.v[6] = mat.m6; 2004 | result.v[7] = mat.m7; 2005 | result.v[8] = mat.m8; 2006 | result.v[9] = mat.m9; 2007 | result.v[10] = mat.m10; 2008 | result.v[11] = mat.m11; 2009 | result.v[12] = mat.m12; 2010 | result.v[13] = mat.m13; 2011 | result.v[14] = mat.m14; 2012 | result.v[15] = mat.m15; 2013 | 2014 | return result; 2015 | } 2016 | 2017 | //---------------------------------------------------------------------------------- 2018 | // Module Functions Definition - Quaternion math 2019 | //---------------------------------------------------------------------------------- 2020 | 2021 | // Add two quaternions 2022 | RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2) 2023 | { 2024 | Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w}; 2025 | 2026 | return result; 2027 | } 2028 | 2029 | // Add quaternion and float value 2030 | RMAPI Quaternion QuaternionAddValue(Quaternion q, float add) 2031 | { 2032 | Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add}; 2033 | 2034 | return result; 2035 | } 2036 | 2037 | // Subtract two quaternions 2038 | RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2) 2039 | { 2040 | Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w}; 2041 | 2042 | return result; 2043 | } 2044 | 2045 | // Subtract quaternion and float value 2046 | RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub) 2047 | { 2048 | Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub}; 2049 | 2050 | return result; 2051 | } 2052 | 2053 | // Get identity quaternion 2054 | RMAPI Quaternion QuaternionIdentity(void) 2055 | { 2056 | Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; 2057 | 2058 | return result; 2059 | } 2060 | 2061 | // Computes the length of a quaternion 2062 | RMAPI float QuaternionLength(Quaternion q) 2063 | { 2064 | float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2065 | 2066 | return result; 2067 | } 2068 | 2069 | // Normalize provided quaternion 2070 | RMAPI Quaternion QuaternionNormalize(Quaternion q) 2071 | { 2072 | Quaternion result = { 0 }; 2073 | 2074 | float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2075 | if (length == 0.0f) length = 1.0f; 2076 | float ilength = 1.0f/length; 2077 | 2078 | result.x = q.x*ilength; 2079 | result.y = q.y*ilength; 2080 | result.z = q.z*ilength; 2081 | result.w = q.w*ilength; 2082 | 2083 | return result; 2084 | } 2085 | 2086 | // Invert provided quaternion 2087 | RMAPI Quaternion QuaternionInvert(Quaternion q) 2088 | { 2089 | Quaternion result = q; 2090 | 2091 | float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; 2092 | 2093 | if (lengthSq != 0.0f) 2094 | { 2095 | float invLength = 1.0f/lengthSq; 2096 | 2097 | result.x *= -invLength; 2098 | result.y *= -invLength; 2099 | result.z *= -invLength; 2100 | result.w *= invLength; 2101 | } 2102 | 2103 | return result; 2104 | } 2105 | 2106 | // Calculate two quaternion multiplication 2107 | RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) 2108 | { 2109 | Quaternion result = { 0 }; 2110 | 2111 | float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w; 2112 | float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w; 2113 | 2114 | result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; 2115 | result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; 2116 | result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; 2117 | result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; 2118 | 2119 | return result; 2120 | } 2121 | 2122 | // Scale quaternion by float value 2123 | RMAPI Quaternion QuaternionScale(Quaternion q, float mul) 2124 | { 2125 | Quaternion result = { 0 }; 2126 | 2127 | result.x = q.x*mul; 2128 | result.y = q.y*mul; 2129 | result.z = q.z*mul; 2130 | result.w = q.w*mul; 2131 | 2132 | return result; 2133 | } 2134 | 2135 | // Divide two quaternions 2136 | RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2) 2137 | { 2138 | Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w }; 2139 | 2140 | return result; 2141 | } 2142 | 2143 | // Calculate linear interpolation between two quaternions 2144 | RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) 2145 | { 2146 | Quaternion result = { 0 }; 2147 | 2148 | result.x = q1.x + amount*(q2.x - q1.x); 2149 | result.y = q1.y + amount*(q2.y - q1.y); 2150 | result.z = q1.z + amount*(q2.z - q1.z); 2151 | result.w = q1.w + amount*(q2.w - q1.w); 2152 | 2153 | return result; 2154 | } 2155 | 2156 | // Calculate slerp-optimized interpolation between two quaternions 2157 | RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) 2158 | { 2159 | Quaternion result = { 0 }; 2160 | 2161 | // QuaternionLerp(q1, q2, amount) 2162 | result.x = q1.x + amount*(q2.x - q1.x); 2163 | result.y = q1.y + amount*(q2.y - q1.y); 2164 | result.z = q1.z + amount*(q2.z - q1.z); 2165 | result.w = q1.w + amount*(q2.w - q1.w); 2166 | 2167 | // QuaternionNormalize(q); 2168 | Quaternion q = result; 2169 | float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2170 | if (length == 0.0f) length = 1.0f; 2171 | float ilength = 1.0f/length; 2172 | 2173 | result.x = q.x*ilength; 2174 | result.y = q.y*ilength; 2175 | result.z = q.z*ilength; 2176 | result.w = q.w*ilength; 2177 | 2178 | return result; 2179 | } 2180 | 2181 | // Calculates spherical linear interpolation between two quaternions 2182 | RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) 2183 | { 2184 | Quaternion result = { 0 }; 2185 | 2186 | #if !defined(EPSILON) 2187 | #define EPSILON 0.000001f 2188 | #endif 2189 | 2190 | float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; 2191 | 2192 | if (cosHalfTheta < 0) 2193 | { 2194 | q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w; 2195 | cosHalfTheta = -cosHalfTheta; 2196 | } 2197 | 2198 | if (fabsf(cosHalfTheta) >= 1.0f) result = q1; 2199 | else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); 2200 | else 2201 | { 2202 | float halfTheta = acosf(cosHalfTheta); 2203 | float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta); 2204 | 2205 | if (fabsf(sinHalfTheta) < EPSILON) 2206 | { 2207 | result.x = (q1.x*0.5f + q2.x*0.5f); 2208 | result.y = (q1.y*0.5f + q2.y*0.5f); 2209 | result.z = (q1.z*0.5f + q2.z*0.5f); 2210 | result.w = (q1.w*0.5f + q2.w*0.5f); 2211 | } 2212 | else 2213 | { 2214 | float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta; 2215 | float ratioB = sinf(amount*halfTheta)/sinHalfTheta; 2216 | 2217 | result.x = (q1.x*ratioA + q2.x*ratioB); 2218 | result.y = (q1.y*ratioA + q2.y*ratioB); 2219 | result.z = (q1.z*ratioA + q2.z*ratioB); 2220 | result.w = (q1.w*ratioA + q2.w*ratioB); 2221 | } 2222 | } 2223 | 2224 | return result; 2225 | } 2226 | 2227 | // Calculate quaternion cubic spline interpolation using Cubic Hermite Spline algorithm 2228 | // as described in the GLTF 2.0 specification: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#interpolation-cubic 2229 | RMAPI Quaternion QuaternionCubicHermiteSpline(Quaternion q1, Quaternion outTangent1, Quaternion q2, Quaternion inTangent2, float t) 2230 | { 2231 | float t2 = t*t; 2232 | float t3 = t2*t; 2233 | float h00 = 2*t3 - 3*t2 + 1; 2234 | float h10 = t3 - 2*t2 + t; 2235 | float h01 = -2*t3 + 3*t2; 2236 | float h11 = t3 - t2; 2237 | 2238 | Quaternion p0 = QuaternionScale(q1, h00); 2239 | Quaternion m0 = QuaternionScale(outTangent1, h10); 2240 | Quaternion p1 = QuaternionScale(q2, h01); 2241 | Quaternion m1 = QuaternionScale(inTangent2, h11); 2242 | 2243 | Quaternion result = { 0 }; 2244 | 2245 | result = QuaternionAdd(p0, m0); 2246 | result = QuaternionAdd(result, p1); 2247 | result = QuaternionAdd(result, m1); 2248 | result = QuaternionNormalize(result); 2249 | 2250 | return result; 2251 | } 2252 | 2253 | // Calculate quaternion based on the rotation from one vector to another 2254 | RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) 2255 | { 2256 | Quaternion result = { 0 }; 2257 | 2258 | float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) 2259 | Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) 2260 | 2261 | result.x = cross.x; 2262 | result.y = cross.y; 2263 | result.z = cross.z; 2264 | result.w = 1.0f + cos2Theta; 2265 | 2266 | // QuaternionNormalize(q); 2267 | // NOTE: Normalize to essentially nlerp the original and identity to 0.5 2268 | Quaternion q = result; 2269 | float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2270 | if (length == 0.0f) length = 1.0f; 2271 | float ilength = 1.0f/length; 2272 | 2273 | result.x = q.x*ilength; 2274 | result.y = q.y*ilength; 2275 | result.z = q.z*ilength; 2276 | result.w = q.w*ilength; 2277 | 2278 | return result; 2279 | } 2280 | 2281 | // Get a quaternion for a given rotation matrix 2282 | RMAPI Quaternion QuaternionFromMatrix(Matrix mat) 2283 | { 2284 | Quaternion result = { 0 }; 2285 | 2286 | float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10; 2287 | float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10; 2288 | float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10; 2289 | float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5; 2290 | 2291 | int biggestIndex = 0; 2292 | float fourBiggestSquaredMinus1 = fourWSquaredMinus1; 2293 | if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) 2294 | { 2295 | fourBiggestSquaredMinus1 = fourXSquaredMinus1; 2296 | biggestIndex = 1; 2297 | } 2298 | 2299 | if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) 2300 | { 2301 | fourBiggestSquaredMinus1 = fourYSquaredMinus1; 2302 | biggestIndex = 2; 2303 | } 2304 | 2305 | if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) 2306 | { 2307 | fourBiggestSquaredMinus1 = fourZSquaredMinus1; 2308 | biggestIndex = 3; 2309 | } 2310 | 2311 | float biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f)*0.5f; 2312 | float mult = 0.25f/biggestVal; 2313 | 2314 | switch (biggestIndex) 2315 | { 2316 | case 0: 2317 | result.w = biggestVal; 2318 | result.x = (mat.m6 - mat.m9)*mult; 2319 | result.y = (mat.m8 - mat.m2)*mult; 2320 | result.z = (mat.m1 - mat.m4)*mult; 2321 | break; 2322 | case 1: 2323 | result.x = biggestVal; 2324 | result.w = (mat.m6 - mat.m9)*mult; 2325 | result.y = (mat.m1 + mat.m4)*mult; 2326 | result.z = (mat.m8 + mat.m2)*mult; 2327 | break; 2328 | case 2: 2329 | result.y = biggestVal; 2330 | result.w = (mat.m8 - mat.m2)*mult; 2331 | result.x = (mat.m1 + mat.m4)*mult; 2332 | result.z = (mat.m6 + mat.m9)*mult; 2333 | break; 2334 | case 3: 2335 | result.z = biggestVal; 2336 | result.w = (mat.m1 - mat.m4)*mult; 2337 | result.x = (mat.m8 + mat.m2)*mult; 2338 | result.y = (mat.m6 + mat.m9)*mult; 2339 | break; 2340 | } 2341 | 2342 | return result; 2343 | } 2344 | 2345 | // Get a matrix for a given quaternion 2346 | RMAPI Matrix QuaternionToMatrix(Quaternion q) 2347 | { 2348 | Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 2349 | 0.0f, 1.0f, 0.0f, 0.0f, 2350 | 0.0f, 0.0f, 1.0f, 0.0f, 2351 | 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() 2352 | 2353 | float a2 = q.x*q.x; 2354 | float b2 = q.y*q.y; 2355 | float c2 = q.z*q.z; 2356 | float ac = q.x*q.z; 2357 | float ab = q.x*q.y; 2358 | float bc = q.y*q.z; 2359 | float ad = q.w*q.x; 2360 | float bd = q.w*q.y; 2361 | float cd = q.w*q.z; 2362 | 2363 | result.m0 = 1 - 2*(b2 + c2); 2364 | result.m1 = 2*(ab + cd); 2365 | result.m2 = 2*(ac - bd); 2366 | 2367 | result.m4 = 2*(ab - cd); 2368 | result.m5 = 1 - 2*(a2 + c2); 2369 | result.m6 = 2*(bc + ad); 2370 | 2371 | result.m8 = 2*(ac + bd); 2372 | result.m9 = 2*(bc - ad); 2373 | result.m10 = 1 - 2*(a2 + b2); 2374 | 2375 | return result; 2376 | } 2377 | 2378 | // Get rotation quaternion for an angle and axis 2379 | // NOTE: Angle must be provided in radians 2380 | RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) 2381 | { 2382 | Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; 2383 | 2384 | float axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); 2385 | 2386 | if (axisLength != 0.0f) 2387 | { 2388 | angle *= 0.5f; 2389 | 2390 | float length = 0.0f; 2391 | float ilength = 0.0f; 2392 | 2393 | // Vector3Normalize(axis) 2394 | length = axisLength; 2395 | if (length == 0.0f) length = 1.0f; 2396 | ilength = 1.0f/length; 2397 | axis.x *= ilength; 2398 | axis.y *= ilength; 2399 | axis.z *= ilength; 2400 | 2401 | float sinres = sinf(angle); 2402 | float cosres = cosf(angle); 2403 | 2404 | result.x = axis.x*sinres; 2405 | result.y = axis.y*sinres; 2406 | result.z = axis.z*sinres; 2407 | result.w = cosres; 2408 | 2409 | // QuaternionNormalize(q); 2410 | Quaternion q = result; 2411 | length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2412 | if (length == 0.0f) length = 1.0f; 2413 | ilength = 1.0f/length; 2414 | result.x = q.x*ilength; 2415 | result.y = q.y*ilength; 2416 | result.z = q.z*ilength; 2417 | result.w = q.w*ilength; 2418 | } 2419 | 2420 | return result; 2421 | } 2422 | 2423 | // Get the rotation angle and axis for a given quaternion 2424 | RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) 2425 | { 2426 | if (fabsf(q.w) > 1.0f) 2427 | { 2428 | // QuaternionNormalize(q); 2429 | float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); 2430 | if (length == 0.0f) length = 1.0f; 2431 | float ilength = 1.0f/length; 2432 | 2433 | q.x = q.x*ilength; 2434 | q.y = q.y*ilength; 2435 | q.z = q.z*ilength; 2436 | q.w = q.w*ilength; 2437 | } 2438 | 2439 | Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; 2440 | float resAngle = 2.0f*acosf(q.w); 2441 | float den = sqrtf(1.0f - q.w*q.w); 2442 | 2443 | if (den > EPSILON) 2444 | { 2445 | resAxis.x = q.x/den; 2446 | resAxis.y = q.y/den; 2447 | resAxis.z = q.z/den; 2448 | } 2449 | else 2450 | { 2451 | // This occurs when the angle is zero. 2452 | // Not a problem: just set an arbitrary normalized axis. 2453 | resAxis.x = 1.0f; 2454 | } 2455 | 2456 | *outAxis = resAxis; 2457 | *outAngle = resAngle; 2458 | } 2459 | 2460 | // Get the quaternion equivalent to Euler angles 2461 | // NOTE: Rotation order is ZYX 2462 | RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) 2463 | { 2464 | Quaternion result = { 0 }; 2465 | 2466 | float x0 = cosf(pitch*0.5f); 2467 | float x1 = sinf(pitch*0.5f); 2468 | float y0 = cosf(yaw*0.5f); 2469 | float y1 = sinf(yaw*0.5f); 2470 | float z0 = cosf(roll*0.5f); 2471 | float z1 = sinf(roll*0.5f); 2472 | 2473 | result.x = x1*y0*z0 - x0*y1*z1; 2474 | result.y = x0*y1*z0 + x1*y0*z1; 2475 | result.z = x0*y0*z1 - x1*y1*z0; 2476 | result.w = x0*y0*z0 + x1*y1*z1; 2477 | 2478 | return result; 2479 | } 2480 | 2481 | // Get the Euler angles equivalent to quaternion (roll, pitch, yaw) 2482 | // NOTE: Angles are returned in a Vector3 struct in radians 2483 | RMAPI Vector3 QuaternionToEuler(Quaternion q) 2484 | { 2485 | Vector3 result = { 0 }; 2486 | 2487 | // Roll (x-axis rotation) 2488 | float x0 = 2.0f*(q.w*q.x + q.y*q.z); 2489 | float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y); 2490 | result.x = atan2f(x0, x1); 2491 | 2492 | // Pitch (y-axis rotation) 2493 | float y0 = 2.0f*(q.w*q.y - q.z*q.x); 2494 | y0 = y0 > 1.0f ? 1.0f : y0; 2495 | y0 = y0 < -1.0f ? -1.0f : y0; 2496 | result.y = asinf(y0); 2497 | 2498 | // Yaw (z-axis rotation) 2499 | float z0 = 2.0f*(q.w*q.z + q.x*q.y); 2500 | float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z); 2501 | result.z = atan2f(z0, z1); 2502 | 2503 | return result; 2504 | } 2505 | 2506 | // Transform a quaternion given a transformation matrix 2507 | RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat) 2508 | { 2509 | Quaternion result = { 0 }; 2510 | 2511 | result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w; 2512 | result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w; 2513 | result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w; 2514 | result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w; 2515 | 2516 | return result; 2517 | } 2518 | 2519 | // Check whether two given quaternions are almost equal 2520 | RMAPI int QuaternionEquals(Quaternion p, Quaternion q) 2521 | { 2522 | #if !defined(EPSILON) 2523 | #define EPSILON 0.000001f 2524 | #endif 2525 | 2526 | int result = (((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && 2527 | ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && 2528 | ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && 2529 | ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))) || 2530 | (((fabsf(p.x + q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && 2531 | ((fabsf(p.y + q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && 2532 | ((fabsf(p.z + q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && 2533 | ((fabsf(p.w + q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))); 2534 | 2535 | return result; 2536 | } 2537 | 2538 | // Decompose a transformation matrix into its rotational, translational and scaling components 2539 | RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) 2540 | { 2541 | // Extract translation. 2542 | translation->x = mat.m12; 2543 | translation->y = mat.m13; 2544 | translation->z = mat.m14; 2545 | 2546 | // Extract upper-left for determinant computation 2547 | const float a = mat.m0; 2548 | const float b = mat.m4; 2549 | const float c = mat.m8; 2550 | const float d = mat.m1; 2551 | const float e = mat.m5; 2552 | const float f = mat.m9; 2553 | const float g = mat.m2; 2554 | const float h = mat.m6; 2555 | const float i = mat.m10; 2556 | const float A = e*i - f*h; 2557 | const float B = f*g - d*i; 2558 | const float C = d*h - e*g; 2559 | 2560 | // Extract scale 2561 | const float det = a*A + b*B + c*C; 2562 | Vector3 abc = { a, b, c }; 2563 | Vector3 def = { d, e, f }; 2564 | Vector3 ghi = { g, h, i }; 2565 | 2566 | float scalex = Vector3Length(abc); 2567 | float scaley = Vector3Length(def); 2568 | float scalez = Vector3Length(ghi); 2569 | Vector3 s = { scalex, scaley, scalez }; 2570 | 2571 | if (det < 0) s = Vector3Negate(s); 2572 | 2573 | *scale = s; 2574 | 2575 | // Remove scale from the matrix if it is not close to zero 2576 | Matrix clone = mat; 2577 | if (!FloatEquals(det, 0)) 2578 | { 2579 | clone.m0 /= s.x; 2580 | clone.m4 /= s.x; 2581 | clone.m8 /= s.x; 2582 | clone.m1 /= s.y; 2583 | clone.m5 /= s.y; 2584 | clone.m9 /= s.y; 2585 | clone.m2 /= s.z; 2586 | clone.m6 /= s.z; 2587 | clone.m10 /= s.z; 2588 | 2589 | // Extract rotation 2590 | *rotation = QuaternionFromMatrix(clone); 2591 | } 2592 | else 2593 | { 2594 | // Set to identity if close to zero 2595 | *rotation = QuaternionIdentity(); 2596 | } 2597 | } 2598 | 2599 | #if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) 2600 | 2601 | // Optional C++ math operators 2602 | //------------------------------------------------------------------------------- 2603 | 2604 | // Vector2 operators 2605 | static constexpr Vector2 Vector2Zeros = { 0, 0 }; 2606 | static constexpr Vector2 Vector2Ones = { 1, 1 }; 2607 | static constexpr Vector2 Vector2UnitX = { 1, 0 }; 2608 | static constexpr Vector2 Vector2UnitY = { 0, 1 }; 2609 | 2610 | inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs) 2611 | { 2612 | return Vector2Add(lhs, rhs); 2613 | } 2614 | 2615 | inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs) 2616 | { 2617 | lhs = Vector2Add(lhs, rhs); 2618 | return lhs; 2619 | } 2620 | 2621 | inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs) 2622 | { 2623 | return Vector2Subtract(lhs, rhs); 2624 | } 2625 | 2626 | inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs) 2627 | { 2628 | lhs = Vector2Subtract(lhs, rhs); 2629 | return lhs; 2630 | } 2631 | 2632 | inline Vector2 operator * (const Vector2& lhs, const float& rhs) 2633 | { 2634 | return Vector2Scale(lhs, rhs); 2635 | } 2636 | 2637 | inline const Vector2& operator *= (Vector2& lhs, const float& rhs) 2638 | { 2639 | lhs = Vector2Scale(lhs, rhs); 2640 | return lhs; 2641 | } 2642 | 2643 | inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs) 2644 | { 2645 | return Vector2Multiply(lhs, rhs); 2646 | } 2647 | 2648 | inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs) 2649 | { 2650 | lhs = Vector2Multiply(lhs, rhs); 2651 | return lhs; 2652 | } 2653 | 2654 | inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs) 2655 | { 2656 | return Vector2Transform(lhs, rhs); 2657 | } 2658 | 2659 | inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs) 2660 | { 2661 | lhs = Vector2Transform(lhs, rhs); 2662 | return lhs; 2663 | } 2664 | 2665 | inline Vector2 operator / (const Vector2& lhs, const float& rhs) 2666 | { 2667 | return Vector2Scale(lhs, 1.0f / rhs); 2668 | } 2669 | 2670 | inline const Vector2& operator /= (Vector2& lhs, const float& rhs) 2671 | { 2672 | lhs = Vector2Scale(lhs, 1.0f / rhs); 2673 | return lhs; 2674 | } 2675 | 2676 | inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs) 2677 | { 2678 | return Vector2Divide(lhs, rhs); 2679 | } 2680 | 2681 | inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs) 2682 | { 2683 | lhs = Vector2Divide(lhs, rhs); 2684 | return lhs; 2685 | } 2686 | 2687 | inline bool operator == (const Vector2& lhs, const Vector2& rhs) 2688 | { 2689 | return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); 2690 | } 2691 | 2692 | inline bool operator != (const Vector2& lhs, const Vector2& rhs) 2693 | { 2694 | return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); 2695 | } 2696 | 2697 | // Vector3 operators 2698 | static constexpr Vector3 Vector3Zeros = { 0, 0, 0 }; 2699 | static constexpr Vector3 Vector3Ones = { 1, 1, 1 }; 2700 | static constexpr Vector3 Vector3UnitX = { 1, 0, 0 }; 2701 | static constexpr Vector3 Vector3UnitY = { 0, 1, 0 }; 2702 | static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 }; 2703 | 2704 | inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs) 2705 | { 2706 | return Vector3Add(lhs, rhs); 2707 | } 2708 | 2709 | inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs) 2710 | { 2711 | lhs = Vector3Add(lhs, rhs); 2712 | return lhs; 2713 | } 2714 | 2715 | inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs) 2716 | { 2717 | return Vector3Subtract(lhs, rhs); 2718 | } 2719 | 2720 | inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs) 2721 | { 2722 | lhs = Vector3Subtract(lhs, rhs); 2723 | return lhs; 2724 | } 2725 | 2726 | inline Vector3 operator * (const Vector3& lhs, const float& rhs) 2727 | { 2728 | return Vector3Scale(lhs, rhs); 2729 | } 2730 | 2731 | inline const Vector3& operator *= (Vector3& lhs, const float& rhs) 2732 | { 2733 | lhs = Vector3Scale(lhs, rhs); 2734 | return lhs; 2735 | } 2736 | 2737 | inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs) 2738 | { 2739 | return Vector3Multiply(lhs, rhs); 2740 | } 2741 | 2742 | inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs) 2743 | { 2744 | lhs = Vector3Multiply(lhs, rhs); 2745 | return lhs; 2746 | } 2747 | 2748 | inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs) 2749 | { 2750 | return Vector3Transform(lhs, rhs); 2751 | } 2752 | 2753 | inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs) 2754 | { 2755 | lhs = Vector3Transform(lhs, rhs); 2756 | return lhs; 2757 | } 2758 | 2759 | inline Vector3 operator / (const Vector3& lhs, const float& rhs) 2760 | { 2761 | return Vector3Scale(lhs, 1.0f / rhs); 2762 | } 2763 | 2764 | inline const Vector3& operator /= (Vector3& lhs, const float& rhs) 2765 | { 2766 | lhs = Vector3Scale(lhs, 1.0f / rhs); 2767 | return lhs; 2768 | } 2769 | 2770 | inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs) 2771 | { 2772 | return Vector3Divide(lhs, rhs); 2773 | } 2774 | 2775 | inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs) 2776 | { 2777 | lhs = Vector3Divide(lhs, rhs); 2778 | return lhs; 2779 | } 2780 | 2781 | inline bool operator == (const Vector3& lhs, const Vector3& rhs) 2782 | { 2783 | return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); 2784 | } 2785 | 2786 | inline bool operator != (const Vector3& lhs, const Vector3& rhs) 2787 | { 2788 | return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); 2789 | } 2790 | 2791 | // Vector4 operators 2792 | static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 }; 2793 | static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 }; 2794 | static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 }; 2795 | static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 }; 2796 | static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 }; 2797 | static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 }; 2798 | 2799 | inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs) 2800 | { 2801 | return Vector4Add(lhs, rhs); 2802 | } 2803 | 2804 | inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs) 2805 | { 2806 | lhs = Vector4Add(lhs, rhs); 2807 | return lhs; 2808 | } 2809 | 2810 | inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs) 2811 | { 2812 | return Vector4Subtract(lhs, rhs); 2813 | } 2814 | 2815 | inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs) 2816 | { 2817 | lhs = Vector4Subtract(lhs, rhs); 2818 | return lhs; 2819 | } 2820 | 2821 | inline Vector4 operator * (const Vector4& lhs, const float& rhs) 2822 | { 2823 | return Vector4Scale(lhs, rhs); 2824 | } 2825 | 2826 | inline const Vector4& operator *= (Vector4& lhs, const float& rhs) 2827 | { 2828 | lhs = Vector4Scale(lhs, rhs); 2829 | return lhs; 2830 | } 2831 | 2832 | inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs) 2833 | { 2834 | return Vector4Multiply(lhs, rhs); 2835 | } 2836 | 2837 | inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs) 2838 | { 2839 | lhs = Vector4Multiply(lhs, rhs); 2840 | return lhs; 2841 | } 2842 | 2843 | inline Vector4 operator / (const Vector4& lhs, const float& rhs) 2844 | { 2845 | return Vector4Scale(lhs, 1.0f / rhs); 2846 | } 2847 | 2848 | inline const Vector4& operator /= (Vector4& lhs, const float& rhs) 2849 | { 2850 | lhs = Vector4Scale(lhs, 1.0f / rhs); 2851 | return lhs; 2852 | } 2853 | 2854 | inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs) 2855 | { 2856 | return Vector4Divide(lhs, rhs); 2857 | } 2858 | 2859 | inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs) 2860 | { 2861 | lhs = Vector4Divide(lhs, rhs); 2862 | return lhs; 2863 | } 2864 | 2865 | inline bool operator == (const Vector4& lhs, const Vector4& rhs) 2866 | { 2867 | return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); 2868 | } 2869 | 2870 | inline bool operator != (const Vector4& lhs, const Vector4& rhs) 2871 | { 2872 | return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); 2873 | } 2874 | 2875 | // Quaternion operators 2876 | static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 }; 2877 | static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 }; 2878 | static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 }; 2879 | 2880 | inline Quaternion operator + (const Quaternion& lhs, const float& rhs) 2881 | { 2882 | return QuaternionAddValue(lhs, rhs); 2883 | } 2884 | 2885 | inline const Quaternion& operator += (Quaternion& lhs, const float& rhs) 2886 | { 2887 | lhs = QuaternionAddValue(lhs, rhs); 2888 | return lhs; 2889 | } 2890 | 2891 | inline Quaternion operator - (const Quaternion& lhs, const float& rhs) 2892 | { 2893 | return QuaternionSubtractValue(lhs, rhs); 2894 | } 2895 | 2896 | inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs) 2897 | { 2898 | lhs = QuaternionSubtractValue(lhs, rhs); 2899 | return lhs; 2900 | } 2901 | 2902 | inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs) 2903 | { 2904 | return QuaternionTransform(lhs, rhs); 2905 | } 2906 | 2907 | inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) 2908 | { 2909 | lhs = QuaternionTransform(lhs, rhs); 2910 | return lhs; 2911 | } 2912 | 2913 | // Matrix operators 2914 | inline Matrix operator + (const Matrix& lhs, const Matrix& rhs) 2915 | { 2916 | return MatrixAdd(lhs, rhs); 2917 | } 2918 | 2919 | inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs) 2920 | { 2921 | lhs = MatrixAdd(lhs, rhs); 2922 | return lhs; 2923 | } 2924 | 2925 | inline Matrix operator - (const Matrix& lhs, const Matrix& rhs) 2926 | { 2927 | return MatrixSubtract(lhs, rhs); 2928 | } 2929 | 2930 | inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs) 2931 | { 2932 | lhs = MatrixSubtract(lhs, rhs); 2933 | return lhs; 2934 | } 2935 | 2936 | inline Matrix operator * (const Matrix& lhs, const Matrix& rhs) 2937 | { 2938 | return MatrixMultiply(lhs, rhs); 2939 | } 2940 | 2941 | inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs) 2942 | { 2943 | lhs = MatrixMultiply(lhs, rhs); 2944 | return lhs; 2945 | } 2946 | //------------------------------------------------------------------------------- 2947 | #endif // C++ operators 2948 | 2949 | #endif // RAYMATH_H 2950 | -------------------------------------------------------------------------------- /raymath/raymath_ext.c.v: -------------------------------------------------------------------------------- 1 | module raymath 2 | 3 | #flag -I @VMODROOT/raymath/ 4 | #include "raymath.h" 5 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Raylib for V 2 | 3 | > Up-to-date, auto-generated Raylib (and Raymath) bindings for V 4 | 5 | Current Raylib Target: v5.5 6 | 7 | ## Installation 8 | 9 | `v install raylib` 10 | 11 | ## Usage 12 | 13 | Barring a small handful of differences, it is the exact same as Raylib's C API. 14 | 15 | Differences: 16 | - Functions and parameters are renamed from `PascalCase` to `camel_case` 17 | - Colours are V constants, not as macros 18 | - Any function that uses or returns a C-string instead uses a V-string 19 | 20 | ## Why? 21 | 22 | There are already a handful of V Raylib bindings, but they almost all are out-of-date or 23 | are poorly maintained. For that reason, I decided to do it myself. 24 | 25 | I also wanted to have documentation comments in the bindings, which is not provided by 26 | many Raylib bindings in general as far as I know. 27 | 28 | ## License 29 | 30 | The Raylib headers are licensed under their respective licenses, which is Zlib. 31 | 32 | Everything else is dual-licensed under MIT and the Unlicense, use whichever works best 33 | for you! :D 34 | -------------------------------------------------------------------------------- /scripts/gitpod-init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | set -e 4 | 5 | # Download V 6 | if [ ! -e 'v/' ] 7 | then 8 | git clone https://github.com/vlang/v 9 | fi 10 | 11 | cd v 12 | if [ ! -e './v' ] 13 | then 14 | make 15 | fi 16 | sudo ./v symlink 17 | cd .. 18 | 19 | # Download Clockwork 20 | if [ ! -e 'clockwork/' ] 21 | then 22 | git clone https://github.com/EmmaTheMartian/clockwork 23 | fi 24 | # Build and install Clockwork 25 | cd clockwork 26 | ../v/v install EmmaTheMartian.Maple 27 | ../v/v run . install 28 | cd .. 29 | 30 | # Install dependencies 31 | clockwork deps 32 | -------------------------------------------------------------------------------- /scripts/jsongen.py: -------------------------------------------------------------------------------- 1 | # This script will clone Raylib on a specific commit, then use Raylib's parser 2 | # to generate JSON files for the Raylib and Raymath APIs. 3 | 4 | import os 5 | 6 | RAYLIB_VERSION = "c1ab645" # Latest version of v5.5 7 | RAYGUI_VERSION = "1e03efc" # Latest version as of Sep 24, 2024 8 | 9 | if not os.path.exists("external"): 10 | os.mkdir("external") 11 | 12 | if not os.path.exists("external/raylib"): 13 | os.system(f"git clone https://github.com/raysan5/raylib external/raylib &&\ 14 | cd raylib &&\ 15 | git reset --hard {RAYLIB_VERSION}") 16 | 17 | if not os.path.exists("external/raygui"): 18 | os.system(f"git clone https://github.com/raysan5/raygui external/raygui &&\ 19 | cd raygui &&\ 20 | git reset --hard {RAYGUI_VERSION}") 21 | 22 | os.system("cd external/raylib/parser && make clean raylib_parser") 23 | os.system("cd external/raylib/parser && ./raylib_parser -i ../src/raylib.h -o raylib_api.json -f JSON -d RLAPI") 24 | os.system("cd external/raylib/parser && ./raylib_parser -i ../src/raymath.h -o raymath_api.json -f JSON -d RMAPI") 25 | os.system("cd external/raylib/parser && ./raylib_parser -i ../../raygui/src/raygui.h -o raygui_api.json -f JSON -d RAYGUIAPI -t \"RAYGUI IMPLEMENTATION\"") 26 | -------------------------------------------------------------------------------- /scripts/raygen.py: -------------------------------------------------------------------------------- 1 | import os 2 | import urllib.request 3 | import json 4 | import re 5 | import sys 6 | 7 | 8 | translate_identifier_re = re.compile(r'(? str: 138 | if pascal in renamed_identifiers: 139 | return renamed_identifiers[pascal] 140 | for k, v in translate_identifier_special_cases.items(): 141 | pascal = pascal.replace(k, v) 142 | return translate_identifier_re.sub('_', pascal).lower() 143 | 144 | def c_type_to_v_type(c_type: str, method_name: str = None) -> str: 145 | # Varaidic args are a pain because C does not declare types for them, 146 | # meaning we need to handle them manually based on the method's name. 147 | # Luckily, there are only **2** methods in the entire API that use 148 | # varaidic arguments! 149 | if c_type == "...": 150 | return varaidic_type_translations[method_name] 151 | # We handle void here because it can be ambigious between no/ return 152 | # value or a void pointer. 153 | elif c_type == "void *" or c_type == "const void *": 154 | return "voidptr" 155 | 156 | # The final annoying thing we have to deal with are fixed-size array 157 | # types. 158 | sizes = [] 159 | if "[" in c_type: 160 | dimensions = c_type.count("[") 161 | sizes = c_type.replace("]", "").split("[")[1:] 162 | c_type = c_type.split("[")[0] 163 | 164 | pointers = c_type.count("*") 165 | c_type = c_type.removeprefix("const ").replace("*", "").strip() 166 | c_type = c_to_v_types.get(c_type, c_type) 167 | c_type = ("&" * pointers) + c_type 168 | c_type = c_type.strip() 169 | 170 | # If we are an array, we will add that to the V type 171 | if len(sizes) > 0: 172 | c_type = "".join([f"[{s}]" for s in sizes]) + c_type 173 | 174 | return c_type 175 | 176 | def generate(path: str, json_path: str, lib: str): 177 | if not os.path.exists(json_path): 178 | raise RuntimeError(f"{json_path} does not exist. You can generate it with scripts/jsongen.py") 179 | 180 | folder = "/".join(path.split("/")[:-1]) 181 | if folder != "": 182 | os.makedirs(folder, exist_ok = True) 183 | 184 | raylib_module = path.split("/")[-1].removesuffix(".c.v") 185 | 186 | # Parse JSON file and generate raylib.c.v 187 | with open(path, "w+") as fp: 188 | fp.write(f"module {lib}\n") 189 | 190 | if raylib_module in module_boilerplates: 191 | fp.write(module_boilerplates[raylib_module]) 192 | 193 | data = None 194 | with open(json_path, "r") as json_fp: 195 | data = json.load(json_fp) 196 | if data is None: 197 | raise RuntimeError(f"Failed to load {json_path}") 198 | 199 | # Translate structs 200 | for struct in data.get("structs", []): 201 | c_name = struct["name"] 202 | 203 | if raylib_module in ignored_structs and c_name in ignored_structs[raylib_module]: 204 | continue 205 | 206 | v_name = struct["name"] 207 | if raylib_module in renamed_structs and c_name in renamed_structs[raylib_module]: 208 | v_name = renamed_structs[raylib_module][c_name] 209 | 210 | fields = struct["fields"] 211 | 212 | fp.write(f"pub type {v_name} = C.{c_name}\n") 213 | if struct["description"] != "": 214 | fp.write(f"// {struct["description"]}\n") 215 | fp.write(f"pub struct C.{c_name} {{\n") 216 | for field in fields: 217 | if field["description"] != "": 218 | fp.write(f"\t// {field["description"]}\n") 219 | fp.write(f"\t{translate_identifier(field["name"])} {c_type_to_v_type(field["type"])}\n") 220 | fp.write('}\n\n') 221 | 222 | # Translate aliases 223 | for alias in data.get("aliases", []): 224 | if alias["description"] != "": 225 | fp.write(f"// {alias["description"]}\n") 226 | fp.write(f"pub type {alias["name"]} = C.{alias["type"]}\n") 227 | 228 | # Translate callbacks 229 | for callback in data.get("callbacks", []): 230 | params = callback.get("params", []) 231 | 232 | has_params = len(params) > 0 233 | for param in params: 234 | param["type"] = c_type_to_v_type(param["type"]) 235 | param["name"] = translate_identifier(param["name"]) 236 | 237 | c_args = "" if not has_params else ", ".join([p["type"] for p in params]) 238 | 239 | if callback["description"] != "": 240 | fp.write(f"// {callback["description"]}\n") 241 | fp.write(f"pub type {callback["name"]} = fn ({c_args}) {c_type_to_v_type(callback["returnType"])}\n\n") 242 | 243 | # Translate enums 244 | for enum in data.get("enums", []): 245 | is_flag_enum = raylib_module in flag_enums and enum["name"] in flag_enums[raylib_module] 246 | 247 | if enum["description"] != "": 248 | fp.write(f"// {enum["description"]}\n") 249 | if is_flag_enum: 250 | fp.write("@[flag]\n") 251 | fp.write(f"pub enum {enum["name"]}") 252 | if raylib_module in enum_types and enum["name"] in enum_types[raylib_module]: 253 | fp.write(f" as {enum_types[raylib_module][enum["name"]]}") 254 | fp.write(" {\n") 255 | for value in enum["values"]: 256 | fp.write(f"\t{value["name"].lower()}") 257 | if not is_flag_enum: 258 | fp.write(f" = {value["value"]}") 259 | if value["description"] != "": 260 | fp.write(f" // {value["description"]}\n") 261 | fp.write("}\n") 262 | 263 | # Bind functions 264 | for function in data.get("functions", []): 265 | c_name = function["name"] 266 | v_name = translate_identifier(function["name"]) 267 | c_return_type = c_type_to_v_type(function["returnType"]) 268 | v_return_type = c_type_to_v_type(function["returnType"]) 269 | comment = function["description"] 270 | 271 | params = function.get("params", []) 272 | has_params = len(params) > 0 273 | for param in params: 274 | # If this arg represents an enum flag, then we 275 | # should use that instead of an int type. We 276 | # handle them here because we need more info 277 | # than is provided to the c_type_to_v_type 278 | # function. 279 | if ( 280 | raylib_module in functions_with_enum_args and 281 | c_name in functions_with_enum_args[raylib_module] and 282 | param["name"] in functions_with_enum_args[raylib_module][c_name] 283 | ): 284 | param["type"] = functions_with_enum_args[raylib_module][c_name][param["name"]] 285 | else: 286 | param["type"] = c_type_to_v_type(param["type"], v_name) 287 | 288 | param["name"] = translate_identifier(param["name"]) 289 | 290 | c_args = [p["type"] for p in params] 291 | decl_args = [f"{p["name"]} {p["type"]}" for p in params] 292 | 293 | call_args = [] 294 | if has_params: 295 | call_args = params 296 | # If our function has a varaidic argument, we need to 297 | # specify that when calling the C function 298 | for arg in call_args: 299 | if arg["type"].startswith("..."): 300 | arg["name"] = "..." + arg["name"] 301 | call_args = [arg["name"] for arg in call_args] 302 | 303 | # Convert C-string arguments to V-strings to make the DX better :D 304 | for index, arg in enumerate(params): 305 | if arg["type"] == "&char": 306 | call_args[index] = f"{arg["name"]}.str" 307 | decl_args[index] = decl_args[index].replace("&char", "string") 308 | 309 | c_args = ", ".join(c_args) 310 | decl_args = ", ".join(decl_args) 311 | call_args = ", ".join(call_args) 312 | 313 | if c_return_type == "&char": 314 | v_return_type = "string" 315 | 316 | # Now we write the binding to the file 317 | fp.write(f"fn C.{c_name}({c_args}) {c_return_type}\n") 318 | if comment != "": 319 | fp.write(f"// {comment}\n") 320 | fp.write(f"@[inline] pub fn {v_name}({decl_args}) {v_return_type} {{\n") 321 | if v_return_type == "string": 322 | fp.write("\tunsafe {") 323 | fp.write(f"\t\treturn C.{c_name}({call_args}).vstring()") 324 | fp.write("\t}") 325 | elif v_return_type != "": 326 | fp.write(f"\treturn C.{c_name}({call_args})\n") 327 | else: 328 | fp.write(f"\tC.{c_name}({call_args})\n") 329 | fp.write('}\n') 330 | 331 | # Run v fmt 332 | os.system(f"v -w fmt {path}") 333 | 334 | if __name__ == "__main__": 335 | # Generate our Raylib, Raymath, and Raygui bindings 336 | generate("raylib.c.v", "external/raylib/parser/raylib_api.json", "raylib") 337 | generate("raymath/raymath.c.v", "external/raylib/parser/raymath_api.json", "raymath") 338 | generate("raygui/raygui.c.v", "external/raylib/parser/raygui_api.json", "raygui") 339 | 340 | # Raygui and Raymath are not distributed as a package like Raylib is. 341 | # To use the libraries, we must redistribute their headers. 342 | os.system("cp external/raygui/src/raygui.h raygui/raygui.h") 343 | os.system("cp external/raylib/src/raymath.h raymath/raymath.h") 344 | # We will also copy the licenses to the raygui/ and raymath/ directory 345 | # since we include a source distribution of them. 346 | os.system("cp external/raygui/LICENSE raygui/raygui-license") 347 | os.system("cp external/raylib/LICENSE raymath/raymath-license") 348 | -------------------------------------------------------------------------------- /v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'raylib' 3 | description: 'Up-to-date, auto-generated Raylib (and Raymath) bindings for V' 4 | version: '5.5' 5 | license: 'MIT/Unlicense' 6 | repo_url: 'https://github.com/emmathemartian/raygen' 7 | dependencies: [] 8 | } 9 | --------------------------------------------------------------------------------