diff --git a/examples/Makefile b/examples/Makefile index 6f13cfd88..4e6b48955 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -118,7 +118,7 @@ ifeq ($(PLATFORM),PLATFORM_WEB) EMSDK_PATH ?= C:/emsdk EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/2.7.13.1_64bit/python-2.7.13.amd64 + PYTHON_PATH = $(EMSDK_PATH)/python/3.7.4_64bit NODE_PATH = $(EMSDK_PATH)/node/12.9.1_64bit/bin export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) endif diff --git a/examples/models/resources/shaders/glsl330/irradiance.fs b/examples/models/resources/shaders/glsl330/irradiance.fs index b42d2143e..4ef03e052 100644 --- a/examples/models/resources/shaders/glsl330/irradiance.fs +++ b/examples/models/resources/shaders/glsl330/irradiance.fs @@ -15,7 +15,7 @@ in vec3 fragPosition; uniform samplerCube environmentMap; // Constant values -const float PI = 3.14159265359f; +const float PI = 3.14159265359; // Output fragment color out vec4 finalColor; @@ -31,8 +31,8 @@ void main() vec3 right = cross(up, normal); up = cross(normal, right); - float sampleDelta = 0.025f; - float nrSamples = 0.0f; + float sampleDelta = 0.025; + float nrSamples = 0.0; for (float phi = 0.0; phi < 2.0*PI; phi += sampleDelta) { diff --git a/examples/models/resources/shaders/glsl330/pbr.vs b/examples/models/resources/shaders/glsl330/pbr.vs index 8bd3faa14..045428c68 100644 --- a/examples/models/resources/shaders/glsl330/pbr.vs +++ b/examples/models/resources/shaders/glsl330/pbr.vs @@ -34,7 +34,7 @@ void main() mat3 normalMatrix = transpose(inverse(mat3(matModel))); // Calculate fragment position based on model transformations - fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); // Send vertex attributes to fragment shader fragTexCoord = vertexTexCoord; diff --git a/examples/models/resources/shaders/glsl330/prefilter.fs b/examples/models/resources/shaders/glsl330/prefilter.fs index 9439810d7..941ea86c0 100644 --- a/examples/models/resources/shaders/glsl330/prefilter.fs +++ b/examples/models/resources/shaders/glsl330/prefilter.fs @@ -18,7 +18,7 @@ uniform samplerCube environmentMap; uniform float roughness; // Constant values -const float PI = 3.14159265359f; +const float PI = 3.14159265359; // Output fragment color out vec4 finalColor; @@ -35,7 +35,7 @@ float DistributionGGX(vec3 N, vec3 H, float roughness) float NdotH = max(dot(N, H), 0.0); float NdotH2 = NdotH*NdotH; - float nom = a2; + float nom = a2; float denom = (NdotH2*(a2 - 1.0) + 1.0); denom = PI*denom*denom; @@ -49,7 +49,7 @@ float RadicalInverse_VdC(uint bits) bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10; // / 0x100000000 + return float(bits)*2.3283064365386963e-10; // / 0x100000000 } vec2 Hammersley(uint i, uint N) @@ -60,7 +60,7 @@ vec2 Hammersley(uint i, uint N) vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) { float a = roughness*roughness; - float phi = 2.0 * PI * Xi.x; + float phi = 2.0*PI*Xi.x; float cosTheta = sqrt((1.0 - Xi.y)/(1.0 + (a*a - 1.0)*Xi.y)); float sinTheta = sqrt(1.0 - cosTheta*cosTheta); diff --git a/examples/shaders/resources/shaders/glsl100/base.fs b/examples/shaders/resources/shaders/glsl100/base.fs index b004ba0bd..c1126423a 100644 --- a/examples/shaders/resources/shaders/glsl100/base.fs +++ b/examples/shaders/resources/shaders/glsl100/base.fs @@ -11,7 +11,6 @@ uniform sampler2D texture0; uniform vec4 colDiffuse; // NOTE: Add here your custom variables -uniform vec2 resolution = vec2(800, 450); void main() { diff --git a/examples/shaders/resources/shaders/glsl100/base_lighting.vs b/examples/shaders/resources/shaders/glsl100/base_lighting.vs new file mode 100644 index 000000000..5245c6155 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/base_lighting.vs @@ -0,0 +1,59 @@ +#version 100 + +// Input vertex attributes +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; + +// Output vertex attributes (to fragment shader) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; + +// NOTE: Add here your custom variables + +// https://github.com/glslify/glsl-inverse +mat3 inverse(mat3 m) +{ + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22*a11 - a12*a21; + float b11 = -a22*a10 + a12*a20; + float b21 = a21*a10 - a11*a20; + + float det = a00*b01 + a01*b11 + a02*b21; + + return mat3(b01, (-a22*a01 + a02*a21), (a12*a01 - a02*a11), + b11, (a22*a00 - a02*a20), (-a12*a00 + a02*a10), + b21, (-a21*a00 + a01*a20), (a11*a00 - a01*a10))/det; +} + +// https://github.com/glslify/glsl-transpose +mat3 transpose(mat3 m) +{ + return mat3(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +void main() +{ + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + + mat3 normalMatrix = transpose(inverse(mat3(matModel))); + fragNormal = normalize(normalMatrix*vertexNormal); + + // Calculate final vertex position + gl_Position = mvp*vec4(vertexPosition, 1.0); +} diff --git a/examples/shaders/resources/shaders/glsl100/fog.fs b/examples/shaders/resources/shaders/glsl100/fog.fs new file mode 100644 index 000000000..eeb2150f9 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/fog.fs @@ -0,0 +1,94 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// NOTE: Add here your custom variables + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct MaterialProperty { + vec3 color; + int useSampler; + sampler2D sampler; +}; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec4 ambient; +uniform vec3 viewPos; +uniform float fogDensity; + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture2D(texture0, fragTexCoord); + vec3 lightDot = vec3(0.0); + vec3 normal = normalize(fragNormal); + vec3 viewD = normalize(viewPos - fragPosition); + vec3 specular = vec3(0.0); + + // NOTE: Implement here your fragment shader code + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + vec3 light = vec3(0.0); + + if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position); + if (lights[i].type == LIGHT_POINT) light = normalize(lights[i].position - fragPosition); + + float NdotL = max(dot(normal, light), 0.0); + lightDot += lights[i].color.rgb*NdotL; + + float specCo = 0.0; + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // Shine: 16.0 + specular += specCo; + } + } + + vec4 finalColor = (texelColor*((colDiffuse + vec4(specular,1))*vec4(lightDot, 1.0))); + finalColor += texelColor*(ambient/10.0); + + // Gamma correction + finalColor = pow(finalColor, vec4(1.0/2.2)); + + // Fog calculation + float dist = length(viewPos - fragPosition); + + // these could be parameters... + const vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0); + //const float fogDensity = 0.16; + + // Exponential fog + float fogFactor = 1.0/exp((dist*fogDensity)*(dist*fogDensity)); + + // Linear fog (less nice) + //const float fogStart = 2.0; + //const float fogEnd = 10.0; + //float fogFactor = (fogEnd - dist)/(fogEnd - fogStart); + + fogFactor = clamp(fogFactor, 0.0, 1.0); + + gl_FragColor = mix(fogColor, finalColor, fogFactor); +} diff --git a/examples/shaders/resources/shaders/glsl100/lighting.fs b/examples/shaders/resources/shaders/glsl100/lighting.fs new file mode 100644 index 000000000..5e4ff64cb --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/lighting.fs @@ -0,0 +1,81 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// NOTE: Add here your custom variables + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct MaterialProperty { + vec3 color; + int useSampler; + sampler2D sampler; +}; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec4 ambient; +uniform vec3 viewPos; + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture2D(texture0, fragTexCoord); + vec3 lightDot = vec3(0.0); + vec3 normal = normalize(fragNormal); + vec3 viewD = normalize(viewPos - fragPosition); + vec3 specular = vec3(0.0); + + // NOTE: Implement here your fragment shader code + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + vec3 light = vec3(0.0); + + if (lights[i].type == LIGHT_DIRECTIONAL) + { + light = -normalize(lights[i].target - lights[i].position); + } + + if (lights[i].type == LIGHT_POINT) + { + light = normalize(lights[i].position - fragPosition); + } + + float NdotL = max(dot(normal, light), 0.0); + lightDot += lights[i].color.rgb*NdotL; + + float specCo = 0.0; + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine + specular += specCo; + } + } + + vec4 finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); + finalColor += texelColor*(ambient/10.0); + + // Gamma correction + gl_FragColor = pow(finalColor, vec4(1.0/2.2)); +} diff --git a/examples/shaders/resources/shaders/glsl100/mask.fs b/examples/shaders/resources/shaders/glsl100/mask.fs new file mode 100644 index 000000000..207106201 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/mask.fs @@ -0,0 +1,24 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from vertex shader) +varying vec2 fragTexCoord; +varying vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform sampler2D mask; +uniform vec4 colDiffuse; +uniform int frame; + +// NOTE: Add here your custom variables + +void main() +{ + vec4 maskColour = texture2D(mask, fragTexCoord + vec2(sin(-float(frame)/150.0)/10.0, cos(-float(frame)/170.0)/10.0)); + if (maskColour.r < 0.25) discard; + vec4 texelColor = texture2D(texture0, fragTexCoord + vec2(sin(float(frame)/90.0)/8.0, cos(float(frame)/60.0)/8.0)); + + gl_FragColor = texelColor*maskColour; +} diff --git a/examples/shaders/resources/shaders/glsl330/basic_lighting.vs b/examples/shaders/resources/shaders/glsl330/base_lighting.vs similarity index 92% rename from examples/shaders/resources/shaders/glsl330/basic_lighting.vs rename to examples/shaders/resources/shaders/glsl330/base_lighting.vs index 509954ddd..f1b75d79a 100644 --- a/examples/shaders/resources/shaders/glsl330/basic_lighting.vs +++ b/examples/shaders/resources/shaders/glsl330/base_lighting.vs @@ -21,7 +21,7 @@ out vec3 fragNormal; void main() { // Send vertex attributes to fragment shader - fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); fragTexCoord = vertexTexCoord; fragColor = vertexColor; diff --git a/examples/shaders/resources/shaders/glsl330/fog.fs b/examples/shaders/resources/shaders/glsl330/fog.fs index 57ed14807..2160f31bb 100644 --- a/examples/shaders/resources/shaders/glsl330/fog.fs +++ b/examples/shaders/resources/shaders/glsl330/fog.fs @@ -55,25 +55,21 @@ void main() if (lights[i].enabled == 1) { vec3 light = vec3(0.0); - if (lights[i].type == LIGHT_DIRECTIONAL) { - light = -normalize(lights[i].target - lights[i].position); - } - if (lights[i].type == LIGHT_POINT) { - light = normalize(lights[i].position - fragPosition); - } + + if (lights[i].type == LIGHT_DIRECTIONAL) light = -normalize(lights[i].target - lights[i].position); + if (lights[i].type == LIGHT_POINT) light = normalize(lights[i].position - fragPosition); + float NdotL = max(dot(normal, light), 0.0); - lightDot += lights[i].color.rgb * NdotL; + lightDot += lights[i].color.rgb*NdotL; float specCo = 0.0; - if(NdotL > 0.0) - specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16);//16 =shine + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // Shine: 16.0 specular += specCo; - } } - finalColor = (texelColor * ((colDiffuse+vec4(specular,1)) * vec4(lightDot, 1.0))); - finalColor += texelColor * (ambient/10.0); + finalColor = (texelColor*((colDiffuse + vec4(specular,1))*vec4(lightDot, 1.0))); + finalColor += texelColor*(ambient/10.0); // Gamma correction finalColor = pow(finalColor, vec4(1.0/2.2)); diff --git a/examples/shaders/resources/shaders/glsl330/fog.vs b/examples/shaders/resources/shaders/glsl330/fog.vs deleted file mode 100644 index 00779cfa3..000000000 --- a/examples/shaders/resources/shaders/glsl330/fog.vs +++ /dev/null @@ -1,32 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; -in vec3 vertexNormal; -in vec4 vertexColor; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; - -// Output vertex attributes (to fragment shader) -out vec2 fragTexCoord; -out vec4 fragColor; -out vec3 fragPosition; -out vec3 fragNormal; - -// NOTE: Add here your custom variables - -void main() -{ - // Send vertex attributes to fragment shader - fragTexCoord = vertexTexCoord; - fragColor = vertexColor; - fragPosition = vec3(matModel*vec4(vertexPosition, 1.0f)); - mat3 normalMatrix = transpose(inverse(mat3(matModel))); - fragNormal = normalize(normalMatrix*vertexNormal); - - // Calculate final vertex position - gl_Position = mvp*vec4(vertexPosition, 1.0); -} diff --git a/examples/shaders/resources/shaders/glsl330/basic_lighting.fs b/examples/shaders/resources/shaders/glsl330/lighting.fs similarity index 97% rename from examples/shaders/resources/shaders/glsl330/basic_lighting.fs rename to examples/shaders/resources/shaders/glsl330/lighting.fs index 50b41f09f..33fa8f9ab 100644 --- a/examples/shaders/resources/shaders/glsl330/basic_lighting.fs +++ b/examples/shaders/resources/shaders/glsl330/lighting.fs @@ -69,7 +69,7 @@ void main() lightDot += lights[i].color.rgb*NdotL; float specCo = 0.0; - if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16); // 16 refers to shine + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine specular += specCo; } } diff --git a/examples/shaders/resources/shaders/glsl330/mask.fs b/examples/shaders/resources/shaders/glsl330/mask.fs index a06279096..a93bed07e 100644 --- a/examples/shaders/resources/shaders/glsl330/mask.fs +++ b/examples/shaders/resources/shaders/glsl330/mask.fs @@ -2,6 +2,7 @@ // Input vertex attributes (from vertex shader) in vec2 fragTexCoord; +in vec4 fragColor; // Input uniform values uniform sampler2D texture0; @@ -13,9 +14,9 @@ out vec4 finalColor; void main() { - vec4 maskColour = texture(mask, fragTexCoord+vec2(sin(-frame/150.0)/10.0,cos(-frame/170.0)/10.0)); + vec4 maskColour = texture(mask, fragTexCoord + vec2(sin(-frame/150.0)/10.0, cos(-frame/170.0)/10.0)); if (maskColour.r < 0.25) discard; - vec4 texelColor = texture(texture0, fragTexCoord+vec2(sin(frame/90.0)/8.0,cos(frame/60.0)/8.0)); + vec4 texelColor = texture(texture0, fragTexCoord + vec2(sin(frame/90.0)/8.0, cos(frame/60.0)/8.0)); - finalColor = texelColor * maskColour; + finalColor = texelColor*maskColour; } diff --git a/examples/shaders/resources/shaders/glsl330/mask.vs b/examples/shaders/resources/shaders/glsl330/mask.vs deleted file mode 100644 index 66a151617..000000000 --- a/examples/shaders/resources/shaders/glsl330/mask.vs +++ /dev/null @@ -1,21 +0,0 @@ -#version 330 - -// Input vertex attributes -in vec3 vertexPosition; -in vec2 vertexTexCoord; - -// Input uniform values -uniform mat4 mvp; -uniform mat4 matModel; - -// Output vertex attributes (to fragment shader) -out vec2 fragTexCoord; - -void main() -{ - // Send vertex attributes to fragment shader - fragTexCoord = vertexTexCoord; - - // Calculate final vertex position - gl_Position = mvp*vec4(vertexPosition, 1.0); -} diff --git a/examples/shaders/rlights.h b/examples/shaders/rlights.h index b564efc3c..0441062b6 100644 --- a/examples/shaders/rlights.h +++ b/examples/shaders/rlights.h @@ -68,17 +68,11 @@ typedef enum { extern "C" { // Prevents name mangling of functions #endif -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -int lightsCount = 0; // Current amount of created lights - //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader); // Create a light and get shader locations void UpdateLightValues(Shader shader, Light light); // Send light properties to shader -//void InitLightLocations(Shader shader, Light *light); // Init light shader locations #ifdef __cplusplus } @@ -110,7 +104,7 @@ void UpdateLightValues(Shader shader, Light light); // Send light proper //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -// ... +static int lightsCount = 0; // Current amount of created lights //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -142,6 +136,8 @@ Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shade char posName[32] = "lights[x].position\0"; char targetName[32] = "lights[x].target\0"; char colorName[32] = "lights[x].color\0"; + + // Set location name [x] depending on lights count enabledName[7] = '0' + lightsCount; typeName[7] = '0' + lightsCount; posName[7] = '0' + lightsCount; diff --git a/examples/shaders/shaders_basic_lighting.c b/examples/shaders/shaders_basic_lighting.c index 74bf27759..21883efab 100644 --- a/examples/shaders/shaders_basic_lighting.c +++ b/examples/shaders/shaders_basic_lighting.c @@ -69,8 +69,8 @@ int main(void) modelB.materials[0].maps[MAP_DIFFUSE].texture = texture; modelC.materials[0].maps[MAP_DIFFUSE].texture = texture; - Shader shader = LoadShader("resources/shaders/glsl330/basic_lighting.vs", - "resources/shaders/glsl330/basic_lighting.fs"); + Shader shader = LoadShader(FormatText("resources/shaders/glsl%i/base_lighting.vs", GLSL_VERSION), + FormatText("resources/shaders/glsl%i/lighting.fs", GLSL_VERSION)); // Get some shader loactions shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel"); @@ -112,7 +112,7 @@ int main(void) UpdateCamera(&camera); // Update camera // Make the lights do differing orbits - angle -= 0.02; + angle -= 0.02f; lights[0].position.x = cosf(angle)*4.0f; lights[0].position.z = sinf(angle)*4.0f; lights[1].position.x = cosf(-angle*0.6f)*4.0f; @@ -128,8 +128,8 @@ int main(void) UpdateLightValues(shader, lights[3]); // Rotate the torus - modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025)); - modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012)); + modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateX(-0.025f)); + modelA.transform = MatrixMultiply(modelA.transform, MatrixRotateZ(0.012f)); // Update the light shader with the camera view position float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; @@ -161,7 +161,7 @@ int main(void) DrawFPS(10, 10); - DrawText("Keys RGB & W toggle lights", 10, 30, 20, DARKGRAY); + DrawText("Use keys RGBW to toggle lights", 10, 30, 20, DARKGRAY); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/shaders/shaders_fog.c b/examples/shaders/shaders_fog.c index e8f2691d2..53fd94073 100644 --- a/examples/shaders/shaders_fog.c +++ b/examples/shaders/shaders_fog.c @@ -32,6 +32,12 @@ #define RLIGHTS_IMPLEMENTATION #include "rlights.h" +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + int main(void) { // Initialization @@ -61,7 +67,8 @@ int main(void) modelC.materials[0].maps[MAP_DIFFUSE].texture = texture; // Load shader and set up some uniforms - Shader shader = LoadShader("resources/shaders/glsl330/fog.vs", "resources/shaders/glsl330/fog.fs"); + Shader shader = LoadShader(FormatText("resources/shaders/glsl%i/base_lighting.vs", GLSL_VERSION), + FormatText("resources/shaders/glsl%i/fog.fs", GLSL_VERSION)); shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel"); shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos"); diff --git a/examples/shaders/shaders_simple_mask.c b/examples/shaders/shaders_simple_mask.c index c8762be3a..88163b34b 100644 --- a/examples/shaders/shaders_simple_mask.c +++ b/examples/shaders/shaders_simple_mask.c @@ -21,6 +21,12 @@ #include "raylib.h" #include "raymath.h" +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + int main(void) { // Initialization @@ -50,8 +56,8 @@ int main(void) Model model3 = LoadModelFromMesh(sphere); // Load the shader - Shader shader = LoadShader("resources/shaders/glsl330/mask.vs", "resources/shaders/glsl330/mask.fs"); - + Shader shader = LoadShader(0, FormatText("resources/shaders/glsl%i/mask.fs", GLSL_VERSION)); + // Load and apply the diffuse texture (colour map) Texture texDiffuse = LoadTexture("resources/plasma.png"); model1.materials[0].maps[MAP_DIFFUSE].texture = texDiffuse; @@ -66,7 +72,7 @@ int main(void) shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(shader, "mask"); // Frame is incremented each frame to animate the shader - int shaderFrame = GetShaderLocation(shader, "framesCounter"); + int shaderFrame = GetShaderLocation(shader, "frame"); // Apply the shader to the two models model1.materials[0].shader = shader; diff --git a/examples/textures/textures_mouse_painting.c b/examples/textures/textures_mouse_painting.c index 0149176c5..dedb8df35 100644 --- a/examples/textures/textures_mouse_painting.c +++ b/examples/textures/textures_mouse_painting.c @@ -106,7 +106,7 @@ int main(void) EndTextureMode(); } - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || (GetGestureDetected() == GESTURE_DRAG)) { // Paint circle into render texture // NOTE: To avoid discontinuous circles, we could store @@ -166,7 +166,7 @@ int main(void) // Draw drawing circle for reference if (mousePos.y > 50) { - if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, colors[colorSelected]); + if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) DrawCircleLines(mousePos.x, mousePos.y, brushSize, GRAY); else DrawCircle(GetMouseX(), GetMouseY(), brushSize, colors[colorSelected]); } @@ -194,7 +194,7 @@ int main(void) DrawRectangle(0, 150, GetScreenWidth(), 80, BLACK); DrawText("IMAGE SAVED: my_amazing_texture_painting.png", 150, 180, 20, RAYWHITE); } - + EndDrawing(); //---------------------------------------------------------------------------------- } diff --git a/src/core.c b/src/core.c index b1eaf0f96..421451583 100644 --- a/src/core.c +++ b/src/core.c @@ -398,18 +398,18 @@ typedef struct CoreData { #if defined(PLATFORM_WEB) bool cursorLockRequired; // Ask for cursor pointer lock on next click #endif -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) || defined(PLATFORM_UWP) char currentButtonState[3]; // Registers current mouse button state char previousButtonState[3]; // Registers previous mouse button state int currentWheelMove; // Registers current mouse wheel variation int previousWheelMove; // Registers previous mouse wheel variation -#endif #if defined(PLATFORM_RPI) char currentButtonStateEvdev[3]; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update) #endif } Mouse; struct { - Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen + Vector2 position[MAX_TOUCH_POINTS]; // Touch position on screen + char currentTouchState[MAX_TOUCH_POINTS]; // Registers current touch state + char previousTouchState[MAX_TOUCH_POINTS]; // Registers previous touch state } Touch; struct { int lastButtonPressed; // Register last gamepad button pressed @@ -445,7 +445,7 @@ typedef struct CoreData { //---------------------------------------------------------------------------------- static CoreData CORE = { 0 }; // Global CORE context -static char **dirFilesPath; // Store directory files paths as strings +static char **dirFilesPath = NULL; // Store directory files paths as strings static int dirFilesCount = 0; // Count directory files strings #if defined(SUPPORT_SCREEN_CAPTURE) @@ -477,8 +477,6 @@ static void SwapBuffers(void); // Copy back buffer to f static void InitTimer(void); // Initialize timer static void Wait(float ms); // Wait for some milliseconds (stop program execution) -static bool GetKeyStatus(int key); // Returns if a key has been pressed -static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed static int GetGamepadButton(int button); // Get gamepad button generic to all platforms static int GetGamepadAxis(int axis); // Get gamepad axis generic to all platforms static void PollInputEvents(void); // Register user events @@ -1718,8 +1716,8 @@ Color ColorFromNormalized(Vector4 normalized) // NOTE: Hue is returned as degrees [0..360] Vector3 ColorToHSV(Color color) { + Vector3 hsv = { 0 }; Vector3 rgb = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - Vector3 hsv = { 0.0f, 0.0f, 0.0f }; float min, max, delta; min = rgb.x < rgb.y? rgb.x : rgb.y; @@ -2306,7 +2304,7 @@ bool IsKeyPressed(int key) { bool pressed = false; - if ((CORE.Input.Keyboard.currentKeyState[key] != CORE.Input.Keyboard.previousKeyState[key]) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true; + if ((CORE.Input.Keyboard.previousKeyState[key] == 0) && (CORE.Input.Keyboard.currentKeyState[key] == 1)) pressed = true; else pressed = false; return pressed; @@ -2315,7 +2313,7 @@ bool IsKeyPressed(int key) // Detect if a key is being pressed (key held down) bool IsKeyDown(int key) { - if (GetKeyStatus(key) == 1) return true; + if (CORE.Input.Keyboard.currentKeyState[key] == 1) return true; else return false; } @@ -2324,7 +2322,7 @@ bool IsKeyReleased(int key) { bool released = false; - if ((CORE.Input.Keyboard.currentKeyState[key] != CORE.Input.Keyboard.previousKeyState[key]) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true; + if ((CORE.Input.Keyboard.previousKeyState[key] == 1) && (CORE.Input.Keyboard.currentKeyState[key] == 0)) released = true; else released = false; return released; @@ -2333,7 +2331,7 @@ bool IsKeyReleased(int key) // Detect if a key is NOT being pressed (key not held down) bool IsKeyUp(int key) { - if (GetKeyStatus(key) == 0) return true; + if (CORE.Input.Keyboard.currentKeyState[key] == 0) return true; else return false; } @@ -2502,9 +2500,10 @@ bool IsMouseButtonPressed(int button) #if defined(PLATFORM_ANDROID) if (IsGestureDetected(GESTURE_TAP)) pressed = true; #else - // NOTE: On PLATFORM_DESKTOP and PLATFORM_WEB IsMouseButtonPressed() is equivalent to GESTURE_TAP - if ((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) && - (GetMouseButtonStatus(button) == 1)) pressed = true; + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) pressed = true; + + // Map touches to mouse buttons checking + if ((CORE.Input.Touch.currentTouchState[button] == 1) && (CORE.Input.Touch.previousTouchState[button] == 0)) pressed = true; #endif return pressed; @@ -2518,9 +2517,10 @@ bool IsMouseButtonDown(int button) #if defined(PLATFORM_ANDROID) if (IsGestureDetected(GESTURE_HOLD)) down = true; #else - // NOTE: On PLATFORM_DESKTOP and PLATFORM_WEB IsMouseButtonDown() is equivalent to GESTURE_HOLD or GESTURE_DRAG - if (GetMouseButtonStatus(button) == 1) down = true; - // || IsGestureDetected(GESTURE_HOLD) || IsGestureDetected(GESTURE_DRAG)) down = true; + if (CORE.Input.Mouse.currentButtonState[button] == 1) down = true; + + // Map touches to mouse buttons checking + if (CORE.Input.Touch.currentTouchState[button] == 1) down = true; #endif return down; @@ -2532,12 +2532,14 @@ bool IsMouseButtonReleased(int button) bool released = false; #if defined(PLATFORM_ANDROID) - # if defined(SUPPORT_GESTURES_SYSTEM) - released = GetGestureDetected() == GESTURE_TAP; - # endif + #if defined(SUPPORT_GESTURES_SYSTEM) + released = GetGestureDetected() == GESTURE_TAP; + #endif #else - if ((CORE.Input.Mouse.currentButtonState[button] != CORE.Input.Mouse.previousButtonState[button]) && - (GetMouseButtonStatus(button) == 0)) released = true; + if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) released = true; + + // Map touches to mouse buttons checking + if ((CORE.Input.Touch.currentTouchState[button] == 0) && (CORE.Input.Touch.previousTouchState[button] == 1)) released = true; #endif return released; @@ -2549,7 +2551,10 @@ bool IsMouseButtonUp(int button) bool up = false; #if !defined(PLATFORM_ANDROID) - if (GetMouseButtonStatus(button) == 0) up = true; + if (CORE.Input.Mouse.currentButtonState[button] == 0) up = true; + + // Map touches to mouse buttons checking + if (CORE.Input.Touch.currentTouchState[button] == 0) up = true; #endif return up; @@ -2578,12 +2583,13 @@ int GetMouseY(void) // Returns mouse position XY Vector2 GetMousePosition(void) { - Vector2 position = { 0.0f, 0.0f }; + Vector2 position = { 0 }; #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) position = GetTouchPosition(0); #else - position = (Vector2){ (CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x, (CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y }; + position.x = (CORE.Input.Mouse.position.x + CORE.Input.Mouse.offset.x)*CORE.Input.Mouse.scale.x; + position.y = (CORE.Input.Mouse.position.y + CORE.Input.Mouse.offset.y)*CORE.Input.Mouse.scale.y; #endif return position; @@ -2682,7 +2688,6 @@ Vector2 GetTouchPosition(int index) // TODO: GLFW is not supporting multi-touch input just yet // https://www.codeproject.com/Articles/668404/Programming-for-Multi-Touch // https://docs.microsoft.com/en-us/windows/win32/wintouch/getting-started-with-multi-touch-messages - if (index == 0) position = GetMousePosition(); #endif @@ -3452,36 +3457,6 @@ static void Wait(float ms) #endif } -// Get one key state -static bool GetKeyStatus(int key) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetKey(CORE.Window.handle, key); -#elif defined(PLATFORM_ANDROID) - // NOTE: Android supports up to 260 keys - if (key < 0 || key > 260) return false; - else return CORE.Input.Keyboard.currentKeyState[key]; -#elif defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - // NOTE: Keys states are filled in PollInputEvents() - if (key < 0 || key > 511) return false; - else return CORE.Input.Keyboard.currentKeyState[key]; -#endif -} - -// Get one mouse button state -static bool GetMouseButtonStatus(int button) -{ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - return glfwGetMouseButton(CORE.Window.handle, button); -#elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual mouse? - return false; -#elif defined(PLATFORM_RPI) || defined(PLATFORM_UWP) - // NOTE: Mouse buttons states are filled in PollInputEvents() - return CORE.Input.Mouse.currentButtonState[button]; -#endif -} - // Get gamepad button generic to all platforms static int GetGamepadButton(int button) { @@ -3595,7 +3570,7 @@ static void PollInputEvents(void) #if defined(PLATFORM_RPI) // Register previous keys states - for (int i = 0; i < 512; i++)CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; // Grab a keypress from the evdev fifo if avalable if (CORE.Input.Keyboard.lastKeyPressed.head != CORE.Input.Keyboard.lastKeyPressed.tail) @@ -3631,6 +3606,7 @@ static void PollInputEvents(void) // Register previous mouse states CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; CORE.Input.Mouse.currentWheelMove = 0; + for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; // Loop over pending messages @@ -3771,16 +3747,7 @@ static void PollInputEvents(void) #endif // PLATFORM_UWP #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - // Mouse input polling - double mouseX; - double mouseY; - - glfwGetCursorPos(CORE.Window.handle, &mouseX, &mouseY); - - CORE.Input.Mouse.position.x = (float)mouseX; - CORE.Input.Mouse.position.y = (float)mouseY; - - // Keyboard input polling (automatically managed by GLFW3 through callback) + // Keyboard/Mouse input polling (automatically managed by GLFW3 through callback) // Register previous keys states for (int i = 0; i < 512; i++) CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; @@ -3788,8 +3755,12 @@ static void PollInputEvents(void) // Register previous mouse states for (int i = 0; i < 3; i++) CORE.Input.Mouse.previousButtonState[i] = CORE.Input.Mouse.currentButtonState[i]; + // Register previous mouse wheel state CORE.Input.Mouse.previousWheelMove = CORE.Input.Mouse.currentWheelMove; CORE.Input.Mouse.currentWheelMove = 0; + + // Register previous touch states + for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; #endif #if defined(PLATFORM_DESKTOP) @@ -4015,23 +3986,30 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i } #endif // SUPPORT_SCREEN_CAPTURE } - else CORE.Input.Keyboard.currentKeyState[key] = action; + else + { + // WARNING: GLFW could return GLFW_REPEAT, we need to consider it as 1 + // to work properly with our implementation (IsKeyDown/IsKeyUp checks) + if (action == GLFW_RELEASE) CORE.Input.Keyboard.currentKeyState[key] = 0; + else CORE.Input.Keyboard.currentKeyState[key] = 1; + } } // GLFW3 Mouse Button Callback, runs on mouse button pressed static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { - CORE.Input.Mouse.previousButtonState[button] = CORE.Input.Mouse.currentButtonState[button]; + // WARNING: GLFW could only return GLFW_PRESS (1) or GLFW_RELEASE (0) for now, + // but future releases may add more actions (i.e. GLFW_REPEAT) CORE.Input.Mouse.currentButtonState[button] = action; - + #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // Process mouse events as touches to be able to use mouse-gestures GestureEvent gestureEvent = { 0 }; // Register touch actions - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP; - + if ((CORE.Input.Mouse.currentButtonState[button] == 1) && (CORE.Input.Mouse.previousButtonState[button] == 0)) gestureEvent.touchAction = TOUCH_DOWN; + else if ((CORE.Input.Mouse.currentButtonState[button] == 0) && (CORE.Input.Mouse.previousButtonState[button] == 1)) gestureEvent.touchAction = TOUCH_UP; + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() // Assign a pointer ID @@ -4055,6 +4033,10 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // GLFW3 Cursor Position Callback, runs on mouse move static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) { + CORE.Input.Mouse.position.x = (float)x; + CORE.Input.Mouse.position.y = (float)y; + CORE.Input.Touch.position[0] = CORE.Input.Mouse.position; + #if defined(SUPPORT_GESTURES_SYSTEM) && defined(SUPPORT_MOUSE_GESTURES) // Process mouse events as touches to be able to use mouse-gestures GestureEvent gestureEvent = { 0 }; @@ -4068,9 +4050,7 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) gestureEvent.pointCount = 1; // Register touch points position, only one point registered - gestureEvent.position[0] = (Vector2){ (float)x, (float)y }; - - CORE.Input.Touch.position[0] = gestureEvent.position[0]; + gestureEvent.position[0] = CORE.Input.Touch.position[0]; // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height gestureEvent.position[0].x /= (float)GetScreenWidth(); @@ -4274,7 +4254,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) int32_t keycode = AKeyEvent_getKeyCode(event); if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN) { - CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down + CORE.Input.Keyboard.currentKeyState[keycode] = 1; // Key down CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; CORE.Input.Keyboard.keyPressedQueueCount++; @@ -4388,8 +4368,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) CORE.Input.Touch.position[0].x = 0; CORE.Input.Touch.position[0].y = 0; } - else // TODO:Not sure what else should be handled - return 0; + else return 0; // TODO: Not sure what else should be handled #if defined(SUPPORT_GESTURES_SYSTEM) GestureEvent gestureEvent = { 0 }; @@ -4496,6 +4475,12 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent // Register touch input events static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData) { + for (int i = 0; i < touchEvent->numTouches; i++) + { + if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) CORE.Input.Touch.currentTouchState[i] = 1; + else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) CORE.Input.Touch.currentTouchState[i] = 0; + } + #if defined(SUPPORT_GESTURES_SYSTEM) GestureEvent gestureEvent = { 0 }; @@ -4638,7 +4623,7 @@ static void ProcessKeyboard(void) // Reset pressed keys array (it will be filled below) for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = 0; - + // Check keys from event input workers (This is the new keyboard reading method) //for (int i = 0; i < 512; i++) CORE.Input.Keyboard.currentKeyState[i] = CORE.Input.Keyboard.currentKeyStateEvdev[i]; diff --git a/src/raylib.h b/src/raylib.h index 48728fc17..0c15849ef 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -156,6 +156,7 @@ #define FormatText TextFormat #define SubText TextSubtext #define ShowWindow UnhideWindow +#define LoadText LoadFileText //---------------------------------------------------------------------------------- // Structures Definition @@ -951,6 +952,8 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r // Files management functions RLAPI unsigned char *LoadFileData(const char *fileName, int *bytesRead); // Load file data as byte array (read) RLAPI void SaveFileData(const char *fileName, void *data, int bytesToWrite); // Save data to file from byte array (write) +RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string +RLAPI void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists @@ -1322,9 +1325,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); //------------------------------------------------------------------------------------ // Shader loading/unloading functions -RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetShaderDefault(void); // Get default shader diff --git a/src/raymath.h b/src/raymath.h index c2dbc61e4..b30a5cfa5 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -268,6 +268,14 @@ RMDEF Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) return result; } +// Rotate Vector by float in Degrees. +RMDEF Vector2 Vector2Rotate(Vector2 v, float degs) +{ + float rads = degs*DEG2RAD; + Vector2 result = {v.x * cosf(rads) - v.y * sinf(rads) , v.x * sinf(rads) + v.y * cosf(rads) }; + return result; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Vector3 math //---------------------------------------------------------------------------------- diff --git a/src/rlgl.h b/src/rlgl.h index 536f8103e..c90905dc5 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -546,9 +546,8 @@ RLAPI void rlUnloadMesh(Mesh mesh); // Unl // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ // Shader loading/unloading functions -RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetShaderDefault(void); // Get default shader @@ -588,6 +587,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR exp RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +RLAPI char *LoadFileText(const char *fileName); // Load chars array from text file RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture) #endif @@ -605,22 +605,20 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data #if defined(RLGL_IMPLEMENTATION) -#if !defined(RLGL_STANDALONE) +#if defined(RLGL_STANDALONE) + #include // Required for: fopen(), fseek(), fread(), fclose() [LoadFileText] +#else // Check if config flags have been externally provided on compilation line #if !defined(EXTERNAL_CONFIG_FLAGS) #include "config.h" // Defines module configuration flags #endif + #include "raymath.h" // Required for: Vector3 and Matrix functions #endif #include // Required for: malloc(), free() -#include // Required for: fopen(), fseek(), fread(), fclose() [LoadText] #include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] #include // Required for: atan2f(), fabs() -#if !defined(RLGL_STANDALONE) - #include "raymath.h" // Required for: Vector3 and Matrix functions -#endif - #if defined(GRAPHICS_API_OPENGL_11) #if defined(__APPLE__) #include // OpenGL 1.1 library for OSX @@ -2984,49 +2982,6 @@ Shader GetShaderDefault(void) #endif } -// Load text data from file -// NOTE: text chars array should be freed manually -char *LoadText(const char *fileName) -{ - char *text = NULL; - - if (fileName != NULL) - { - FILE *textFile = fopen(fileName, "rt"); - - if (textFile != NULL) - { - // WARNING: When reading a file as 'text' file, - // text mode causes carriage return-linefeed translation... - // ...but using fseek() should return correct byte-offset - fseek(textFile, 0, SEEK_END); - int size = ftell(textFile); - fseek(textFile, 0, SEEK_SET); - - if (size > 0) - { - text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); - int count = fread(text, sizeof(char), size, textFile); - - // WARNING: \r\n is converted to \n on reading, so, - // read bytes count gets reduced by the number of lines - if (count < size) - { - text = RL_REALLOC(text, count + 1); - } - - // zero-terminate the string - text[count] = '\0'; - } - - fclose(textFile); - } - else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); - } - - return text; -} - // Load shader from files and bind default locations // NOTE: If shader string is NULL, using default vertex/fragment shaders Shader LoadShader(const char *vsFileName, const char *fsFileName) @@ -3038,8 +2993,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName) char *vShaderStr = NULL; char *fShaderStr = NULL; - if (vsFileName != NULL) vShaderStr = LoadText(vsFileName); - if (fsFileName != NULL) fShaderStr = LoadText(fsFileName); + if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName); + if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName); shader = LoadShaderCode(vShaderStr, fShaderStr); @@ -4643,6 +4598,50 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) #endif #if defined(RLGL_STANDALONE) +// Load text data from file, returns a '\0' terminated string +// NOTE: text chars array should be freed manually +char *LoadFileText(const char *fileName) +{ + char *text = NULL; + + if (fileName != NULL) + { + FILE *textFile = fopen(fileName, "rt"); + + if (textFile != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(textFile, 0, SEEK_END); + int size = ftell(textFile); + fseek(textFile, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); + int count = fread(text, sizeof(char), size, textFile); + + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < size) text = RL_REALLOC(text, count + 1); + + // Zero-terminate the string + text[count] = '\0'; + + TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName); + + fclose(textFile); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); + + return text; +} + // Get pixel data size in bytes (image or texture) // NOTE: Size depends on pixel format int GetPixelDataSize(int width, int height, int format) diff --git a/src/shell.html b/src/shell.html index 507b35acf..92556f83c 100644 --- a/src/shell.html +++ b/src/shell.html @@ -173,8 +173,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB
Downloading...
- - + +
@@ -305,7 +305,7 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB construct(target, args) { const result = new target(...args); audioContexList.push(result); - if (result.state == "suspended") audioBtn.value = "🔈 RESUME"; + if (result.state == "suspended") audioBtn.value = "AUDIO ON"; return result; } }); @@ -318,8 +318,8 @@ jwE50AGjLCVuS8Yt4H7OgZLKK5EKOsLviEWJSL/+0uMi7gLUSBseYwqEbXvSHCec1CJvZPyHCmYQffaB else if (ctx.state == "running") ctx.suspend(); }); - if (resumed) audioBtn.value = "🔇 SUSPEND"; - else audioBtn.value = "🔈 RESUME"; + if (resumed) audioBtn.value = "AUDIO OFF"; + else audioBtn.value = "AUDIO ON"; } {{{ SCRIPT }}} diff --git a/src/textures.c b/src/textures.c index 98b060d7b..1814b203c 100644 --- a/src/textures.c +++ b/src/textures.c @@ -73,7 +73,7 @@ #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 // Required for: rlLoadTexture() rlDeleteTextures(), - // rlGenerateMipmaps(), some funcs for DrawTexturePro() + // rlGenerateMipmaps(), some funcs for DrawTexturePro() // Support only desired texture formats on stb_image #if !defined(SUPPORT_FILEFORMAT_BMP) diff --git a/src/utils.c b/src/utils.c index 9aaf548b4..34369744f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -169,32 +169,36 @@ unsigned char *LoadFileData(const char *fileName, int *bytesRead) unsigned char *data = NULL; *bytesRead = 0; - FILE *file = fopen(fileName, "rb"); - - if (file != NULL) + if (fileName != NULL) { - // WARNING: On binary streams SEEK_END could not be found, - // using fseek() and ftell() could not work in some (rare) cases - fseek(file, 0, SEEK_END); - int size = ftell(file); - fseek(file, 0, SEEK_SET); + FILE *file = fopen(fileName, "rb"); - if (size > 0) + if (file != NULL) { - data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size); + // WARNING: On binary streams SEEK_END could not be found, + // using fseek() and ftell() could not work in some (rare) cases + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, 0, SEEK_SET); - // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] - int count = fread(data, sizeof(unsigned char), size, file); - *bytesRead = count; + if (size > 0) + { + data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size); - if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName); - else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName); + // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] + int count = fread(data, sizeof(unsigned char), size, file); + *bytesRead = count; + + if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName); + else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName); + + fclose(file); } - else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName); - - fclose(file); + else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); } - else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); + else TRACELOG(LOG_WARNING, "File name provided is not valid"); return data; } @@ -202,18 +206,88 @@ unsigned char *LoadFileData(const char *fileName, int *bytesRead) // Save data to file from buffer void SaveFileData(const char *fileName, void *data, int bytesToWrite) { - FILE *file = fopen(fileName, "wb"); - - if (file != NULL) + if (fileName != NULL) { - int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file); + FILE *file = fopen(fileName, "wb"); - if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName); - else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName); + if (file != NULL) + { + int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file); - fclose(file); + if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName); + else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName); + else TRACELOG(LOG_INFO, "[%s] File successfully saved", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); } - else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); + else TRACELOG(LOG_WARNING, "File name provided is not valid"); +} + +// Load text data from file, returns a '\0' terminated string +// NOTE: text chars array should be freed manually +char *LoadFileText(const char *fileName) +{ + char *text = NULL; + + if (fileName != NULL) + { + FILE *textFile = fopen(fileName, "rt"); + + if (textFile != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(textFile, 0, SEEK_END); + int size = ftell(textFile); + fseek(textFile, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); + int count = fread(text, sizeof(char), size, textFile); + + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < size) text = RL_REALLOC(text, count + 1); + + // Zero-terminate the string + text[count] = '\0'; + + TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName); + + fclose(textFile); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); + + return text; +} + +// Save text data to file (write), string must be '\0' terminated +void SaveFileText(const char *fileName, char *text) +{ + if (fileName != NULL) + { + FILE *file = fopen(fileName, "wt"); + + if (file != NULL) + { + int count = fprintf(file, "%s", text); + + if (count == 0) TRACELOG(LOG_WARNING, "[%s] Text file could not be written", fileName); + else TRACELOG(LOG_INFO, "[%s] Text file successfully saved", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); } #if defined(PLATFORM_ANDROID)