Merge branch 'raysan5:master' into master
This commit is contained in:
commit
e8d9225ddf
18 changed files with 315 additions and 118 deletions
|
@ -13,7 +13,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers
|
||||||
| [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
|
| [raylib-cs](https://github.com/raylib-cs/raylib-cs) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | Zlib |
|
||||||
| [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
|
| [Raylib-CsLo](https://github.com/NotNotTech/Raylib-CsLo) | 4.2 | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
|
||||||
| [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
|
| [Raylib-CSharp-Vinculum](https://github.com/ZeroElectric/Raylib-CSharp-Vinculum) | **5.0** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MPL-2.0 |
|
||||||
| [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.1-dev** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT |
|
| [Raylib-CSharp](https://github.com/MrScautHD/Raylib-CSharp) | **5.5** | [C#](https://en.wikipedia.org/wiki/C_Sharp_(programming_language)) | MIT |
|
||||||
| [cl-raylib](https://github.com/longlene/cl-raylib) | 4.0 | [Common Lisp](https://common-lisp.net) | MIT |
|
| [cl-raylib](https://github.com/longlene/cl-raylib) | 4.0 | [Common Lisp](https://common-lisp.net) | MIT |
|
||||||
| [claylib/wrap](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib |
|
| [claylib/wrap](https://github.com/defun-games/claylib) | 4.5 | [Common Lisp](https://common-lisp.net) | Zlib |
|
||||||
| [claw-raylib](https://github.com/bohonghuang/claw-raylib) | **auto** | [Common Lisp](https://common-lisp.net) | Apache-2.0 |
|
| [claw-raylib](https://github.com/bohonghuang/claw-raylib) | **auto** | [Common Lisp](https://common-lisp.net) | Apache-2.0 |
|
||||||
|
|
12
build.zig
12
build.zig
|
@ -205,7 +205,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
raylib.root_module.addCMacro("PLATFORM_DRM", "");
|
raylib.root_module.addCMacro("PLATFORM_DRM", "");
|
||||||
raylib.root_module.addCMacro("EGL_NO_X11", "");
|
raylib.root_module.addCMacro("EGL_NO_X11", "");
|
||||||
raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "");
|
raylib.root_module.addCMacro("DEFAULT_BATCH_BUFFER_ELEMENT", "");
|
||||||
} else if (target.result.abi == .android) {
|
} else if (target.result.abi.isAndroid()) {
|
||||||
|
|
||||||
//these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems
|
//these are the only tag options per https://developer.android.com/ndk/guides/other_build_systems
|
||||||
const hostTuple = switch (builtin.target.os.tag) {
|
const hostTuple = switch (builtin.target.os.tag) {
|
||||||
|
@ -215,7 +215,14 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
else => @panic("unsupported host OS"),
|
else => @panic("unsupported host OS"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const androidTriple = try target.result.linuxTriple(b.allocator);
|
const androidTriple = switch (target.result.cpu.arch) {
|
||||||
|
.x86 => "i686-linux-android",
|
||||||
|
.x86_64 => "x86_64-linux-android",
|
||||||
|
.arm => "arm-linux-androideabi",
|
||||||
|
.aarch64 => "aarch64-linux-android",
|
||||||
|
.riscv64 => "riscv64-linux-android",
|
||||||
|
else => error.InvalidAndroidTarget,
|
||||||
|
} catch @panic("invalid android target!");
|
||||||
const androidNdkPathString: []const u8 = options.android_ndk;
|
const androidNdkPathString: []const u8 = options.android_ndk;
|
||||||
if (androidNdkPathString.len < 1) @panic("no ndk path provided and ANDROID_NDK_HOME is not set");
|
if (androidNdkPathString.len < 1) @panic("no ndk path provided and ANDROID_NDK_HOME is not set");
|
||||||
const androidApiLevel: []const u8 = options.android_api_version;
|
const androidApiLevel: []const u8 = options.android_api_version;
|
||||||
|
@ -249,6 +256,7 @@ fn compileRaylib(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.
|
||||||
raylib.root_module.linkSystemLibrary("GLESv2", .{});
|
raylib.root_module.linkSystemLibrary("GLESv2", .{});
|
||||||
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
|
raylib.root_module.addCMacro("GRAPHICS_API_OPENGL_ES2", "");
|
||||||
}
|
}
|
||||||
|
raylib.root_module.linkSystemLibrary("EGL", .{});
|
||||||
|
|
||||||
setDesktopPlatform(raylib, .android);
|
setDesktopPlatform(raylib, .android);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -108,7 +108,7 @@ static void SetSoundPosition(Camera listener, Sound sound, Vector3 position, flo
|
||||||
// Calculate normalized vectors for spatial positioning
|
// Calculate normalized vectors for spatial positioning
|
||||||
Vector3 normalizedDirection = Vector3Normalize(direction);
|
Vector3 normalizedDirection = Vector3Normalize(direction);
|
||||||
Vector3 forward = Vector3Normalize(Vector3Subtract(listener.target, listener.position));
|
Vector3 forward = Vector3Normalize(Vector3Subtract(listener.target, listener.position));
|
||||||
Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, listener.up));
|
Vector3 right = Vector3Normalize(Vector3CrossProduct(listener.up, forward));
|
||||||
|
|
||||||
// Reduce volume for sounds behind the listener
|
// Reduce volume for sounds behind the listener
|
||||||
float dotProduct = Vector3DotProduct(forward, normalizedDirection);
|
float dotProduct = Vector3DotProduct(forward, normalizedDirection);
|
||||||
|
|
|
@ -125,6 +125,8 @@ int main()
|
||||||
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, SHADER_UNIFORM_FLOAT);
|
SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &ambientIntensity, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
// Get location for shader parameters that can be modified in real time
|
// Get location for shader parameters that can be modified in real time
|
||||||
|
int metallicValueLoc = GetShaderLocation(shader, "metallicValue");
|
||||||
|
int roughnessValueLoc = GetShaderLocation(shader, "roughnessValue");
|
||||||
int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
|
||||||
int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
|
||||||
int textureTilingLoc = GetShaderLocation(shader, "tiling");
|
int textureTilingLoc = GetShaderLocation(shader, "tiling");
|
||||||
|
@ -141,7 +143,7 @@ int main()
|
||||||
|
|
||||||
// Setup materials[0].maps default parameters
|
// Setup materials[0].maps default parameters
|
||||||
car.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
car.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
||||||
car.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
|
car.materials[0].maps[MATERIAL_MAP_METALNESS].value = 1.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
car.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
||||||
car.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 };
|
car.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 };
|
||||||
|
@ -163,8 +165,8 @@ int main()
|
||||||
floor.materials[0].shader = shader;
|
floor.materials[0].shader = shader;
|
||||||
|
|
||||||
floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
|
floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.8f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
|
floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.1f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
|
||||||
floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK;
|
floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK;
|
||||||
|
|
||||||
|
@ -229,6 +231,10 @@ int main()
|
||||||
Vector4 floorEmissiveColor = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color);
|
Vector4 floorEmissiveColor = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color);
|
||||||
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, SHADER_UNIFORM_VEC4);
|
SetShaderValue(shader, emissiveColorLoc, &floorEmissiveColor, SHADER_UNIFORM_VEC4);
|
||||||
|
|
||||||
|
// Set floor metallic and roughness values
|
||||||
|
SetShaderValue(shader, metallicValueLoc, &floor.materials[0].maps[MATERIAL_MAP_METALNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
SetShaderValue(shader, roughnessValueLoc, &floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 5.0f, WHITE); // Draw floor model
|
DrawModel(floor, (Vector3){ 0.0f, 0.0f, 0.0f }, 5.0f, WHITE); // Draw floor model
|
||||||
|
|
||||||
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
// Set old car model texture tiling, emissive color and emissive intensity parameters on shader
|
||||||
|
@ -238,6 +244,10 @@ int main()
|
||||||
float emissiveIntensity = 0.01f;
|
float emissiveIntensity = 0.01f;
|
||||||
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
|
SetShaderValue(shader, emissiveIntensityLoc, &emissiveIntensity, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
|
// Set old car metallic and roughness values
|
||||||
|
SetShaderValue(shader, metallicValueLoc, &car.materials[0].maps[MATERIAL_MAP_METALNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
SetShaderValue(shader, roughnessValueLoc, &car.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value, SHADER_UNIFORM_FLOAT);
|
||||||
|
|
||||||
DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model
|
DrawModel(car, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.25f, WHITE); // Draw car model
|
||||||
|
|
||||||
// Draw spheres to show the lights positions
|
// Draw spheres to show the lights positions
|
||||||
|
|
|
@ -3139,7 +3139,7 @@
|
||||||
"name": "fileName"
|
"name": "fileName"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "char *",
|
"type": "const char *",
|
||||||
"name": "text"
|
"name": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4409,7 +4409,7 @@
|
||||||
"name": "fileName"
|
"name": "fileName"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "char *",
|
"type": "const char *",
|
||||||
"name": "text"
|
"name": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4707,7 +4707,7 @@
|
||||||
"returnType": "unsigned char *",
|
"returnType": "unsigned char *",
|
||||||
"params": [
|
"params": [
|
||||||
{
|
{
|
||||||
"type": "const unsigned char *",
|
"type": "const char *",
|
||||||
"name": "data"
|
"name": "data"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -3108,7 +3108,7 @@ return {
|
||||||
returnType = "bool",
|
returnType = "bool",
|
||||||
params = {
|
params = {
|
||||||
{type = "const char *", name = "fileName"},
|
{type = "const char *", name = "fileName"},
|
||||||
{type = "char *", name = "text"}
|
{type = "const char *", name = "text"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4006,7 +4006,7 @@ return {
|
||||||
returnType = "bool",
|
returnType = "bool",
|
||||||
params = {
|
params = {
|
||||||
{type = "const char *", name = "fileName"},
|
{type = "const char *", name = "fileName"},
|
||||||
{type = "char *", name = "text"}
|
{type = "const char *", name = "text"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4211,7 +4211,7 @@ return {
|
||||||
description = "Decode Base64 string data, memory must be MemFree()",
|
description = "Decode Base64 string data, memory must be MemFree()",
|
||||||
returnType = "unsigned char *",
|
returnType = "unsigned char *",
|
||||||
params = {
|
params = {
|
||||||
{type = "const unsigned char *", name = "data"},
|
{type = "const char *", name = "data"},
|
||||||
{type = "int *", name = "outputSize"}
|
{type = "int *", name = "outputSize"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -985,7 +985,7 @@ Callback 005: SaveFileTextCallback() (2 input parameters)
|
||||||
Return type: bool
|
Return type: bool
|
||||||
Description: FileIO: Save text data
|
Description: FileIO: Save text data
|
||||||
Param[1]: fileName (type: const char *)
|
Param[1]: fileName (type: const char *)
|
||||||
Param[2]: text (type: char *)
|
Param[2]: text (type: const char *)
|
||||||
Callback 006: AudioCallback() (2 input parameters)
|
Callback 006: AudioCallback() (2 input parameters)
|
||||||
Name: AudioCallback
|
Name: AudioCallback
|
||||||
Return type: void
|
Return type: void
|
||||||
|
@ -1656,7 +1656,7 @@ Function 123: SaveFileText() (2 input parameters)
|
||||||
Return type: bool
|
Return type: bool
|
||||||
Description: Save text data to file (write), string must be '\0' terminated, returns true on success
|
Description: Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||||
Param[1]: fileName (type: const char *)
|
Param[1]: fileName (type: const char *)
|
||||||
Param[2]: text (type: char *)
|
Param[2]: text (type: const char *)
|
||||||
Function 124: FileExists() (1 input parameters)
|
Function 124: FileExists() (1 input parameters)
|
||||||
Name: FileExists
|
Name: FileExists
|
||||||
Return type: bool
|
Return type: bool
|
||||||
|
@ -1795,7 +1795,7 @@ Function 149: DecodeDataBase64() (2 input parameters)
|
||||||
Name: DecodeDataBase64
|
Name: DecodeDataBase64
|
||||||
Return type: unsigned char *
|
Return type: unsigned char *
|
||||||
Description: Decode Base64 string data, memory must be MemFree()
|
Description: Decode Base64 string data, memory must be MemFree()
|
||||||
Param[1]: data (type: const unsigned char *)
|
Param[1]: data (type: const char *)
|
||||||
Param[2]: outputSize (type: int *)
|
Param[2]: outputSize (type: int *)
|
||||||
Function 150: ComputeCRC32() (2 input parameters)
|
Function 150: ComputeCRC32() (2 input parameters)
|
||||||
Name: ComputeCRC32
|
Name: ComputeCRC32
|
||||||
|
|
|
@ -672,7 +672,7 @@
|
||||||
</Callback>
|
</Callback>
|
||||||
<Callback name="SaveFileTextCallback" retType="bool" paramCount="2" desc="FileIO: Save text data">
|
<Callback name="SaveFileTextCallback" retType="bool" paramCount="2" desc="FileIO: Save text data">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
<Param type="char *" name="text" desc="" />
|
<Param type="const char *" name="text" desc="" />
|
||||||
</Callback>
|
</Callback>
|
||||||
<Callback name="AudioCallback" retType="void" paramCount="2" desc="">
|
<Callback name="AudioCallback" retType="void" paramCount="2" desc="">
|
||||||
<Param type="void *" name="bufferData" desc="" />
|
<Param type="void *" name="bufferData" desc="" />
|
||||||
|
@ -1046,7 +1046,7 @@
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="SaveFileText" retType="bool" paramCount="2" desc="Save text data to file (write), string must be '\0' terminated, returns true on success">
|
<Function name="SaveFileText" retType="bool" paramCount="2" desc="Save text data to file (write), string must be '\0' terminated, returns true on success">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
<Param type="char *" name="text" desc="" />
|
<Param type="const char *" name="text" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="FileExists" retType="bool" paramCount="1" desc="Check if file exists">
|
<Function name="FileExists" retType="bool" paramCount="1" desc="Check if file exists">
|
||||||
<Param type="const char *" name="fileName" desc="" />
|
<Param type="const char *" name="fileName" desc="" />
|
||||||
|
@ -1129,7 +1129,7 @@
|
||||||
<Param type="int *" name="outputSize" desc="" />
|
<Param type="int *" name="outputSize" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="DecodeDataBase64" retType="unsigned char *" paramCount="2" desc="Decode Base64 string data, memory must be MemFree()">
|
<Function name="DecodeDataBase64" retType="unsigned char *" paramCount="2" desc="Decode Base64 string data, memory must be MemFree()">
|
||||||
<Param type="const unsigned char *" name="data" desc="" />
|
<Param type="const char *" name="data" desc="" />
|
||||||
<Param type="int *" name="outputSize" desc="" />
|
<Param type="int *" name="outputSize" desc="" />
|
||||||
</Function>
|
</Function>
|
||||||
<Function name="ComputeCRC32" retType="unsigned int" paramCount="2" desc="Compute CRC32 hash code">
|
<Function name="ComputeCRC32" retType="unsigned int" paramCount="2" desc="Compute CRC32 hash code">
|
||||||
|
|
2
src/external/rprand.h
vendored
2
src/external/rprand.h
vendored
|
@ -90,7 +90,7 @@
|
||||||
#define RPRAND_FREE(ptr) free(ptr)
|
#define RPRAND_FREE(ptr) free(ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Simple log system to avoid RPNG_LOG() calls if required
|
// Simple log system to avoid log calls if required
|
||||||
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
// NOTE: Avoiding those calls, also avoids const strings memory usage
|
||||||
#define RPRAND_SHOW_LOG_INFO
|
#define RPRAND_SHOW_LOG_INFO
|
||||||
#if defined(RPNG_SHOW_LOG_INFO)
|
#if defined(RPNG_SHOW_LOG_INFO)
|
||||||
|
|
|
@ -70,6 +70,16 @@ typedef struct {
|
||||||
EGLConfig config; // Graphic config
|
EGLConfig config; // Graphic config
|
||||||
} PlatformData;
|
} PlatformData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Store data for both Hover and Touch events
|
||||||
|
// Used to ignore Hover events which are interpreted as Touch events
|
||||||
|
int32_t pointCount; // Number of touch points active
|
||||||
|
int32_t pointId[MAX_TOUCH_POINTS]; // Point identifiers
|
||||||
|
Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen
|
||||||
|
|
||||||
|
int32_t hoverPoints[MAX_TOUCH_POINTS]; // Hover Points
|
||||||
|
} TouchRaw;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -246,6 +256,8 @@ static const KeyboardKey mapKeycode[KEYCODE_MAP_SIZE] = {
|
||||||
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
KEY_KP_EQUAL // AKEYCODE_NUMPAD_EQUALS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static TouchRaw touchRaw = { 0 };
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Internal Functions Declaration
|
// Module Internal Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -801,6 +813,8 @@ int InitPlatform(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++) touchRaw.hoverPoints[i] = -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1269,25 +1283,85 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register touch points count
|
// Register touch points count
|
||||||
CORE.Input.Touch.pointCount = AMotionEvent_getPointerCount(event);
|
touchRaw.pointCount = AMotionEvent_getPointerCount(event);
|
||||||
|
|
||||||
for (int i = 0; (i < CORE.Input.Touch.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||||
{
|
{
|
||||||
// Register touch points id
|
// Register touch points id
|
||||||
CORE.Input.Touch.pointId[i] = AMotionEvent_getPointerId(event, i);
|
touchRaw.pointId[i] = AMotionEvent_getPointerId(event, i);
|
||||||
|
|
||||||
// Register touch points position
|
// Register touch points position
|
||||||
CORE.Input.Touch.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
touchRaw.position[i] = (Vector2){ AMotionEvent_getX(event, i), AMotionEvent_getY(event, i) };
|
||||||
|
|
||||||
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
// Normalize CORE.Input.Touch.position[i] for CORE.Window.screen.width and CORE.Window.screen.height
|
||||||
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
float widthRatio = (float)(CORE.Window.screen.width + CORE.Window.renderOffset.x)/(float)CORE.Window.display.width;
|
||||||
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
float heightRatio = (float)(CORE.Window.screen.height + CORE.Window.renderOffset.y)/(float)CORE.Window.display.height;
|
||||||
CORE.Input.Touch.position[i].x = CORE.Input.Touch.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
touchRaw.position[i].x = touchRaw.position[i].x*widthRatio - (float)CORE.Window.renderOffset.x/2;
|
||||||
CORE.Input.Touch.position[i].y = CORE.Input.Touch.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
touchRaw.position[i].y = touchRaw.position[i].y*heightRatio - (float)CORE.Window.renderOffset.y/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t action = AMotionEvent_getAction(event);
|
int32_t action = AMotionEvent_getAction(event);
|
||||||
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
|
||||||
|
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
|
||||||
|
if (flags == AMOTION_EVENT_ACTION_HOVER_ENTER)
|
||||||
|
{
|
||||||
|
// The new pointer is hover
|
||||||
|
// So add it to hoverPoints
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
if (touchRaw.hoverPoints[i] == -1)
|
||||||
|
{
|
||||||
|
touchRaw.hoverPoints[i] = touchRaw.pointId[pointerIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags == AMOTION_EVENT_ACTION_POINTER_UP) || (flags == AMOTION_EVENT_ACTION_UP) || (flags == AMOTION_EVENT_ACTION_HOVER_EXIT))
|
||||||
|
{
|
||||||
|
// One of the touchpoints is released, remove it from touch point arrays
|
||||||
|
if (flags == AMOTION_EVENT_ACTION_HOVER_EXIT)
|
||||||
|
{
|
||||||
|
// If the touchPoint is hover, remove it from hoverPoints
|
||||||
|
for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
||||||
|
{
|
||||||
|
if (touchRaw.hoverPoints[i] == touchRaw.pointId[pointerIndex])
|
||||||
|
{
|
||||||
|
touchRaw.hoverPoints[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = pointerIndex; (i < touchRaw.pointCount - 1) && (i < MAX_TOUCH_POINTS - 1); i++)
|
||||||
|
{
|
||||||
|
touchRaw.pointId[i] = touchRaw.pointId[i+1];
|
||||||
|
touchRaw.position[i] = touchRaw.position[i+1];
|
||||||
|
}
|
||||||
|
touchRaw.pointCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pointCount = 0;
|
||||||
|
for (int i = 0; (i < touchRaw.pointCount) && (i < MAX_TOUCH_POINTS); i++)
|
||||||
|
{
|
||||||
|
// If the touchPoint is hover, Ignore it
|
||||||
|
bool hover = false;
|
||||||
|
for (int j = 0; j < MAX_TOUCH_POINTS; j++)
|
||||||
|
{
|
||||||
|
// Check if the touchPoint is in hoverPointers
|
||||||
|
if (touchRaw.hoverPoints[j] == touchRaw.pointId[i])
|
||||||
|
{
|
||||||
|
hover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hover) continue;
|
||||||
|
|
||||||
|
CORE.Input.Touch.pointId[pointCount] = touchRaw.pointId[i];
|
||||||
|
CORE.Input.Touch.position[pointCount] = touchRaw.position[i];
|
||||||
|
pointCount++;
|
||||||
|
}
|
||||||
|
CORE.Input.Touch.pointCount = pointCount;
|
||||||
|
|
||||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||||
GestureEvent gestureEvent = { 0 };
|
GestureEvent gestureEvent = { 0 };
|
||||||
|
@ -1312,20 +1386,6 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
||||||
ProcessGestureEvent(gestureEvent);
|
ProcessGestureEvent(gestureEvent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
|
|
||||||
|
|
||||||
if (flags == AMOTION_EVENT_ACTION_POINTER_UP || flags == AMOTION_EVENT_ACTION_UP)
|
|
||||||
{
|
|
||||||
// One of the touchpoints is released, remove it from touch point arrays
|
|
||||||
for (int i = pointerIndex; (i < CORE.Input.Touch.pointCount - 1) && (i < MAX_TOUCH_POINTS); i++)
|
|
||||||
{
|
|
||||||
CORE.Input.Touch.pointId[i] = CORE.Input.Touch.pointId[i+1];
|
|
||||||
CORE.Input.Touch.position[i] = CORE.Input.Touch.position[i+1];
|
|
||||||
}
|
|
||||||
|
|
||||||
CORE.Input.Touch.pointCount--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When all touchpoints are tapped and released really quickly, this event is generated
|
// When all touchpoints are tapped and released really quickly, this event is generated
|
||||||
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
if (flags == AMOTION_EVENT_ACTION_CANCEL) CORE.Input.Touch.pointCount = 0;
|
||||||
|
|
||||||
|
|
|
@ -1752,6 +1752,10 @@ static void ErrorCallback(int error, const char *description)
|
||||||
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
|
// NOTE: Window resizing not enabled by default, use SetConfigFlags()
|
||||||
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
static void WindowSizeCallback(GLFWwindow *window, int width, int height)
|
||||||
{
|
{
|
||||||
|
// WARNING: On window minimization, callback is called,
|
||||||
|
// but we don't want to change internal screen values, it breaks things
|
||||||
|
if ((width == 0) || (height == 0)) return;
|
||||||
|
|
||||||
// Reset viewport and projection matrix for new size
|
// Reset viewport and projection matrix for new size
|
||||||
SetupViewport(width, height);
|
SetupViewport(width, height);
|
||||||
|
|
||||||
|
|
|
@ -954,7 +954,7 @@ typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args);
|
||||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data
|
||||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data
|
||||||
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data
|
||||||
typedef bool (*SaveFileTextCallback)(const char *fileName, char *text); // FileIO: Save text data
|
typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
|
@ -1123,7 +1123,7 @@ RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save
|
||||||
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success
|
||||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||||
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||||
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
// File system functions
|
// File system functions
|
||||||
|
@ -1154,7 +1154,7 @@ RLAPI long GetFileModTime(const char *fileName); // Get file mo
|
||||||
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
||||||
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
||||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
|
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
|
||||||
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
RLAPI unsigned char *DecodeDataBase64(const char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
||||||
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
|
RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code
|
||||||
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes)
|
||||||
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes)
|
||||||
|
|
21
src/rcore.c
21
src/rcore.c
|
@ -523,25 +523,25 @@ const char *TextFormat(const char *text, ...); // Formatting of tex
|
||||||
#define PLATFORM_DESKTOP_GLFW
|
#define PLATFORM_DESKTOP_GLFW
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We're using `#pragma message` because `#warning` is not adopted by MSVC.
|
// We're using '#pragma message' because '#warning' is not adopted by MSVC
|
||||||
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
#if defined(SUPPORT_CLIPBOARD_IMAGE)
|
||||||
#if !defined(SUPPORT_MODULE_RTEXTURES)
|
#if !defined(SUPPORT_MODULE_RTEXTURES)
|
||||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_MODULE_RTEXTURES to work properly")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
|
// It's nice to have support Bitmap on Linux as well, but not as necessary as Windows
|
||||||
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
|
#if !defined(SUPPORT_FILEFORMAT_BMP) && defined(_WIN32)
|
||||||
#pragma message ("Warning: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
#pragma message ("WARNING: Enabling SUPPORT_CLIPBOARD_IMAGE requires SUPPORT_FILEFORMAT_BMP, specially on Windows")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// From what I've tested applications on Wayland saves images on clipboard as PNG.
|
// From what I've tested applications on Wayland saves images on clipboard as PNG
|
||||||
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
|
#if (!defined(SUPPORT_FILEFORMAT_PNG) || !defined(SUPPORT_FILEFORMAT_JPG)) && !defined(_WIN32)
|
||||||
#pragma message ("Warning: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
#pragma message ("WARNING: Getting image from the clipboard might not work without SUPPORT_FILEFORMAT_PNG or SUPPORT_FILEFORMAT_JPG")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined.
|
// Not needed because `rtexture.c` will automatically defined STBI_REQUIRED when any SUPPORT_FILEFORMAT_* is defined
|
||||||
// #if !defined(STBI_REQUIRED)
|
// #if !defined(STBI_REQUIRED)
|
||||||
// #pragma message ("Warning: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
// #pragma message ("WARNING: "STBI_REQUIRED is not defined, that means we can't load images from clipbard"
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
#endif // SUPPORT_CLIPBOARD_IMAGE
|
#endif // SUPPORT_CLIPBOARD_IMAGE
|
||||||
|
@ -2314,9 +2314,12 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
|
||||||
// WARNING: files.count is not reseted to 0 after unloading
|
// WARNING: files.count is not reseted to 0 after unloading
|
||||||
void UnloadDirectoryFiles(FilePathList files)
|
void UnloadDirectoryFiles(FilePathList files)
|
||||||
{
|
{
|
||||||
|
if (files.paths != NULL)
|
||||||
|
{
|
||||||
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
||||||
|
|
||||||
RL_FREE(files.paths);
|
RL_FREE(files.paths);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create directories (including full path requested), returns 0 on success
|
// Create directories (including full path requested), returns 0 on success
|
||||||
|
@ -2572,7 +2575,7 @@ char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode Base64 string data
|
// Decode Base64 string data
|
||||||
unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
unsigned char *DecodeDataBase64(const char *data, int *outputSize)
|
||||||
{
|
{
|
||||||
static const unsigned char base64decodeTable[] = {
|
static const unsigned char base64decodeTable[] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -3738,7 +3741,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const
|
||||||
// Scan all files and directories recursively from a base path
|
// Scan all files and directories recursively from a base path
|
||||||
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *files, const char *filter)
|
||||||
{
|
{
|
||||||
char path[MAX_FILEPATH_LENGTH] = { 0 };
|
static char path[MAX_FILEPATH_LENGTH] = { 0 };
|
||||||
memset(path, 0, MAX_FILEPATH_LENGTH);
|
memset(path, 0, MAX_FILEPATH_LENGTH);
|
||||||
|
|
||||||
struct dirent *dp = NULL;
|
struct dirent *dp = NULL;
|
||||||
|
|
|
@ -56,8 +56,8 @@
|
||||||
*
|
*
|
||||||
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
||||||
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||||
* #define RL_CULL_DISTANCE_NEAR 0.001 // Default projection matrix near cull distance
|
* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance
|
||||||
* #define RL_CULL_DISTANCE_FAR 10000.0 // Default projection matrix far cull distance
|
* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance
|
||||||
*
|
*
|
||||||
* When loading a shader, the following vertex attributes and uniform
|
* When loading a shader, the following vertex attributes and uniform
|
||||||
* location names are tried to be set automatically:
|
* location names are tried to be set automatically:
|
||||||
|
@ -234,10 +234,10 @@
|
||||||
|
|
||||||
// Projection matrix culling
|
// Projection matrix culling
|
||||||
#ifndef RL_CULL_DISTANCE_NEAR
|
#ifndef RL_CULL_DISTANCE_NEAR
|
||||||
#define RL_CULL_DISTANCE_NEAR 0.001 // Default near cull distance
|
#define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance
|
||||||
#endif
|
#endif
|
||||||
#ifndef RL_CULL_DISTANCE_FAR
|
#ifndef RL_CULL_DISTANCE_FAR
|
||||||
#define RL_CULL_DISTANCE_FAR 10000.0 // Default far cull distance
|
#define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Texture parameters (equivalent to OpenGL defines)
|
// Texture parameters (equivalent to OpenGL defines)
|
||||||
|
|
189
src/rmodels.c
189
src/rmodels.c
|
@ -496,12 +496,18 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
|
||||||
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
|
vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis
|
||||||
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
|
vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z };
|
||||||
|
|
||||||
|
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
|
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
|
rlNormal3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||||
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z);
|
||||||
|
|
||||||
|
rlNormal3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z);
|
||||||
|
rlNormal3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||||
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z);
|
||||||
|
rlNormal3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1423,9 +1429,13 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
|
|
||||||
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
|
rlEnableTexture(material.maps[MATERIAL_MAP_DIFFUSE].texture.id);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
if (mesh.animVertices) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animVertices);
|
||||||
|
else rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.vertices);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
rlEnableStatePointer(GL_TEXTURE_COORD_ARRAY, mesh.texcoords);
|
||||||
rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
if (mesh.normals) rlEnableStatePointer(GL_VERTEX_ARRAY, mesh.animNormals);
|
||||||
|
else rlEnableStatePointer(GL_NORMAL_ARRAY, mesh.normals);
|
||||||
|
|
||||||
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
rlEnableStatePointer(GL_COLOR_ARRAY, mesh.colors);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
|
@ -3598,16 +3608,16 @@ BoundingBox GetMeshBoundingBox(Mesh mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute mesh tangents
|
// Compute mesh tangents
|
||||||
// NOTE: To calculate mesh tangents and binormals we need mesh vertex positions and texture coordinates
|
|
||||||
// Implementation based on: https://answers.unity.com/questions/7789/calculating-tangents-vector4.html
|
|
||||||
void GenMeshTangents(Mesh *mesh)
|
void GenMeshTangents(Mesh *mesh)
|
||||||
{
|
{
|
||||||
if ((mesh->vertices == NULL) || (mesh->texcoords == NULL))
|
// Check if input mesh data is useful
|
||||||
|
if ((mesh == NULL) || (mesh->vertices == NULL) || (mesh->texcoords == NULL) || (mesh->normals == NULL))
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires texcoord vertex attribute data");
|
TRACELOG(LOG_WARNING, "MESH: Tangents generation requires vertices, texcoords and normals vertex attribute data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate or reallocate tangents data
|
||||||
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
if (mesh->tangents == NULL) mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3615,26 +3625,51 @@ void GenMeshTangents(Mesh *mesh)
|
||||||
mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
mesh->tangents = (float *)RL_MALLOC(mesh->vertexCount*4*sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 *tan1 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
// Allocate temporary arrays for tangents calculation
|
||||||
Vector3 *tan2 = (Vector3 *)RL_MALLOC(mesh->vertexCount*sizeof(Vector3));
|
Vector3 *tan1 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||||
|
Vector3 *tan2 = (Vector3 *)RL_CALLOC(mesh->vertexCount, sizeof(Vector3));
|
||||||
|
|
||||||
if (mesh->vertexCount % 3 != 0)
|
if (tan1 == NULL || tan2 == NULL)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "MESH: vertexCount expected to be a multiple of 3. Expect uninitialized values.");
|
TRACELOG(LOG_WARNING, "MESH: Failed to allocate temporary memory for tangent calculation");
|
||||||
|
if (tan1) RL_FREE(tan1);
|
||||||
|
if (tan2) RL_FREE(tan2);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i <= mesh->vertexCount - 3; i += 3)
|
// Process all triangles of the mesh
|
||||||
|
// 'triangleCount' must be always valid
|
||||||
|
for (int t = 0; t < mesh->triangleCount; t++)
|
||||||
{
|
{
|
||||||
// Get triangle vertices
|
// Get triangle vertex indices
|
||||||
Vector3 v1 = { mesh->vertices[(i + 0)*3 + 0], mesh->vertices[(i + 0)*3 + 1], mesh->vertices[(i + 0)*3 + 2] };
|
int i0, i1, i2;
|
||||||
Vector3 v2 = { mesh->vertices[(i + 1)*3 + 0], mesh->vertices[(i + 1)*3 + 1], mesh->vertices[(i + 1)*3 + 2] };
|
|
||||||
Vector3 v3 = { mesh->vertices[(i + 2)*3 + 0], mesh->vertices[(i + 2)*3 + 1], mesh->vertices[(i + 2)*3 + 2] };
|
if (mesh->indices != NULL)
|
||||||
|
{
|
||||||
|
// Use indices if available
|
||||||
|
i0 = mesh->indices[t*3 + 0];
|
||||||
|
i1 = mesh->indices[t*3 + 1];
|
||||||
|
i2 = mesh->indices[t*3 + 2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Sequential access for non-indexed mesh
|
||||||
|
i0 = t*3 + 0;
|
||||||
|
i1 = t*3 + 1;
|
||||||
|
i2 = t*3 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get triangle vertices position
|
||||||
|
Vector3 v1 = { mesh->vertices[i0*3 + 0], mesh->vertices[i0*3 + 1], mesh->vertices[i0*3 + 2] };
|
||||||
|
Vector3 v2 = { mesh->vertices[i1*3 + 0], mesh->vertices[i1*3 + 1], mesh->vertices[i1*3 + 2] };
|
||||||
|
Vector3 v3 = { mesh->vertices[i2*3 + 0], mesh->vertices[i2*3 + 1], mesh->vertices[i2*3 + 2] };
|
||||||
|
|
||||||
// Get triangle texcoords
|
// Get triangle texcoords
|
||||||
Vector2 uv1 = { mesh->texcoords[(i + 0)*2 + 0], mesh->texcoords[(i + 0)*2 + 1] };
|
Vector2 uv1 = { mesh->texcoords[i0*2 + 0], mesh->texcoords[i0*2 + 1] };
|
||||||
Vector2 uv2 = { mesh->texcoords[(i + 1)*2 + 0], mesh->texcoords[(i + 1)*2 + 1] };
|
Vector2 uv2 = { mesh->texcoords[i1*2 + 0], mesh->texcoords[i1*2 + 1] };
|
||||||
Vector2 uv3 = { mesh->texcoords[(i + 2)*2 + 0], mesh->texcoords[(i + 2)*2 + 1] };
|
Vector2 uv3 = { mesh->texcoords[i2*2 + 0], mesh->texcoords[i2*2 + 1] };
|
||||||
|
|
||||||
|
// Calculate triangle edges
|
||||||
float x1 = v2.x - v1.x;
|
float x1 = v2.x - v1.x;
|
||||||
float y1 = v2.y - v1.y;
|
float y1 = v2.y - v1.y;
|
||||||
float z1 = v2.z - v1.z;
|
float z1 = v2.z - v1.z;
|
||||||
|
@ -3642,65 +3677,95 @@ void GenMeshTangents(Mesh *mesh)
|
||||||
float y2 = v3.y - v1.y;
|
float y2 = v3.y - v1.y;
|
||||||
float z2 = v3.z - v1.z;
|
float z2 = v3.z - v1.z;
|
||||||
|
|
||||||
|
// Calculate texture coordinate differences
|
||||||
float s1 = uv2.x - uv1.x;
|
float s1 = uv2.x - uv1.x;
|
||||||
float t1 = uv2.y - uv1.y;
|
float t1 = uv2.y - uv1.y;
|
||||||
float s2 = uv3.x - uv1.x;
|
float s2 = uv3.x - uv1.x;
|
||||||
float t2 = uv3.y - uv1.y;
|
float t2 = uv3.y - uv1.y;
|
||||||
|
|
||||||
|
// Calculate denominator and check for degenerate UV
|
||||||
float div = s1*t2 - s2*t1;
|
float div = s1*t2 - s2*t1;
|
||||||
float r = (div == 0.0f)? 0.0f : 1.0f/div;
|
float r = (fabsf(div) < 0.0001f)? 0.0f : 1.0f/div;
|
||||||
|
|
||||||
|
// Calculate tangent and bitangent directions
|
||||||
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
|
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
|
||||||
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
|
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
|
||||||
|
|
||||||
tan1[i + 0] = sdir;
|
// Accumulate tangents and bitangents for each vertex of the triangle
|
||||||
tan1[i + 1] = sdir;
|
tan1[i0] = Vector3Add(tan1[i0], sdir);
|
||||||
tan1[i + 2] = sdir;
|
tan1[i1] = Vector3Add(tan1[i1], sdir);
|
||||||
|
tan1[i2] = Vector3Add(tan1[i2], sdir);
|
||||||
|
|
||||||
tan2[i + 0] = tdir;
|
tan2[i0] = Vector3Add(tan2[i0], tdir);
|
||||||
tan2[i + 1] = tdir;
|
tan2[i1] = Vector3Add(tan2[i1], tdir);
|
||||||
tan2[i + 2] = tdir;
|
tan2[i2] = Vector3Add(tan2[i2], tdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute tangents considering normals
|
// Calculate final tangents for each vertex
|
||||||
for (int i = 0; i < mesh->vertexCount; i++)
|
for (int i = 0; i < mesh->vertexCount; i++)
|
||||||
{
|
{
|
||||||
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
||||||
Vector3 tangent = tan1[i];
|
Vector3 tangent = tan1[i];
|
||||||
|
|
||||||
// TODO: Review, not sure if tangent computation is right, just used reference proposed maths...
|
// Handle zero tangent (can happen with degenerate UVs)
|
||||||
#if defined(COMPUTE_TANGENTS_METHOD_01)
|
if (Vector3Length(tangent) < 0.0001f)
|
||||||
Vector3 tmp = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
{
|
||||||
tmp = Vector3Normalize(tmp);
|
// Create a tangent perpendicular to the normal
|
||||||
mesh->tangents[i*4 + 0] = tmp.x;
|
if (fabsf(normal.z) > 0.707f) tangent = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||||
mesh->tangents[i*4 + 1] = tmp.y;
|
else tangent = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||||
mesh->tangents[i*4 + 2] = tmp.z;
|
|
||||||
mesh->tangents[i*4 + 3] = 1.0f;
|
|
||||||
#else
|
|
||||||
Vector3OrthoNormalize(&normal, &tangent);
|
|
||||||
mesh->tangents[i*4 + 0] = tangent.x;
|
mesh->tangents[i*4 + 0] = tangent.x;
|
||||||
mesh->tangents[i*4 + 1] = tangent.y;
|
mesh->tangents[i*4 + 1] = tangent.y;
|
||||||
mesh->tangents[i*4 + 2] = tangent.z;
|
mesh->tangents[i*4 + 2] = tangent.z;
|
||||||
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
mesh->tangents[i*4 + 3] = 1.0f;
|
||||||
#endif
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gram-Schmidt orthogonalization to make tangent orthogonal to normal
|
||||||
|
// T_prime = T - N * dot(N, T)
|
||||||
|
Vector3 orthogonalized = Vector3Subtract(tangent, Vector3Scale(normal, Vector3DotProduct(normal, tangent)));
|
||||||
|
|
||||||
|
// Handle cases where orthogonalized vector is too small
|
||||||
|
if (Vector3Length(orthogonalized) < 0.0001f)
|
||||||
|
{
|
||||||
|
// Create a tangent perpendicular to the normal
|
||||||
|
if (fabsf(normal.z) > 0.707f) orthogonalized = (Vector3){ 1.0f, 0.0f, 0.0f };
|
||||||
|
else orthogonalized = Vector3Normalize((Vector3){ -normal.y, normal.x, 0.0f });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Normalize the orthogonalized tangent
|
||||||
|
orthogonalized = Vector3Normalize(orthogonalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the calculated tangent
|
||||||
|
mesh->tangents[i*4 + 0] = orthogonalized.x;
|
||||||
|
mesh->tangents[i*4 + 1] = orthogonalized.y;
|
||||||
|
mesh->tangents[i*4 + 2] = orthogonalized.z;
|
||||||
|
|
||||||
|
// Calculate the handedness (w component)
|
||||||
|
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, orthogonalized), tan2[i]) < 0.0f)? -1.0f : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free temporary arrays
|
||||||
RL_FREE(tan1);
|
RL_FREE(tan1);
|
||||||
RL_FREE(tan2);
|
RL_FREE(tan2);
|
||||||
|
|
||||||
|
// Update vertex buffers if available
|
||||||
if (mesh->vboId != NULL)
|
if (mesh->vboId != NULL)
|
||||||
{
|
{
|
||||||
if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
|
if (mesh->vboId[SHADER_LOC_VERTEX_TANGENT] != 0)
|
||||||
{
|
{
|
||||||
// Update existing vertex buffer
|
// Update existing tangent vertex buffer
|
||||||
rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
|
rlUpdateVertexBuffer(mesh->vboId[SHADER_LOC_VERTEX_TANGENT], mesh->tangents, mesh->vertexCount*4*sizeof(float), 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Load a new tangent attributes buffer
|
// Create new tangent vertex buffer
|
||||||
mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
|
mesh->vboId[SHADER_LOC_VERTEX_TANGENT] = rlLoadVertexBuffer(mesh->tangents, mesh->vertexCount*4*sizeof(float), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up vertex attributes for shader
|
||||||
rlEnableVertexArray(mesh->vaoId);
|
rlEnableVertexArray(mesh->vaoId);
|
||||||
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
|
rlSetVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, 4, RL_FLOAT, 0, 0, 0);
|
||||||
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
|
rlEnableVertexAttribute(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT);
|
||||||
|
@ -5201,7 +5266,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
/*********************************************************************************************
|
/*********************************************************************************************
|
||||||
|
|
||||||
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
|
Function implemented by Wilhem Barbier(@wbrbr), with modifications by Tyler Bezera(@gamerfiend)
|
||||||
Transform handling implemented by Paul Melis (@paulmelis).
|
Transform handling implemented by Paul Melis (@paulmelis)
|
||||||
Reviewed by Ramon Santamaria (@raysan5)
|
Reviewed by Ramon Santamaria (@raysan5)
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
|
@ -5211,10 +5276,10 @@ static Model LoadGLTF(const char *fileName)
|
||||||
PBR specular/glossiness flow and extended texture flows not supported
|
PBR specular/glossiness flow and extended texture flows not supported
|
||||||
- Supports multiple meshes per model (every primitives is loaded as a separate mesh)
|
- Supports multiple meshes per model (every primitives is loaded as a separate mesh)
|
||||||
- Supports basic animations
|
- Supports basic animations
|
||||||
- Transforms, including parent-child relations, are applied on the mesh data, but the
|
- Transforms, including parent-child relations, are applied on the mesh data,
|
||||||
hierarchy is not kept (as it can't be represented).
|
but the hierarchy is not kept (as it can't be represented)
|
||||||
- Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
|
- Mesh instances in the glTF file (i.e. same mesh linked from multiple nodes)
|
||||||
are turned into separate raylib Meshes.
|
are turned into separate raylib Meshes
|
||||||
|
|
||||||
RESTRICTIONS:
|
RESTRICTIONS:
|
||||||
- Only triangle meshes supported
|
- Only triangle meshes supported
|
||||||
|
@ -5430,7 +5495,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
// Any glTF mesh linked from more than one Node (i.e. instancing)
|
||||||
// is turned into multiple Mesh's, as each Node will have its own
|
// is turned into multiple Mesh's, as each Node will have its own
|
||||||
// transform applied.
|
// transform applied.
|
||||||
// Note: the code below disregards the scenes defined in the file, all nodes are used.
|
// NOTE: The code below disregards the scenes defined in the file, all nodes are used.
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
int meshIndex = 0;
|
int meshIndex = 0;
|
||||||
for (unsigned int i = 0; i < data->nodes_count; i++)
|
for (unsigned int i = 0; i < data->nodes_count; i++)
|
||||||
|
@ -5815,15 +5880,17 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
for (unsigned int p = 0; p < mesh->primitives_count; p++)
|
||||||
{
|
{
|
||||||
|
bool hasJoints = false;
|
||||||
|
|
||||||
// NOTE: We only support primitives defined by triangles
|
// NOTE: We only support primitives defined by triangles
|
||||||
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
if (mesh->primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||||
|
|
||||||
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
for (unsigned int j = 0; j < mesh->primitives[p].attributes_count; j++)
|
||||||
{
|
{
|
||||||
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
||||||
|
|
||||||
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
if (mesh->primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
||||||
{
|
{
|
||||||
|
hasJoints = true;
|
||||||
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
cgltf_accessor *attribute = mesh->primitives[p].attributes[j].data;
|
||||||
|
|
||||||
// NOTE: JOINTS_n can only be vec4 and u8/u16
|
// NOTE: JOINTS_n can only be vec4 and u8/u16
|
||||||
|
@ -5878,7 +5945,6 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
if (attribute->type == cgltf_type_vec4)
|
if (attribute->type == cgltf_type_vec4)
|
||||||
{
|
{
|
||||||
// TODO: Support component types: u8, u16?
|
|
||||||
if (attribute->component_type == cgltf_component_type_r_8u)
|
if (attribute->component_type == cgltf_component_type_r_8u)
|
||||||
{
|
{
|
||||||
// Init raylib mesh bone weight to copy glTF attribute data
|
// Init raylib mesh bone weight to copy glTF attribute data
|
||||||
|
@ -5914,6 +5980,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
// Load 4 components of float data type into mesh.boneWeights
|
// Load 4 components of float data type into mesh.boneWeights
|
||||||
// for cgltf_attribute_type_weights we have:
|
// for cgltf_attribute_type_weights we have:
|
||||||
|
|
||||||
// - data.meshes[0] (256 vertices)
|
// - data.meshes[0] (256 vertices)
|
||||||
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
||||||
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
||||||
|
@ -5924,6 +5991,33 @@ static Model LoadGLTF(const char *fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we are animated, and the mesh was not given any bone assignments, but is the child of a bone node
|
||||||
|
// in this case we need to fully attach all the verts to the parent bone so it will animate with the bone
|
||||||
|
if (data->skins_count > 0 && !hasJoints && node->parent != NULL && node->parent->mesh == NULL)
|
||||||
|
{
|
||||||
|
int parentBoneId = -1;
|
||||||
|
for (int joint = 0; joint < model.boneCount; joint++)
|
||||||
|
{
|
||||||
|
if (data->skins[0].joints[joint] == node->parent)
|
||||||
|
{
|
||||||
|
parentBoneId = joint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentBoneId >= 0)
|
||||||
|
{
|
||||||
|
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||||
|
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
|
for (int vertexIndex = 0; vertexIndex < model.meshes[meshIndex].vertexCount*4; vertexIndex += 4)
|
||||||
|
{
|
||||||
|
model.meshes[meshIndex].boneIds[vertexIndex] = (unsigned char)parentBoneId;
|
||||||
|
model.meshes[meshIndex].boneWeights[vertexIndex] = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Animated vertex data
|
// Animated vertex data
|
||||||
model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
model.meshes[meshIndex].animVertices = RL_CALLOC(model.meshes[meshIndex].vertexCount*3, sizeof(float));
|
||||||
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
memcpy(model.meshes[meshIndex].animVertices, model.meshes[meshIndex].vertices, model.meshes[meshIndex].vertexCount*3*sizeof(float));
|
||||||
|
@ -5944,7 +6038,6 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
meshIndex++; // Move to next mesh
|
meshIndex++; // Move to next mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free all cgltf loaded data
|
// Free all cgltf loaded data
|
||||||
|
|
24
src/rtext.c
24
src/rtext.c
|
@ -161,6 +161,10 @@ extern void LoadFontDefault(void)
|
||||||
{
|
{
|
||||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||||
|
|
||||||
|
// check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
|
||||||
|
if (defaultFont.glyphs != NULL && !isGpuReady)
|
||||||
|
return;
|
||||||
|
|
||||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||||
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||||
|
|
||||||
|
@ -257,7 +261,18 @@ extern void LoadFontDefault(void)
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGpuReady) defaultFont.texture = LoadTextureFromImage(imFont);
|
if (isGpuReady)
|
||||||
|
{
|
||||||
|
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
||||||
|
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||||
|
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||||
|
if (defaultFont.glyphs != NULL)
|
||||||
|
{
|
||||||
|
UnloadImage(imFont);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -282,7 +297,7 @@ extern void LoadFontDefault(void)
|
||||||
|
|
||||||
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
|
testPosX += (int)(defaultFont.recs[i].width + (float)charsDivisor);
|
||||||
|
|
||||||
if (testPosX >= defaultFont.texture.width)
|
if (testPosX >= imFont.width)
|
||||||
{
|
{
|
||||||
currentLine++;
|
currentLine++;
|
||||||
currentPosX = 2*charsDivisor + charsWidth[i];
|
currentPosX = 2*charsDivisor + charsWidth[i];
|
||||||
|
@ -316,6 +331,9 @@ extern void UnloadFontDefault(void)
|
||||||
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
||||||
RL_FREE(defaultFont.glyphs);
|
RL_FREE(defaultFont.glyphs);
|
||||||
RL_FREE(defaultFont.recs);
|
RL_FREE(defaultFont.recs);
|
||||||
|
defaultFont.glyphCount = 0;
|
||||||
|
defaultFont.glyphs = NULL;
|
||||||
|
defaultFont.recs = NULL;
|
||||||
}
|
}
|
||||||
#endif // SUPPORT_DEFAULT_FONT
|
#endif // SUPPORT_DEFAULT_FONT
|
||||||
|
|
||||||
|
@ -1560,7 +1578,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace text string
|
// Replace text string
|
||||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
// REQUIRES: strstr(), strncpy(), strcpy()
|
||||||
// WARNING: Allocated memory must be manually freed
|
// WARNING: Allocated memory must be manually freed
|
||||||
char *TextReplace(const char *text, const char *replace, const char *by)
|
char *TextReplace(const char *text, const char *replace, const char *by)
|
||||||
{
|
{
|
||||||
|
|
|
@ -832,10 +832,11 @@ Image GenImageGradientLinear(int width, int height, int direction, Color start,
|
||||||
|
|
||||||
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
// Calculate how far the top-left pixel is along the gradient direction from the center of said gradient
|
||||||
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
|
float startingPos = 0.5f - (cosDir*width/2) - (sinDir*height/2);
|
||||||
|
|
||||||
// With directions that lie in the first or third quadrant (i.e. from top-left to
|
// With directions that lie in the first or third quadrant (i.e. from top-left to
|
||||||
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
|
// bottom-right or vice-versa), pixel (0, 0) is the farthest point on the gradient
|
||||||
// (i.e. the pixel which should become one of the gradient's ends color); while for
|
// (i.e. the pixel which should become one of the gradient's ends color); while for
|
||||||
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0).
|
// directions that lie in the second or fourth quadrant, that point is pixel (width, 0)
|
||||||
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
|
float maxPosValue = ((signbit(sinDir) != 0) == (signbit(cosDir) != 0))? fabsf(startingPos) : fabsf(startingPos + width*cosDir);
|
||||||
for (int i = 0; i < width; i++)
|
for (int i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
|
@ -3835,7 +3836,7 @@ void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c
|
||||||
|
|
||||||
// Calculate the inverse of the sum of the barycentric coordinates for normalization
|
// Calculate the inverse of the sum of the barycentric coordinates for normalization
|
||||||
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
|
// NOTE 1: Here, we act as if we multiply by 255 the reciprocal, which avoids additional
|
||||||
// calculations in the loop. This is acceptable because we are only interpolating colors.
|
// calculations in the loop. This is acceptable because we are only interpolating colors
|
||||||
// NOTE 2: This sum remains constant throughout the triangle
|
// NOTE 2: This sum remains constant throughout the triangle
|
||||||
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
|
float wInvSum = 255.0f/(w1Row + w2Row + w3Row);
|
||||||
|
|
||||||
|
|
|
@ -405,7 +405,7 @@ void UnloadFileText(char *text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save text data to file (write), string must be '\0' terminated
|
// Save text data to file (write), string must be '\0' terminated
|
||||||
bool SaveFileText(const char *fileName, char *text)
|
bool SaveFileText(const char *fileName, const char *text)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue