Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop

This commit is contained in:
Joshua Reisenauer 2016-05-22 15:03:10 -07:00
commit f232f34981
56 changed files with 1652 additions and 1167 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ src_android/obj/
templates/android_project/bin/ templates/android_project/bin/
templates/android_project/obj/ templates/android_project/obj/
templates/android_project/libs/ templates/android_project/libs/
local.properties
# Ignore thumbnails created by windows # Ignore thumbnails created by windows
Thumbs.db Thumbs.db

View File

@ -36,7 +36,8 @@ int main()
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
if (IsGamepadAvailable(GAMEPAD_PLAYER1)) if (IsGamepadAvailable(GAMEPAD_PLAYER1))
{ {
gamepadMovement = GetGamepadMovement(GAMEPAD_PLAYER1); gamepadMovement.x = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_X);
gamepadMovement.y = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_Y);
ballPosition.x += gamepadMovement.x; ballPosition.x += gamepadMovement.x;
ballPosition.y -= gamepadMovement.y; ballPosition.y -= gamepadMovement.y;

View File

@ -30,26 +30,26 @@ int main()
bool isDebug = false; bool isDebug = false;
// Create rectangle physic object // Create rectangle physic object
PhysicObject *rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 }); PhysicObject rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 });
rectangle->rigidbody.enabled = true; // Enable physic object rigidbody behaviour rectangle->rigidbody.enabled = true; // Enable physic object rigidbody behaviour
rectangle->rigidbody.applyGravity = true; rectangle->rigidbody.applyGravity = true;
rectangle->rigidbody.friction = 0.1f; rectangle->rigidbody.friction = 0.1f;
rectangle->rigidbody.bounciness = 6.0f; rectangle->rigidbody.bounciness = 6.0f;
// Create square physic object // Create square physic object
PhysicObject *square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 }); PhysicObject square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 });
square->rigidbody.enabled = true; // Enable physic object rigidbody behaviour square->rigidbody.enabled = true; // Enable physic object rigidbody behaviour
square->rigidbody.applyGravity = true; square->rigidbody.applyGravity = true;
square->rigidbody.friction = 0.1f; square->rigidbody.friction = 0.1f;
// Create walls physic objects // Create walls physic objects
PhysicObject *floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 }); PhysicObject floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
PhysicObject *leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight }); PhysicObject leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight }); PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
PhysicObject *roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 }); PhysicObject roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
// Create pplatform physic object // Create pplatform physic object
PhysicObject *platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 }); PhysicObject platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 });
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
@ -114,7 +114,8 @@ int main()
// De-Initialization // De-Initialization
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------
ClosePhysics(); // Unitialize physics module ClosePhysics(); // Unitialize physics (including all loaded objects)
CloseWindow(); // Close window and OpenGL context CloseWindow(); // Close window and OpenGL context
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -17,7 +17,7 @@
#define LINE_LENGTH 75 #define LINE_LENGTH 75
#define TRIANGLE_LENGTH 12 #define TRIANGLE_LENGTH 12
void DrawRigidbodyCircle(PhysicObject *obj, Color color); void DrawRigidbodyCircle(PhysicObject obj, Color color);
int main() int main()
{ {
@ -36,7 +36,7 @@ int main()
bool isDebug = false; bool isDebug = false;
// Create rectangle physic objects // Create rectangle physic objects
PhysicObject *rectangles[3]; PhysicObject rectangles[3];
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
rectangles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/3) : (screenHeight/1.5f)) }, 0.0f, (Vector2){ 50, 50 }); rectangles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/3) : (screenHeight/1.5f)) }, 0.0f, (Vector2){ 50, 50 });
@ -46,7 +46,7 @@ int main()
// Create circles physic objects // Create circles physic objects
// NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle. // NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle.
PhysicObject *circles[3]; PhysicObject circles[3];
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
circles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/1.5f) : (screenHeight/4)) }, 0.0f, (Vector2){ 0, 0 }); circles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/1.5f) : (screenHeight/4)) }, 0.0f, (Vector2){ 0, 0 });
@ -57,10 +57,10 @@ int main()
} }
// Create walls physic objects // Create walls physic objects
PhysicObject *leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight }); PhysicObject leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight }); PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
PhysicObject *topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 }); PhysicObject topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
PhysicObject *bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 }); PhysicObject bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
//-------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------

View File

@ -33,5 +33,5 @@ void main()
else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor; else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
else tc = sum*sum*0.0075 + texelColor; else tc = sum*sum*0.0075 + texelColor;
finalColor = tc; gl_FragColor = tc;
} }

View File

@ -20,7 +20,7 @@ float angle = 0.8;
uniform vec2 center = vec2(200.0, 200.0); uniform vec2 center = vec2(200.0, 200.0);
void main (void) void main()
{ {
vec2 texSize = vec2(renderWidth, renderHeight); vec2 texSize = vec2(renderWidth, renderHeight);
vec2 tc = fragTexCoord*texSize; vec2 tc = fragTexCoord*texSize;

View File

@ -17,7 +17,7 @@ void main()
{ {
vec4 sum = vec4(0); vec4 sum = vec4(0);
vec4 tc = vec4(0); vec4 tc = vec4(0);
for (int i = -4; i < 4; i++) for (int i = -4; i < 4; i++)
{ {
for (int j = -3; j < 3; j++) for (int j = -3; j < 3; j++)

View File

@ -1,82 +0,0 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec3 fragNormal;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
// Light uniform values
uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
uniform float lightIntensity = 1.0;
uniform float lightSpecIntensity = 1.0;
// Material uniform values
uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
uniform float matGlossiness = 50.0;
// World uniform values
uniform vec3 lightPosition;
uniform vec3 cameraPosition;
// Calculate ambient lighting component
vec3 AmbientLighting()
{
return (matAmbientColor*lightAmbientColor);
}
// Calculate diffuse lighting component
vec3 DiffuseLighting(in vec3 N, in vec3 L)
{
// Lambertian reflection calculation
float diffuse = clamp(dot(N, L), 0, 1);
return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
}
// Calculate specular lighting component
vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
{
float specular = 0.0;
// Calculate specular reflection only if the surface is oriented to the light source
if (dot(N, L) > 0)
{
// Calculate half vector
vec3 H = normalize(L + V);
// Calculate specular intensity
specular = pow(dot(N, H), 3 + matGlossiness);
}
return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
}
void main()
{
// Normalize input vectors
vec3 L = normalize(lightPosition);
vec3 V = normalize(cameraPosition);
vec3 N = normalize(fragNormal);
// Calculate lighting components
vec3 ambient = AmbientLighting();
vec3 diffuse = DiffuseLighting(N, L);
vec3 specular = SpecularLighting(N, L, V);
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
// Calculate final fragment color
finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
}

View File

@ -1,29 +0,0 @@
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
// Input uniform values
uniform mat4 mvpMatrix;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec3 fragNormal;
// NOTE: Add here your custom variables
uniform mat4 modelMatrix;
void main()
{
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
// Calculate view vector normal from model
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
fragNormal = normalize(normalMatrix*vertexNormal);
// Calculate final vertex position
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
}

View File

@ -21,7 +21,7 @@ float angle = 0.8;
uniform vec2 center = vec2(200.0, 200.0); uniform vec2 center = vec2(200.0, 200.0);
void main (void) void main()
{ {
vec2 texSize = vec2(renderWidth, renderHeight); vec2 texSize = vec2(renderWidth, renderHeight);
vec2 tc = fragTexCoord*texSize; vec2 tc = fragTexCoord*texSize;

View File

@ -0,0 +1,136 @@
#version 330
in vec3 fragPosition;
in vec2 fragTexCoord;
in vec4 fragColor;
in vec3 fragNormal;
out vec4 finalColor;
uniform sampler2D texture0;
uniform vec4 colAmbient;
uniform vec4 colDiffuse;
uniform vec4 colSpecular;
uniform float glossiness;
uniform mat4 modelMatrix;
uniform vec3 viewDir;
struct Light {
int enabled;
int type;
vec3 position;
vec3 direction;
vec4 diffuse;
float intensity;
float attenuation;
float coneAngle;
};
const int maxLights = 8;
uniform int lightsCount;
uniform Light lights[maxLights];
vec3 CalcPointLight(Light l, vec3 n, vec3 v)
{
vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
vec3 surfaceToLight = l.position - surfacePos;
// Diffuse shading
float brightness = clamp(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n)), 0, 1);
float diff = 1.0/dot(surfaceToLight/l.attenuation, surfaceToLight/l.attenuation)*brightness*l.intensity;
// Specular shading
float spec = 0.0;
if (diff > 0.0)
{
vec3 h = normalize(-l.direction + v);
spec = pow(dot(n, h), 3 + glossiness);
}
return (diff*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
}
vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v)
{
vec3 lightDir = normalize(-l.direction);
// Diffuse shading
float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
// Specular shading
float spec = 0.0;
if (diff > 0.0)
{
vec3 h = normalize(lightDir + v);
spec = pow(dot(n, h), 3 + glossiness);
}
// Combine results
return (diff*l.intensity*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
}
vec3 CalcSpotLight(Light l, vec3 n, vec3 v)
{
vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
vec3 lightToSurface = normalize(surfacePos - l.position);
vec3 lightDir = normalize(-l.direction);
// Diffuse shading
float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
// Spot attenuation
float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0);
attenuation = dot(lightToSurface, -lightDir);
float lightToSurfaceAngle = degrees(acos(attenuation));
if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;
float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;
// Combine diffuse and attenuation
float diffAttenuation = diff*attenuation;
// Specular shading
float spec = 0.0;
if (diffAttenuation > 0.0)
{
vec3 h = normalize(lightDir + v);
spec = pow(dot(n, h), 3 + glossiness);
}
return falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb);
}
void main()
{
// Calculate fragment normal in screen space
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
vec3 normal = normalize(normalMatrix*fragNormal);
// Normalize normal and view direction vectors
vec3 n = normalize(normal);
vec3 v = normalize(viewDir);
// Calculate diffuse texture color fetching
vec4 texelColor = texture(texture0, fragTexCoord);
vec3 lighting = colAmbient.rgb;
for (int i = 0; i < lightsCount; i++)
{
// Check if light is enabled
if (lights[i].enabled == 1)
{
// Calculate lighting based on light type
switch (lights[i].type)
{
case 0: lighting += CalcPointLight(lights[i], n, v); break;
case 1: lighting += CalcDirectionalLight(lights[i], n, v); break;
case 2: lighting += CalcSpotLight(lights[i], n, v); break;
default: break;
}
}
}
// Calculate final fragment color
finalColor = vec4(texelColor.rgb*lighting, texelColor.a);
}

View File

@ -0,0 +1,23 @@
#version 330
in vec3 vertexPosition;
in vec3 vertexNormal;
in vec2 vertexTexCoord;
in vec4 vertexColor;
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec4 fragColor;
out vec3 fragNormal;
uniform mat4 mvpMatrix;
void main()
{
fragPosition = vertexPosition;
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
fragNormal = vertexNormal;
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
}

View File

@ -1,171 +0,0 @@
/*******************************************************************************************
*
* raylib [shaders] example - Basic lighting: Blinn-Phong
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2014 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#define SHININESS_SPEED 1.0f
#define LIGHT_SPEED 0.25f
// Light type
typedef struct Light {
Vector3 position;
Vector3 direction;
float intensity;
float specIntensity;
Color diffuse;
Color ambient;
Color specular;
} Light;
int main()
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
// Camera initialization
Camera camera = {{ 8.0f, 8.0f, 8.0f }, { 0.0f, 3.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
// Model initialization
Vector3 position = { 0.0f, 0.0f, 0.0f };
Model model = LoadModel("resources/model/dwarf.obj");
Shader shader = LoadShader("resources/shaders/glsl330/phong.vs", "resources/shaders/glsl330/phong.fs");
SetModelShader(&model, shader);
// Shader locations initialization
int lIntensityLoc = GetShaderLocation(shader, "lightIntensity");
int lAmbientLoc = GetShaderLocation(shader, "lightAmbientColor");
int lDiffuseLoc = GetShaderLocation(shader, "lightDiffuseColor");
int lSpecularLoc = GetShaderLocation(shader, "lightSpecularColor");
int lSpecIntensityLoc = GetShaderLocation(shader, "lightSpecIntensity");
int mAmbientLoc = GetShaderLocation(shader, "matAmbientColor");
int mSpecularLoc = GetShaderLocation(shader, "matSpecularColor");
int mGlossLoc = GetShaderLocation(shader, "matGlossiness");
// Camera and light vectors shader locations
int cameraLoc = GetShaderLocation(shader, "cameraPosition");
int lightLoc = GetShaderLocation(shader, "lightPosition");
// Model and View matrix locations (required for lighting)
int modelLoc = GetShaderLocation(shader, "modelMatrix");
//int viewLoc = GetShaderLocation(shader, "viewMatrix"); // Not used
// Light and material definitions
Light light;
Material matBlinn;
// Light initialization
light.position = (Vector3){ 4.0f, 2.0f, 0.0f };
light.direction = (Vector3){ 5.0f, 1.0f, 1.0f };
light.intensity = 1.0f;
light.diffuse = WHITE;
light.ambient = (Color){ 150, 75, 0, 255 };
light.specular = WHITE;
light.specIntensity = 1.0f;
// Material initialization
matBlinn.colDiffuse = WHITE;
matBlinn.colAmbient = (Color){ 50, 50, 50, 255 };
matBlinn.colSpecular = WHITE;
matBlinn.glossiness = 50.0f;
// Setup camera
SetCameraMode(CAMERA_FREE); // Set camera mode
SetCameraPosition(camera.position); // Set internal camera position to match our camera position
SetCameraTarget(camera.target); // Set internal camera target to match our camera target
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera); // Update camera position
// NOTE: Model transform can be set in model.transform or directly with params at draw... WATCH OUT!
SetShaderValueMatrix(shader, modelLoc, model.transform); // Send model matrix to shader
//SetShaderValueMatrix(shader, viewLoc, GetCameraMatrix(camera)); // Not used
// Glossiness input control
if(IsKeyDown(KEY_UP)) matBlinn.glossiness += SHININESS_SPEED;
else if(IsKeyDown(KEY_DOWN))
{
matBlinn.glossiness -= SHININESS_SPEED;
if( matBlinn.glossiness < 0) matBlinn.glossiness = 0.0f;
}
// Light X movement
if (IsKeyDown(KEY_D)) light.position.x += LIGHT_SPEED;
else if(IsKeyDown(KEY_A)) light.position.x -= LIGHT_SPEED;
// Light Y movement
if (IsKeyDown(KEY_LEFT_SHIFT)) light.position.y += LIGHT_SPEED;
else if (IsKeyDown(KEY_LEFT_CONTROL)) light.position.y -= LIGHT_SPEED;
// Light Z movement
if (IsKeyDown(KEY_S)) light.position.z += LIGHT_SPEED;
else if (IsKeyDown(KEY_W)) light.position.z -= LIGHT_SPEED;
// Send light values to shader
SetShaderValue(shader, lIntensityLoc, &light.intensity, 1);
SetShaderValue(shader, lAmbientLoc, ColorToFloat(light.ambient), 3);
SetShaderValue(shader, lDiffuseLoc, ColorToFloat(light.diffuse), 3);
SetShaderValue(shader, lSpecularLoc, ColorToFloat(light.specular), 3);
SetShaderValue(shader, lSpecIntensityLoc, &light.specIntensity, 1);
// Send material values to shader
SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.colAmbient), 3);
SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.colSpecular), 3);
SetShaderValue(shader, mGlossLoc, &matBlinn.glossiness, 1);
// Send camera and light transform values to shader
SetShaderValue(shader, cameraLoc, VectorToFloat(camera.position), 3);
SetShaderValue(shader, lightLoc, VectorToFloat(light.position), 3);
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
Begin3dMode(camera);
DrawModel(model, position, 4.0f, matBlinn.colDiffuse);
DrawSphere(light.position, 0.5f, GOLD);
DrawGrid(20, 1.0f);
End3dMode();
DrawFPS(10, 10); // Draw FPS
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
UnloadModel(model);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -0,0 +1,118 @@
/*******************************************************************************************
*
* raylib [shaders] example - Standard lighting (materials and lights)
*
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
*
* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
* on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
* raylib comes with shaders ready for both versions, check raylib/shaders install folder
*
* This example has been created using raylib 1.3 (www.raylib.com)
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
* Copyright (c) 2016 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include "raymath.h"
int main()
{
// Initialization
//--------------------------------------------------------------------------------------
int screenWidth = 800;
int screenHeight = 450;
SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available)
InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader");
// Define the camera to look into our 3d world
Camera camera = {{ 4.0f, 4.0f, 4.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position
Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model
Texture2D texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture
Material material = LoadStandardMaterial();
material.texDiffuse = texDiffuse;
material.colDiffuse = (Color){255, 255, 255, 255};
material.colAmbient = (Color){0, 0, 10, 255};
material.colSpecular = (Color){255, 255, 255, 255};
material.glossiness = 50.0f;
dwarf.material = material; // Apply material to model
Light spotLight = CreateLight(LIGHT_SPOT, (Vector3){3.0f, 5.0f, 2.0f}, (Color){255, 255, 255, 255});
spotLight->target = (Vector3){0.0f, 0.0f, 0.0f};
spotLight->intensity = 2.0f;
spotLight->diffuse = (Color){255, 100, 100, 255};
spotLight->coneAngle = 60.0f;
Light dirLight = CreateLight(LIGHT_DIRECTIONAL, (Vector3){0.0f, -3.0f, -3.0f}, (Color){255, 255, 255, 255});
dirLight->target = (Vector3){1.0f, -2.0f, -2.0f};
dirLight->intensity = 2.0f;
dirLight->diffuse = (Color){100, 255, 100, 255};
Light pointLight = CreateLight(LIGHT_POINT, (Vector3){0.0f, 4.0f, 5.0f}, (Color){255, 255, 255, 255});
pointLight->intensity = 2.0f;
pointLight->diffuse = (Color){100, 100, 255, 255};
pointLight->attenuation = 3.0f;
// Setup orbital camera
SetCameraMode(CAMERA_ORBITAL); // Set a orbital camera mode
SetCameraPosition(camera.position); // Set internal camera position to match our camera position
SetCameraTarget(camera.target); // Set internal camera target to match our camera target
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
UpdateCamera(&camera); // Update internal camera and our camera
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
Begin3dMode(camera);
DrawModel(dwarf, position, 2.0f, WHITE); // Draw 3d model with texture
DrawLights(); // Draw all created lights in 3D world
DrawGrid(10, 1.0f); // Draw a grid
End3dMode();
DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, GRAY);
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadMaterial(material); // Unload material and assigned textures
UnloadModel(dwarf); // Unload model
// Destroy all created lights
DestroyLight(pointLight);
DestroyLight(dirLight);
DestroyLight(spotLight);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

View File

@ -1,20 +1,26 @@
#version 100 #version 100
// Input vertex attributes
attribute vec3 vertexPosition; attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord; attribute vec2 vertexTexCoord;
attribute vec3 vertexNormal; attribute vec3 vertexNormal;
attribute vec4 vertexColor;
varying vec2 fragTexCoord; // Input uniform values
uniform mat4 mvpMatrix; uniform mat4 mvpMatrix;
// Output vertex attributes (to fragment shader)
varying vec2 fragTexCoord;
varying vec4 fragColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
{ {
vec3 normal = vertexNormal; // Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord; fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
// Calculate final vertex position
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
} }

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -22,21 +25,13 @@ void main()
} }
} }
if (texture2D(texture0, fragTexCoord).r < 0.3) // Texel color fetching from texture sampler
{ vec4 texelColor = texture(texture0, fragTexCoord);
tc = sum*sum*0.012 + texture2D(texture0, fragTexCoord);
} // Calculate final fragment color
else if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
{ else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
if (texture2D(texture0, fragTexCoord).r < 0.5) else tc = sum*sum*0.0075 + texelColor;
{
tc = sum*sum*0.009 + texture2D(texture0, fragTexCoord);
}
else
{
tc = sum*sum*0.0075 + texture2D(texture0, fragTexCoord);
}
}
gl_FragColor = tc; gl_FragColor = tc;
} }

View File

@ -2,7 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -16,6 +20,7 @@ float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );
void main() void main()
{ {
// Texel color fetching from texture sampler
vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0]; vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0];
for (int i = 1; i < 3; i++) for (int i = 1; i < 3; i++)

View File

@ -2,12 +2,15 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
float hatchOffsetY = 5.0f; float hatchOffsetY = 5.0f;
float lumThreshold01 = 0.9f; float lumThreshold01 = 0.9f;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -46,7 +49,7 @@ vec4 PostFX(sampler2D tex, vec2 uv)
return c; return c;
} }
void main(void) void main()
{ {
vec3 tc = PostFX(texture0, fragTexCoord).rgb; vec3 tc = PostFX(texture0, fragTexCoord).rgb;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;

View File

@ -2,12 +2,15 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float PI = 3.1415926535; const float PI = 3.1415926535;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -11,10 +14,12 @@ uniform vec4 fragTintColor;
void main() void main()
{ {
vec4 base = texture2D(texture0, fragTexCoord)*fragTintColor; // Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
// Convert to grayscale using NTSC conversion weights // Convert texel color to grayscale using NTSC conversion weights
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114)); float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(gray, gray, gray, fragTintColor.a); // Calculate final fragment color
gl_FragColor = vec4(gray, gray, gray, texelColor.a);
} }

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -14,7 +17,7 @@ float frequency = 720/3.0;
uniform float time; uniform float time;
void main (void) void main()
{ {
/* /*
// Scanlines method 1 // Scanlines method 1

View File

@ -2,28 +2,32 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float renderWidth = 1280; const float renderWidth = 800.0; // HARDCODED for example!
const float renderHeight = 720; const float renderHeight = 480.0; // Use uniforms instead...
float radius = 250.0; float radius = 250.0;
float angle = 0.8; float angle = 0.8;
uniform vec2 center = vec2(200, 200); uniform vec2 center = vec2(200.0, 200.0);
void main (void) void main()
{ {
vec2 texSize = vec2(renderWidth, renderHeight); vec2 texSize = vec2(renderWidth, renderHeight);
vec2 tc = fragTexCoord*texSize; vec2 tc = fragTexCoord*texSize;
tc -= center; tc -= center;
float dist = length(tc);
float dist = length(tc);
if (dist < radius) if (dist < radius)
{ {
float percent = (radius - dist)/radius; float percent = (radius - dist)/radius;
@ -33,7 +37,7 @@ void main (void)
tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c))); tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
} }
tc += center; tc += center;
vec3 color = texture2D(texture0, tc/texSize).rgb; vec3 color = texture2D(texture0, tc/texSize).rgb;

View File

@ -2,8 +2,11 @@
precision mediump float; precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec2 fragTexCoord; varying vec2 fragTexCoord;
varying vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
@ -11,6 +14,7 @@ uniform vec4 fragTintColor;
void main() void main()
{ {
// Texel color fetching from texture sampler
vec4 texelColor = texture2D(texture0, fragTexCoord); vec4 texelColor = texture2D(texture0, fragTexCoord);
// NOTE: Implement here your fragment shader code // NOTE: Implement here your fragment shader code

View File

@ -1,18 +1,26 @@
#version 330 #version 330
// Input vertex attributes
in vec3 vertexPosition; in vec3 vertexPosition;
in vec2 vertexTexCoord; in vec2 vertexTexCoord;
in vec3 vertexNormal; in vec3 vertexNormal;
in vec4 vertexColor;
out vec2 fragTexCoord; // Input uniform values
uniform mat4 mvpMatrix; uniform mat4 mvpMatrix;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
{ {
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord; fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
// Calculate final vertex position
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
} }

View File

@ -1,12 +1,16 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
@ -18,25 +22,17 @@ void main()
{ {
for (int j = -3; j < 3; j++) for (int j = -3; j < 3; j++)
{ {
sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004) * 0.25; sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004)*0.25;
} }
} }
if (texture(texture0, fragTexCoord).r < 0.3) // Texel color fetching from texture sampler
{ vec4 texelColor = texture(texture0, fragTexCoord);
tc = sum*sum*0.012 + texture(texture0, fragTexCoord);
}
else
{
if (texture(texture0, fragTexCoord).r < 0.5)
{
tc = sum*sum*0.009 + texture(texture0, fragTexCoord);
}
else
{
tc = sum*sum*0.0075 + texture(texture0, fragTexCoord);
}
}
fragColor = tc; // Calculate final fragment color
if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
else tc = sum*sum*0.0075 + texelColor;
finalColor = tc;
} }

View File

@ -1,12 +1,16 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float renderWidth = 1280.0; const float renderWidth = 1280.0;
@ -17,13 +21,14 @@ float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
void main() void main()
{ {
vec3 tc = texture(texture0, fragTexCoord).rgb*weight[0]; // Texel color fetching from texture sampler
vec3 texelColor = texture(texture0, fragTexCoord).rgb*weight[0];
for (int i = 1; i < 3; i++) for (int i = 1; i < 3; i++)
{ {
tc += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i]; texelColor += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
tc += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i]; texelColor += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
} }
fragColor = vec4(tc, 1.0); finalColor = vec4(texelColor, 1.0);
} }

View File

@ -1,13 +1,17 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// NOTE: Add here your custom variables // Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
float hatchOffsetY = 5.0; float hatchOffsetY = 5.0;
float lumThreshold01 = 0.9; float lumThreshold01 = 0.9;
@ -27,18 +31,18 @@ void main()
if (lum < lumThreshold02) if (lum < lumThreshold02)
{ {
if (mod(gl_FragCoord .x - gl_FragCoord .y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0); if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
} }
if (lum < lumThreshold03) if (lum < lumThreshold03)
{ {
if (mod(gl_FragCoord .x + gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0); if (mod(gl_FragCoord.x + gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
} }
if (lum < lumThreshold04) if (lum < lumThreshold04)
{ {
if (mod(gl_FragCoord .x - gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0); if (mod(gl_FragCoord.x - gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
} }
fragColor = vec4(tc, 1.0); finalColor = vec4(tc, 1.0);
} }

View File

@ -1,12 +1,16 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float renderWidth = 1280.0; const float renderWidth = 1280.0;
@ -46,9 +50,9 @@ vec4 PostFX(sampler2D tex, vec2 uv)
return c; return c;
} }
void main(void) void main()
{ {
vec3 tc = PostFX(texture0, fragTexCoord).rgb; vec3 tc = PostFX(texture0, fragTexCoord).rgb;
fragColor = vec4(tc, 1.0); finalColor = vec4(tc, 1.0);
} }

27
shaders/glsl330/depth.fs Normal file
View File

@ -0,0 +1,27 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0; // Depth texture
uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
void main()
{
float zNear = 0.01; // camera z near
float zFar = 10.0; // camera z far
float z = texture(texture0, fragTexCoord).x;
// Linearize depth value
float depth = (2.0*zNear)/(zFar + zNear - z*(zFar - zNear));
// Calculate final fragment color
finalColor = vec4(depth, depth, depth, 1.0f);
}

View File

@ -1,20 +1,26 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
{ {
vec4 base = texture(texture0, fragTexCoord)*fragTintColor; // Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
// Convert to grayscale using NTSC conversion weights // Convert texel color to grayscale using NTSC conversion weights
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114)); float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
fragColor = vec4(gray, gray, gray, fragTintColor.a); // Calculate final fragment color
finalColor = vec4(gray, gray, gray, texelColor.a);
} }

View File

@ -1,76 +1,85 @@
#version 330 #version 330
// Vertex shader input data // Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec3 fragNormal; in vec3 fragNormal;
// Diffuse data // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Light attributes // Output fragment color
uniform vec3 light_ambientColor = vec3(0.6, 0.3, 0); out vec4 finalColor;
uniform vec3 light_diffuseColor = vec3(1, 0.5, 0);
uniform vec3 light_specularColor = vec3(0, 1, 0);
uniform float light_intensity = 1;
uniform float light_specIntensity = 1;
// Material attributes // NOTE: Add here your custom variables
uniform vec3 mat_ambientColor = vec3(1, 1, 1);
uniform vec3 mat_specularColor = vec3(1, 1, 1);
uniform float mat_glossiness = 50;
// World attributes // Light uniform values
uniform vec3 lightPos; uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
uniform vec3 cameraPos; uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
uniform float lightIntensity = 1.0;
uniform float lightSpecIntensity = 1.0;
// Material uniform values
uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
uniform float matGlossiness = 50.0;
// World uniform values
uniform vec3 lightPosition;
uniform vec3 cameraPosition;
// Fragment shader output data // Fragment shader output data
out vec4 fragColor; out vec4 fragColor;
// Calculate ambient lighting component
vec3 AmbientLighting() vec3 AmbientLighting()
{ {
return mat_ambientColor * light_ambientColor; return (matAmbientColor*lightAmbientColor);
} }
// Calculate diffuse lighting component
vec3 DiffuseLighting(in vec3 N, in vec3 L) vec3 DiffuseLighting(in vec3 N, in vec3 L)
{ {
// Lambertian reflection calculation // Lambertian reflection calculation
float diffuse = clamp(dot(N, L), 0, 1); float diffuse = clamp(dot(N, L), 0, 1);
return tintColor.xyz * light_diffuseColor * light_intensity * diffuse; return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
} }
// Calculate specular lighting component
vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V) vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
{ {
float specular = 0; float specular = 0.0;
// Calculate specular reflection only if the surface is oriented to the light source // Calculate specular reflection only if the surface is oriented to the light source
if(dot(N, L) > 0) if (dot(N, L) > 0)
{ {
// Calculate half vector // Calculate half vector
vec3 H = normalize(L + V); vec3 H = normalize(L + V);
// Calculate specular intensity // Calculate specular intensity
specular = pow(dot(N, H), 3 + mat_glossiness); specular = pow(dot(N, H), 3 + matGlossiness);
} }
return mat_specularColor * light_specularColor * light_specIntensity * specular; return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
} }
void main() void main()
{ {
// Normalize input vectors // Normalize input vectors
vec3 L = normalize(lightPos); vec3 L = normalize(lightPosition);
vec3 V = normalize(cameraPos); vec3 V = normalize(cameraPosition);
vec3 N = normalize(fragNormal); vec3 N = normalize(fragNormal);
// Calculate lighting components
vec3 ambient = AmbientLighting(); vec3 ambient = AmbientLighting();
vec3 diffuse = DiffuseLighting(N, L); vec3 diffuse = DiffuseLighting(N, L);
vec3 specular = SpecularLighting(N, L, V); vec3 specular = SpecularLighting(N, L, V);
// Get base color from texture // Texel color fetching from texture sampler
vec4 textureColor = texture(texture0, fragTexCoord); vec4 texelColor = texture(texture0, fragTexCoord);
vec3 finalColor = textureColor.rgb;
// Calculate final fragment color
fragColor = vec4(finalColor * (ambient + diffuse + specular), textureColor.a); finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
} }

View File

@ -1,23 +1,25 @@
#version 330 #version 330
// Vertex input data // Input vertex attributes
in vec3 vertexPosition; in vec3 vertexPosition;
in vec2 vertexTexCoord; in vec2 vertexTexCoord;
in vec3 vertexNormal; in vec3 vertexNormal;
// Projection and model data // Input uniform values
uniform mat4 mvpMatrix; uniform mat4 mvpMatrix;
uniform mat4 modelMatrix;
// Attributes to fragment shader // Output vertex attributes (to fragment shader)
out vec2 fragTexCoord; out vec2 fragTexCoord;
out vec3 fragNormal; out vec3 fragNormal;
// NOTE: Add here your custom variables
uniform mat4 modelMatrix;
void main() void main()
{ {
// Send texture coord to fragment shader // Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord; fragTexCoord = vertexTexCoord;
// Calculate view vector normal from model // Calculate view vector normal from model
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
fragNormal = normalize(normalMatrix*vertexNormal); fragNormal = normalize(normalMatrix*vertexNormal);

View File

@ -1,13 +1,17 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// NOTE: Add here your custom variables // Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
const float renderWidth = 1280.0; const float renderWidth = 1280.0;
const float renderHeight = 720.0; const float renderHeight = 720.0;
@ -24,5 +28,5 @@ void main()
vec3 tc = texture(texture0, coord).rgb; vec3 tc = texture(texture0, coord).rgb;
fragColor = vec4(tc, 1.0); finalColor = vec4(tc, 1.0);
} }

View File

@ -1,12 +1,16 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
float gamma = 0.6; float gamma = 0.6;
@ -14,13 +18,14 @@ float numColors = 8.0;
void main() void main()
{ {
vec3 color = texture(texture0, fragTexCoord.xy).rgb; // Texel color fetching from texture sampler
vec3 texelColor = texture(texture0, fragTexCoord.xy).rgb;
color = pow(color, vec3(gamma, gamma, gamma)); texelColor = pow(texelColor, vec3(gamma, gamma, gamma));
color = color*numColors; texelColor = texelColor*numColors;
color = floor(color); texelColor = floor(texelColor);
color = color/numColors; texelColor = texelColor/numColors;
color = pow(color, vec3(1.0/gamma)); texelColor = pow(texelColor, vec3(1.0/gamma));
fragColor = vec4(color, 1.0); finalColor = vec4(texelColor, 1.0);
} }

View File

@ -1,27 +1,32 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
{ {
vec3 color = texture(texture0, fragTexCoord).rgb; // Texel color fetching from texture sampler
vec3 texelColor = texture(texture0, fragTexCoord).rgb;
vec3 colors[3]; vec3 colors[3];
colors[0] = vec3(0.0, 0.0, 1.0); colors[0] = vec3(0.0, 0.0, 1.0);
colors[1] = vec3(1.0, 1.0, 0.0); colors[1] = vec3(1.0, 1.0, 0.0);
colors[2] = vec3(1.0, 0.0, 0.0); colors[2] = vec3(1.0, 0.0, 0.0);
float lum = (color.r + color.g + color.b)/3.0; float lum = (texelColor.r + texelColor.g + texelColor.b)/3.0;
int ix = (lum < 0.5)? 0:1; int ix = (lum < 0.5)? 0:1;
vec3 tc = mix(colors[ix], colors[ix + 1], (lum - float(ix)*0.5)/0.5); vec3 tc = mix(colors[ix], colors[ix + 1], (lum - float(ix)*0.5)/0.5);
fragColor = vec4(tc, 1.0); finalColor = vec4(tc, 1.0);
} }

View File

@ -1,12 +1,16 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
float offset = 0.0; float offset = 0.0;
@ -14,7 +18,7 @@ float frequency = 720.0/3.0;
uniform float time; uniform float time;
void main (void) void main()
{ {
/* /*
// Scanlines method 1 // Scanlines method 1
@ -35,7 +39,8 @@ void main (void)
float globalPos = (fragTexCoord.y + offset) * frequency; float globalPos = (fragTexCoord.y + offset) * frequency;
float wavePos = cos((fract(globalPos) - 0.5)*3.14); float wavePos = cos((fract(globalPos) - 0.5)*3.14);
vec4 color = texture(texture0, fragTexCoord); // Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
fragColor = mix(vec4(0.0, 0.3, 0.0, 0.0), color, wavePos); finalColor = mix(vec4(0.0, 0.3, 0.0, 0.0), texelColor, wavePos);
} }

View File

@ -1,27 +1,32 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
const float renderWidth = 1280.0; const float renderWidth = 800.0; // HARDCODED for example!
const float renderHeight = 720.0; const float renderHeight = 480.0; // Use uniforms instead...
float radius = 250.0; float radius = 250.0;
float angle = 0.8; float angle = 0.8;
uniform vec2 center = vec2(200.0, 200.0); uniform vec2 center = vec2(200.0, 200.0);
void main (void) void main()
{ {
vec2 texSize = vec2(renderWidth, renderHeight); vec2 texSize = vec2(renderWidth, renderHeight);
vec2 tc = fragTexCoord*texSize; vec2 tc = fragTexCoord*texSize;
tc -= center; tc -= center;
float dist = length(tc); float dist = length(tc);
if (dist < radius) if (dist < radius)
@ -37,5 +42,5 @@ void main (void)
tc += center; tc += center;
vec3 color = texture(texture0, tc/texSize).rgb; vec3 color = texture(texture0, tc/texSize).rgb;
fragColor = vec4(color, 1.0);; finalColor = vec4(color, 1.0);;
} }

View File

@ -1,19 +1,24 @@
#version 330 #version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord; in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 fragColor; // Input uniform values
uniform sampler2D texture0; uniform sampler2D texture0;
uniform vec4 fragTintColor; uniform vec4 fragTintColor;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables // NOTE: Add here your custom variables
void main() void main()
{ {
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord); vec4 texelColor = texture(texture0, fragTexCoord);
// NOTE: Implement here your fragment shader code // NOTE: Implement here your fragment shader code
fragColor = texelColor*fragTintColor; finalColor = texelColor*fragTintColor;
} }

View File

@ -59,8 +59,9 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define MAX_STREAM_BUFFERS 2 #define MAX_STREAM_BUFFERS 2 // Number of buffers for each alSource
#define MAX_AUDIO_CONTEXTS 4 // Number of open AL sources #define MAX_MIX_CHANNELS 4 // Number of open AL sources
#define MAX_MUSIC_STREAMS 2 // Number of simultanious music sources
#if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
// NOTE: On RPI and Android should be lower to avoid frame-stalls // NOTE: On RPI and Android should be lower to avoid frame-stalls
@ -76,37 +77,32 @@
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Music type (file streaming from memory) // Used to create custom audio streams that are not bound to a specific file. There can be
// NOTE: Anything longer than ~10 seconds should be streamed... // no more than 4 concurrent mixchannels in use. This is due to each active mixc being tied to
typedef struct Music { // a dedicated mix channel.
stb_vorbis *stream; typedef struct MixChannel_t {
jar_xm_context_t *chipctx; // Stores jar_xm context
ALuint buffers[MAX_STREAM_BUFFERS];
ALuint source;
ALenum format;
int channels;
int sampleRate;
int totalSamplesLeft;
float totalLengthSeconds;
bool loop;
bool chipTune; // True if chiptune is loaded
} Music;
// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
// a dedicated mix channel. All audio is 32bit floating point in stereo.
typedef struct AudioContext_t {
unsigned short sampleRate; // default is 48000 unsigned short sampleRate; // default is 48000
unsigned char channels; // 1=mono,2=stereo unsigned char channels; // 1=mono,2=stereo
unsigned char mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream unsigned char mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream
bool floatingPoint; // if false then the short datatype is used instead bool floatingPoint; // if false then the short datatype is used instead
bool playing; bool playing; // false if paused
ALenum alFormat; // openAL format specifier ALenum alFormat; // openAL format specifier
ALuint alSource; // openAL source ALuint alSource; // openAL source
ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
} AudioContext_t; } MixChannel_t;
// Music type (file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel...
typedef struct Music {
stb_vorbis *stream;
jar_xm_context_t *chipctx; // Stores jar_xm mixc
MixChannel_t *mixc; // mix channel
int totalSamplesLeft;
float totalLengthSeconds;
bool loop;
bool chipTune; // True if chiptune is loaded
} Music;
#if defined(AUDIO_STANDALONE) #if defined(AUDIO_STANDALONE)
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
@ -115,23 +111,28 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS]; // What mix channels are currently active static MixChannel_t* mixChannelsActive_g[MAX_MIX_CHANNELS]; // What mix channels are currently active
static bool musicEnabled = false; static bool musicEnabled_g = false;
static Music currentMusic; // Current music loaded static Music currentMusic[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time
// NOTE: Only one music file playing at a time
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static Wave LoadWAV(const char *fileName); // Load WAV file static Wave LoadWAV(const char *fileName); // Load WAV file
static Wave LoadOGG(char *fileName); // Load OGG file static Wave LoadOGG(char *fileName); // Load OGG file
static void UnloadWave(Wave wave); // Unload wave data static void UnloadWave(Wave wave); // Unload wave data
static bool BufferMusicStream(ALuint buffer); // Fill music buffers with data static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data
static void EmptyMusicStream(void); // Empty music buffers static void EmptyMusicStream(int index); // Empty music buffers
static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // pass two arrays of the same legnth in static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // pass two arrays of same length in static void CloseMixChannel(MixChannel_t* mixc); // Frees mix channel
static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses
static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed
static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // Pass two arrays of the same legnth in
static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // Pass two arrays of same length in
static int IsMusicStreamReadyForBuffering(int index); // Checks if music buffer is ready to be refilled
#if defined(AUDIO_STANDALONE) #if defined(AUDIO_STANDALONE)
const char *GetExtension(const char *fileName); // Get the extension for a filename const char *GetExtension(const char *fileName); // Get the extension for a filename
@ -142,7 +143,7 @@ void TraceLog(int msgType, const char *text, ...); // Outputs a trace log messa
// Module Functions Definition - Audio Device initialization and Closing // Module Functions Definition - Audio Device initialization and Closing
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Initialize audio device and context // Initialize audio device and mixc
void InitAudioDevice(void) void InitAudioDevice(void)
{ {
// Open and initialize a device with default settings // Open and initialize a device with default settings
@ -158,7 +159,7 @@ void InitAudioDevice(void)
alcCloseDevice(device); alcCloseDevice(device);
TraceLog(ERROR, "Could not setup audio context"); TraceLog(ERROR, "Could not setup mix channel");
} }
TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
@ -169,15 +170,19 @@ void InitAudioDevice(void)
alListener3f(AL_ORIENTATION, 0, 0, -1); alListener3f(AL_ORIENTATION, 0, 0, -1);
} }
// Close the audio device for the current context, and destroys the context // Close the audio device for all contexts
void CloseAudioDevice(void) void CloseAudioDevice(void)
{ {
StopMusicStream(); // Stop music streaming and close current stream for(int index=0; index<MAX_MUSIC_STREAMS; index++)
{
if(currentMusic[index].mixc) StopMusicStream(index); // Stop music streaming and close current stream
}
ALCdevice *device; ALCdevice *device;
ALCcontext *context = alcGetCurrentContext(); ALCcontext *context = alcGetCurrentContext();
if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing"); if (context == NULL) TraceLog(WARNING, "Could not get current mix channel for closing");
device = alcGetContextsDevice(context); device = alcGetContextsDevice(context);
@ -202,187 +207,141 @@ bool IsAudioDeviceReady(void)
// Module Functions Definition - Custom audio output // Module Functions Definition - Custom audio output
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // For streaming into mix channels.
// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time. // The mixChannel is what audio muxing channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point // exmple usage is InitMixChannel(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint) static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
{ {
if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL; if(mixChannel >= MAX_MIX_CHANNELS) return NULL;
if(!IsAudioDeviceReady()) InitAudioDevice(); if(!IsAudioDeviceReady()) InitAudioDevice();
else StopMusicStream();
if(!mixChannelsActive_g[mixChannel]){ if(!mixChannelsActive_g[mixChannel]){
AudioContext_t *ac = (AudioContext_t*)malloc(sizeof(AudioContext_t)); MixChannel_t *mixc = (MixChannel_t*)malloc(sizeof(MixChannel_t));
ac->sampleRate = sampleRate; mixc->sampleRate = sampleRate;
ac->channels = channels; mixc->channels = channels;
ac->mixChannel = mixChannel; mixc->mixChannel = mixChannel;
ac->floatingPoint = floatingPoint; mixc->floatingPoint = floatingPoint;
mixChannelsActive_g[mixChannel] = ac; mixChannelsActive_g[mixChannel] = mixc;
// setup openAL format // setup openAL format
if(channels == 1) if(channels == 1)
{ {
if(floatingPoint) if(floatingPoint)
ac->alFormat = AL_FORMAT_MONO_FLOAT32; mixc->alFormat = AL_FORMAT_MONO_FLOAT32;
else else
ac->alFormat = AL_FORMAT_MONO16; mixc->alFormat = AL_FORMAT_MONO16;
} }
else if(channels == 2) else if(channels == 2)
{ {
if(floatingPoint) if(floatingPoint)
ac->alFormat = AL_FORMAT_STEREO_FLOAT32; mixc->alFormat = AL_FORMAT_STEREO_FLOAT32;
else else
ac->alFormat = AL_FORMAT_STEREO16; mixc->alFormat = AL_FORMAT_STEREO16;
} }
// Create an audio source // Create an audio source
alGenSources(1, &ac->alSource); alGenSources(1, &mixc->alSource);
alSourcef(ac->alSource, AL_PITCH, 1); alSourcef(mixc->alSource, AL_PITCH, 1);
alSourcef(ac->alSource, AL_GAIN, 1); alSourcef(mixc->alSource, AL_GAIN, 1);
alSource3f(ac->alSource, AL_POSITION, 0, 0, 0); alSource3f(mixc->alSource, AL_POSITION, 0, 0, 0);
alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0); alSource3f(mixc->alSource, AL_VELOCITY, 0, 0, 0);
// Create Buffer // Create Buffer
alGenBuffers(MAX_STREAM_BUFFERS, ac->alBuffer); alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
//fill buffers //fill buffers
int x; int x;
for(x=0;x<MAX_STREAM_BUFFERS;x++) for(x=0;x<MAX_STREAM_BUFFERS;x++)
FillAlBufferWithSilence(ac, ac->alBuffer[x]); FillAlBufferWithSilence(mixc, mixc->alBuffer[x]);
alSourceQueueBuffers(ac->alSource, MAX_STREAM_BUFFERS, ac->alBuffer); alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer);
alSourcePlay(ac->alSource); mixc->playing = true;
ac->playing = true; alSourcePlay(mixc->alSource);
return ac; return mixc;
} }
return NULL; return NULL;
} }
// Frees buffer in audio context // Frees buffer in mix channel
void CloseAudioContext(AudioContext ctx) static void CloseMixChannel(MixChannel_t* mixc)
{ {
AudioContext_t *context = (AudioContext_t*)ctx; if(mixc){
if(context){ alSourceStop(mixc->alSource);
alSourceStop(context->alSource); mixc->playing = false;
context->playing = false;
//flush out all queued buffers //flush out all queued buffers
ALuint buffer = 0; ALuint buffer = 0;
int queued = 0; int queued = 0;
alGetSourcei(context->alSource, AL_BUFFERS_QUEUED, &queued); alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued);
while (queued > 0) while (queued > 0)
{ {
alSourceUnqueueBuffers(context->alSource, 1, &buffer); alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
queued--; queued--;
} }
//delete source and buffers //delete source and buffers
alDeleteSources(1, &context->alSource); alDeleteSources(1, &mixc->alSource);
alDeleteBuffers(MAX_STREAM_BUFFERS, context->alBuffer); alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
mixChannelsActive_g[context->mixChannel] = NULL; mixChannelsActive_g[mixc->mixChannel] = NULL;
free(context); free(mixc);
ctx = NULL; mixc = NULL;
} }
} }
// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in. // Pushes more audio data into mixc mix channel, only one buffer per call
// Call "UpdateAudioContext(ctx, NULL, 0)" if you want to pause the audio. // Call "BufferMixChannel(mixc, NULL, 0)" if you want to pause the audio.
// @Returns number of samples that where processed. // @Returns number of samples that where processed.
unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements) static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements)
{ {
AudioContext_t *context = (AudioContext_t*)ctx; if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples
if(!context || (context->channels == 2 && numberElements % 2 != 0)) return 0; // when there is two channels there must be an even number of samples
if (!data || !numberElements) if (!data || !numberElements)
{ // pauses audio until data is given { // pauses audio until data is given
alSourcePause(context->alSource); if(mixc->playing){
context->playing = false; alSourcePause(mixc->alSource);
mixc->playing = false;
}
return 0; return 0;
} }
else else if(!mixc->playing)
{ // restart audio otherwise { // restart audio otherwise
ALint state; alSourcePlay(mixc->alSource);
alGetSourcei(context->alSource, AL_SOURCE_STATE, &state); mixc->playing = true;
if (state != AL_PLAYING){
alSourcePlay(context->alSource);
context->playing = true;
}
} }
if (context && context->playing && mixChannelsActive_g[context->mixChannel] == context)
ALuint buffer = 0;
alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
if(!buffer) return 0;
if(mixc->floatingPoint) // process float buffers
{ {
ALint processed = 0; float *ptr = (float*)data;
ALuint buffer = 0; alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate);
unsigned short numberProcessed = 0;
unsigned short numberRemaining = numberElements;
alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any)
if(!processed) return 0; // nothing to process, queue is still full
while (processed > 0)
{
if(context->floatingPoint) // process float buffers
{
float *ptr = (float*)data;
alSourceUnqueueBuffers(context->alSource, 1, &buffer);
if(numberRemaining >= MUSIC_BUFFER_SIZE_FLOAT)
{
alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate);
numberProcessed+=MUSIC_BUFFER_SIZE_FLOAT;
numberRemaining-=MUSIC_BUFFER_SIZE_FLOAT;
}
else
{
alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(float), context->sampleRate);
numberProcessed+=numberRemaining;
numberRemaining=0;
}
alSourceQueueBuffers(context->alSource, 1, &buffer);
processed--;
}
else if(!context->floatingPoint) // process short buffers
{
short *ptr = (short*)data;
alSourceUnqueueBuffers(context->alSource, 1, &buffer);
if(numberRemaining >= MUSIC_BUFFER_SIZE_SHORT)
{
alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(short), context->sampleRate);
numberProcessed+=MUSIC_BUFFER_SIZE_SHORT;
numberRemaining-=MUSIC_BUFFER_SIZE_SHORT;
}
else
{
alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(short), context->sampleRate);
numberProcessed+=numberRemaining;
numberRemaining=0;
}
alSourceQueueBuffers(context->alSource, 1, &buffer);
processed--;
}
else
break;
}
return numberProcessed;
} }
return 0; else // process short buffers
{
short *ptr = (short*)data;
alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate);
}
alSourceQueueBuffers(mixc->alSource, 1, &buffer);
return numberElements;
} }
// fill buffer with zeros, returns number processed // fill buffer with zeros, returns number processed
static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer) static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer)
{ {
if(context->floatingPoint){ if(mixc->floatingPoint){
float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f}; float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f};
alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate); alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), mixc->sampleRate);
return MUSIC_BUFFER_SIZE_FLOAT; return MUSIC_BUFFER_SIZE_FLOAT;
} }
else else
{ {
short pcm[MUSIC_BUFFER_SIZE_SHORT] = {0}; short pcm[MUSIC_BUFFER_SIZE_SHORT] = {0};
alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), context->sampleRate); alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate);
return MUSIC_BUFFER_SIZE_SHORT; return MUSIC_BUFFER_SIZE_SHORT;
} }
} }
@ -417,6 +376,42 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len)
} }
} }
// used to output raw audio streams, returns negative numbers on error
// if floating point is false the data size is 16bit short, otherwise it is float 32bit
RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint)
{
int mixIndex;
for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
{
if(mixChannelsActive_g[mixIndex] == NULL) break;
else if(mixIndex == MAX_MIX_CHANNELS - 1) return -1; // error
}
if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint))
return mixIndex;
else
return -2; // error
}
void CloseRawAudioContext(RawAudioContext ctx)
{
if(mixChannelsActive_g[ctx])
CloseMixChannel(mixChannelsActive_g[ctx]);
}
int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements)
{
int numBuffered = 0;
if(ctx >= 0)
{
MixChannel_t* mixc = mixChannelsActive_g[ctx];
numBuffered = BufferMixChannel(mixc, data, numberElements);
}
return numBuffered;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -767,207 +762,216 @@ void SetSoundPitch(Sound sound, float pitch)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Start music playing (open stream) // Start music playing (open stream)
void PlayMusicStream(char *fileName) // returns 0 on success
int PlayMusicStream(int musicIndex, char *fileName)
{ {
int mixIndex;
if(currentMusic[musicIndex].stream || currentMusic[musicIndex].chipctx) return 1; // error
for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
{
if(mixChannelsActive_g[mixIndex] == NULL) break;
else if(mixIndex == MAX_MIX_CHANNELS - 1) return 2; // error
}
if (strcmp(GetExtension(fileName),"ogg") == 0) if (strcmp(GetExtension(fileName),"ogg") == 0)
{ {
// Stop current music, clean buffers, unload current stream
StopMusicStream();
// Open audio stream // Open audio stream
currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL); currentMusic[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL);
if (currentMusic.stream == NULL) if (currentMusic[musicIndex].stream == NULL)
{ {
TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
return 3; // error
} }
else else
{ {
// Get file info // Get file info
stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream); stb_vorbis_info info = stb_vorbis_get_info(currentMusic[musicIndex].stream);
currentMusic.channels = info.channels;
currentMusic.sampleRate = info.sample_rate;
TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels); TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16; currentMusic[musicIndex].loop = true; // We loop by default
else currentMusic.format = AL_FORMAT_MONO16; musicEnabled_g = true;
currentMusic.loop = true; // We loop by default currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
musicEnabled = true; currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
// Create an audio source if (info.channels == 2){
alGenSources(1, &currentMusic.source); // Generate pointer to audio source currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false);
currentMusic[musicIndex].mixc->playing = true;
alSourcef(currentMusic.source, AL_PITCH, 1); }
alSourcef(currentMusic.source, AL_GAIN, 1); else{
alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0); currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false);
alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0); currentMusic[musicIndex].mixc->playing = true;
//alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE); // ERROR: Buffers do not queue! }
if(!currentMusic[musicIndex].mixc) return 4; // error
// Generate two OpenAL buffers
alGenBuffers(2, currentMusic.buffers);
// Fill buffers with music...
BufferMusicStream(currentMusic.buffers[0]);
BufferMusicStream(currentMusic.buffers[1]);
// Queue buffers and start playing
alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
alSourcePlay(currentMusic.source);
// NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
currentMusic.totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
} }
} }
else if (strcmp(GetExtension(fileName),"xm") == 0) else if (strcmp(GetExtension(fileName),"xm") == 0)
{ {
// Stop current music, clean buffers, unload current stream
StopMusicStream();
// new song settings for xm chiptune
currentMusic.chipTune = true;
currentMusic.channels = 2;
currentMusic.sampleRate = 48000;
currentMusic.loop = true;
// only stereo is supported for xm // only stereo is supported for xm
if(!jar_xm_create_context_from_file(&currentMusic.chipctx, currentMusic.sampleRate, fileName)) if(!jar_xm_create_context_from_file(&currentMusic[musicIndex].chipctx, 48000, fileName))
{ {
currentMusic.format = AL_FORMAT_STEREO16; currentMusic[musicIndex].chipTune = true;
jar_xm_set_max_loop_count(currentMusic.chipctx, 0); // infinite number of loops currentMusic[musicIndex].loop = true;
currentMusic.totalSamplesLeft = jar_xm_get_remaining_samples(currentMusic.chipctx); jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
currentMusic.totalLengthSeconds = ((float)currentMusic.totalSamplesLeft) / ((float)currentMusic.sampleRate); currentMusic[musicIndex].totalSamplesLeft = jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
musicEnabled = true; currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f;
musicEnabled_g = true;
TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic.totalSamplesLeft); TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic.totalLengthSeconds); TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
// Set up OpenAL currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false);
alGenSources(1, &currentMusic.source); if(!currentMusic[musicIndex].mixc) return 5; // error
alSourcef(currentMusic.source, AL_PITCH, 1); currentMusic[musicIndex].mixc->playing = true;
alSourcef(currentMusic.source, AL_GAIN, 1);
alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
alGenBuffers(2, currentMusic.buffers);
BufferMusicStream(currentMusic.buffers[0]);
BufferMusicStream(currentMusic.buffers[1]);
alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
alSourcePlay(currentMusic.source);
// NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
}
else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
}
else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
}
// Stop music playing (close stream)
void StopMusicStream(void)
{
if (musicEnabled)
{
alSourceStop(currentMusic.source);
EmptyMusicStream(); // Empty music buffers
alDeleteSources(1, &currentMusic.source);
alDeleteBuffers(2, currentMusic.buffers);
if (currentMusic.chipTune)
{
jar_xm_free_context(currentMusic.chipctx);
} }
else else
{ {
stb_vorbis_close(currentMusic.stream); TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
return 6; // error
} }
} }
else
{
TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
return 7; // error
}
return 0; // normal return
}
musicEnabled = false; // Stop music playing for individual music index of currentMusic array (close stream)
void StopMusicStream(int index)
{
if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
{
CloseMixChannel(currentMusic[index].mixc);
if (currentMusic[index].chipTune)
{
jar_xm_free_context(currentMusic[index].chipctx);
}
else
{
stb_vorbis_close(currentMusic[index].stream);
}
if(!getMusicStreamCount()) musicEnabled_g = false;
if(currentMusic[index].stream || currentMusic[index].chipctx)
{
currentMusic[index].stream = NULL;
currentMusic[index].chipctx = NULL;
}
}
}
//get number of music channels active at this time, this does not mean they are playing
int getMusicStreamCount(void)
{
int musicCount = 0;
for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) musicCount++;
return musicCount;
} }
// Pause music playing // Pause music playing
void PauseMusicStream(void) void PauseMusicStream(int index)
{ {
// Pause music stream if music available! // Pause music stream if music available!
if (musicEnabled) if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc && musicEnabled_g)
{ {
TraceLog(INFO, "Pausing music stream"); TraceLog(INFO, "Pausing music stream");
alSourcePause(currentMusic.source); alSourcePause(currentMusic[index].mixc->alSource);
musicEnabled = false; currentMusic[index].mixc->playing = false;
} }
} }
// Resume music playing // Resume music playing
void ResumeMusicStream(void) void ResumeMusicStream(int index)
{ {
// Resume music playing... if music available! // Resume music playing... if music available!
ALenum state; ALenum state;
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
if (state == AL_PAUSED) if (state == AL_PAUSED)
{ {
TraceLog(INFO, "Resuming music stream"); TraceLog(INFO, "Resuming music stream");
alSourcePlay(currentMusic.source); alSourcePlay(currentMusic[index].mixc->alSource);
musicEnabled = true; currentMusic[index].mixc->playing = true;
}
} }
} }
// Check if music is playing // Check if any music is playing
bool IsMusicPlaying(void) bool IsMusicPlaying(int index)
{ {
bool playing = false; bool playing = false;
ALint state; ALint state;
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
if (state == AL_PLAYING) playing = true; alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
if (state == AL_PLAYING) playing = true;
}
return playing; return playing;
} }
// Set volume for music // Set volume for music
void SetMusicVolume(float volume) void SetMusicVolume(int index, float volume)
{ {
alSourcef(currentMusic.source, AL_GAIN, volume); if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
alSourcef(currentMusic[index].mixc->alSource, AL_GAIN, volume);
}
}
void SetMusicPitch(int index, float pitch)
{
if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
alSourcef(currentMusic[index].mixc->alSource, AL_PITCH, pitch);
}
} }
// Get current music time length (in seconds) // Get current music time length (in seconds)
float GetMusicTimeLength(void) float GetMusicTimeLength(int index)
{ {
float totalSeconds; float totalSeconds;
if (currentMusic.chipTune) if (currentMusic[index].chipTune)
{ {
totalSeconds = currentMusic.totalLengthSeconds; totalSeconds = currentMusic[index].totalLengthSeconds;
} }
else else
{ {
totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream); totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[index].stream);
} }
return totalSeconds; return totalSeconds;
} }
// Get current music time played (in seconds) // Get current music time played (in seconds)
float GetMusicTimePlayed(void) float GetMusicTimePlayed(int index)
{ {
float secondsPlayed; float secondsPlayed = 0.0f;
if (currentMusic.chipTune) if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
{ {
uint64_t samples; if (currentMusic[index].chipTune)
jar_xm_get_position(currentMusic.chipctx, NULL, NULL, NULL, &samples); {
secondsPlayed = (float)samples / (currentMusic.sampleRate * currentMusic.channels); // Not sure if this is the correct value uint64_t samples;
jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
secondsPlayed = (float)samples / (48000 * currentMusic[index].mixc->channels); // Not sure if this is the correct value
}
else
{
int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels);
}
} }
else
{
int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
}
return secondsPlayed; return secondsPlayed;
} }
@ -977,116 +981,118 @@ float GetMusicTimePlayed(void)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Fill music buffers with new data from music stream // Fill music buffers with new data from music stream
static bool BufferMusicStream(ALuint buffer) static bool BufferMusicStream(int index, int numBuffers)
{ {
short pcm[MUSIC_BUFFER_SIZE_SHORT]; short pcm[MUSIC_BUFFER_SIZE_SHORT];
float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
int size = 0; // Total size of data steamed (in bytes) int size = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts
int streamedBytes = 0; // samples of data obtained, channels are not included in calculation
bool active = true; // We can get more data from stream (not finished) bool active = true; // We can get more data from stream (not finished)
if (musicEnabled) if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
{ {
if (currentMusic.chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
{ size = MUSIC_BUFFER_SIZE_SHORT / 2;
int readlen = MUSIC_BUFFER_SIZE_SHORT / 2;
jar_xm_generate_samples_16bit(currentMusic.chipctx, pcm, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
size += readlen * currentMusic.channels; // Not sure if this is what it needs
}
else else
size = currentMusic[index].totalSamplesLeft / 2;
for(int x=0; x<numBuffers; x++)
{ {
while (size < MUSIC_BUFFER_SIZE_SHORT) jar_xm_generate_samples_16bit(currentMusic[index].chipctx, pcm, size); // reads 2*readlen shorts and moves them to buffer+size memory location
BufferMixChannel(currentMusic[index].mixc, pcm, size * 2);
currentMusic[index].totalSamplesLeft -= size * 2;
if(currentMusic[index].totalSamplesLeft <= 0)
{ {
streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size); active = false;
if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels); break;
else break;
} }
} }
TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
}
if (size > 0)
{
alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate);
currentMusic.totalSamplesLeft -= size;
if(currentMusic.totalSamplesLeft <= 0) active = false; // end if no more samples left
} }
else else
{ {
active = false; if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
TraceLog(WARNING, "No more data obtained from stream"); size = MUSIC_BUFFER_SIZE_SHORT;
else
size = currentMusic[index].totalSamplesLeft;
for(int x=0; x<numBuffers; x++)
{
int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].mixc->channels, pcm, size);
BufferMixChannel(currentMusic[index].mixc, pcm, streamedBytes * currentMusic[index].mixc->channels);
currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].mixc->channels;
if(currentMusic[index].totalSamplesLeft <= 0)
{
active = false;
break;
}
}
} }
return active; return active;
} }
// Empty music buffers // Empty music buffers
static void EmptyMusicStream(void) static void EmptyMusicStream(int index)
{ {
ALuint buffer = 0; ALuint buffer = 0;
int queued = 0; int queued = 0;
alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued); alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued);
while (queued > 0) while (queued > 0)
{ {
alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); alSourceUnqueueBuffers(currentMusic[index].mixc->alSource, 1, &buffer);
queued--; queued--;
} }
} }
// Update (re-fill) music buffers if data already processed //determine if a music stream is ready to be written to
void UpdateMusicStream(void) static int IsMusicStreamReadyForBuffering(int index)
{ {
ALuint buffer = 0;
ALint processed = 0; ALint processed = 0;
alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed);
return processed;
}
// Update (re-fill) music buffers if data already processed
void UpdateMusicStream(int index)
{
ALenum state;
bool active = true; bool active = true;
int numBuffers = IsMusicStreamReadyForBuffering(index);
if (musicEnabled)
if (currentMusic[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].mixc && numBuffers)
{ {
// Get the number of already processed buffers (if any) active = BufferMusicStream(index, numBuffers);
alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
if (!active && currentMusic[index].loop)
while (processed > 0)
{ {
// Recover processed buffer for refill if (currentMusic[index].chipTune)
alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
// Refill buffer
active = BufferMusicStream(buffer);
// If no more data to stream, restart music (if loop)
if ((!active) && (currentMusic.loop))
{ {
if(currentMusic.chipTune) currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * 48000;
{
currentMusic.totalSamplesLeft = currentMusic.totalLengthSeconds * currentMusic.sampleRate;
}
else
{
stb_vorbis_seek_start(currentMusic.stream);
currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream)*currentMusic.channels;
}
active = BufferMusicStream(buffer);
} }
else
// Add refilled buffer to queue again... don't let the music stop! {
alSourceQueueBuffers(currentMusic.source, 1, &buffer); stb_vorbis_seek_start(currentMusic[index].stream);
currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); }
active = true;
processed--;
} }
ALenum state; if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source); if (state != AL_PLAYING && active) alSourcePlay(currentMusic[index].mixc->alSource);
if (!active) StopMusicStream(); if (!active) StopMusicStream(index);
} }
else
return;
} }
// Load WAV file into Wave structure // Load WAV file into Wave structure

View File

@ -61,10 +61,7 @@ typedef struct Wave {
short channels; short channels;
} Wave; } Wave;
// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be typedef int RawAudioContext;
// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
// a dedicated mix channel.
typedef void* AudioContext;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
@ -82,13 +79,6 @@ void InitAudioDevice(void); // Initialize au
void CloseAudioDevice(void); // Close the audio device and context (and music stream) void CloseAudioDevice(void); // Close the audio device and context (and music stream)
bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
void CloseAudioContext(AudioContext ctx); // Frees audio context
unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSound(char *fileName); // Load sound to memory
Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data
Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource)
@ -100,15 +90,24 @@ bool IsSoundPlaying(Sound sound); // Check if a so
void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
void PlayMusicStream(char *fileName); // Start music playing (open stream) int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream)
void UpdateMusicStream(void); // Updates buffers for music streaming void UpdateMusicStream(int index); // Updates buffers for music streaming
void StopMusicStream(void); // Stop music playing (close stream) void StopMusicStream(int index); // Stop music playing (close stream)
void PauseMusicStream(void); // Pause music playing void PauseMusicStream(int index); // Pause music playing
void ResumeMusicStream(void); // Resume playing paused music void ResumeMusicStream(int index); // Resume playing paused music
bool IsMusicPlaying(void); // Check if music is playing bool IsMusicPlaying(int index); // Check if music is playing
void SetMusicVolume(float volume); // Set volume for music (1.0 is max level) void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level)
float GetMusicTimeLength(void); // Get music time length (in seconds) float GetMusicTimeLength(int index); // Get music time length (in seconds)
float GetMusicTimePlayed(void); // Get current music time played (in seconds) float GetMusicTimePlayed(int index); // Get current music time played (in seconds)
int getMusicStreamCount(void);
void SetMusicPitch(int index, float pitch);
// used to output raw audio streams, returns negative numbers on error
// if floating point is false the data size is 16bit short, otherwise it is float 32bit
RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
void CloseRawAudioContext(RawAudioContext ctx);
int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -18,11 +18,11 @@
* float speed = 1.f; * float speed = 1.f;
* float currentTime = 0.f; * float currentTime = 0.f;
* float currentPos[2] = {0,0}; * float currentPos[2] = {0,0};
* float newPos[2] = {1,1}; * float finalPos[2] = {1,1};
* float tempPosition[2] = currentPos;//x,y positions * float startPosition[2] = currentPos;//x,y positions
* while(currentPos[0] < newPos[0]) * while(currentPos[0] < finalPos[0])
* currentPos[0] = EaseSineIn(currentTime, tempPosition[0], tempPosition[0]-newPos[0], speed); * currentPos[0] = EaseSineIn(currentTime, startPosition[0], startPosition[0]-finalPos[0], speed);
* currentPos[1] = EaseSineIn(currentTime, tempPosition[1], tempPosition[1]-newPos[0], speed); * currentPos[1] = EaseSineIn(currentTime, startPosition[1], startPosition[1]-finalPos[0], speed);
* currentTime += diffTime(); * currentTime += diffTime();
* *
* A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/) * A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)

View File

@ -65,6 +65,16 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw a line in 3D world space
void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex3f(startPos.x, startPos.y, startPos.z);
rlVertex3f(endPos.x, endPos.y, endPos.z);
rlEnd();
}
// Draw cube // Draw cube
// NOTE: Cube position is the center position // NOTE: Cube position is the center position
void DrawCube(Vector3 position, float width, float height, float length, Color color) void DrawCube(Vector3 position, float width, float height, float length, Color color)
@ -292,9 +302,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for(int i = 0; i < (rings + 2); i++) for (int i = 0; i < (rings + 2); i++)
{ {
for(int j = 0; j < slices; j++) for (int j = 0; j < slices; j++)
{ {
rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)), rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
sin(DEG2RAD*(270+(180/(rings + 1))*i)), sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@ -331,9 +341,9 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for(int i = 0; i < (rings + 2); i++) for (int i = 0; i < (rings + 2); i++)
{ {
for(int j = 0; j < slices; j++) for (int j = 0; j < slices; j++)
{ {
rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)), rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
sin(DEG2RAD*(270+(180/(rings + 1))*i)), sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@ -376,7 +386,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
if (radiusTop > 0) if (radiusTop > 0)
{ {
// Draw Body ------------------------------------------------------------------------------------- // Draw Body -------------------------------------------------------------------------------------
for(int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left
rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right
@ -388,7 +398,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
} }
// Draw Cap -------------------------------------------------------------------------------------- // Draw Cap --------------------------------------------------------------------------------------
for(int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
rlVertex3f(0, height, 0); rlVertex3f(0, height, 0);
rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop); rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
@ -398,7 +408,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
else else
{ {
// Draw Cone ------------------------------------------------------------------------------------- // Draw Cone -------------------------------------------------------------------------------------
for(int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
rlVertex3f(0, height, 0); rlVertex3f(0, height, 0);
rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
@ -407,7 +417,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
} }
// Draw Base ----------------------------------------------------------------------------------------- // Draw Base -----------------------------------------------------------------------------------------
for(int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
rlVertex3f(0, 0, 0); rlVertex3f(0, 0, 0);
rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
@ -421,7 +431,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
// NOTE: It could be also used for pyramid and cone // NOTE: It could be also used for pyramid and cone
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color) void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
{ {
if(sides < 3) sides = 3; if (sides < 3) sides = 3;
rlPushMatrix(); rlPushMatrix();
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
@ -429,7 +439,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for(int i = 0; i < 360; i += 360/sides) for (int i = 0; i < 360; i += 360/sides)
{ {
rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
@ -490,7 +500,7 @@ void DrawGrid(int slices, float spacing)
int halfSlices = slices / 2; int halfSlices = slices / 2;
rlBegin(RL_LINES); rlBegin(RL_LINES);
for(int i = -halfSlices; i <= halfSlices; i++) for (int i = -halfSlices; i <= halfSlices; i++)
{ {
if (i == 0) if (i == 0)
{ {
@ -553,7 +563,7 @@ Model LoadModel(const char *fileName)
if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
else else
{ {
rlglLoadMesh(&model.mesh); // Upload vertex data to GPU rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial(); model.material = LoadDefaultMaterial();
@ -563,13 +573,13 @@ Model LoadModel(const char *fileName)
} }
// Load a 3d model (from vertex data) // Load a 3d model (from vertex data)
Model LoadModelEx(Mesh data) Model LoadModelEx(Mesh data, bool dynamic)
{ {
Model model = { 0 }; Model model = { 0 };
model.mesh = data; model.mesh = data;
rlglLoadMesh(&model.mesh); // Upload vertex data to GPU rlglLoadMesh(&model.mesh, dynamic); // Upload vertex data to GPU
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial(); model.material = LoadDefaultMaterial();
@ -668,7 +678,7 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
model.mesh = GenMeshHeightmap(heightmap, size); model.mesh = GenMeshHeightmap(heightmap, size);
rlglLoadMesh(&model.mesh); rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial(); model.material = LoadDefaultMaterial();
@ -683,7 +693,7 @@ Model LoadCubicmap(Image cubicmap)
model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
rlglLoadMesh(&model.mesh); rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial(); model.material = LoadDefaultMaterial();
@ -691,31 +701,14 @@ Model LoadCubicmap(Image cubicmap)
return model; return model;
} }
// Unload 3d model from memory // Unload 3d model from memory (mesh and material)
void UnloadModel(Model model) void UnloadModel(Model model)
{ {
// Unload mesh data rlglUnloadMesh(&model.mesh);
if (model.mesh.vertices != NULL) free(model.mesh.vertices);
if (model.mesh.texcoords != NULL) free(model.mesh.texcoords);
if (model.mesh.normals != NULL) free(model.mesh.normals);
if (model.mesh.colors != NULL) free(model.mesh.colors);
if (model.mesh.tangents != NULL) free(model.mesh.tangents);
if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2);
if (model.mesh.indices != NULL) free(model.mesh.indices);
TraceLog(INFO, "Unloaded model data from RAM (CPU)");
rlDeleteBuffers(model.mesh.vboId[0]); // vertex
rlDeleteBuffers(model.mesh.vboId[1]); // texcoords
rlDeleteBuffers(model.mesh.vboId[2]); // normals
rlDeleteBuffers(model.mesh.vboId[3]); // colors
rlDeleteBuffers(model.mesh.vboId[4]); // tangents
rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2
rlDeleteBuffers(model.mesh.vboId[6]); // indices
rlDeleteVertexArrays(model.mesh.vaoId);
UnloadMaterial(model.material); UnloadMaterial(model.material);
TraceLog(INFO, "Unloaded model data from RAM and VRAM");
} }
// Load material data (from file) // Load material data (from file)
@ -749,6 +742,18 @@ Material LoadDefaultMaterial(void)
return material; return material;
} }
// Load standard material (uses material attributes and lighting shader)
// NOTE: Standard shader supports multiple maps and lights
Material LoadStandardMaterial(void)
{
Material material = LoadDefaultMaterial();
material.shader = GetStandardShader();
return material;
}
// Unload material from memory
void UnloadMaterial(Material material) void UnloadMaterial(Material material)
{ {
rlDeleteTextures(material.texDiffuse.id); rlDeleteTextures(material.texDiffuse.id);
@ -793,9 +798,9 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ }; Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
for(int z = 0; z < mapZ-1; z++) for (int z = 0; z < mapZ-1; z++)
{ {
for(int x = 0; x < mapX-1; x++) for (int x = 0; x < mapX-1; x++)
{ {
// Fill vertices array with data // Fill vertices array with data
//---------------------------------------------------------- //----------------------------------------------------------
@ -1245,42 +1250,29 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
//Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates
model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
model.material.colDiffuse = tint; // model.material.colDiffuse = tint;
rlglDrawEx(model.mesh, model.material, model.transform, false); rlglDrawMesh(model.mesh, model.material, model.transform);
} }
// Draw a model wires (with texture if set) // Draw a model wires (with texture if set)
void DrawModelWires(Model model, Vector3 position, float scale, Color tint) void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
{ {
Vector3 vScale = { scale, scale, scale }; rlEnableWireMode();
Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
// Calculate transformation matrix from function parameters
// Get transform matrix (rotation -> scale -> translation)
Matrix matRotation = MatrixRotate(rotationAxis, 0.0f);
Matrix matScale = MatrixScale(vScale.x, vScale.y, vScale.z);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); DrawModel(model, position, scale, tint);
model.material.colDiffuse = tint;
rlglDrawEx(model.mesh, model.material, model.transform, true); rlDisableWireMode();
} }
// Draw a model wires (with texture if set) with extended parameters // Draw a model wires (with texture if set) with extended parameters
void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{ {
// Calculate transformation matrix from function parameters rlEnableWireMode();
// Get transform matrix (rotation -> scale -> translation)
Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
model.material.colDiffuse = tint;
rlglDrawEx(model.mesh, model.material, model.transform, true); rlDisableWireMode();
} }
// Draw a billboard // Draw a billboard
@ -1425,7 +1417,7 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius
float vector = VectorDotProduct(raySpherePos, ray.direction); float vector = VectorDotProduct(raySpherePos, ray.direction);
float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
if(d >= 0.0f) collision = true; if (d >= 0.0f) collision = true;
return collision; return collision;
} }
@ -1440,14 +1432,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
float vector = VectorDotProduct(raySpherePos, ray.direction); float vector = VectorDotProduct(raySpherePos, ray.direction);
float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
if(d >= 0.0f) collision = true; if (d >= 0.0f) collision = true;
// Calculate collision point // Calculate collision point
Vector3 offset = ray.direction; Vector3 offset = ray.direction;
float collisionDistance = 0; float collisionDistance = 0;
// Check if ray origin is inside the sphere to calculate the correct collision point // Check if ray origin is inside the sphere to calculate the correct collision point
if(distance < sphereRadius) collisionDistance = vector + sqrt(d); if (distance < sphereRadius) collisionDistance = vector + sqrt(d);
else collisionDistance = vector - sqrt(d); else collisionDistance = vector - sqrt(d);
VectorScale(&offset, collisionDistance); VectorScale(&offset, collisionDistance);
@ -1785,11 +1777,11 @@ static Mesh LoadOBJ(const char *fileName)
// First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
// NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition) // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
// NOTE: faces MUST be defined as TRIANGLES (3 vertex per face) // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
while(!feof(objFile)) while (!feof(objFile))
{ {
fscanf(objFile, "%c", &dataType); fscanf(objFile, "%c", &dataType);
switch(dataType) switch (dataType)
{ {
case '#': // Comments case '#': // Comments
case 'o': // Object name (One OBJ file can contain multible named meshes) case 'o': // Object name (One OBJ file can contain multible named meshes)
@ -1850,11 +1842,11 @@ static Mesh LoadOBJ(const char *fileName)
// Second reading pass: Get vertex data to fill intermediate arrays // Second reading pass: Get vertex data to fill intermediate arrays
// NOTE: This second pass is required in case of multiple meshes defined in same OBJ // NOTE: This second pass is required in case of multiple meshes defined in same OBJ
// TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals) // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals)
while(!feof(objFile)) while (!feof(objFile))
{ {
fscanf(objFile, "%c", &dataType); fscanf(objFile, "%c", &dataType);
switch(dataType) switch (dataType)
{ {
case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break; case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break;
case 'v': case 'v':
@ -1911,11 +1903,11 @@ static Mesh LoadOBJ(const char *fileName)
if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName); if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
// Third reading pass: Get faces (triangles) data and fill VertexArray // Third reading pass: Get faces (triangles) data and fill VertexArray
while(!feof(objFile)) while (!feof(objFile))
{ {
fscanf(objFile, "%c", &dataType); fscanf(objFile, "%c", &dataType);
switch(dataType) switch (dataType)
{ {
case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break; case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break;
case 'f': case 'f':
@ -2031,7 +2023,7 @@ static Material LoadMTL(const char *fileName)
return material; return material;
} }
while(!feof(mtlFile)) while (!feof(mtlFile))
{ {
fgets(buffer, MAX_BUFFER_SIZE, mtlFile); fgets(buffer, MAX_BUFFER_SIZE, mtlFile);
@ -2086,7 +2078,10 @@ static Material LoadMTL(const char *fileName)
{ {
if (buffer[1] == 's') // Ns int Shininess (specular exponent). Ranges from 0 to 1000. if (buffer[1] == 's') // Ns int Shininess (specular exponent). Ranges from 0 to 1000.
{ {
sscanf(buffer, "Ns %i", &material.glossiness); int shininess = 0;
sscanf(buffer, "Ns %i", &shininess);
material.glossiness = (float)shininess;
} }
else if (buffer[1] == 'i') // Ni int Refraction index. else if (buffer[1] == 'i') // Ni int Refraction index.
{ {

View File

@ -49,7 +49,7 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
static PhysicObject *physicObjects[MAX_PHYSIC_OBJECTS]; // Physic objects pool static PhysicObject physicObjects[MAX_PHYSIC_OBJECTS]; // Physic objects pool
static int physicObjectsCount; // Counts current enabled physic objects static int physicObjectsCount; // Counts current enabled physic objects
static Vector2 gravityForce; // Gravity force static Vector2 gravityForce; // Gravity force
@ -463,10 +463,10 @@ void ClosePhysics()
} }
// Create a new physic object dinamically, initialize it and add to pool // Create a new physic object dinamically, initialize it and add to pool
PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale) PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale)
{ {
// Allocate dynamic memory // Allocate dynamic memory
PhysicObject *obj = (PhysicObject *)malloc(sizeof(PhysicObject)); PhysicObject obj = (PhysicObject)malloc(sizeof(PhysicObjectData));
// Initialize physic object values with generic values // Initialize physic object values with generic values
obj->id = physicObjectsCount; obj->id = physicObjectsCount;
@ -498,7 +498,7 @@ PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale
} }
// Destroy a specific physic object and take it out of the list // Destroy a specific physic object and take it out of the list
void DestroyPhysicObject(PhysicObject *pObj) void DestroyPhysicObject(PhysicObject pObj)
{ {
// Free dynamic memory allocation // Free dynamic memory allocation
free(physicObjects[pObj->id]); free(physicObjects[pObj->id]);
@ -520,7 +520,7 @@ void DestroyPhysicObject(PhysicObject *pObj)
} }
// Apply directional force to a physic object // Apply directional force to a physic object
void ApplyForce(PhysicObject *pObj, Vector2 force) void ApplyForce(PhysicObject pObj, Vector2 force)
{ {
if (pObj->rigidbody.enabled) if (pObj->rigidbody.enabled)
{ {
@ -571,7 +571,7 @@ Rectangle TransformToRectangle(Transform transform)
} }
// Draw physic object information at screen position // Draw physic object information at screen position
void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize) void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize)
{ {
// Draw physic object ID // Draw physic object ID
DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK); DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK);

View File

@ -66,13 +66,13 @@ typedef struct Collider {
int radius; // Used for COLLIDER_CIRCLE int radius; // Used for COLLIDER_CIRCLE
} Collider; } Collider;
typedef struct PhysicObject { typedef struct PhysicObjectData {
unsigned int id; unsigned int id;
Transform transform; Transform transform;
Rigidbody rigidbody; Rigidbody rigidbody;
Collider collider; Collider collider;
bool enabled; bool enabled;
} PhysicObject; } PhysicObjectData, *PhysicObject;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
@ -85,14 +85,14 @@ void InitPhysics(Vector2 gravity);
void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection
void ClosePhysics(); // Unitialize all physic objects and empty the objects pool void ClosePhysics(); // Unitialize all physic objects and empty the objects pool
PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale); // Create a new physic object dinamically, initialize it and add to pool PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale); // Create a new physic object dinamically, initialize it and add to pool
void DestroyPhysicObject(PhysicObject *pObj); // Destroy a specific physic object and take it out of the list void DestroyPhysicObject(PhysicObject pObj); // Destroy a specific physic object and take it out of the list
void ApplyForce(PhysicObject *pObj, Vector2 force); // Apply directional force to a physic object void ApplyForce(PhysicObject pObj, Vector2 force); // Apply directional force to a physic object
void ApplyForceAtPosition(Vector2 position, float force, float radius); // Apply radial force to all physic objects in range void ApplyForceAtPosition(Vector2 position, float force, float radius); // Apply radial force to all physic objects in range
Rectangle TransformToRectangle(Transform transform); // Convert Transform data type to Rectangle (position and scale) Rectangle TransformToRectangle(Transform transform); // Convert Transform data type to Rectangle (position and scale)
void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize); // Draw physic object information at screen position void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize); // Draw physic object information at screen position
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -398,7 +398,7 @@ typedef struct Shader {
// Uniform locations // Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
int tintColorLoc; // Color uniform location point (fragment shader) int tintColorLoc; // Diffuse color uniform location point (fragment shader)
// Texture map locations // Texture map locations
int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader)
@ -418,18 +418,36 @@ typedef struct Material {
Color colAmbient; // Ambient color Color colAmbient; // Ambient color
Color colSpecular; // Specular color Color colSpecular; // Specular color
float glossiness; // Glossiness level float glossiness; // Glossiness level (Ranges from 0 to 1000)
float normalDepth; // Normal map depth float normalDepth; // Normal map depth
} Material; } Material;
// 3d Model type // Model type
// TODO: Replace shader/testure by material
typedef struct Model { typedef struct Model {
Mesh mesh; // Vertex data buffers (RAM and VRAM) Mesh mesh; // Vertex data buffers (RAM and VRAM)
Matrix transform; // Local transform matrix Matrix transform; // Local transform matrix
Material material; // Shader and textures data Material material; // Shader and textures data
} Model; } Model;
// Light type
typedef struct LightData {
int id;
int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
bool enabled;
Vector3 position;
Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
float attenuation; // Lost of light intensity with distance (world distance)
Color diffuse; // Use Vector3 diffuse
float intensity;
float coneAngle; // Spot light max angle
} LightData, *Light;
// Light types
typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
// Ray type (useful for raycast) // Ray type (useful for raycast)
typedef struct Ray { typedef struct Ray {
Vector3 position; Vector3 position;
@ -451,10 +469,7 @@ typedef struct Wave {
short channels; short channels;
} Wave; } Wave;
// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be typedef int RawAudioContext;
// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
// a dedicated mix channel.
typedef void* AudioContext;
// Texture formats // Texture formats
// NOTE: Support depends on OpenGL version and platform // NOTE: Support depends on OpenGL version and platform
@ -539,13 +554,13 @@ typedef struct Collider {
int radius; // Used for COLLIDER_CIRCLE int radius; // Used for COLLIDER_CIRCLE
} Collider; } Collider;
typedef struct PhysicObject { typedef struct PhysicObjectData {
unsigned int id; unsigned int id;
Transform transform; Transform transform;
Rigidbody rigidbody; Rigidbody rigidbody;
Collider collider; Collider collider;
bool enabled; bool enabled;
} PhysicObject; } PhysicObjectData, *PhysicObject;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
@ -787,6 +802,7 @@ const char *SubText(const char *text, int position, int length);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models) // Basic 3d Shapes Drawing Functions (Module: models)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube
void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires
@ -806,7 +822,7 @@ void DrawGizmo(Vector3 position);
// Model 3d Loading and Drawing Functions (Module: models) // Model 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) Model LoadModelEx(Mesh data, bool dynamic); // Load a 3d model (from mesh data)
Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource) Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource)
Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model
Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based)
@ -815,6 +831,7 @@ void SetModelTexture(Model *model, Texture2D texture); // Link a textur
Material LoadMaterial(const char *fileName); // Load material data (from file) Material LoadMaterial(const char *fileName); // Load material data (from file)
Material LoadDefaultMaterial(void); // Load default material (uses default models shader) Material LoadDefaultMaterial(void); // Load default material (uses default models shader)
Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader)
void UnloadMaterial(Material material); // Unload material textures from VRAM void UnloadMaterial(Material material); // Unload material textures from VRAM
void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
@ -844,6 +861,7 @@ void UnloadShader(Shader shader); // Unload a
void SetDefaultShader(void); // Set default shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw
void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw
Shader GetDefaultShader(void); // Get default shader Shader GetDefaultShader(void); // Get default shader
Shader GetStandardShader(void); // Get default shader
Texture2D GetDefaultTexture(void); // Get default texture Texture2D GetDefaultTexture(void); // Get default texture
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
@ -853,6 +871,10 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // S
void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied)
Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool
void DrawLights(void); // Draw all created lights in 3D world
void DestroyLight(Light light); // Destroy a light and take it out of the list
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Physics System Functions (Module: physac) // Physics System Functions (Module: physac)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -860,14 +882,14 @@ void InitPhysics(Vector2 gravity);
void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection
void ClosePhysics(); // Unitialize all physic objects and empty the objects pool void ClosePhysics(); // Unitialize all physic objects and empty the objects pool
PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale); // Create a new physic object dinamically, initialize it and add to pool PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale); // Create a new physic object dinamically, initialize it and add to pool
void DestroyPhysicObject(PhysicObject *pObj); // Destroy a specific physic object and take it out of the list void DestroyPhysicObject(PhysicObject pObj); // Destroy a specific physic object and take it out of the list
void ApplyForce(PhysicObject *pObj, Vector2 force); // Apply directional force to a physic object void ApplyForce(PhysicObject pObj, Vector2 force); // Apply directional force to a physic object
void ApplyForceAtPosition(Vector2 position, float force, float radius); // Apply radial force to all physic objects in range void ApplyForceAtPosition(Vector2 position, float force, float radius); // Apply radial force to all physic objects in range
Rectangle TransformToRectangle(Transform transform); // Convert Transform data type to Rectangle (position and scale) Rectangle TransformToRectangle(Transform transform); // Convert Transform data type to Rectangle (position and scale)
void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize); // Draw physic object information at screen position void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize); // Draw physic object information at screen position
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio) // Audio Loading and Playing Functions (Module: audio)
@ -876,13 +898,6 @@ void InitAudioDevice(void); // Initialize au
void CloseAudioDevice(void); // Close the audio device and context (and music stream) void CloseAudioDevice(void); // Close the audio device and context (and music stream)
bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
void CloseAudioContext(AudioContext ctx); // Frees audio context
unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSound(char *fileName); // Load sound to memory
Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data
Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource)
@ -894,15 +909,24 @@ bool IsSoundPlaying(Sound sound); // Check if a so
void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
void PlayMusicStream(char *fileName); // Start music playing (open stream) int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream)
void UpdateMusicStream(void); // Updates buffers for music streaming void UpdateMusicStream(int index); // Updates buffers for music streaming
void StopMusicStream(void); // Stop music playing (close stream) void StopMusicStream(int index); // Stop music playing (close stream)
void PauseMusicStream(void); // Pause music playing void PauseMusicStream(int index); // Pause music playing
void ResumeMusicStream(void); // Resume playing paused music void ResumeMusicStream(int index); // Resume playing paused music
bool IsMusicPlaying(void); // Check if music is playing bool IsMusicPlaying(int index); // Check if music is playing
void SetMusicVolume(float volume); // Set volume for music (1.0 is max level) void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level)
float GetMusicTimeLength(void); // Get current music time length (in seconds) float GetMusicTimeLength(int index); // Get current music time length (in seconds)
float GetMusicTimePlayed(void); // Get current music time played (in seconds) float GetMusicTimePlayed(int index); // Get current music time played (in seconds)
int getMusicStreamCount(void);
void SetMusicPitch(int index, float pitch);
// used to output raw audio streams, returns negative numbers on error
// if floating point is false the data size is 16bit short, otherwise it is float 32bit
RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
void CloseRawAudioContext(RawAudioContext ctx);
int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -71,6 +71,8 @@
#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes #define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations) #define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
// NOTE: Every vertex are 3 floats (12 bytes) // NOTE: Every vertex are 3 floats (12 bytes)
#define MAX_LIGHTS 8 // Max lights supported by standard shader
#ifndef GL_SHADING_LANGUAGE_VERSION #ifndef GL_SHADING_LANGUAGE_VERSION
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_SHADING_LANGUAGE_VERSION 0x8B8C
@ -189,6 +191,7 @@ static bool useTempBuffer = false;
// Shader Programs // Shader Programs
static Shader defaultShader; static Shader defaultShader;
static Shader standardShader;
static Shader currentShader; // By default, defaultShader static Shader currentShader; // By default, defaultShader
// Flags for supported extensions // Flags for supported extensions
@ -199,6 +202,10 @@ static bool texCompETC1Supported = false; // ETC1 texture compression support
static bool texCompETC2Supported = false; // ETC2/EAC texture compression support static bool texCompETC2Supported = false; // ETC2/EAC texture compression support
static bool texCompPVRTSupported = false; // PVR texture compression support static bool texCompPVRTSupported = false; // PVR texture compression support
static bool texCompASTCSupported = false; // ASTC texture compression support static bool texCompASTCSupported = false; // ASTC texture compression support
// Lighting data
static Light lights[MAX_LIGHTS]; // Lights pool
static int lightsCount; // Counts current enabled physic objects
#endif #endif
// Compressed textures support flags // Compressed textures support flags
@ -227,14 +234,18 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id
static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring) static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring)
static Shader LoadStandardShader(void); // Load standard shader (support materials and lighting)
static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
static void UnloadDefaultShader(void); // Unload default shader static void UnloadDefaultShader(void); // Unload default shader
static void UnloadStandardShader(void); // Unload standard shader
static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads) static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads)
static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data
static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data static void DrawDefaultBuffers(void); // Draw default internal buffers vertex data
static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU
static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array
static char *ReadTextFile(const char *fileName); static char *ReadTextFile(const char *fileName);
#endif #endif
@ -740,6 +751,24 @@ void rlDisableDepthTest(void)
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
} }
// Enable wire mode
void rlEnableWireMode(void)
{
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif
}
// Disable wire mode
void rlDisableWireMode(void)
{
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}
// Unload texture from GPU memory // Unload texture from GPU memory
void rlDeleteTextures(unsigned int id) void rlDeleteTextures(unsigned int id)
{ {
@ -991,6 +1020,7 @@ void rlglInit(void)
// Init default Shader (customized for GL 3.3 and ES2) // Init default Shader (customized for GL 3.3 and ES2)
defaultShader = LoadDefaultShader(); defaultShader = LoadDefaultShader();
standardShader = LoadStandardShader();
currentShader = defaultShader; currentShader = defaultShader;
LoadDefaultBuffers(); // Initialize default vertex arrays buffers (lines, triangles, quads) LoadDefaultBuffers(); // Initialize default vertex arrays buffers (lines, triangles, quads)
@ -1019,6 +1049,7 @@ void rlglClose(void)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
UnloadDefaultShader(); UnloadDefaultShader();
UnloadStandardShader();
UnloadDefaultBuffers(); UnloadDefaultBuffers();
// Delete default white texture // Delete default white texture
@ -1033,178 +1064,18 @@ void rlglClose(void)
void rlglDraw(void) void rlglDraw(void)
{ {
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
/*
for (int i = 0; i < modelsCount; i++)
{
rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform);
}
*/
// NOTE: Default buffers always drawn at the end
UpdateDefaultBuffers(); UpdateDefaultBuffers();
DrawDefaultBuffers(); DrawDefaultBuffers();
#endif #endif
} }
// Draw a 3d mesh with material and transform
void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires)
{
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
#endif
#if defined(GRAPHICS_API_OPENGL_11)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
// NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY); // Enable colors array
glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array
if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array
if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array
rlPushMatrix();
rlMultMatrixf(MatrixToFloat(transform));
rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
rlPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable colors array
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram(material.shader.id);
// At this point the modelview matrix just contains the view matrix (camera)
// That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matView = modelview; // View matrix (camera)
Matrix matProjection = projection; // Projection matrix (perspective)
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates
// Calculate model-view-projection matrix (MVP)
Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates
// Send combined model-view-projection matrix to shader
glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
// Apply color tinting (material.colDiffuse)
// NOTE: Just update one uniform on fragment shader
float vColor[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
glUniform4fv(material.shader.tintColorLoc, 1, vColor);
// Set shader textures (diffuse, normal, specular)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
glUniform1i(material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0
if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
glUniform1i(material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1
}
if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
{
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2
}
if (vaoSupported)
{
glBindVertexArray(mesh.vaoId);
}
else
{
// Bind mesh VBO data: vertex position (shader-location = 0)
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
glVertexAttribPointer(material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.vertexLoc);
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
glVertexAttribPointer(material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.texcoordLoc);
// Bind mesh VBO data: vertex normals (shader-location = 2, if available)
if (material.shader.normalLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.normalLoc);
}
// Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available)
if (material.shader.colorLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(material.shader.colorLoc);
}
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if (material.shader.tangentLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.tangentLoc);
}
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if (material.shader.texcoord2Loc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.texcoord2Loc);
}
if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
}
// Draw call!
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
if (material.texNormal.id != 0)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
if (material.texSpecular.id != 0)
{
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
}
glActiveTexture(GL_TEXTURE0); // Set shader active texture to default 0
glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
if (vaoSupported) glBindVertexArray(0); // Unbind VAO
else
{
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs
if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glUseProgram(0); // Unbind shader program
#endif
#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: glPolygonMode() not available on OpenGL ES
if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif
}
// Initialize Graphics Device (OpenGL stuff) // Initialize Graphics Device (OpenGL stuff)
// NOTE: Stores global variables screenWidth and screenHeight // NOTE: Stores global variables screenWidth and screenHeight
void rlglInitGraphics(int offsetX, int offsetY, int width, int height) void rlglInitGraphics(int offsetX, int offsetY, int width, int height)
@ -1526,7 +1397,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
{ {
TraceLog(WARNING, "Framebuffer object could not be created..."); TraceLog(WARNING, "Framebuffer object could not be created...");
switch(status) switch (status)
{ {
case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break;
@ -1642,7 +1513,7 @@ void rlglGenerateMipmaps(Texture2D texture)
} }
// Upload vertex data into a VAO (if supported) and VBO // Upload vertex data into a VAO (if supported) and VBO
void rlglLoadMesh(Mesh *mesh) void rlglLoadMesh(Mesh *mesh, bool dynamic)
{ {
mesh->vaoId = 0; // Vertex Array Object mesh->vaoId = 0; // Vertex Array Object
mesh->vboId[0] = 0; // Vertex positions VBO mesh->vboId[0] = 0; // Vertex positions VBO
@ -1652,6 +1523,9 @@ void rlglLoadMesh(Mesh *mesh)
mesh->vboId[4] = 0; // Vertex tangents VBO mesh->vboId[4] = 0; // Vertex tangents VBO
mesh->vboId[5] = 0; // Vertex texcoords2 VBO mesh->vboId[5] = 0; // Vertex texcoords2 VBO
mesh->vboId[6] = 0; // Vertex indices VBO mesh->vboId[6] = 0; // Vertex indices VBO
int drawHint = GL_STATIC_DRAW;
if (dynamic) drawHint = GL_DYNAMIC_DRAW;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
GLuint vaoId = 0; // Vertex Array Objects (VAO) GLuint vaoId = 0; // Vertex Array Objects (VAO)
@ -1669,14 +1543,14 @@ void rlglLoadMesh(Mesh *mesh)
// Enable vertex attributes: position (shader-location = 0) // Enable vertex attributes: position (shader-location = 0)
glGenBuffers(1, &vboId[0]); glGenBuffers(1, &vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint);
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
// Enable vertex attributes: texcoords (shader-location = 1) // Enable vertex attributes: texcoords (shader-location = 1)
glGenBuffers(1, &vboId[1]); glGenBuffers(1, &vboId[1]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[1]); glBindBuffer(GL_ARRAY_BUFFER, vboId[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint);
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
@ -1685,7 +1559,7 @@ void rlglLoadMesh(Mesh *mesh)
{ {
glGenBuffers(1, &vboId[2]); glGenBuffers(1, &vboId[2]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); glBindBuffer(GL_ARRAY_BUFFER, vboId[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint);
glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
} }
@ -1701,7 +1575,7 @@ void rlglLoadMesh(Mesh *mesh)
{ {
glGenBuffers(1, &vboId[3]); glGenBuffers(1, &vboId[3]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[3]); glBindBuffer(GL_ARRAY_BUFFER, vboId[3]);
glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint);
glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(3); glEnableVertexAttribArray(3);
} }
@ -1717,7 +1591,7 @@ void rlglLoadMesh(Mesh *mesh)
{ {
glGenBuffers(1, &vboId[4]); glGenBuffers(1, &vboId[4]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[4]); glBindBuffer(GL_ARRAY_BUFFER, vboId[4]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, drawHint);
glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(4); glEnableVertexAttribArray(4);
} }
@ -1733,7 +1607,7 @@ void rlglLoadMesh(Mesh *mesh)
{ {
glGenBuffers(1, &vboId[5]); glGenBuffers(1, &vboId[5]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[5]); glBindBuffer(GL_ARRAY_BUFFER, vboId[5]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint);
glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0); glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(5); glEnableVertexAttribArray(5);
} }
@ -1776,6 +1650,270 @@ void rlglLoadMesh(Mesh *mesh)
#endif #endif
} }
// Update vertex data on GPU (upload new data to one buffer)
void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex)
{
// Activate mesh VAO
if (vaoSupported) glBindVertexArray(mesh.vaoId);
switch (buffer)
{
case 0: // Update vertices (vertex position)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.vertices, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.vertices);
} break;
case 1: // Update texcoords (vertex texture coordinates)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords);
} break;
case 2: // Update normals (vertex normals)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.normals, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.normals);
} break;
case 3: // Update colors (vertex colors)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.colors, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*numVertex, mesh.colors);
} break;
case 4: // Update tangents (vertex tangents)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.tangents, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.tangents);
} break;
case 5: // Update texcoords2 (vertex second texture coordinates)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords2, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords2);
} break;
default: break;
}
// Unbind the current VAO
if (vaoSupported) glBindVertexArray(0);
// Another option would be using buffer mapping...
//mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
// Now we can modify vertices
//glUnmapBuffer(GL_ARRAY_BUFFER);
}
// Draw a 3d mesh with material and transform
void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
{
#if defined(GRAPHICS_API_OPENGL_11)
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
// NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY); // Enable colors array
glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array
if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array
if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array
rlPushMatrix();
rlMultMatrixf(MatrixToFloat(transform));
rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
rlPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY); // Disable colors array
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
glUseProgram(material.shader.id);
// At this point the modelview matrix just contains the view matrix (camera)
// That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matView = modelview; // View matrix (camera)
Matrix matProjection = projection; // Projection matrix (perspective)
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates
// Calculate model-view-projection matrix (MVP)
Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates
// Send combined model-view-projection matrix to shader
glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
// Upload to shader material.colDiffuse
float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse);
// Check if using standard shader to get location points
// NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations)
if (material.shader.id == standardShader.id)
{
// Send model transformations matrix to shader
glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform));
// Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position)
glUniform3f(glGetUniformLocation(material.shader.id, "viewDir"), matView.m8, matView.m9, matView.m10);
// Setup shader uniforms for lights
SetShaderLights(material.shader);
// Upload to shader material.colAmbient
glUniform4f(glGetUniformLocation(material.shader.id, "colAmbient"), (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
// Upload to shader material.colSpecular
glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
// Upload to shader glossiness
glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness);
}
// Set shader textures (diffuse, normal, specular)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
glUniform1i(material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0
if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
glUniform1i(material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1
// TODO: Upload to shader normalDepth
//glUniform1f(???, material.normalDepth);
}
if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
{
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2
}
if (vaoSupported)
{
glBindVertexArray(mesh.vaoId);
}
else
{
// Bind mesh VBO data: vertex position (shader-location = 0)
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
glVertexAttribPointer(material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.vertexLoc);
// Bind mesh VBO data: vertex texcoords (shader-location = 1)
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
glVertexAttribPointer(material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.texcoordLoc);
// Bind mesh VBO data: vertex normals (shader-location = 2, if available)
if (material.shader.normalLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.normalLoc);
}
// Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available)
if (material.shader.colorLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(material.shader.colorLoc);
}
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if (material.shader.tangentLoc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.tangentLoc);
}
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if (material.shader.texcoord2Loc != -1)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.texcoord2Loc);
}
if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
}
// Draw call!
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
if (material.texNormal.id != 0)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
if (material.texSpecular.id != 0)
{
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
}
glActiveTexture(GL_TEXTURE0); // Set shader active texture to default 0
glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
if (vaoSupported) glBindVertexArray(0); // Unbind VAO
else
{
glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs
if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glUseProgram(0); // Unbind shader program
#endif
}
// Unload mesh data from CPU and GPU
void rlglUnloadMesh(Mesh *mesh)
{
if (mesh->vertices != NULL) free(mesh->vertices);
if (mesh->texcoords != NULL) free(mesh->texcoords);
if (mesh->normals != NULL) free(mesh->normals);
if (mesh->colors != NULL) free(mesh->colors);
if (mesh->tangents != NULL) free(mesh->tangents);
if (mesh->texcoords2 != NULL) free(mesh->texcoords2);
if (mesh->indices != NULL) free(mesh->indices);
rlDeleteBuffers(mesh->vboId[0]); // vertex
rlDeleteBuffers(mesh->vboId[1]); // texcoords
rlDeleteBuffers(mesh->vboId[2]); // normals
rlDeleteBuffers(mesh->vboId[3]); // colors
rlDeleteBuffers(mesh->vboId[4]); // tangents
rlDeleteBuffers(mesh->vboId[5]); // texcoords2
rlDeleteBuffers(mesh->vboId[6]); // indices
rlDeleteVertexArrays(mesh->vaoId);
}
// Read screen pixel data (color buffer) // Read screen pixel data (color buffer)
unsigned char *rlglReadScreenPixels(int width, int height) unsigned char *rlglReadScreenPixels(int width, int height)
{ {
@ -2022,6 +2160,17 @@ Shader GetDefaultShader(void)
#endif #endif
} }
// Get default shader
Shader GetStandardShader(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
return standardShader;
#else
Shader shader = { 0 };
return shader;
#endif
}
// Get shader uniform location // Get shader uniform location
int GetShaderLocation(Shader shader, const char *uniformName) int GetShaderLocation(Shader shader, const char *uniformName)
{ {
@ -2098,6 +2247,78 @@ void SetBlendMode(int mode)
} }
} }
// Create a new light, initialize it and add to pool
Light CreateLight(int type, Vector3 position, Color diffuse)
{
// Allocate dynamic memory
Light light = (Light)malloc(sizeof(LightData));
// Initialize light values with generic values
light->id = lightsCount;
light->type = type;
light->enabled = true;
light->position = position;
light->target = (Vector3){ 0.0f, 0.0f, 0.0f };
light->intensity = 1.0f;
light->diffuse = diffuse;
// Add new light to the array
lights[lightsCount] = light;
// Increase enabled lights count
lightsCount++;
return light;
}
// Draw all created lights in 3D world
void DrawLights(void)
{
for (int i = 0; i < lightsCount; i++)
{
switch (lights[i]->type)
{
case LIGHT_POINT: DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); break;
case LIGHT_DIRECTIONAL:
{
Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
} break;
case LIGHT_SPOT:
{
Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
DrawCylinderWires(lights[i]->position, 0.0f, 0.3f*lights[i]->coneAngle/50, 0.6f, 5, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
} break;
default: break;
}
}
}
// Destroy a light and take it out of the list
void DestroyLight(Light light)
{
// Free dynamic memory allocation
free(lights[light->id]);
// Remove *obj from the pointers array
for (int i = light->id; i < lightsCount; i++)
{
// Resort all the following pointers of the array
if ((i + 1) < lightsCount)
{
lights[i] = lights[i + 1];
lights[i]->id = lights[i + 1]->id;
}
else free(lights[i]);
}
// Decrease enabled physic objects count
lightsCount--;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -2293,15 +2514,15 @@ static Shader LoadDefaultShader(void)
"varying vec4 fragColor; \n" "varying vec4 fragColor; \n"
#endif #endif
"uniform sampler2D texture0; \n" "uniform sampler2D texture0; \n"
"uniform vec4 fragTintColor; \n" "uniform vec4 colDiffuse; \n"
"void main() \n" "void main() \n"
"{ \n" "{ \n"
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
" vec4 texelColor = texture(texture0, fragTexCoord); \n" " vec4 texelColor = texture(texture0, fragTexCoord); \n"
" finalColor = texelColor*fragTintColor*fragColor; \n" " finalColor = texelColor*colDiffuse*fragColor; \n"
#elif defined(GRAPHICS_API_OPENGL_ES2) #elif defined(GRAPHICS_API_OPENGL_ES2)
" vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0 " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
" gl_FragColor = texelColor*fragTintColor*fragColor; \n" " gl_FragColor = texelColor*colDiffuse*fragColor; \n"
#endif #endif
"} \n"; "} \n";
@ -2315,6 +2536,24 @@ static Shader LoadDefaultShader(void)
return shader; return shader;
} }
// Load standard shader
// NOTE: This shader supports:
// - Up to 3 different maps: diffuse, normal, specular
// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth
// - Up to 8 lights: Point, Directional or Spot
static Shader LoadStandardShader(void)
{
// Load standard shader (TODO: rewrite as char pointers)
Shader shader = LoadShader("resources/shaders/standard.vs", "resources/shaders/standard.fs");
if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
else TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded", shader.id);
if (shader.id != 0) LoadDefaultShaderLocations(&shader);
return shader;
}
// Get location handlers to for shader attributes and uniforms // Get location handlers to for shader attributes and uniforms
// NOTE: If any location is not found, loc point becomes -1 // NOTE: If any location is not found, loc point becomes -1
static void LoadDefaultShaderLocations(Shader *shader) static void LoadDefaultShaderLocations(Shader *shader)
@ -2328,18 +2567,18 @@ static void LoadDefaultShaderLocations(Shader *shader)
// vertex texcoord2 location = 5 // vertex texcoord2 location = 5
// Get handles to GLSL input attibute locations // Get handles to GLSL input attibute locations
shader->vertexLoc = glGetAttribLocation(shader->id, "vertexPosition"); shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
shader->texcoordLoc = glGetAttribLocation(shader->id, "vertexTexCoord"); shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
shader->normalLoc = glGetAttribLocation(shader->id, "vertexNormal"); shader->normalLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME);
shader->colorLoc = glGetAttribLocation(shader->id, "vertexColor"); shader->colorLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME);
shader->tangentLoc = glGetAttribLocation(shader->id, "vertexTangent"); shader->tangentLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME);
shader->texcoord2Loc = glGetAttribLocation(shader->id, "vertexTexCoord2"); shader->texcoord2Loc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME);
// Get handles to GLSL uniform locations (vertex shader) // Get handles to GLSL uniform locations (vertex shader)
shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix");
// Get handles to GLSL uniform locations (fragment shader) // Get handles to GLSL uniform locations (fragment shader)
shader->tintColorLoc = glGetUniformLocation(shader->id, "fragTintColor"); shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse");
shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0"); shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0");
shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1"); shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1");
shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2"); shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
@ -2350,13 +2589,26 @@ static void UnloadDefaultShader(void)
{ {
glUseProgram(0); glUseProgram(0);
//glDetachShader(defaultShaderProgram, vertexShader); //glDetachShader(defaultShader, vertexShader);
//glDetachShader(defaultShaderProgram, fragmentShader); //glDetachShader(defaultShader, fragmentShader);
//glDeleteShader(vertexShader); // Already deleted on shader compilation //glDeleteShader(vertexShader); // Already deleted on shader compilation
//glDeleteShader(fragmentShader); // Already deleted on sahder compilation //glDeleteShader(fragmentShader); // Already deleted on shader compilation
glDeleteProgram(defaultShader.id); glDeleteProgram(defaultShader.id);
} }
// Unload standard shader
static void UnloadStandardShader(void)
{
glUseProgram(0);
//glDetachShader(defaultShader, vertexShader);
//glDetachShader(defaultShader, fragmentShader);
//glDeleteShader(vertexShader); // Already deleted on shader compilation
//glDeleteShader(fragmentShader); // Already deleted on shader compilation
glDeleteProgram(standardShader.id);
}
// Load default internal buffers (lines, triangles, quads) // Load default internal buffers (lines, triangles, quads)
static void LoadDefaultBuffers(void) static void LoadDefaultBuffers(void)
{ {
@ -2800,6 +3052,79 @@ static void UnloadDefaultBuffers(void)
free(quads.indices); free(quads.indices);
} }
// Sets shader uniform values for lights array
// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f
static void SetShaderLights(Shader shader)
{
int locPoint = glGetUniformLocation(shader.id, "lightsCount");
glUniform1i(locPoint, lightsCount);
char locName[32] = "lights[x].position\0";
for (int i = 0; i < lightsCount; i++)
{
locName[7] = '0' + i;
memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1);
locPoint = GetShaderLocation(shader, locName);
glUniform1i(locPoint, lights[i]->enabled);
memcpy(&locName[10], "type\0", strlen("type\0") + 1);
locPoint = GetShaderLocation(shader, locName);
glUniform1i(locPoint, lights[i]->type);
memcpy(&locName[10], "diffuse\0", strlen("diffuse\0") + 2);
locPoint = glGetUniformLocation(shader.id, locName);
glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255);
memcpy(&locName[10], "intensity\0", strlen("intensity\0"));
locPoint = glGetUniformLocation(shader.id, locName);
glUniform1f(locPoint, lights[i]->intensity);
switch (lights[i]->type)
{
case LIGHT_POINT:
{
memcpy(&locName[10], "position\0", strlen("position\0") + 1);
locPoint = GetShaderLocation(shader, locName);
glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
memcpy(&locName[10], "attenuation\0", strlen("attenuation\0"));
locPoint = GetShaderLocation(shader, locName);
glUniform1f(locPoint, lights[i]->attenuation);
} break;
case LIGHT_DIRECTIONAL:
{
memcpy(&locName[10], "direction\0", strlen("direction\0") + 2);
locPoint = GetShaderLocation(shader, locName);
Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z };
VectorNormalize(&direction);
glUniform3f(locPoint, direction.x, direction.y, direction.z);
} break;
case LIGHT_SPOT:
{
memcpy(&locName[10], "position\0", strlen("position\0") + 1);
locPoint = GetShaderLocation(shader, locName);
glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
memcpy(&locName[10], "direction\0", strlen("direction\0") + 2);
locPoint = GetShaderLocation(shader, locName);
Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z };
VectorNormalize(&direction);
glUniform3f(locPoint, direction.x, direction.y, direction.z);
memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0"));
locPoint = GetShaderLocation(shader, locName);
glUniform1f(locPoint, lights[i]->coneAngle);
} break;
default: break;
}
// TODO: Pass to the shader any other required data from LightData struct
}
}
// Read text data from file // Read text data from file
// NOTE: text chars array should be freed manually // NOTE: text chars array should be freed manually
static char *ReadTextFile(const char *fileName) static char *ReadTextFile(const char *fileName)
@ -2970,7 +3295,7 @@ static void TraceLog(int msgType, const char *text, ...)
va_list args; va_list args;
va_start(args, text); va_start(args, text);
switch(msgType) switch (msgType)
{ {
case INFO: fprintf(stdout, "INFO: "); break; case INFO: fprintf(stdout, "INFO: "); break;
case ERROR: fprintf(stdout, "ERROR: "); break; case ERROR: fprintf(stdout, "ERROR: "); break;

View File

@ -196,19 +196,35 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
// Material type // Material type
typedef struct Material { typedef struct Material {
Shader shader; Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular)
Texture2D texDiffuse; // Diffuse texture Texture2D texDiffuse; // Diffuse texture
Texture2D texNormal; // Normal texture Texture2D texNormal; // Normal texture
Texture2D texSpecular; // Specular texture Texture2D texSpecular; // Specular texture
Color colDiffuse; Color colDiffuse; // Diffuse color
Color colAmbient; Color colAmbient; // Ambient color
Color colSpecular; Color colSpecular; // Specular color
float glossiness; float glossiness; // Glossiness level (Ranges from 0 to 1000)
float normalDepth; float normalDepth; // Normal map depth
} Material; } Material;
// Light type
typedef struct LightData {
int id;
int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
bool enabled;
Vector3 position;
Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
float attenuation; // Lost of light intensity with distance (world distance)
Color diffuse; // Use Vector3 diffuse
float intensity;
float coneAngle; // Spot light max angle
} LightData, *Light;
// Color blending modes (pre-defined) // Color blending modes (pre-defined)
typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
@ -256,6 +272,8 @@ void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo)
void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer
void rlEnableDepthTest(void); // Enable depth test void rlEnableDepthTest(void); // Enable depth test
void rlDisableDepthTest(void); // Disable depth test void rlDisableDepthTest(void); // Disable depth test
void rlEnableWireMode(void); // Enable wire mode
void rlDisableWireMode(void); // Disable wire mode
void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU
void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU
@ -277,8 +295,11 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data
void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture
void rlglLoadMesh(Mesh *mesh); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires); void rlglLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
void rlglDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
void rlglUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
@ -306,6 +327,9 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // S
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied)
Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool
void DestroyLight(Light light); // Destroy a light and take it out of the list
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -446,7 +446,6 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
} }
// Get collision rectangle for two rectangles collision // Get collision rectangle for two rectangles collision
// TODO: Depending on rec1 and rec2 order, it fails -> Review!
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
{ {
Rectangle retRec = { 0, 0, 0, 0 }; Rectangle retRec = { 0, 0, 0, 0 };

2
src/windows_compile.bat Normal file
View File

@ -0,0 +1,2 @@
set PATH=C:\raylib\MinGW\bin;%PATH%
mingw32-make

View File

@ -1,10 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
# location of the SDK. This is only used by Ant
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=C:\\android-sdk

View File

@ -1,10 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
# location of the SDK. This is only used by Ant
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=C:\\android-sdk