Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
This commit is contained in:
commit
f232f34981
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@ src_android/obj/
|
||||
templates/android_project/bin/
|
||||
templates/android_project/obj/
|
||||
templates/android_project/libs/
|
||||
local.properties
|
||||
|
||||
# Ignore thumbnails created by windows
|
||||
Thumbs.db
|
||||
|
@ -36,7 +36,8 @@ int main()
|
||||
//----------------------------------------------------------------------------------
|
||||
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.y -= gamepadMovement.y;
|
||||
|
@ -30,26 +30,26 @@ int main()
|
||||
bool isDebug = false;
|
||||
|
||||
// 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.applyGravity = true;
|
||||
rectangle->rigidbody.friction = 0.1f;
|
||||
rectangle->rigidbody.bounciness = 6.0f;
|
||||
|
||||
// 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.applyGravity = true;
|
||||
square->rigidbody.friction = 0.1f;
|
||||
|
||||
// Create walls physic objects
|
||||
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 *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 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 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 });
|
||||
|
||||
// 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
|
||||
//--------------------------------------------------------------------------------------
|
||||
ClosePhysics(); // Unitialize physics module
|
||||
ClosePhysics(); // Unitialize physics (including all loaded objects)
|
||||
|
||||
CloseWindow(); // Close window and OpenGL context
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#define LINE_LENGTH 75
|
||||
#define TRIANGLE_LENGTH 12
|
||||
|
||||
void DrawRigidbodyCircle(PhysicObject *obj, Color color);
|
||||
void DrawRigidbodyCircle(PhysicObject obj, Color color);
|
||||
|
||||
int main()
|
||||
{
|
||||
@ -36,7 +36,7 @@ int main()
|
||||
bool isDebug = false;
|
||||
|
||||
// Create rectangle physic objects
|
||||
PhysicObject *rectangles[3];
|
||||
PhysicObject rectangles[3];
|
||||
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 });
|
||||
@ -46,7 +46,7 @@ int main()
|
||||
|
||||
// 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.
|
||||
PhysicObject *circles[3];
|
||||
PhysicObject circles[3];
|
||||
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 });
|
||||
@ -57,10 +57,10 @@ int main()
|
||||
}
|
||||
|
||||
// Create walls physic objects
|
||||
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 *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 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 topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
|
||||
PhysicObject bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -33,5 +33,5 @@ void main()
|
||||
else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
|
||||
else tc = sum*sum*0.0075 + texelColor;
|
||||
|
||||
finalColor = tc;
|
||||
gl_FragColor = tc;
|
||||
}
|
@ -20,7 +20,7 @@ float angle = 0.8;
|
||||
|
||||
uniform vec2 center = vec2(200.0, 200.0);
|
||||
|
||||
void main (void)
|
||||
void main()
|
||||
{
|
||||
vec2 texSize = vec2(renderWidth, renderHeight);
|
||||
vec2 tc = fragTexCoord*texSize;
|
||||
|
@ -17,7 +17,7 @@ void main()
|
||||
{
|
||||
vec4 sum = vec4(0);
|
||||
vec4 tc = vec4(0);
|
||||
|
||||
|
||||
for (int i = -4; i < 4; i++)
|
||||
{
|
||||
for (int j = -3; j < 3; j++)
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -21,7 +21,7 @@ float angle = 0.8;
|
||||
|
||||
uniform vec2 center = vec2(200.0, 200.0);
|
||||
|
||||
void main (void)
|
||||
void main()
|
||||
{
|
||||
vec2 texSize = vec2(renderWidth, renderHeight);
|
||||
vec2 tc = fragTexCoord*texSize;
|
||||
|
136
examples/resources/shaders/standard.fs
Normal file
136
examples/resources/shaders/standard.fs
Normal 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);
|
||||
}
|
23
examples/resources/shaders/standard.vs
Normal file
23
examples/resources/shaders/standard.vs
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
118
examples/shaders_standard_lighting.c
Normal file
118
examples/shaders_standard_lighting.c
Normal 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;
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
#version 100
|
||||
|
||||
// Input vertex attributes
|
||||
attribute vec3 vertexPosition;
|
||||
attribute vec2 vertexTexCoord;
|
||||
attribute vec3 vertexNormal;
|
||||
attribute vec4 vertexColor;
|
||||
|
||||
varying vec2 fragTexCoord;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvpMatrix;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 normal = vertexNormal;
|
||||
|
||||
// Send vertex attributes to fragment shader
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragColor = vertexColor;
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
|
||||
}
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -22,21 +25,13 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
if (texture2D(texture0, fragTexCoord).r < 0.3)
|
||||
{
|
||||
tc = sum*sum*0.012 + texture2D(texture0, fragTexCoord);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (texture2D(texture0, fragTexCoord).r < 0.5)
|
||||
{
|
||||
tc = sum*sum*0.009 + texture2D(texture0, fragTexCoord);
|
||||
}
|
||||
else
|
||||
{
|
||||
tc = sum*sum*0.0075 + texture2D(texture0, fragTexCoord);
|
||||
}
|
||||
}
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||
|
||||
// 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;
|
||||
|
||||
gl_FragColor = tc;
|
||||
}
|
@ -2,7 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -16,6 +20,7 @@ float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );
|
||||
|
||||
void main()
|
||||
{
|
||||
// Texel color fetching from texture sampler
|
||||
vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0];
|
||||
|
||||
for (int i = 1; i < 3; i++)
|
||||
|
@ -2,12 +2,15 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
float hatchOffsetY = 5.0f;
|
||||
float lumThreshold01 = 0.9f;
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -46,7 +49,7 @@ vec4 PostFX(sampler2D tex, vec2 uv)
|
||||
return c;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
void main()
|
||||
{
|
||||
vec3 tc = PostFX(texture0, fragTexCoord).rgb;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
|
@ -2,12 +2,15 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
const float PI = 3.1415926535;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -11,10 +14,12 @@ uniform vec4 fragTintColor;
|
||||
|
||||
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
|
||||
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
|
||||
// Convert texel color to grayscale using NTSC conversion weights
|
||||
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);
|
||||
}
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -14,7 +17,7 @@ float frequency = 720/3.0;
|
||||
|
||||
uniform float time;
|
||||
|
||||
void main (void)
|
||||
void main()
|
||||
{
|
||||
/*
|
||||
// Scanlines method 1
|
||||
|
@ -2,28 +2,32 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
const float renderWidth = 1280;
|
||||
const float renderHeight = 720;
|
||||
const float renderWidth = 800.0; // HARDCODED for example!
|
||||
const float renderHeight = 480.0; // Use uniforms instead...
|
||||
|
||||
float radius = 250.0;
|
||||
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 tc = fragTexCoord*texSize;
|
||||
tc -= center;
|
||||
float dist = length(tc);
|
||||
|
||||
float dist = length(tc);
|
||||
|
||||
if (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 += center;
|
||||
vec3 color = texture2D(texture0, tc/texSize).rgb;
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
@ -11,6 +14,7 @@ uniform vec4 fragTintColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture2D(texture0, fragTexCoord);
|
||||
|
||||
// NOTE: Implement here your fragment shader code
|
||||
|
@ -1,18 +1,26 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
in vec4 vertexColor;
|
||||
|
||||
out vec2 fragTexCoord;
|
||||
|
||||
// Input uniform values
|
||||
uniform mat4 mvpMatrix;
|
||||
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec2 fragTexCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
// Send vertex attributes to fragment shader
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragColor = vertexColor;
|
||||
|
||||
// Calculate final vertex position
|
||||
gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
@ -18,25 +22,17 @@ void main()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = 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;
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
const float renderWidth = 1280.0;
|
||||
@ -17,13 +21,14 @@ float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
|
||||
|
||||
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++)
|
||||
{
|
||||
tc += 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];
|
||||
texelColor += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
|
||||
}
|
||||
|
||||
fragColor = vec4(tc, 1.0);
|
||||
finalColor = vec4(texelColor, 1.0);
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
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 lumThreshold01 = 0.9;
|
||||
@ -27,18 +31,18 @@ void main()
|
||||
|
||||
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 (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 (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);
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
const float renderWidth = 1280.0;
|
||||
@ -46,9 +50,9 @@ vec4 PostFX(sampler2D tex, vec2 uv)
|
||||
return c;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
void main()
|
||||
{
|
||||
vec3 tc = PostFX(texture0, fragTexCoord).rgb;
|
||||
|
||||
fragColor = vec4(tc, 1.0);
|
||||
finalColor = vec4(tc, 1.0);
|
||||
}
|
27
shaders/glsl330/depth.fs
Normal file
27
shaders/glsl330/depth.fs
Normal 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);
|
||||
}
|
@ -1,20 +1,26 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
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
|
||||
float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
|
||||
// Convert texel color to grayscale using NTSC conversion weights
|
||||
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);
|
||||
}
|
@ -1,76 +1,85 @@
|
||||
#version 330
|
||||
|
||||
// Vertex shader input data
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec3 fragNormal;
|
||||
|
||||
// Diffuse data
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Light attributes
|
||||
uniform vec3 light_ambientColor = vec3(0.6, 0.3, 0);
|
||||
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;
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// Material attributes
|
||||
uniform vec3 mat_ambientColor = vec3(1, 1, 1);
|
||||
uniform vec3 mat_specularColor = vec3(1, 1, 1);
|
||||
uniform float mat_glossiness = 50;
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
// World attributes
|
||||
uniform vec3 lightPos;
|
||||
uniform vec3 cameraPos;
|
||||
// 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;
|
||||
|
||||
// Fragment shader output data
|
||||
out vec4 fragColor;
|
||||
|
||||
// Calculate ambient lighting component
|
||||
vec3 AmbientLighting()
|
||||
{
|
||||
return mat_ambientColor * light_ambientColor;
|
||||
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 tintColor.xyz * light_diffuseColor * light_intensity * diffuse;
|
||||
// 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;
|
||||
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 + mat_glossiness);
|
||||
}
|
||||
// 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 mat_specularColor * light_specularColor * light_specIntensity * specular;
|
||||
return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Normalize input vectors
|
||||
vec3 L = normalize(lightPos);
|
||||
vec3 V = normalize(cameraPos);
|
||||
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);
|
||||
|
||||
// Get base color from texture
|
||||
vec4 textureColor = texture(texture0, fragTexCoord);
|
||||
vec3 finalColor = textureColor.rgb;
|
||||
|
||||
fragColor = vec4(finalColor * (ambient + diffuse + specular), textureColor.a);
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||
|
||||
// Calculate final fragment color
|
||||
finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
|
||||
}
|
@ -1,23 +1,25 @@
|
||||
#version 330
|
||||
|
||||
// Vertex input data
|
||||
// Input vertex attributes
|
||||
in vec3 vertexPosition;
|
||||
in vec2 vertexTexCoord;
|
||||
in vec3 vertexNormal;
|
||||
|
||||
// Projection and model data
|
||||
// Input uniform values
|
||||
uniform mat4 mvpMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
|
||||
// Attributes to fragment shader
|
||||
// Output vertex attributes (to fragment shader)
|
||||
out vec2 fragTexCoord;
|
||||
out vec3 fragNormal;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
uniform mat4 modelMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Send texture coord to fragment shader
|
||||
// Send vertex attributes to fragment shader
|
||||
fragTexCoord = vertexTexCoord;
|
||||
|
||||
|
||||
// Calculate view vector normal from model
|
||||
mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
|
||||
fragNormal = normalize(normalMatrix*vertexNormal);
|
||||
|
@ -1,13 +1,17 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
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 renderHeight = 720.0;
|
||||
@ -24,5 +28,5 @@ void main()
|
||||
|
||||
vec3 tc = texture(texture0, coord).rgb;
|
||||
|
||||
fragColor = vec4(tc, 1.0);
|
||||
finalColor = vec4(tc, 1.0);
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
float gamma = 0.6;
|
||||
@ -14,13 +18,14 @@ float numColors = 8.0;
|
||||
|
||||
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));
|
||||
color = color*numColors;
|
||||
color = floor(color);
|
||||
color = color/numColors;
|
||||
color = pow(color, vec3(1.0/gamma));
|
||||
texelColor = pow(texelColor, vec3(gamma, gamma, gamma));
|
||||
texelColor = texelColor*numColors;
|
||||
texelColor = floor(texelColor);
|
||||
texelColor = texelColor/numColors;
|
||||
texelColor = pow(texelColor, vec3(1.0/gamma));
|
||||
|
||||
fragColor = vec4(color, 1.0);
|
||||
finalColor = vec4(texelColor, 1.0);
|
||||
}
|
@ -1,27 +1,32 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 color = texture(texture0, fragTexCoord).rgb;
|
||||
// Texel color fetching from texture sampler
|
||||
vec3 texelColor = texture(texture0, fragTexCoord).rgb;
|
||||
vec3 colors[3];
|
||||
colors[0] = vec3(0.0, 0.0, 1.0);
|
||||
colors[1] = vec3(1.0, 1.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;
|
||||
|
||||
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);
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
float offset = 0.0;
|
||||
@ -14,7 +18,7 @@ float frequency = 720.0/3.0;
|
||||
|
||||
uniform float time;
|
||||
|
||||
void main (void)
|
||||
void main()
|
||||
{
|
||||
/*
|
||||
// Scanlines method 1
|
||||
@ -35,7 +39,8 @@ void main (void)
|
||||
float globalPos = (fragTexCoord.y + offset) * frequency;
|
||||
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);
|
||||
}
|
@ -1,27 +1,32 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
const float renderWidth = 1280.0;
|
||||
const float renderHeight = 720.0;
|
||||
const float renderWidth = 800.0; // HARDCODED for example!
|
||||
const float renderHeight = 480.0; // Use uniforms instead...
|
||||
|
||||
float radius = 250.0;
|
||||
float angle = 0.8;
|
||||
|
||||
uniform vec2 center = vec2(200.0, 200.0);
|
||||
|
||||
void main (void)
|
||||
void main()
|
||||
{
|
||||
vec2 texSize = vec2(renderWidth, renderHeight);
|
||||
vec2 tc = fragTexCoord*texSize;
|
||||
tc -= center;
|
||||
|
||||
float dist = length(tc);
|
||||
|
||||
if (dist < radius)
|
||||
@ -37,5 +42,5 @@ void main (void)
|
||||
tc += center;
|
||||
vec3 color = texture(texture0, tc/texSize).rgb;
|
||||
|
||||
fragColor = vec4(color, 1.0);;
|
||||
finalColor = vec4(color, 1.0);;
|
||||
}
|
@ -1,19 +1,24 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 fragTintColor;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// NOTE: Add here your custom variables
|
||||
|
||||
void main()
|
||||
{
|
||||
// Texel color fetching from texture sampler
|
||||
vec4 texelColor = texture(texture0, fragTexCoord);
|
||||
|
||||
// NOTE: Implement here your fragment shader code
|
||||
|
||||
fragColor = texelColor*fragTintColor;
|
||||
finalColor = texelColor*fragTintColor;
|
||||
}
|
||||
|
708
src/audio.c
708
src/audio.c
@ -59,8 +59,9 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#define MAX_STREAM_BUFFERS 2
|
||||
#define MAX_AUDIO_CONTEXTS 4 // Number of open AL sources
|
||||
#define MAX_STREAM_BUFFERS 2 // Number of buffers for each alSource
|
||||
#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)
|
||||
// NOTE: On RPI and Android should be lower to avoid frame-stalls
|
||||
@ -76,37 +77,32 @@
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Music type (file streaming from memory)
|
||||
// NOTE: Anything longer than ~10 seconds should be streamed...
|
||||
typedef struct Music {
|
||||
stb_vorbis *stream;
|
||||
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 {
|
||||
// Used to create custom audio streams that are not bound to a specific file. There can be
|
||||
// no more than 4 concurrent mixchannels in use. This is due to each active mixc being tied to
|
||||
// a dedicated mix channel.
|
||||
typedef struct MixChannel_t {
|
||||
unsigned short sampleRate; // default is 48000
|
||||
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
|
||||
bool floatingPoint; // if false then the short datatype is used instead
|
||||
bool playing;
|
||||
bool playing; // false if paused
|
||||
ALenum alFormat; // openAL format specifier
|
||||
ALuint alSource; // openAL source
|
||||
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)
|
||||
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
|
||||
//----------------------------------------------------------------------------------
|
||||
static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS]; // What mix channels are currently active
|
||||
static bool musicEnabled = false;
|
||||
static Music currentMusic; // Current music loaded
|
||||
// NOTE: Only one music file playing at a time
|
||||
static MixChannel_t* mixChannelsActive_g[MAX_MIX_CHANNELS]; // What mix channels are currently active
|
||||
static bool musicEnabled_g = false;
|
||||
static Music currentMusic[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
static Wave LoadWAV(const char *fileName); // Load WAV file
|
||||
static Wave LoadOGG(char *fileName); // Load OGG file
|
||||
static void UnloadWave(Wave wave); // Unload wave data
|
||||
static Wave LoadWAV(const char *fileName); // Load WAV file
|
||||
static Wave LoadOGG(char *fileName); // Load OGG file
|
||||
static void UnloadWave(Wave wave); // Unload wave data
|
||||
|
||||
static bool BufferMusicStream(ALuint buffer); // Fill music buffers with data
|
||||
static void EmptyMusicStream(void); // Empty music buffers
|
||||
static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data
|
||||
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 void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // pass two arrays of same length in
|
||||
|
||||
static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
|
||||
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)
|
||||
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
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Initialize audio device and context
|
||||
// Initialize audio device and mixc
|
||||
void InitAudioDevice(void)
|
||||
{
|
||||
// Open and initialize a device with default settings
|
||||
@ -158,7 +159,7 @@ void InitAudioDevice(void)
|
||||
|
||||
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));
|
||||
@ -169,15 +170,19 @@ void InitAudioDevice(void)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
|
||||
@ -202,187 +207,141 @@ bool IsAudioDeviceReady(void)
|
||||
// Module Functions Definition - Custom audio output
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// 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)
|
||||
// For streaming into mix channels.
|
||||
// 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 InitMixChannel(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
|
||||
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();
|
||||
else StopMusicStream();
|
||||
|
||||
if(!mixChannelsActive_g[mixChannel]){
|
||||
AudioContext_t *ac = (AudioContext_t*)malloc(sizeof(AudioContext_t));
|
||||
ac->sampleRate = sampleRate;
|
||||
ac->channels = channels;
|
||||
ac->mixChannel = mixChannel;
|
||||
ac->floatingPoint = floatingPoint;
|
||||
mixChannelsActive_g[mixChannel] = ac;
|
||||
MixChannel_t *mixc = (MixChannel_t*)malloc(sizeof(MixChannel_t));
|
||||
mixc->sampleRate = sampleRate;
|
||||
mixc->channels = channels;
|
||||
mixc->mixChannel = mixChannel;
|
||||
mixc->floatingPoint = floatingPoint;
|
||||
mixChannelsActive_g[mixChannel] = mixc;
|
||||
|
||||
// setup openAL format
|
||||
if(channels == 1)
|
||||
{
|
||||
if(floatingPoint)
|
||||
ac->alFormat = AL_FORMAT_MONO_FLOAT32;
|
||||
mixc->alFormat = AL_FORMAT_MONO_FLOAT32;
|
||||
else
|
||||
ac->alFormat = AL_FORMAT_MONO16;
|
||||
mixc->alFormat = AL_FORMAT_MONO16;
|
||||
}
|
||||
else if(channels == 2)
|
||||
{
|
||||
if(floatingPoint)
|
||||
ac->alFormat = AL_FORMAT_STEREO_FLOAT32;
|
||||
mixc->alFormat = AL_FORMAT_STEREO_FLOAT32;
|
||||
else
|
||||
ac->alFormat = AL_FORMAT_STEREO16;
|
||||
mixc->alFormat = AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
// Create an audio source
|
||||
alGenSources(1, &ac->alSource);
|
||||
alSourcef(ac->alSource, AL_PITCH, 1);
|
||||
alSourcef(ac->alSource, AL_GAIN, 1);
|
||||
alSource3f(ac->alSource, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0);
|
||||
alGenSources(1, &mixc->alSource);
|
||||
alSourcef(mixc->alSource, AL_PITCH, 1);
|
||||
alSourcef(mixc->alSource, AL_GAIN, 1);
|
||||
alSource3f(mixc->alSource, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(mixc->alSource, AL_VELOCITY, 0, 0, 0);
|
||||
|
||||
// Create Buffer
|
||||
alGenBuffers(MAX_STREAM_BUFFERS, ac->alBuffer);
|
||||
alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
|
||||
|
||||
//fill buffers
|
||||
int 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);
|
||||
alSourcePlay(ac->alSource);
|
||||
ac->playing = true;
|
||||
alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer);
|
||||
mixc->playing = true;
|
||||
alSourcePlay(mixc->alSource);
|
||||
|
||||
return ac;
|
||||
return mixc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Frees buffer in audio context
|
||||
void CloseAudioContext(AudioContext ctx)
|
||||
// Frees buffer in mix channel
|
||||
static void CloseMixChannel(MixChannel_t* mixc)
|
||||
{
|
||||
AudioContext_t *context = (AudioContext_t*)ctx;
|
||||
if(context){
|
||||
alSourceStop(context->alSource);
|
||||
context->playing = false;
|
||||
if(mixc){
|
||||
alSourceStop(mixc->alSource);
|
||||
mixc->playing = false;
|
||||
|
||||
//flush out all queued buffers
|
||||
ALuint buffer = 0;
|
||||
int queued = 0;
|
||||
alGetSourcei(context->alSource, AL_BUFFERS_QUEUED, &queued);
|
||||
alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued);
|
||||
while (queued > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(context->alSource, 1, &buffer);
|
||||
alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
|
||||
queued--;
|
||||
}
|
||||
|
||||
//delete source and buffers
|
||||
alDeleteSources(1, &context->alSource);
|
||||
alDeleteBuffers(MAX_STREAM_BUFFERS, context->alBuffer);
|
||||
mixChannelsActive_g[context->mixChannel] = NULL;
|
||||
free(context);
|
||||
ctx = NULL;
|
||||
alDeleteSources(1, &mixc->alSource);
|
||||
alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
|
||||
mixChannelsActive_g[mixc->mixChannel] = NULL;
|
||||
free(mixc);
|
||||
mixc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in.
|
||||
// Call "UpdateAudioContext(ctx, NULL, 0)" if you want to pause the audio.
|
||||
// Pushes more audio data into mixc mix channel, only one buffer per call
|
||||
// Call "BufferMixChannel(mixc, NULL, 0)" if you want to pause the audio.
|
||||
// @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(!context || (context->channels == 2 && numberElements % 2 != 0)) return 0; // when there is two channels there must be an even number of samples
|
||||
if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples
|
||||
|
||||
if (!data || !numberElements)
|
||||
{ // pauses audio until data is given
|
||||
alSourcePause(context->alSource);
|
||||
context->playing = false;
|
||||
if(mixc->playing){
|
||||
alSourcePause(mixc->alSource);
|
||||
mixc->playing = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
else if(!mixc->playing)
|
||||
{ // restart audio otherwise
|
||||
ALint state;
|
||||
alGetSourcei(context->alSource, AL_SOURCE_STATE, &state);
|
||||
if (state != AL_PLAYING){
|
||||
alSourcePlay(context->alSource);
|
||||
context->playing = true;
|
||||
}
|
||||
alSourcePlay(mixc->alSource);
|
||||
mixc->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;
|
||||
ALuint buffer = 0;
|
||||
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;
|
||||
float *ptr = (float*)data;
|
||||
alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate);
|
||||
}
|
||||
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
|
||||
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};
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
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)
|
||||
{
|
||||
// Stop current music, clean buffers, unload current stream
|
||||
StopMusicStream();
|
||||
|
||||
// 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);
|
||||
return 3; // error
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get file info
|
||||
stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
|
||||
|
||||
currentMusic.channels = info.channels;
|
||||
currentMusic.sampleRate = info.sample_rate;
|
||||
stb_vorbis_info info = stb_vorbis_get_info(currentMusic[musicIndex].stream);
|
||||
|
||||
TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
|
||||
TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
|
||||
TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
|
||||
|
||||
if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
|
||||
else currentMusic.format = AL_FORMAT_MONO16;
|
||||
currentMusic[musicIndex].loop = true; // We loop by default
|
||||
musicEnabled_g = true;
|
||||
|
||||
|
||||
currentMusic.loop = true; // We loop by default
|
||||
musicEnabled = true;
|
||||
|
||||
// Create an audio source
|
||||
alGenSources(1, ¤tMusic.source); // Generate pointer to audio source
|
||||
|
||||
alSourcef(currentMusic.source, AL_PITCH, 1);
|
||||
alSourcef(currentMusic.source, AL_GAIN, 1);
|
||||
alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
|
||||
//alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE); // ERROR: Buffers do not queue!
|
||||
|
||||
// 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);
|
||||
currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
|
||||
currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
|
||||
|
||||
if (info.channels == 2){
|
||||
currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false);
|
||||
currentMusic[musicIndex].mixc->playing = true;
|
||||
}
|
||||
else{
|
||||
currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false);
|
||||
currentMusic[musicIndex].mixc->playing = true;
|
||||
}
|
||||
if(!currentMusic[musicIndex].mixc) return 4; // error
|
||||
}
|
||||
}
|
||||
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
|
||||
if(!jar_xm_create_context_from_file(¤tMusic.chipctx, currentMusic.sampleRate, fileName))
|
||||
if(!jar_xm_create_context_from_file(¤tMusic[musicIndex].chipctx, 48000, fileName))
|
||||
{
|
||||
currentMusic.format = AL_FORMAT_STEREO16;
|
||||
jar_xm_set_max_loop_count(currentMusic.chipctx, 0); // infinite number of loops
|
||||
currentMusic.totalSamplesLeft = jar_xm_get_remaining_samples(currentMusic.chipctx);
|
||||
currentMusic.totalLengthSeconds = ((float)currentMusic.totalSamplesLeft) / ((float)currentMusic.sampleRate);
|
||||
musicEnabled = true;
|
||||
currentMusic[musicIndex].chipTune = true;
|
||||
currentMusic[musicIndex].loop = true;
|
||||
jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
|
||||
currentMusic[musicIndex].totalSamplesLeft = jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
|
||||
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 track length: %11.6f sec", fileName, currentMusic.totalLengthSeconds);
|
||||
TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
|
||||
TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
|
||||
|
||||
// Set up OpenAL
|
||||
alGenSources(1, ¤tMusic.source);
|
||||
alSourcef(currentMusic.source, AL_PITCH, 1);
|
||||
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, ¤tMusic.source);
|
||||
alDeleteBuffers(2, currentMusic.buffers);
|
||||
|
||||
if (currentMusic.chipTune)
|
||||
{
|
||||
jar_xm_free_context(currentMusic.chipctx);
|
||||
currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false);
|
||||
if(!currentMusic[musicIndex].mixc) return 5; // error
|
||||
currentMusic[musicIndex].mixc->playing = true;
|
||||
}
|
||||
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
|
||||
void PauseMusicStream(void)
|
||||
void PauseMusicStream(int index)
|
||||
{
|
||||
// Pause music stream if music available!
|
||||
if (musicEnabled)
|
||||
if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc && musicEnabled_g)
|
||||
{
|
||||
TraceLog(INFO, "Pausing music stream");
|
||||
alSourcePause(currentMusic.source);
|
||||
musicEnabled = false;
|
||||
alSourcePause(currentMusic[index].mixc->alSource);
|
||||
currentMusic[index].mixc->playing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Resume music playing
|
||||
void ResumeMusicStream(void)
|
||||
void ResumeMusicStream(int index)
|
||||
{
|
||||
// Resume music playing... if music available!
|
||||
ALenum state;
|
||||
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
|
||||
|
||||
if (state == AL_PAUSED)
|
||||
{
|
||||
TraceLog(INFO, "Resuming music stream");
|
||||
alSourcePlay(currentMusic.source);
|
||||
musicEnabled = true;
|
||||
if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
|
||||
alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
|
||||
if (state == AL_PAUSED)
|
||||
{
|
||||
TraceLog(INFO, "Resuming music stream");
|
||||
alSourcePlay(currentMusic[index].mixc->alSource);
|
||||
currentMusic[index].mixc->playing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if music is playing
|
||||
bool IsMusicPlaying(void)
|
||||
// Check if any music is playing
|
||||
bool IsMusicPlaying(int index)
|
||||
{
|
||||
bool playing = false;
|
||||
ALint state;
|
||||
|
||||
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
|
||||
if (state == AL_PLAYING) playing = true;
|
||||
|
||||
if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
|
||||
alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
|
||||
if (state == AL_PLAYING) playing = true;
|
||||
}
|
||||
|
||||
return playing;
|
||||
}
|
||||
|
||||
// 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)
|
||||
float GetMusicTimeLength(void)
|
||||
float GetMusicTimeLength(int index)
|
||||
{
|
||||
float totalSeconds;
|
||||
if (currentMusic.chipTune)
|
||||
if (currentMusic[index].chipTune)
|
||||
{
|
||||
totalSeconds = currentMusic.totalLengthSeconds;
|
||||
totalSeconds = currentMusic[index].totalLengthSeconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
|
||||
totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[index].stream);
|
||||
}
|
||||
|
||||
return totalSeconds;
|
||||
}
|
||||
|
||||
// Get current music time played (in seconds)
|
||||
float GetMusicTimePlayed(void)
|
||||
float GetMusicTimePlayed(int index)
|
||||
{
|
||||
float secondsPlayed;
|
||||
if (currentMusic.chipTune)
|
||||
float secondsPlayed = 0.0f;
|
||||
if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
|
||||
{
|
||||
uint64_t samples;
|
||||
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
|
||||
if (currentMusic[index].chipTune)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -977,116 +981,118 @@ float GetMusicTimePlayed(void)
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// 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];
|
||||
float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
|
||||
|
||||
int size = 0; // Total size of data steamed (in bytes)
|
||||
int streamedBytes = 0; // samples of data obtained, channels are not included in calculation
|
||||
int size = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts
|
||||
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.
|
||||
{
|
||||
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
|
||||
}
|
||||
if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
|
||||
size = MUSIC_BUFFER_SIZE_SHORT / 2;
|
||||
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);
|
||||
if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels);
|
||||
else break;
|
||||
active = false;
|
||||
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
|
||||
{
|
||||
active = false;
|
||||
TraceLog(WARNING, "No more data obtained from stream");
|
||||
if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
|
||||
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;
|
||||
}
|
||||
|
||||
// Empty music buffers
|
||||
static void EmptyMusicStream(void)
|
||||
static void EmptyMusicStream(int index)
|
||||
{
|
||||
ALuint buffer = 0;
|
||||
int queued = 0;
|
||||
|
||||
alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
|
||||
alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued);
|
||||
|
||||
while (queued > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
|
||||
alSourceUnqueueBuffers(currentMusic[index].mixc->alSource, 1, &buffer);
|
||||
|
||||
queued--;
|
||||
}
|
||||
}
|
||||
|
||||
// Update (re-fill) music buffers if data already processed
|
||||
void UpdateMusicStream(void)
|
||||
//determine if a music stream is ready to be written to
|
||||
static int IsMusicStreamReadyForBuffering(int index)
|
||||
{
|
||||
ALuint buffer = 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;
|
||||
|
||||
if (musicEnabled)
|
||||
int numBuffers = IsMusicStreamReadyForBuffering(index);
|
||||
|
||||
if (currentMusic[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].mixc && numBuffers)
|
||||
{
|
||||
// Get the number of already processed buffers (if any)
|
||||
alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
|
||||
|
||||
while (processed > 0)
|
||||
active = BufferMusicStream(index, numBuffers);
|
||||
|
||||
if (!active && currentMusic[index].loop)
|
||||
{
|
||||
// Recover processed buffer for refill
|
||||
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[index].chipTune)
|
||||
{
|
||||
if(currentMusic.chipTune)
|
||||
{
|
||||
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);
|
||||
currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * 48000;
|
||||
}
|
||||
|
||||
// Add refilled buffer to queue again... don't let the music stop!
|
||||
alSourceQueueBuffers(currentMusic.source, 1, &buffer);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
|
||||
|
||||
processed--;
|
||||
else
|
||||
{
|
||||
stb_vorbis_seek_start(currentMusic[index].stream);
|
||||
currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
|
||||
}
|
||||
active = true;
|
||||
}
|
||||
|
||||
|
||||
ALenum state;
|
||||
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
|
||||
if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
|
||||
|
||||
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
|
||||
|
39
src/audio.h
39
src/audio.h
@ -61,10 +61,7 @@ typedef struct Wave {
|
||||
short channels;
|
||||
} Wave;
|
||||
|
||||
// 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.
|
||||
typedef void* AudioContext;
|
||||
typedef int RawAudioContext;
|
||||
|
||||
#ifdef __cplusplus
|
||||
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)
|
||||
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 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)
|
||||
@ -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 SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
||||
|
||||
void PlayMusicStream(char *fileName); // Start music playing (open stream)
|
||||
void UpdateMusicStream(void); // Updates buffers for music streaming
|
||||
void StopMusicStream(void); // Stop music playing (close stream)
|
||||
void PauseMusicStream(void); // Pause music playing
|
||||
void ResumeMusicStream(void); // Resume playing paused music
|
||||
bool IsMusicPlaying(void); // Check if music is playing
|
||||
void SetMusicVolume(float volume); // Set volume for music (1.0 is max level)
|
||||
float GetMusicTimeLength(void); // Get music time length (in seconds)
|
||||
float GetMusicTimePlayed(void); // Get current music time played (in seconds)
|
||||
int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream)
|
||||
void UpdateMusicStream(int index); // Updates buffers for music streaming
|
||||
void StopMusicStream(int index); // Stop music playing (close stream)
|
||||
void PauseMusicStream(int index); // Pause music playing
|
||||
void ResumeMusicStream(int index); // Resume playing paused music
|
||||
bool IsMusicPlaying(int index); // Check if music is playing
|
||||
void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level)
|
||||
float GetMusicTimeLength(int index); // Get music time length (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
|
||||
}
|
||||
|
@ -18,11 +18,11 @@
|
||||
* float speed = 1.f;
|
||||
* float currentTime = 0.f;
|
||||
* float currentPos[2] = {0,0};
|
||||
* float newPos[2] = {1,1};
|
||||
* float tempPosition[2] = currentPos;//x,y positions
|
||||
* while(currentPos[0] < newPos[0])
|
||||
* currentPos[0] = EaseSineIn(currentTime, tempPosition[0], tempPosition[0]-newPos[0], speed);
|
||||
* currentPos[1] = EaseSineIn(currentTime, tempPosition[1], tempPosition[1]-newPos[0], speed);
|
||||
* float finalPos[2] = {1,1};
|
||||
* float startPosition[2] = currentPos;//x,y positions
|
||||
* while(currentPos[0] < finalPos[0])
|
||||
* currentPos[0] = EaseSineIn(currentTime, startPosition[0], startPosition[0]-finalPos[0], speed);
|
||||
* currentPos[1] = EaseSineIn(currentTime, startPosition[1], startPosition[1]-finalPos[0], speed);
|
||||
* currentTime += diffTime();
|
||||
*
|
||||
* A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
|
||||
|
137
src/models.c
137
src/models.c
@ -65,6 +65,16 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
|
||||
// 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
|
||||
// NOTE: Cube position is the center position
|
||||
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);
|
||||
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)),
|
||||
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);
|
||||
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)),
|
||||
sin(DEG2RAD*(270+(180/(rings + 1))*i)),
|
||||
@ -376,7 +386,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
|
||||
if (radiusTop > 0)
|
||||
{
|
||||
// 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+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 --------------------------------------------------------------------------------------
|
||||
for(int i = 0; i < 360; i += 360/sides)
|
||||
for (int i = 0; i < 360; i += 360/sides)
|
||||
{
|
||||
rlVertex3f(0, height, 0);
|
||||
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
|
||||
{
|
||||
// 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(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 -----------------------------------------------------------------------------------------
|
||||
for(int i = 0; i < 360; i += 360/sides)
|
||||
for (int i = 0; i < 360; i += 360/sides)
|
||||
{
|
||||
rlVertex3f(0, 0, 0);
|
||||
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
|
||||
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();
|
||||
rlTranslatef(position.x, position.y, position.z);
|
||||
@ -429,7 +439,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
|
||||
rlBegin(RL_LINES);
|
||||
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+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
|
||||
@ -490,7 +500,7 @@ void DrawGrid(int slices, float spacing)
|
||||
int halfSlices = slices / 2;
|
||||
|
||||
rlBegin(RL_LINES);
|
||||
for(int i = -halfSlices; i <= halfSlices; i++)
|
||||
for (int i = -halfSlices; i <= halfSlices; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
@ -553,7 +563,7 @@ Model LoadModel(const char *fileName)
|
||||
if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
|
||||
else
|
||||
{
|
||||
rlglLoadMesh(&model.mesh); // Upload vertex data to GPU
|
||||
rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
|
||||
|
||||
model.transform = MatrixIdentity();
|
||||
model.material = LoadDefaultMaterial();
|
||||
@ -563,13 +573,13 @@ Model LoadModel(const char *fileName)
|
||||
}
|
||||
|
||||
// Load a 3d model (from vertex data)
|
||||
Model LoadModelEx(Mesh data)
|
||||
Model LoadModelEx(Mesh data, bool dynamic)
|
||||
{
|
||||
Model model = { 0 };
|
||||
|
||||
model.mesh = data;
|
||||
|
||||
rlglLoadMesh(&model.mesh); // Upload vertex data to GPU
|
||||
rlglLoadMesh(&model.mesh, dynamic); // Upload vertex data to GPU
|
||||
|
||||
model.transform = MatrixIdentity();
|
||||
model.material = LoadDefaultMaterial();
|
||||
@ -668,7 +678,7 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
|
||||
|
||||
model.mesh = GenMeshHeightmap(heightmap, size);
|
||||
|
||||
rlglLoadMesh(&model.mesh);
|
||||
rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
|
||||
|
||||
model.transform = MatrixIdentity();
|
||||
model.material = LoadDefaultMaterial();
|
||||
@ -683,7 +693,7 @@ Model LoadCubicmap(Image cubicmap)
|
||||
|
||||
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.material = LoadDefaultMaterial();
|
||||
@ -691,31 +701,14 @@ Model LoadCubicmap(Image cubicmap)
|
||||
return model;
|
||||
}
|
||||
|
||||
// Unload 3d model from memory
|
||||
// Unload 3d model from memory (mesh and material)
|
||||
void UnloadModel(Model model)
|
||||
{
|
||||
// Unload mesh data
|
||||
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
|
||||
rlglUnloadMesh(&model.mesh);
|
||||
|
||||
rlDeleteVertexArrays(model.mesh.vaoId);
|
||||
|
||||
UnloadMaterial(model.material);
|
||||
|
||||
TraceLog(INFO, "Unloaded model data from RAM and VRAM");
|
||||
}
|
||||
|
||||
// Load material data (from file)
|
||||
@ -749,6 +742,18 @@ Material LoadDefaultMaterial(void)
|
||||
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)
|
||||
{
|
||||
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 };
|
||||
|
||||
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
|
||||
//----------------------------------------------------------
|
||||
@ -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
|
||||
|
||||
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)
|
||||
void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
|
||||
{
|
||||
Vector3 vScale = { scale, scale, scale };
|
||||
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);
|
||||
rlEnableWireMode();
|
||||
|
||||
model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
|
||||
model.material.colDiffuse = tint;
|
||||
DrawModel(model, position, scale, tint);
|
||||
|
||||
rlglDrawEx(model.mesh, model.material, model.transform, true);
|
||||
rlDisableWireMode();
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// Calculate transformation matrix from function parameters
|
||||
// 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);
|
||||
rlEnableWireMode();
|
||||
|
||||
model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
|
||||
model.material.colDiffuse = tint;
|
||||
DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
|
||||
|
||||
rlglDrawEx(model.mesh, model.material, model.transform, true);
|
||||
rlDisableWireMode();
|
||||
}
|
||||
|
||||
// Draw a billboard
|
||||
@ -1425,7 +1417,7 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius
|
||||
float vector = VectorDotProduct(raySpherePos, ray.direction);
|
||||
float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
|
||||
|
||||
if(d >= 0.0f) collision = true;
|
||||
if (d >= 0.0f) collision = true;
|
||||
|
||||
return collision;
|
||||
}
|
||||
@ -1440,14 +1432,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
|
||||
float vector = VectorDotProduct(raySpherePos, ray.direction);
|
||||
float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
|
||||
|
||||
if(d >= 0.0f) collision = true;
|
||||
if (d >= 0.0f) collision = true;
|
||||
|
||||
// Calculate collision point
|
||||
Vector3 offset = ray.direction;
|
||||
float collisionDistance = 0;
|
||||
|
||||
// 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);
|
||||
|
||||
VectorScale(&offset, collisionDistance);
|
||||
@ -1785,11 +1777,11 @@ static Mesh LoadOBJ(const char *fileName)
|
||||
// First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
|
||||
// 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)
|
||||
while(!feof(objFile))
|
||||
while (!feof(objFile))
|
||||
{
|
||||
fscanf(objFile, "%c", &dataType);
|
||||
|
||||
switch(dataType)
|
||||
switch (dataType)
|
||||
{
|
||||
case '#': // Comments
|
||||
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
|
||||
// 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)
|
||||
while(!feof(objFile))
|
||||
while (!feof(objFile))
|
||||
{
|
||||
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 '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);
|
||||
|
||||
// Third reading pass: Get faces (triangles) data and fill VertexArray
|
||||
while(!feof(objFile))
|
||||
while (!feof(objFile))
|
||||
{
|
||||
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 'f':
|
||||
@ -2031,7 +2023,7 @@ static Material LoadMTL(const char *fileName)
|
||||
return material;
|
||||
}
|
||||
|
||||
while(!feof(mtlFile))
|
||||
while (!feof(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.
|
||||
{
|
||||
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.
|
||||
{
|
||||
|
12
src/physac.c
12
src/physac.c
@ -49,7 +49,7 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// 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 Vector2 gravityForce; // Gravity force
|
||||
|
||||
@ -463,10 +463,10 @@ void ClosePhysics()
|
||||
}
|
||||
|
||||
// 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
|
||||
PhysicObject *obj = (PhysicObject *)malloc(sizeof(PhysicObject));
|
||||
PhysicObject obj = (PhysicObject)malloc(sizeof(PhysicObjectData));
|
||||
|
||||
// Initialize physic object values with generic values
|
||||
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
|
||||
void DestroyPhysicObject(PhysicObject *pObj)
|
||||
void DestroyPhysicObject(PhysicObject pObj)
|
||||
{
|
||||
// Free dynamic memory allocation
|
||||
free(physicObjects[pObj->id]);
|
||||
@ -520,7 +520,7 @@ void DestroyPhysicObject(PhysicObject *pObj)
|
||||
}
|
||||
|
||||
// Apply directional force to a physic object
|
||||
void ApplyForce(PhysicObject *pObj, Vector2 force)
|
||||
void ApplyForce(PhysicObject pObj, Vector2 force)
|
||||
{
|
||||
if (pObj->rigidbody.enabled)
|
||||
{
|
||||
@ -571,7 +571,7 @@ Rectangle TransformToRectangle(Transform transform)
|
||||
}
|
||||
|
||||
// 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
|
||||
DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK);
|
||||
|
12
src/physac.h
12
src/physac.h
@ -66,13 +66,13 @@ typedef struct Collider {
|
||||
int radius; // Used for COLLIDER_CIRCLE
|
||||
} Collider;
|
||||
|
||||
typedef struct PhysicObject {
|
||||
typedef struct PhysicObjectData {
|
||||
unsigned int id;
|
||||
Transform transform;
|
||||
Rigidbody rigidbody;
|
||||
Collider collider;
|
||||
bool enabled;
|
||||
} PhysicObject;
|
||||
} PhysicObjectData, *PhysicObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
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 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
|
||||
void DestroyPhysicObject(PhysicObject *pObj); // Destroy a specific physic object and take it out of the list
|
||||
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 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
|
||||
|
||||
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
|
||||
}
|
||||
|
86
src/raylib.h
86
src/raylib.h
@ -398,7 +398,7 @@ typedef struct Shader {
|
||||
|
||||
// Uniform locations
|
||||
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
|
||||
int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader)
|
||||
@ -418,18 +418,36 @@ typedef struct Material {
|
||||
Color colAmbient; // Ambient color
|
||||
Color colSpecular; // Specular color
|
||||
|
||||
float glossiness; // Glossiness level
|
||||
float glossiness; // Glossiness level (Ranges from 0 to 1000)
|
||||
float normalDepth; // Normal map depth
|
||||
} Material;
|
||||
|
||||
// 3d Model type
|
||||
// TODO: Replace shader/testure by material
|
||||
// Model type
|
||||
typedef struct Model {
|
||||
Mesh mesh; // Vertex data buffers (RAM and VRAM)
|
||||
Matrix transform; // Local transform matrix
|
||||
Material material; // Shader and textures data
|
||||
} 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)
|
||||
typedef struct Ray {
|
||||
Vector3 position;
|
||||
@ -451,10 +469,7 @@ typedef struct Wave {
|
||||
short channels;
|
||||
} Wave;
|
||||
|
||||
// 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.
|
||||
typedef void* AudioContext;
|
||||
typedef int RawAudioContext;
|
||||
|
||||
// Texture formats
|
||||
// NOTE: Support depends on OpenGL version and platform
|
||||
@ -539,13 +554,13 @@ typedef struct Collider {
|
||||
int radius; // Used for COLLIDER_CIRCLE
|
||||
} Collider;
|
||||
|
||||
typedef struct PhysicObject {
|
||||
typedef struct PhysicObjectData {
|
||||
unsigned int id;
|
||||
Transform transform;
|
||||
Rigidbody rigidbody;
|
||||
Collider collider;
|
||||
bool enabled;
|
||||
} PhysicObject;
|
||||
} PhysicObjectData, *PhysicObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
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)
|
||||
//------------------------------------------------------------------------------------
|
||||
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 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
|
||||
@ -806,7 +822,7 @@ void DrawGizmo(Vector3 position);
|
||||
// Model 3d Loading and Drawing Functions (Module: models)
|
||||
//------------------------------------------------------------------------------------
|
||||
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 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)
|
||||
@ -815,6 +831,7 @@ void SetModelTexture(Model *model, Texture2D texture); // Link a textur
|
||||
|
||||
Material LoadMaterial(const char *fileName); // Load material data (from file)
|
||||
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 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 SetCustomShader(Shader shader); // Set custom shader to be used in batch draw
|
||||
Shader GetDefaultShader(void); // Get default shader
|
||||
Shader GetStandardShader(void); // Get default shader
|
||||
Texture2D GetDefaultTexture(void); // Get default texture
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -860,14 +882,14 @@ void InitPhysics(Vector2 gravity);
|
||||
void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection
|
||||
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
|
||||
void DestroyPhysicObject(PhysicObject *pObj); // Destroy a specific physic object and take it out of the list
|
||||
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 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
|
||||
|
||||
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)
|
||||
@ -876,13 +898,6 @@ void InitAudioDevice(void); // Initialize au
|
||||
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
|
||||
|
||||
// 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 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)
|
||||
@ -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 SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
||||
|
||||
void PlayMusicStream(char *fileName); // Start music playing (open stream)
|
||||
void UpdateMusicStream(void); // Updates buffers for music streaming
|
||||
void StopMusicStream(void); // Stop music playing (close stream)
|
||||
void PauseMusicStream(void); // Pause music playing
|
||||
void ResumeMusicStream(void); // Resume playing paused music
|
||||
bool IsMusicPlaying(void); // Check if music is playing
|
||||
void SetMusicVolume(float volume); // Set volume for music (1.0 is max level)
|
||||
float GetMusicTimeLength(void); // Get current music time length (in seconds)
|
||||
float GetMusicTimePlayed(void); // Get current music time played (in seconds)
|
||||
int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream)
|
||||
void UpdateMusicStream(int index); // Updates buffers for music streaming
|
||||
void StopMusicStream(int index); // Stop music playing (close stream)
|
||||
void PauseMusicStream(int index); // Pause music playing
|
||||
void ResumeMusicStream(int index); // Resume playing paused music
|
||||
bool IsMusicPlaying(int index); // Check if music is playing
|
||||
void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level)
|
||||
float GetMusicTimeLength(int index); // Get current music time length (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
|
||||
}
|
||||
|
703
src/rlgl.c
703
src/rlgl.c
@ -71,6 +71,8 @@
|
||||
#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)
|
||||
// NOTE: Every vertex are 3 floats (12 bytes)
|
||||
|
||||
#define MAX_LIGHTS 8 // Max lights supported by standard shader
|
||||
|
||||
#ifndef GL_SHADING_LANGUAGE_VERSION
|
||||
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
|
||||
@ -189,6 +191,7 @@ static bool useTempBuffer = false;
|
||||
|
||||
// Shader Programs
|
||||
static Shader defaultShader;
|
||||
static Shader standardShader;
|
||||
static Shader currentShader; // By default, defaultShader
|
||||
|
||||
// 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 texCompPVRTSupported = false; // PVR 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
|
||||
|
||||
// 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 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 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 UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with 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 SetShaderLights(Shader shader); // Sets shader uniform values for lights array
|
||||
|
||||
static char *ReadTextFile(const char *fileName);
|
||||
#endif
|
||||
|
||||
@ -740,6 +751,24 @@ void rlDisableDepthTest(void)
|
||||
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
|
||||
void rlDeleteTextures(unsigned int id)
|
||||
{
|
||||
@ -991,6 +1020,7 @@ void rlglInit(void)
|
||||
|
||||
// Init default Shader (customized for GL 3.3 and ES2)
|
||||
defaultShader = LoadDefaultShader();
|
||||
standardShader = LoadStandardShader();
|
||||
currentShader = defaultShader;
|
||||
|
||||
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)
|
||||
UnloadDefaultShader();
|
||||
UnloadStandardShader();
|
||||
UnloadDefaultBuffers();
|
||||
|
||||
// Delete default white texture
|
||||
@ -1033,178 +1064,18 @@ void rlglClose(void)
|
||||
void rlglDraw(void)
|
||||
{
|
||||
#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();
|
||||
DrawDefaultBuffers();
|
||||
#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)
|
||||
// NOTE: Stores global variables screenWidth and screenHeight
|
||||
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...");
|
||||
|
||||
switch(status)
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); 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
|
||||
void rlglLoadMesh(Mesh *mesh)
|
||||
void rlglLoadMesh(Mesh *mesh, bool dynamic)
|
||||
{
|
||||
mesh->vaoId = 0; // Vertex Array Object
|
||||
mesh->vboId[0] = 0; // Vertex positions VBO
|
||||
@ -1652,6 +1523,9 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
mesh->vboId[4] = 0; // Vertex tangents VBO
|
||||
mesh->vboId[5] = 0; // Vertex texcoords2 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)
|
||||
GLuint vaoId = 0; // Vertex Array Objects (VAO)
|
||||
@ -1669,14 +1543,14 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
// Enable vertex attributes: position (shader-location = 0)
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// Enable vertex attributes: texcoords (shader-location = 1)
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
@ -1685,7 +1559,7 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
{
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(2);
|
||||
}
|
||||
@ -1701,7 +1575,7 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
{
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(3);
|
||||
}
|
||||
@ -1717,7 +1591,7 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
{
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(4);
|
||||
}
|
||||
@ -1733,7 +1607,7 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
{
|
||||
glGenBuffers(1, &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);
|
||||
glEnableVertexAttribArray(5);
|
||||
}
|
||||
@ -1776,6 +1650,270 @@ void rlglLoadMesh(Mesh *mesh)
|
||||
#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)
|
||||
unsigned char *rlglReadScreenPixels(int width, int height)
|
||||
{
|
||||
@ -2022,6 +2160,17 @@ Shader GetDefaultShader(void)
|
||||
#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
|
||||
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
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -2293,15 +2514,15 @@ static Shader LoadDefaultShader(void)
|
||||
"varying vec4 fragColor; \n"
|
||||
#endif
|
||||
"uniform sampler2D texture0; \n"
|
||||
"uniform vec4 fragTintColor; \n"
|
||||
"uniform vec4 colDiffuse; \n"
|
||||
"void main() \n"
|
||||
"{ \n"
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
" vec4 texelColor = texture(texture0, fragTexCoord); \n"
|
||||
" finalColor = texelColor*fragTintColor*fragColor; \n"
|
||||
" finalColor = texelColor*colDiffuse*fragColor; \n"
|
||||
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||
" 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
|
||||
"} \n";
|
||||
|
||||
@ -2315,6 +2536,24 @@ static Shader LoadDefaultShader(void)
|
||||
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
|
||||
// NOTE: If any location is not found, loc point becomes -1
|
||||
static void LoadDefaultShaderLocations(Shader *shader)
|
||||
@ -2328,18 +2567,18 @@ static void LoadDefaultShaderLocations(Shader *shader)
|
||||
// vertex texcoord2 location = 5
|
||||
|
||||
// Get handles to GLSL input attibute locations
|
||||
shader->vertexLoc = glGetAttribLocation(shader->id, "vertexPosition");
|
||||
shader->texcoordLoc = glGetAttribLocation(shader->id, "vertexTexCoord");
|
||||
shader->normalLoc = glGetAttribLocation(shader->id, "vertexNormal");
|
||||
shader->colorLoc = glGetAttribLocation(shader->id, "vertexColor");
|
||||
shader->tangentLoc = glGetAttribLocation(shader->id, "vertexTangent");
|
||||
shader->texcoord2Loc = glGetAttribLocation(shader->id, "vertexTexCoord2");
|
||||
shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
|
||||
shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
|
||||
shader->normalLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME);
|
||||
shader->colorLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME);
|
||||
shader->tangentLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME);
|
||||
shader->texcoord2Loc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME);
|
||||
|
||||
// Get handles to GLSL uniform locations (vertex shader)
|
||||
shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix");
|
||||
|
||||
// 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->mapNormalLoc = glGetUniformLocation(shader->id, "texture1");
|
||||
shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
|
||||
@ -2350,13 +2589,26 @@ static void UnloadDefaultShader(void)
|
||||
{
|
||||
glUseProgram(0);
|
||||
|
||||
//glDetachShader(defaultShaderProgram, vertexShader);
|
||||
//glDetachShader(defaultShaderProgram, fragmentShader);
|
||||
//glDetachShader(defaultShader, vertexShader);
|
||||
//glDetachShader(defaultShader, fragmentShader);
|
||||
//glDeleteShader(vertexShader); // Already deleted on shader compilation
|
||||
//glDeleteShader(fragmentShader); // Already deleted on sahder compilation
|
||||
//glDeleteShader(fragmentShader); // Already deleted on shader compilation
|
||||
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)
|
||||
static void LoadDefaultBuffers(void)
|
||||
{
|
||||
@ -2800,6 +3052,79 @@ static void UnloadDefaultBuffers(void)
|
||||
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
|
||||
// NOTE: text chars array should be freed manually
|
||||
static char *ReadTextFile(const char *fileName)
|
||||
@ -2970,7 +3295,7 @@ static void TraceLog(int msgType, const char *text, ...)
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
|
||||
switch(msgType)
|
||||
switch (msgType)
|
||||
{
|
||||
case INFO: fprintf(stdout, "INFO: "); break;
|
||||
case ERROR: fprintf(stdout, "ERROR: "); break;
|
||||
|
46
src/rlgl.h
46
src/rlgl.h
@ -196,19 +196,35 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
|
||||
|
||||
// Material type
|
||||
typedef struct Material {
|
||||
Shader shader;
|
||||
Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular)
|
||||
|
||||
Texture2D texDiffuse; // Diffuse texture
|
||||
Texture2D texNormal; // Normal texture
|
||||
Texture2D texSpecular; // Specular texture
|
||||
Texture2D texDiffuse; // Diffuse texture
|
||||
Texture2D texNormal; // Normal texture
|
||||
Texture2D texSpecular; // Specular texture
|
||||
|
||||
Color colDiffuse;
|
||||
Color colAmbient;
|
||||
Color colSpecular;
|
||||
Color colDiffuse; // Diffuse color
|
||||
Color colAmbient; // Ambient color
|
||||
Color colSpecular; // Specular color
|
||||
|
||||
float glossiness;
|
||||
float normalDepth;
|
||||
float glossiness; // Glossiness level (Ranges from 0 to 1000)
|
||||
float normalDepth; // Normal map depth
|
||||
} 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)
|
||||
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 rlEnableDepthTest(void); // Enable 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 rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) 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)
|
||||
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 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
|
||||
|
||||
@ -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 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
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -446,7 +446,6 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
|
||||
}
|
||||
|
||||
// Get collision rectangle for two rectangles collision
|
||||
// TODO: Depending on rec1 and rec2 order, it fails -> Review!
|
||||
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
|
||||
{
|
||||
Rectangle retRec = { 0, 0, 0, 0 };
|
||||
|
2
src/windows_compile.bat
Normal file
2
src/windows_compile.bat
Normal file
@ -0,0 +1,2 @@
|
||||
set PATH=C:\raylib\MinGW\bin;%PATH%
|
||||
mingw32-make
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user