From 1674465bdc17f522013c5552bd154f04254d8e74 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Mar 2016 19:00:12 +0100 Subject: Adjust buffers usage - Removed DrawQuad() function - DrawBillboard() uses DrawBillboardRec() - DrawPlane() uses RL_TRIANGLES - DrawRectangleV() uses RL_TRIANGLES, that way, [shapes] module uses only TRIANGLES buffers. --- src/raylib.h | 1 - 1 file changed, 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index c598ec30..36ca216d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -740,7 +740,6 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ -void DrawQuad(Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Color color); // Draw a quad void DrawRay(Ray ray, Color color); // Draw a ray line void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) void DrawGizmo(Vector3 position); // Draw simple gizmo -- cgit v1.2.3 From 6106ab8a2eda76454b0cd3ff46a079896a90eee8 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Mar 2016 20:26:01 +0100 Subject: Added color to DrawBoundigBox() --- src/models.c | 4 ++-- src/raylib.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 4eb2e104..a3649a07 100644 --- a/src/models.c +++ b/src/models.c @@ -1213,7 +1213,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec } // Draw a bounding box with wires -void DrawBoundingBox(BoundingBox box) +void DrawBoundingBox(BoundingBox box, Color color) { Vector3 size; @@ -1223,7 +1223,7 @@ void DrawBoundingBox(BoundingBox box) Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; - DrawCubeWires(center, size.x, size.y, size.z, GREEN); + DrawCubeWires(center, size.x, size.y, size.z, color); } // Detect collision between two spheres diff --git a/src/raylib.h b/src/raylib.h index 36ca216d..73f92fc2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -760,7 +760,7 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint); void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -void DrawBoundingBox(BoundingBox box); // Draw bounding box (wires) +void DrawBoundingBox(BoundingBox box, Color color) // Draw bounding box (wires) void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec -- cgit v1.2.3 From 4011c13d4b0b7a684def27bac29f084085bf87a5 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Mar 2016 20:54:02 +0100 Subject: Updated BoundingBox collision detections --- examples/models_box_collisions.c | 40 +++++++++++++++++---------------- src/models.c | 48 +++++++++++++++++----------------------- src/raylib.h | 10 ++++----- 3 files changed, 46 insertions(+), 52 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/models_box_collisions.c b/examples/models_box_collisions.c index 3751041f..ffd0a2af 100644 --- a/examples/models_box_collisions.c +++ b/examples/models_box_collisions.c @@ -53,27 +53,29 @@ int main() collision = false; // Check collisions player vs enemy-box - if (CheckCollisionBoxes((Vector3){ playerPosition.x - playerSize.x/2, - playerPosition.y - playerSize.y/2, - playerPosition.z - playerSize.z/2 }, - (Vector3){ playerPosition.x + playerSize.x/2, - playerPosition.y + playerSize.y/2, - playerPosition.z + playerSize.z/2 }, - (Vector3){ enemyBoxPos.x - enemyBoxSize.x/2, - enemyBoxPos.y - enemyBoxSize.y/2, - enemyBoxPos.z - enemyBoxSize.z/2 }, - (Vector3){ enemyBoxPos.x + enemyBoxSize.x/2, - enemyBoxPos.y + enemyBoxSize.y/2, - enemyBoxPos.z + enemyBoxSize.z/2 })) collision = true; + if (CheckCollisionBoxes( + (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, + playerPosition.y - playerSize.y/2, + playerPosition.z - playerSize.z/2 }, + (Vector3){ playerPosition.x + playerSize.x/2, + playerPosition.y + playerSize.y/2, + playerPosition.z + playerSize.z/2 }}, + (BoundingBox){(Vector3){ enemyBoxPos.x - enemyBoxSize.x/2, + enemyBoxPos.y - enemyBoxSize.y/2, + enemyBoxPos.z - enemyBoxSize.z/2 }, + (Vector3){ enemyBoxPos.x + enemyBoxSize.x/2, + enemyBoxPos.y + enemyBoxSize.y/2, + enemyBoxPos.z + enemyBoxSize.z/2 }})) collision = true; // Check collisions player vs enemy-sphere - if (CheckCollisionBoxSphere((Vector3){ playerPosition.x - playerSize.x/2, - playerPosition.y - playerSize.y/2, - playerPosition.z - playerSize.z/2 }, - (Vector3){ playerPosition.x + playerSize.x/2, - playerPosition.y + playerSize.y/2, - playerPosition.z + playerSize.z/2 }, - enemySpherePos, enemySphereSize)) collision = true; + if (CheckCollisionBoxSphere( + (BoundingBox){(Vector3){ playerPosition.x - playerSize.x/2, + playerPosition.y - playerSize.y/2, + playerPosition.z - playerSize.z/2 }, + (Vector3){ playerPosition.x + playerSize.x/2, + playerPosition.y + playerSize.y/2, + playerPosition.z + playerSize.z/2 }}, + enemySpherePos, enemySphereSize)) collision = true; if (collision) playerColor = RED; else playerColor = GREEN; diff --git a/src/models.c b/src/models.c index a3649a07..fc95f58d 100644 --- a/src/models.c +++ b/src/models.c @@ -1244,14 +1244,14 @@ bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, floa // Detect collision between two boxes // NOTE: Boxes are defined by two points minimum and maximum -bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2) +bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2) { bool collision = true; - if ((maxBBox1.x >= minBBox2.x) && (minBBox1.x <= maxBBox2.x)) + if ((box1.max.x >= box2.min.x) && (box1.min.x <= box2.max.x)) { - if ((maxBBox1.y < minBBox2.y) || (minBBox1.y > maxBBox2.y)) collision = false; - if ((maxBBox1.z < minBBox2.z) || (minBBox1.z > maxBBox2.z)) collision = false; + if ((box1.max.y < box2.min.y) || (box1.min.y > box2.max.y)) collision = false; + if ((box1.max.z < box2.min.z) || (box1.min.z > box2.max.z)) collision = false; } else collision = false; @@ -1259,30 +1259,22 @@ bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, V } // Detect collision between box and sphere -bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere) +bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere) { bool collision = false; - if ((centerSphere.x - minBBox.x > radiusSphere) && (centerSphere.y - minBBox.y > radiusSphere) && (centerSphere.z - minBBox.z > radiusSphere) && - (maxBBox.x - centerSphere.x > radiusSphere) && (maxBBox.y - centerSphere.y > radiusSphere) && (maxBBox.z - centerSphere.z > radiusSphere)) - { - collision = true; - } - else - { - float dmin = 0; + float dmin = 0; - if (centerSphere.x - minBBox.x <= radiusSphere) dmin += (centerSphere.x - minBBox.x)*(centerSphere.x - minBBox.x); - else if (maxBBox.x - centerSphere.x <= radiusSphere) dmin += (centerSphere.x - maxBBox.x)*(centerSphere.x - maxBBox.x); + if (centerSphere.x < box.min.x) dmin += pow(centerSphere.x - box.min.x, 2); + else if (centerSphere.x > box.max.x) dmin += pow(centerSphere.x - box.max.x, 2); - if (centerSphere.y - minBBox.y <= radiusSphere) dmin += (centerSphere.y - minBBox.y)*(centerSphere.y - minBBox.y); - else if (maxBBox.y - centerSphere.y <= radiusSphere) dmin += (centerSphere.y - maxBBox.y)*(centerSphere.y - maxBBox.y); + if (centerSphere.y < box.min.y) dmin += pow(centerSphere.y - box.min.y, 2); + else if (centerSphere.y > box.max.y) dmin += pow(centerSphere.y - box.max.y, 2); - if (centerSphere.z - minBBox.z <= radiusSphere) dmin += (centerSphere.z - minBBox.z)*(centerSphere.z - minBBox.z); - else if (maxBBox.z - centerSphere.z <= radiusSphere) dmin += (centerSphere.z - maxBBox.z)*(centerSphere.z - maxBBox.z); + if (centerSphere.z < box.min.z) dmin += pow(centerSphere.z - box.min.z, 2); + else if (centerSphere.z > box.max.z) dmin += pow(centerSphere.z - box.max.z, 2); - if (dmin <= radiusSphere*radiusSphere) collision = true; - } + if (dmin <= (radiusSphere*radiusSphere)) collision = true; return collision; } @@ -1333,17 +1325,17 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi } // Detect collision between ray and bounding box -bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox) +bool CheckCollisionRayBox(Ray ray, BoundingBox box) { bool collision = false; float t[8]; - t[0] = (minBBox.x - ray.position.x)/ray.direction.x; - t[1] = (maxBBox.x - ray.position.x)/ray.direction.x; - t[2] = (minBBox.y - ray.position.y)/ray.direction.y; - t[3] = (maxBBox.y - ray.position.y)/ray.direction.y; - t[4] = (minBBox.z - ray.position.z)/ray.direction.z; - t[5] = (maxBBox.z - ray.position.z)/ray.direction.z; + t[0] = (box.min.x - ray.position.x)/ray.direction.x; + t[1] = (box.max.x - ray.position.x)/ray.direction.x; + t[2] = (box.min.y - ray.position.y)/ray.direction.y; + t[3] = (box.max.y - ray.position.y)/ray.direction.y; + t[4] = (box.min.z - ray.position.z)/ray.direction.z; + t[5] = (box.max.z - ray.position.z)/ray.direction.z; t[6] = fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])); t[7] = fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])); diff --git a/src/raylib.h b/src/raylib.h index 73f92fc2..b7dc1a8c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -760,18 +760,18 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint); void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -void DrawBoundingBox(BoundingBox box, Color color) // Draw bounding box (wires) +void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec -BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits +BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres -bool CheckCollisionBoxes(Vector3 minBBox1, Vector3 maxBBox1, Vector3 minBBox2, Vector3 maxBBox2); // Detect collision between two boxes -bool CheckCollisionBoxSphere(Vector3 minBBox, Vector3 maxBBox, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere +bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes +bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection -bool CheckCollisionRayBox(Ray ray, Vector3 minBBox, Vector3 maxBBox); // Detect collision between ray and box +bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap // NOTE: Return the normal vector of the impacted surface //------------------------------------------------------------------------------------ -- cgit v1.2.3 From 4476a9e241b952f631afb6c8c3f3c69a481219e3 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 2 Mar 2016 17:13:31 +0100 Subject: Review rlglUnproject() system --- examples/core_3d_picking.c | 4 ++-- src/core.c | 42 ++++++++++++++++++------------------ src/raylib.h | 1 + src/raymath.h | 2 +- src/rlgl.c | 54 +++++++++++----------------------------------- 5 files changed, 37 insertions(+), 66 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_3d_picking.c b/examples/core_3d_picking.c index fdf77030..612f6374 100644 --- a/examples/core_3d_picking.c +++ b/examples/core_3d_picking.c @@ -53,8 +53,8 @@ int main() // Check collision between ray and box collision = CheckCollisionRayBox(ray, - (Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 }, - (Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }); + (BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 }, + (Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }}); } //---------------------------------------------------------------------------------- diff --git a/src/core.c b/src/core.c index dbcfa6bc..1589439e 100644 --- a/src/core.c +++ b/src/core.c @@ -612,11 +612,11 @@ void Begin3dMode(Camera camera) // Setup perspective projection float aspect = (float)screenWidth/(float)screenHeight; - double top = 0.1*tan(45.0*PI/360.0); + double top = 0.01*tan(45.0*PI/360.0); double right = top*aspect; // NOTE: zNear and zFar values are important when computing depth buffer values - rlFrustum(-right, right, -top, top, 0.1f, 1000.0f); + rlFrustum(-right, right, -top, top, 0.01, 1000.0); rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -867,16 +867,8 @@ int StorageLoadValue(int position) } // Returns a ray trace from mouse position -//http://www.songho.ca/opengl/gl_transform.html -//http://www.songho.ca/opengl/gl_matrix.html -//http://www.sjbaker.org/steve/omniv/matrices_can_be_your_friends.html -//https://www.opengl.org/archives/resources/faq/technical/transformations.htm Ray GetMouseRay(Vector2 mousePosition, Camera camera) -{ - // Tutorial used: https://mkonrad.net/2014/08/07/simple-opengl-object-picking-in-3d.html - // Similar to http://antongerdelan.net, the problem is maybe in MatrixPerspective vs MatrixFrustum - // or matrix order (transpose it or not... that's the question) - +{ Ray ray; // Calculate normalized device coordinates @@ -886,40 +878,48 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) float z = 1.0f; // Store values in a vector - Vector3 deviceCoords = {x, y, z}; + Vector3 deviceCoords = { x, y, z }; - // Device debug message - TraceLog(INFO, "device(%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); + TraceLog(DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); - // Calculate projection matrix (from perspective instead of frustum - Matrix matProj = MatrixPerspective(45.0f, (float)((float)GetScreenWidth() / (float)GetScreenHeight()), 0.01f, 1000.0f); + // Calculate projection matrix (from perspective instead of frustum) + Matrix matProj = MatrixPerspective(45.0, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); // Calculate view matrix from camera look at Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); // Do I need to transpose it? It seems that yes... - // NOTE: matrix order is maybe incorrect... In OpenGL to get world position from + // NOTE: matrix order may be incorrect... In OpenGL to get world position from // camera view it just needs to get inverted, but here we need to transpose it too. // For example, if you get view matrix, transpose and inverted and you transform it // to a vector, you will get its 3d world position coordinates (camera.position). // If you don't transpose, final position will be wrong. MatrixTranspose(&matView); +//#define USE_RLGL_UNPROJECT +#if defined(USE_RLGL_UNPROJECT) // OPTION 1: Use rlglUnproject() + + Vector3 nearPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); + Vector3 farPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); + +#else // OPTION 2: Compute unprojection directly here + // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it Matrix matProjView = MatrixMultiply(matProj, matView); MatrixInvert(&matProjView); // Calculate far and near points - Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f}; - Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f}; + Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f }; + Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f }; // Multiply points by unproject matrix QuaternionTransform(&near, matProjView); QuaternionTransform(&far, matProjView); // Calculate normalized world points in vectors - Vector3 nearPoint = {near.x / near.w, near.y / near.w, near.z / near.w}; - Vector3 farPoint = {far.x / far.w, far.y / far.w, far.z / far.w}; + Vector3 nearPoint = { near.x/near.w, near.y/near.w, near.z/near.w}; + Vector3 farPoint = { far.x/far.w, far.y/far.w, far.z/far.w}; +#endif // Calculate normalized direction vector Vector3 direction = VectorSubtract(farPoint, nearPoint); diff --git a/src/raylib.h b/src/raylib.h index b7dc1a8c..4f36e203 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -312,6 +312,7 @@ typedef struct Camera { Vector3 position; Vector3 target; Vector3 up; + //float fovy; // Field-Of-View apperture in Y (degrees) } Camera; // Bounding box type diff --git a/src/raymath.h b/src/raymath.h index 35cee39f..52e92b50 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -803,7 +803,7 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, // Returns perspective projection matrix RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far) { - double top = near*tanf(fovy*PI/360.0f); + double top = near*tan(fovy*PI/360.0); double right = top*aspect; return MatrixFrustum(-right, right, -top, top, near, far); diff --git a/src/rlgl.c b/src/rlgl.c index 7616c1a4..e1949274 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1611,54 +1611,24 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) } // Get world coordinates from screen coordinates -// NOTE: Using global variables: screenWidth, screenHeight Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { - Vector3 result = { 0.0f, 0.0f, 0.0f }; // Object coordinates + Vector3 result = { 0.0f, 0.0f, 0.0f }; - //GLint viewport[4]; - //glGetIntegerv(GL_VIEWPORT, viewport); // Not available on OpenGL ES 2.0 - - // Viewport data - int x = 0; // viewport[0] - int y = 0; // viewport[1] - int width = screenWidth; // viewport[2] - int height = screenHeight; // viewport[3] + // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it + Matrix matProjView = MatrixMultiply(proj, view); + MatrixInvert(&matProjView); - Matrix modelviewprojection = MatrixMultiply(view, proj); - MatrixInvert(&modelviewprojection); -/* - // NOTE: Compute unproject using Vector3 - - // Transformation of normalized coordinates between -1 and 1 - result.x = ((source.x - (float)x)/(float)width)*2.0f - 1.0f; - result.y = ((source.y - (float)y)/(float)height)*2.0f - 1.0f; - result.z = source.z*2.0f - 1.0f; - - // Object coordinates (multiply vector by matrix) - VectorTransform(&result, modelviewprojection); -*/ - - // NOTE: Compute unproject using Quaternion (Vector4) - Quaternion quat; + // Create quaternion from source point + Quaternion quat = { source.x, source.y, source.z, 1.0f }; - quat.x = ((source.x - (float)x)/(float)width)*2.0f - 1.0f; - quat.y = ((source.y - (float)y)/(float)height)*2.0f - 1.0f; - quat.z = source.z*2.0f - 1.0f; - quat.w = 1.0f; + // Multiply quat point by unproject matrix + QuaternionTransform(&quat, matProjView); - QuaternionTransform(&quat, modelviewprojection); - - if (quat.w != 0.0f) - { - quat.x /= quat.w; - quat.y /= quat.w; - quat.z /= quat.w; - } - - result.x = quat.x; - result.y = quat.y; - result.z = quat.z; + // Normalized world points in vectors + result.x = quat.x/quat.w; + result.y = quat.y/quat.w; + result.z = quat.z/quat.w; return result; } -- cgit v1.2.3 From fffbf48dec317d55262de62f8bab757a31d0eebd Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 2 Mar 2016 19:22:55 +0100 Subject: Added support for Nearest-Neighbor image scaling Specially useful on default font scaling --- src/raylib.h | 1 + src/textures.c | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 4f36e203..f8f1683e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -691,6 +691,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) +void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) diff --git a/src/textures.c b/src/textures.c index 36819daf..cb3113dc 100644 --- a/src/textures.c +++ b/src/textures.c @@ -919,6 +919,39 @@ void ImageResize(Image *image, int newWidth, int newHeight) free(pixels); } +// Resize and image to new size using Nearest-Neighbor scaling algorithm +void ImageResizeNN(Image *image,int newWidth,int newHeight) +{ + Color *pixels = GetImageData(*image); + Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color)); + + // EDIT: added +1 to account for an early rounding problem + int x_ratio = (int)((image->width<<16)/newWidth) + 1; + int y_ratio = (int)((image->height<<16)/newHeight) + 1; + + int x2, y2; + for (int i = 0; i < newHeight; i++) + { + for (int j = 0; j < newWidth; j++) + { + x2 = ((j*x_ratio) >> 16); + y2 = ((i*y_ratio) >> 16); + + output[(i*newWidth) + j] = pixels[(y2*image->width) + x2] ; + } + } + + int format = image->format; + + UnloadImage(*image); + + *image = LoadImageEx(output, newWidth, newHeight); + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + + free(output); + free(pixels); +} + // Draw an image (source) within an image (destination) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) { @@ -1046,8 +1079,9 @@ Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, float scaleFactor = (float)fontSize/imSize.y; TraceLog(INFO, "Scalefactor: %f", scaleFactor); - // TODO: Allow nearest-neighbor scaling algorithm - ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); + // Using nearest-neighbor scaling algorithm for default font + if (font.texture.id == GetDefaultFont().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); + else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); } free(pixels); -- cgit v1.2.3 From dcbf2a0e0c904870ac3ac59a3623a3954ab0243f Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 3 Mar 2016 13:24:56 +0100 Subject: Replaced tabs by spaces --- games/tetris.c | 466 ++++++++++++++++++++++++++++----------------------------- src/core.c | 12 +- src/raylib.h | 2 +- 3 files changed, 240 insertions(+), 240 deletions(-) (limited to 'src/raylib.h') diff --git a/games/tetris.c b/games/tetris.c index 62400201..84ba9196 100644 --- a/games/tetris.c +++ b/games/tetris.c @@ -179,22 +179,22 @@ void InitGame(void) // Initialize grid matrices for (int i = 0; i < GRID_HORIZONTAL_SIZE; i++) - { - for (int j = 0; j < GRID_VERTICAL_SIZE; j++) - { + { + for (int j = 0; j < GRID_VERTICAL_SIZE; j++) + { if ((j == GRID_VERTICAL_SIZE - 1) || (i == 0) || (i == GRID_HORIZONTAL_SIZE - 1)) grid[i][j] = BLOCK; else grid[i][j] = EMPTY; - } - } + } + } // Initialize incoming piece matrices for (int i = 0; i < 4; i++) - { - for (int j = 0; j< 4; j++) - { - incomingPiece[i][j] = EMPTY; - } - } + { + for (int j = 0; j< 4; j++) + { + incomingPiece[i][j] = EMPTY; + } + } } // Update game (one frame) @@ -423,34 +423,34 @@ static bool Createpiece() piecePositionY = 0; // If the game is starting and you are going to create the first piece, we create an extra one - if (beginPlay) - { + if (beginPlay) + { GetRandompiece(); beginPlay = false; - } - + } + // We assign the incoming piece to the actual piece for (int i = 0; i < 4; i++) - { - for (int j = 0; j< 4; j++) - { - piece[i][j] = incomingPiece[i][j]; - } - } - + { + for (int j = 0; j< 4; j++) + { + piece[i][j] = incomingPiece[i][j]; + } + } + // We assign a random piece to the incoming one - GetRandompiece(); + GetRandompiece(); // Assign the piece to the grid for (int i = piecePositionX; i < piecePositionX + 4; i++) - { - for (int j = 0; j < 4; j++) - { - if (piece[i - (int)piecePositionX][j] == MOVING) grid[i][j] = MOVING; - } - } - - return true; + { + for (int j = 0; j < 4; j++) + { + if (piece[i - (int)piecePositionX][j] == MOVING) grid[i][j] = MOVING; + } + } + + return true; } static void GetRandompiece() @@ -459,22 +459,22 @@ static void GetRandompiece() int random = rand() % 7; for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - incomingPiece[i][j] = EMPTY; - } - } + { + for (int j = 0; j < 4; j++) + { + incomingPiece[i][j] = EMPTY; + } + } switch(random) - { - case 0: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //Cube - case 1: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //L - case 2: { incomingPiece[1][2] = MOVING; incomingPiece[2][0] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; } break; //L inversa - case 3: { incomingPiece[0][1] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //Recta - case 4: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][1] = MOVING; } break; //Creu tallada - case 5: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[3][2] = MOVING; } break; //S - case 6: { incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //S inversa + { + case 0: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //Cube + case 1: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; } break; //L + case 2: { incomingPiece[1][2] = MOVING; incomingPiece[2][0] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; } break; //L inversa + case 3: { incomingPiece[0][1] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //Recta + case 4: { incomingPiece[1][0] = MOVING; incomingPiece[1][1] = MOVING; incomingPiece[1][2] = MOVING; incomingPiece[2][1] = MOVING; } break; //Creu tallada + case 5: { incomingPiece[1][1] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[3][2] = MOVING; } break; //S + case 6: { incomingPiece[1][2] = MOVING; incomingPiece[2][2] = MOVING; incomingPiece[2][1] = MOVING; incomingPiece[3][1] = MOVING; } break; //S inversa } } @@ -482,34 +482,34 @@ static void ResolveFallingMovement(bool *detection, bool *pieceActive) { // If we finished moving this piece, we stop it if (*detection) - { + { for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if (grid[i][j] == MOVING) - { - grid[i][j] = FULL; - *detection = false; - *pieceActive = false; - } - } - } - } + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j] = FULL; + *detection = false; + *pieceActive = false; + } + } + } + } // We move down the piece - else - { + else + { for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if (grid[i][j] == MOVING) - { - grid[i][j+1] = MOVING; - grid[i][j] = EMPTY; - } - } - } + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j+1] = MOVING; + grid[i][j] = EMPTY; + } + } + } piecePositionY++; } } @@ -519,78 +519,78 @@ static bool ResolveLateralMovement() bool collision = false; // Move left - if (IsKeyDown(KEY_LEFT)) - { + if (IsKeyDown(KEY_LEFT)) + { // Check if is possible to move to left - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if (grid[i][j] == MOVING) - { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { // Check if we are touching the left wall or we have a full square at the left - if ((i-1 == 0) || (grid[i-1][j] == FULL)) collision = true; - } - } - } + if ((i-1 == 0) || (grid[i-1][j] == FULL)) collision = true; + } + } + } // If able, move left - if (!collision) - { - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right - { + if (!collision) + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) // We check the matrix from left to right + { // Move everything to the left - if (grid[i][j] == MOVING) - { - grid[i-1][j] = MOVING; - grid[i][j] = EMPTY; - } - } - } + if (grid[i][j] == MOVING) + { + grid[i-1][j] = MOVING; + grid[i][j] = EMPTY; + } + } + } piecePositionX--; - } - } + } + } // Move right - else if (IsKeyDown(KEY_RIGHT)) - { + else if (IsKeyDown(KEY_RIGHT)) + { // Check if is possible to move to right - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if (grid[i][j] == MOVING) - { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { // Check if we are touching the right wall or we have a full square at the right - if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == FULL)) + if ((i+1 == GRID_HORIZONTAL_SIZE - 1) || (grid[i+1][j] == FULL)) { collision = true; } - } - } - } + } + } + } // If able move right - if (!collision) - { - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left - { + if (!collision) + { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = GRID_HORIZONTAL_SIZE - 1; i >= 1; i--) // We check the matrix from right to left + { // Move everything to the right - if (grid[i][j] == MOVING) - { - grid[i+1][j] = MOVING; - grid[i][j] = EMPTY; - } - } - } + if (grid[i][j] == MOVING) + { + grid[i+1][j] = MOVING; + grid[i][j] = EMPTY; + } + } + } piecePositionX++; - } - } + } + } return collision; } @@ -599,164 +599,164 @@ static bool ResolveTurnMovement() { // Input for turning the piece if (IsKeyDown(KEY_UP)) - { - int aux; - bool checker = false; + { + int aux; + bool checker = false; // Check all turning possibilities - if ((grid[piecePositionX + 3][piecePositionY] == MOVING) && + if ((grid[piecePositionX + 3][piecePositionY] == MOVING) && (grid[piecePositionX][piecePositionY] != EMPTY) && (grid[piecePositionX][piecePositionY] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 3][piecePositionY + 3] == MOVING) && + if ((grid[piecePositionX + 3][piecePositionY + 3] == MOVING) && (grid[piecePositionX + 3][piecePositionY] != EMPTY) && (grid[piecePositionX + 3][piecePositionY] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX][piecePositionY + 3] == MOVING) && + if ((grid[piecePositionX][piecePositionY + 3] == MOVING) && (grid[piecePositionX + 3][piecePositionY + 3] != EMPTY) && (grid[piecePositionX + 3][piecePositionY + 3] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX][piecePositionY] == MOVING) && + if ((grid[piecePositionX][piecePositionY] == MOVING) && (grid[piecePositionX][piecePositionY + 3] != EMPTY) && (grid[piecePositionX][piecePositionY + 3] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 1][piecePositionY] == MOVING) && + if ((grid[piecePositionX + 1][piecePositionY] == MOVING) && (grid[piecePositionX][piecePositionY + 2] != EMPTY) && (grid[piecePositionX][piecePositionY + 2] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 3][piecePositionY + 1] == MOVING) && + if ((grid[piecePositionX + 3][piecePositionY + 1] == MOVING) && (grid[piecePositionX + 1][piecePositionY] != EMPTY) && (grid[piecePositionX + 1][piecePositionY] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 2][piecePositionY + 3] == MOVING) && + if ((grid[piecePositionX + 2][piecePositionY + 3] == MOVING) && (grid[piecePositionX + 3][piecePositionY + 1] != EMPTY) && (grid[piecePositionX + 3][piecePositionY + 1] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX][piecePositionY + 2] == MOVING) && + if ((grid[piecePositionX][piecePositionY + 2] == MOVING) && (grid[piecePositionX + 2][piecePositionY + 3] != EMPTY) && (grid[piecePositionX + 2][piecePositionY + 3] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 2][piecePositionY] == MOVING) && + if ((grid[piecePositionX + 2][piecePositionY] == MOVING) && (grid[piecePositionX][piecePositionY + 1] != EMPTY) && (grid[piecePositionX][piecePositionY + 1] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 3][piecePositionY + 2] == MOVING) && + if ((grid[piecePositionX + 3][piecePositionY + 2] == MOVING) && (grid[piecePositionX + 2][piecePositionY] != EMPTY) && (grid[piecePositionX + 2][piecePositionY] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 1][piecePositionY + 3] == MOVING) && + if ((grid[piecePositionX + 1][piecePositionY + 3] == MOVING) && (grid[piecePositionX + 3][piecePositionY + 2] != EMPTY) && (grid[piecePositionX + 3][piecePositionY + 2] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX][piecePositionY + 1] == MOVING) && + if ((grid[piecePositionX][piecePositionY + 1] == MOVING) && (grid[piecePositionX + 1][piecePositionY + 3] != EMPTY) && (grid[piecePositionX + 1][piecePositionY + 3] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 1][piecePositionY + 1] == MOVING) && + if ((grid[piecePositionX + 1][piecePositionY + 1] == MOVING) && (grid[piecePositionX + 1][piecePositionY + 2] != EMPTY) && (grid[piecePositionX + 1][piecePositionY + 2] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 2][piecePositionY + 1] == MOVING) && + if ((grid[piecePositionX + 2][piecePositionY + 1] == MOVING) && (grid[piecePositionX + 1][piecePositionY + 1] != EMPTY) && (grid[piecePositionX + 1][piecePositionY + 1] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 2][piecePositionY + 2] == MOVING) && + if ((grid[piecePositionX + 2][piecePositionY + 2] == MOVING) && (grid[piecePositionX + 2][piecePositionY + 1] != EMPTY) && (grid[piecePositionX + 2][piecePositionY + 1] != MOVING)) - { + { checker = true; } - if ((grid[piecePositionX + 1][piecePositionY + 2] == MOVING) && + if ((grid[piecePositionX + 1][piecePositionY + 2] == MOVING) && (grid[piecePositionX + 2][piecePositionY + 2] != EMPTY) && (grid[piecePositionX + 2][piecePositionY + 2] != MOVING)) - { + { checker = true; } - if (!checker) - { - aux = piece[0][0]; - piece[0][0] = piece[3][0]; - piece[3][0] = piece[3][3]; - piece[3][3] = piece[0][3]; - piece[0][3] = aux; - - aux = piece[1][0]; - piece[1][0] = piece[3][1]; - piece[3][1] = piece[2][3]; - piece[2][3] = piece[0][2]; - piece[0][2] = aux; - - aux = piece[2][0]; - piece[2][0] = piece[3][2]; - piece[3][2] = piece[1][3]; - piece[1][3] = piece[0][1]; - piece[0][1] = aux; - - aux = piece[1][1]; - piece[1][1] = piece[2][1]; - piece[2][1] = piece[2][2]; - piece[2][2] = piece[1][2]; - piece[1][2] = aux; - } - - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if (grid[i][j] == MOVING) - { - grid[i][j] = EMPTY; - } - } - } - - for (int i = piecePositionX; i < piecePositionX + 4; i++) - { - for (int j = piecePositionY; j < piecePositionY + 4; j++) - { - if (piece[i - piecePositionX][j - piecePositionY] == MOVING) - { - grid[i][j] = MOVING; - } - } - } + if (!checker) + { + aux = piece[0][0]; + piece[0][0] = piece[3][0]; + piece[3][0] = piece[3][3]; + piece[3][3] = piece[0][3]; + piece[0][3] = aux; + + aux = piece[1][0]; + piece[1][0] = piece[3][1]; + piece[3][1] = piece[2][3]; + piece[2][3] = piece[0][2]; + piece[0][2] = aux; + + aux = piece[2][0]; + piece[2][0] = piece[3][2]; + piece[3][2] = piece[1][3]; + piece[1][3] = piece[0][1]; + piece[0][1] = aux; + + aux = piece[1][1]; + piece[1][1] = piece[2][1]; + piece[2][1] = piece[2][2]; + piece[2][2] = piece[1][2]; + piece[1][2] = aux; + } + + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if (grid[i][j] == MOVING) + { + grid[i][j] = EMPTY; + } + } + } + + for (int i = piecePositionX; i < piecePositionX + 4; i++) + { + for (int j = piecePositionY; j < piecePositionY + 4; j++) + { + if (piece[i - piecePositionX][j - piecePositionY] == MOVING) + { + grid[i][j] = MOVING; + } + } + } return true; - } + } return false; } @@ -764,44 +764,44 @@ static bool ResolveTurnMovement() static void CheckDetection(bool *detection) { for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { - if ((grid[i][j] == MOVING) && ((grid[i][j+1] == FULL) || (grid[i][j+1] == BLOCK))) *detection = true; - } - } + { + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { + if ((grid[i][j] == MOVING) && ((grid[i][j+1] == FULL) || (grid[i][j+1] == BLOCK))) *detection = true; + } + } } static void CheckCompletition(bool *lineToDelete) { int calculator; - for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) - { - calculator = 0; - for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) - { + for (int j = GRID_VERTICAL_SIZE - 2; j >= 0; j--) + { + calculator = 0; + for (int i = 1; i < GRID_HORIZONTAL_SIZE - 1; i++) + { // Count each square of the line - if (grid[i][j] == FULL) - { - calculator++; - } + if (grid[i][j] == FULL) + { + calculator++; + } // Check if we completed the whole line - if (calculator == GRID_HORIZONTAL_SIZE - 2) - { + if (calculator == GRID_HORIZONTAL_SIZE - 2) + { *lineToDelete = true; calculator = 0; - // points++; + // points++; // Mark the completed line - for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++) - { - grid[z][j] = FADING; - } - } - } - } + for (int z = 1; z < GRID_HORIZONTAL_SIZE - 1; z++) + { + grid[z][j] = FADING; + } + } + } + } } static void DeleteCompleteLines() diff --git a/src/core.c b/src/core.c index 1589439e..259e1f29 100644 --- a/src/core.c +++ b/src/core.c @@ -1752,8 +1752,8 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // Normalize gestureEvent.position[0] for screenWidth and screenHeight gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures system for processing + + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); #endif } @@ -1890,7 +1890,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // TODO: GPU assets reload in case of lost focus (lost context) // NOTE: This problem has been solved just unbinding and rebinding context from display - /* + /* if (assetsReloadRequired) { for (int i = 0; i < assetsCount; i++) @@ -2471,9 +2471,9 @@ static void *GamepadThread(void *arg) const int joystickAxisY = 1; // Read gamepad event - struct js_event gamepadEvent; + struct js_event gamepadEvent; - while (1) + while (1) { if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) { @@ -2507,7 +2507,7 @@ static void *GamepadThread(void *arg) */ } } - } + } return NULL; } diff --git a/src/raylib.h b/src/raylib.h index f8f1683e..00afb4f3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -385,7 +385,7 @@ typedef struct Model { Matrix transform; Texture2D texture; // Only for OpenGL 1.1, on newer versions this should be in the shader Shader shader; - //Material material; + //Material material; } Model; // Ray type (useful for raycast) -- cgit v1.2.3 From d8bd8634ab7d5179cb1481206176af1f8e592e75 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 5 Mar 2016 13:05:45 +0100 Subject: 3d Camera: Added support for field-of-view Y --- examples/core_3d_camera_first_person.c | 3 ++- examples/core_3d_camera_free.c | 2 ++ examples/core_3d_mode.c | 1 + examples/core_3d_picking.c | 2 ++ examples/core_world_screen.c | 3 ++- examples/models_billboard.c | 3 ++- examples/models_box_collisions.c | 2 +- examples/models_cubicmap.c | 3 ++- examples/models_geometric_shapes.c | 2 +- examples/models_heightmap.c | 2 +- examples/models_obj_loading.c | 2 +- examples/shaders_basic_lighting.c | 2 +- examples/shaders_custom_uniform.c | 2 +- examples/shaders_model_shader.c | 2 +- examples/shaders_postprocessing.c | 2 +- src/camera.c | 8 +++++++- src/camera.h | 1 + src/core.c | 20 ++++++++++---------- src/models.c | 28 +++++++++------------------- src/raylib.h | 9 +++++---- 20 files changed, 53 insertions(+), 46 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_3d_camera_first_person.c b/examples/core_3d_camera_first_person.c index 2b8dc7fc..16d388df 100644 --- a/examples/core_3d_camera_first_person.c +++ b/examples/core_3d_camera_first_person.c @@ -23,7 +23,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); // Define the camera to look into our 3d world (position, target, up vector) - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 60.0f }; // Generates some random columns float heights[MAX_COLUMNS]; @@ -40,6 +40,7 @@ int main() Vector3 playerPosition = { 4.0f, 2.0f, 4.0f }; // Define player position SetCameraMode(CAMERA_FIRST_PERSON); // Set a first person camera mode + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/core_3d_camera_free.c b/examples/core_3d_camera_free.c index 4b45373d..234c46b3 100644 --- a/examples/core_3d_camera_free.c +++ b/examples/core_3d_camera_free.c @@ -25,12 +25,14 @@ int main() camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; SetCameraMode(CAMERA_FREE); // Set a free 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 + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/core_3d_mode.c b/examples/core_3d_mode.c index 7be5dd45..5f761655 100644 --- a/examples/core_3d_mode.c +++ b/examples/core_3d_mode.c @@ -25,6 +25,7 @@ int main() camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; diff --git a/examples/core_3d_picking.c b/examples/core_3d_picking.c index 612f6374..33eaed8a 100644 --- a/examples/core_3d_picking.c +++ b/examples/core_3d_picking.c @@ -25,6 +25,7 @@ int main() camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; @@ -35,6 +36,7 @@ int main() SetCameraMode(CAMERA_FREE); // Set a free camera mode SetCameraPosition(camera.position); // Set internal camera position to match our camera position + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/core_world_screen.c b/examples/core_world_screen.c index b70b40dd..d89a296b 100644 --- a/examples/core_world_screen.c +++ b/examples/core_world_screen.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera free"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; @@ -30,6 +30,7 @@ int main() SetCameraMode(CAMERA_FREE); // Set a free 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 + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models_billboard.c b/examples/models_billboard.c index bac42d35..654b3618 100644 --- a/examples/models_billboard.c +++ b/examples/models_billboard.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - drawing billboards"); // Define the camera to look into our 3d world - Camera camera = {{ 5.0f, 4.0f, 5.0f }, { 0.0f, 2.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 5.0f, 4.0f, 5.0f }, { 0.0f, 2.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Texture2D bill = LoadTexture("resources/billboard.png"); // Our texture billboard Vector3 billPosition = { 0.0f, 2.0f, 0.0f }; // Position where draw billboard @@ -29,6 +29,7 @@ int main() SetCameraMode(CAMERA_ORBITAL); // Set an 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 + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models_box_collisions.c b/examples/models_box_collisions.c index ffd0a2af..69cec418 100644 --- a/examples/models_box_collisions.c +++ b/examples/models_box_collisions.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - box collisions"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Vector3 playerPosition = { 0.0f, 1.0f, 2.0f }; Vector3 playerSize = { 1.0f, 2.0f, 1.0f }; diff --git a/examples/models_cubicmap.c b/examples/models_cubicmap.c index e2a902ef..1ca27dfd 100644 --- a/examples/models_cubicmap.c +++ b/examples/models_cubicmap.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - cubesmap loading and drawing"); // Define the camera to look into our 3d world - Camera camera = {{ 16.0f, 14.0f, 16.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 16.0f, 14.0f, 16.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Image image = LoadImage("resources/cubicmap.png"); // Load cubicmap image (RAM) Texture2D cubicmap = LoadTextureFromImage(image); // Convert image to texture to display (VRAM) @@ -37,6 +37,7 @@ int main() SetCameraMode(CAMERA_ORBITAL); // Set an orbital camera mode SetCameraPosition(camera.position); // Set internal camera position to match our custom camera position + SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models_geometric_shapes.c b/examples/models_geometric_shapes.c index 9ea5b423..a13a1f3b 100644 --- a/examples/models_geometric_shapes.c +++ b/examples/models_geometric_shapes.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - geometric shapes"); // Define the camera to look into our 3d world - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models_heightmap.c b/examples/models_heightmap.c index f1da3301..c8e5ff35 100644 --- a/examples/models_heightmap.c +++ b/examples/models_heightmap.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - heightmap loading and drawing"); // Define our custom camera to look into our 3d world - Camera camera = {{ 18.0f, 16.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 18.0f, 16.0f, 18.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) diff --git a/examples/models_obj_loading.c b/examples/models_obj_loading.c index 41f4569a..e8dd0adc 100644 --- a/examples/models_obj_loading.c +++ b/examples/models_obj_loading.c @@ -21,7 +21,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [models] example - obj model loading"); // Define the camera to look into our 3d world - Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture diff --git a/examples/shaders_basic_lighting.c b/examples/shaders_basic_lighting.c index 84bd1af4..18aea8e1 100644 --- a/examples/shaders_basic_lighting.c +++ b/examples/shaders_basic_lighting.c @@ -36,7 +36,7 @@ int main() 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 }}; + 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 }; diff --git a/examples/shaders_custom_uniform.c b/examples/shaders_custom_uniform.c index 0377cfff..ecfbaa71 100644 --- a/examples/shaders_custom_uniform.c +++ b/examples/shaders_custom_uniform.c @@ -30,7 +30,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [shaders] example - custom uniform variable"); // Define the camera to look into our 3d world - Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture diff --git a/examples/shaders_model_shader.c b/examples/shaders_model_shader.c index 5d8c3711..a10ec235 100644 --- a/examples/shaders_model_shader.c +++ b/examples/shaders_model_shader.c @@ -30,7 +30,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader"); // Define the camera to look into our 3d world - Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture diff --git a/examples/shaders_postprocessing.c b/examples/shaders_postprocessing.c index 0f851658..44829648 100644 --- a/examples/shaders_postprocessing.c +++ b/examples/shaders_postprocessing.c @@ -30,7 +30,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [shaders] example - postprocessing shader"); // Define the camera to look into our 3d world - Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; + Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture diff --git a/src/camera.c b/src/camera.c index 517e4a2b..8e5c527e 100644 --- a/src/camera.c +++ b/src/camera.c @@ -84,7 +84,7 @@ typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_D //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }}; +static Camera internalCamera = {{ 2.0f, 0.0f, 2.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; static Vector2 cameraAngle = { 0.0f, 0.0f }; static float cameraTargetDistance = 5.0f; static Vector2 cameraMousePosition = { 0.0f, 0.0f }; @@ -212,6 +212,12 @@ void SetCameraTarget(Vector3 target) cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); } +// Set internal camera fovy +void SetCameraFovy(float fovy) +{ + internalCamera.fovy = fovy; +} + // Set camera pan key to combine with mouse movement (free camera) void SetCameraPanControl(int panKey) { diff --git a/src/camera.h b/src/camera.h index 9ad09c6f..8d8029af 100644 --- a/src/camera.h +++ b/src/camera.h @@ -81,6 +81,7 @@ void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and void SetCameraPosition(Vector3 position); // Set internal camera position void SetCameraTarget(Vector3 target); // Set internal camera target +void SetCameraFovy(float fovy); // Set internal camera field-of-view-y void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) diff --git a/src/core.c b/src/core.c index 259e1f29..a8cc593a 100644 --- a/src/core.c +++ b/src/core.c @@ -609,10 +609,10 @@ void Begin3dMode(Camera camera) rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (PROJECTION) - + // Setup perspective projection float aspect = (float)screenWidth/(float)screenHeight; - double top = 0.01*tan(45.0*PI/360.0); + double top = 0.01*tan(camera.fovy*PI/360.0); double right = top*aspect; // NOTE: zNear and zFar values are important when computing depth buffer values @@ -883,7 +883,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) TraceLog(DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); // Calculate projection matrix (from perspective instead of frustum) - Matrix matProj = MatrixPerspective(45.0, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); + Matrix matProj = MatrixPerspective(camera.fovy, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); // Calculate view matrix from camera look at Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); @@ -936,7 +936,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Vector2 WorldToScreen(Vector3 position, Camera camera) { // Calculate projection matrix (from perspective instead of frustum - Matrix matProj = MatrixPerspective(45.0f, (float)((float)GetScreenWidth() / (float)GetScreenHeight()), 0.01f, 1000.0f); + Matrix matProj = MatrixPerspective(camera.fovy, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0); // Calculate view matrix from camera look at (and transpose it) Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); @@ -1752,8 +1752,8 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int // Normalize gestureEvent.position[0] for screenWidth and screenHeight gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures system for processing + + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); #endif } @@ -1890,7 +1890,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // TODO: GPU assets reload in case of lost focus (lost context) // NOTE: This problem has been solved just unbinding and rebinding context from display - /* + /* if (assetsReloadRequired) { for (int i = 0; i < assetsCount; i++) @@ -2471,9 +2471,9 @@ static void *GamepadThread(void *arg) const int joystickAxisY = 1; // Read gamepad event - struct js_event gamepadEvent; + struct js_event gamepadEvent; - while (1) + while (1) { if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) { @@ -2507,7 +2507,7 @@ static void *GamepadThread(void *arg) */ } } - } + } return NULL; } diff --git a/src/models.c b/src/models.c index fc95f58d..a0b0e656 100644 --- a/src/models.c +++ b/src/models.c @@ -558,19 +558,9 @@ Model LoadModel(const char *fileName) // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() model = rlglLoadModel(mesh); // Upload vertex data to GPU - // Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM - // NOTE 1: We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes... - // NOTE 2: ...but we could keep CPU vertex data in case we need to update the mesh - - /* - if (rlGetVersion() != OPENGL_11) - { - free(mesh.vertices); - free(mesh.texcoords); - free(mesh.normals); - free(mesh.colors); - } - */ + // NOTE: Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM + // We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes... + // ...but we could keep CPU vertex data in case we need to update the mesh } return model; @@ -1082,16 +1072,16 @@ void UnloadModel(Model model) free(model.mesh.vertices); free(model.mesh.texcoords); free(model.mesh.normals); - if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); - if (model.mesh.tangents != NULL) free(model.mesh.tangents); - if (model.mesh.colors != NULL) free(model.mesh.colors); + free(model.mesh.colors); + //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used + //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used rlDeleteBuffers(model.mesh.vboId[0]); // vertex rlDeleteBuffers(model.mesh.vboId[1]); // texcoords rlDeleteBuffers(model.mesh.vboId[2]); // normals - rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 - rlDeleteBuffers(model.mesh.vboId[4]); // tangents - rlDeleteBuffers(model.mesh.vboId[5]); // colors + //rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) rlDeleteVertexArrays(model.mesh.vaoId); diff --git a/src/raylib.h b/src/raylib.h index 00afb4f3..b6cf98fe 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -309,10 +309,10 @@ typedef struct SpriteFont { // Camera type, defines a camera position/orientation in 3d space typedef struct Camera { - Vector3 position; - Vector3 target; - Vector3 up; - //float fovy; // Field-Of-View apperture in Y (degrees) + Vector3 position; // Camera position + Vector3 target; // Camera target it looks-at + Vector3 up; // Camera up vector (rotation over its axis) + float fovy; // Field-Of-View apperture in Y (degrees) } Camera; // Bounding box type @@ -630,6 +630,7 @@ void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and void SetCameraPosition(Vector3 position); // Set internal camera position void SetCameraTarget(Vector3 target); // Set internal camera target +void SetCameraFovy(float fovy); // Set internal camera field-of-view-y void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) -- cgit v1.2.3 From 5ea18b9426823e92f1fc16e686702f2caadf83c9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 5 Mar 2016 15:40:08 +0100 Subject: Support 2d camera system -IN PROGRESS- --- examples/core_2d_camera.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ src/core.c | 21 ++++++++++++-- src/raylib.h | 11 +++++++- 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 examples/core_2d_camera.c (limited to 'src/raylib.h') diff --git a/examples/core_2d_camera.c b/examples/core_2d_camera.c new file mode 100644 index 00000000..71c474f0 --- /dev/null +++ b/examples/core_2d_camera.c @@ -0,0 +1,71 @@ +/******************************************************************************************* +* +* raylib [core] example - 2d camera +* +* This example has been created using raylib 1.5 (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" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera"); + + Camera2D camera; + + camera.position = (Vector2){ 0, 0 }; + camera.origin = (Vector2){ 100, 100 }; + camera.rotation = 0.0f; + camera.zoom = 1.0f; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + if (IsKeyDown(KEY_RIGHT)) camera.position.x--; + else if (IsKeyDown(KEY_LEFT)) camera.position.x++; + else if (IsKeyDown(KEY_UP)) camera.position.y++; + else if (IsKeyDown(KEY_DOWN)) camera.position.y--; + + if (IsKeyDown(KEY_R)) camera.rotation--; + else if (IsKeyDown(KEY_F)) camera.rotation++; + + if (IsKeyDown(KEY_W)) camera.zoom += 0.005f; + if (IsKeyDown(KEY_S)) camera.zoom -= 0.005f; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawingEx(camera); + + ClearBackground(RAYWHITE); + + DrawText("2D CAMERA TEST", 20, 20, 20, GRAY); + + DrawRectangle(0, 300, screenWidth, 50, GRAY); + DrawRectangle(400, 250, 40, 40, RED); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/src/core.c b/src/core.c index a8cc593a..870ca3b4 100644 --- a/src/core.c +++ b/src/core.c @@ -560,8 +560,25 @@ void BeginDrawing(void) // NOTE: Not required with OpenGL 3.3+ } -// Setup drawing canvas with extended parameters -void BeginDrawingEx(int blendMode, Shader shader, Matrix transform) +// Setup drawing canvas with 2d camera +void BeginDrawingEx(Camera2D camera) +{ + BeginDrawing(); + + // TODO: Consider origin offset on position, rotation, scaling + + Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); + Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); + Matrix matTranslation = MatrixTranslate(camera.position.x, camera.position.y, 0.0f); + Matrix matOrigin = MatrixTranslate(-camera.origin.x, -camera.origin.y, 0.0f); + + Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + + rlMultMatrixf(MatrixToFloat(matTransform)); +} + +// Setup drawing canvas with pro parameters +void BeginDrawingPro(int blendMode, Shader shader, Matrix transform) { BeginDrawing(); diff --git a/src/raylib.h b/src/raylib.h index b6cf98fe..7173a556 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -315,6 +315,14 @@ typedef struct Camera { float fovy; // Field-Of-View apperture in Y (degrees) } Camera; +// Camera2D type, defines a 2d camera +typedef struct Camera2D { + Vector2 position; // Camera position + Vector2 origin; // Camera origin (for rotation and zoom) + float rotation; // Camera rotation in degrees + float zoom; // Camera zoom (scaling), should be 1.0f by default +} Camera2D; + // Bounding box type typedef struct BoundingBox { Vector3 min; @@ -528,7 +536,8 @@ int GetScreenHeight(void); // Get current scree void ClearBackground(Color color); // Sets Background Color void BeginDrawing(void); // Setup drawing canvas to start drawing -void BeginDrawingEx(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with extended parameters +void BeginDrawingEx(Camera2D camera); // Setup drawing canvas with 2d camera +void BeginDrawingPro(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with pro parameters void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) -- cgit v1.2.3 From 0d911127d759e3f507b598c1666da1635c863e51 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 5 Mar 2016 16:17:54 +0100 Subject: Split mesh generation from model loading --- src/models.c | 138 ++++++++++++++++++++++++++++++----------------------------- src/raylib.h | 2 +- 2 files changed, 71 insertions(+), 69 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index a0b0e656..ee5e57c7 100644 --- a/src/models.c +++ b/src/models.c @@ -56,6 +56,8 @@ extern unsigned int whiteTexture; // Module specific Functions Declaration //---------------------------------------------------------------------------------- static Mesh LoadOBJ(const char *fileName); +static Mesh GenMeshHeightmap(Image image, Vector3 size); +static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); //---------------------------------------------------------------------------------- // Module Functions Definition @@ -582,6 +584,63 @@ Model LoadModelEx(Mesh data) // Load a heightmap image as a 3d model // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) +{ + Mesh mesh = GenMeshHeightmap(heightmap, size); + Model model = rlglLoadModel(mesh); + + return model; +} + +// Load a map image as a 3d model (cubes based) +Model LoadCubicmap(Image cubicmap) +{ + Mesh mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); + Model model = rlglLoadModel(mesh); + + return model; +} + +// Unload 3d model from memory +void UnloadModel(Model model) +{ + // Unload mesh data + free(model.mesh.vertices); + free(model.mesh.texcoords); + free(model.mesh.normals); + free(model.mesh.colors); + //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used + //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used + + rlDeleteBuffers(model.mesh.vboId[0]); // vertex + rlDeleteBuffers(model.mesh.vboId[1]); // texcoords + rlDeleteBuffers(model.mesh.vboId[2]); // normals + //rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) + + rlDeleteVertexArrays(model.mesh.vaoId); + + if (model.mesh.vaoId > 0) TraceLog(INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", model.mesh.vaoId); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Unloaded model data from VRAM (GPU)", model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]); +} + +// Link a texture to a model +void SetModelTexture(Model *model, Texture2D texture) +{ + if (texture.id <= 0) + { + // Use default white texture (use mesh color) + model->texture.id = whiteTexture; // OpenGL 1.1 + model->shader.texDiffuseId = whiteTexture; // OpenGL 3.3 / ES 2.0 + } + else + { + model->texture = texture; + model->shader.texDiffuseId = texture.id; + } +} + +static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) { #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) @@ -687,27 +746,17 @@ Model LoadHeightmap(Image heightmap, Vector3 size) // NOTE: Not used any more... just one plain color defined at DrawModel() for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - - Model model = rlglLoadModel(mesh); - - // Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM... - // ...but we keep CPU RAM vertex data in case we need to update the mesh - - return model; + return mesh; } -// Load a map image as a 3d model (cubes based) -Model LoadCubicmap(Image cubicmap) +static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) { Mesh mesh; Color *cubicmapPixels = GetImageData(cubicmap); - // Map cube size will be 1.0 - float mapCubeSide = 1.0f; - int mapWidth = cubicmap.width*(int)mapCubeSide; - int mapHeight = cubicmap.height*(int)mapCubeSide; + int mapWidth = cubicmap.width*(int)cubeSize.x; + int mapHeight = cubicmap.height*(int)cubeSize.z; // NOTE: Max possible number of triangles numCubes * (12 triangles by cube) int maxTriangles = cubicmap.width*cubicmap.height*12; @@ -716,9 +765,9 @@ Model LoadCubicmap(Image cubicmap) int tcCounter = 0; // Used to count texcoords int nCounter = 0; // Used to count normals - float w = mapCubeSide; - float h = mapCubeSide; - float h2 = mapCubeSide*1.5f; // TODO: Review walls height... + float w = cubeSize.x; + float h = cubeSize.z; + float h2 = cubeSize.y; Vector3 *mapVertices = (Vector3 *)malloc(maxTriangles*3*sizeof(Vector3)); Vector2 *mapTexcoords = (Vector2 *)malloc(maxTriangles*3*sizeof(Vector2)); @@ -747,9 +796,9 @@ Model LoadCubicmap(Image cubicmap) RectangleF topTexUV = { 0.0f, 0.5f, 0.5f, 0.5f }; RectangleF bottomTexUV = { 0.5f, 0.5f, 0.5f, 0.5f }; - for (int z = 0; z < mapHeight; z += mapCubeSide) + for (int z = 0; z < mapHeight; z += cubeSize.z) { - for (int x = 0; x < mapWidth; x += mapCubeSide) + for (int x = 0; x < mapWidth; x += cubeSize.x) { // Define the 8 vertex of the cube, we will combine them accordingly later... Vector3 v1 = { x - w/2, h2, z - h/2 }; @@ -1053,56 +1102,9 @@ Model LoadCubicmap(Image cubicmap) free(mapNormals); free(mapTexcoords); - free(cubicmapPixels); - - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - - Model model = rlglLoadModel(mesh); - - // Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM... - // ...but we keep CPU RAM vertex data in case we need to update the mesh - - return model; -} - -// Unload 3d model from memory -void UnloadModel(Model model) -{ - // Unload mesh data - free(model.mesh.vertices); - free(model.mesh.texcoords); - free(model.mesh.normals); - free(model.mesh.colors); - //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used - //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used + free(cubicmapPixels); // Free image pixel data - rlDeleteBuffers(model.mesh.vboId[0]); // vertex - rlDeleteBuffers(model.mesh.vboId[1]); // texcoords - rlDeleteBuffers(model.mesh.vboId[2]); // normals - //rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) - - rlDeleteVertexArrays(model.mesh.vaoId); - - if (model.mesh.vaoId > 0) TraceLog(INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", model.mesh.vaoId); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Unloaded model data from VRAM (GPU)", model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]); -} - -// Link a texture to a model -void SetModelTexture(Model *model, Texture2D texture) -{ - if (texture.id <= 0) - { - // Use default white texture (use mesh color) - model->texture.id = whiteTexture; // OpenGL 1.1 - model->shader.texDiffuseId = whiteTexture; // OpenGL 3.3 / ES 2.0 - } - else - { - model->texture = texture; - model->shader.texDiffuseId = texture.id; - } + return mesh; } // Draw a model (with texture if set) diff --git a/src/raylib.h b/src/raylib.h index 7173a556..9545f96d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -761,7 +761,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 vertex data) +Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) //Model LoadModelFromRES(const char *rresName, int resId); // TODO: 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) -- cgit v1.2.3 From 305efcf5ad715305ccb33b0e1d2d9baf4a34976a Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 5 Mar 2016 17:05:02 +0100 Subject: Redesigned physics module (IN PROGRESS) physac modules is being redesigned. Physics base behaviour is done and it is composed by three steps: apply physics, resolve collisions and fix overlapping. A basic example is currently in progress. The next steps are try to add torque and unoriented physic collisions and implement physics basic functions to add forces. Rigidbody grounding state is automatically calculated and has a perfect result. Rigidbodies interacts well with each others. To achieve physics accuracy, UpdatePhysics() is called a number of times per frame. In a future, it should be changed to another thread and call it without any target frame restriction. Basic physics example has been redone (not finished) using the new module functions. Forces examples will be redone so I removed it from branch. --- examples/physics_basic_rigidbody.c | 131 ++++----- examples/physics_rigidbody_force.c | 135 --------- examples/physics_rigidbody_force.png | Bin 18510 -> 0 bytes src/physac.c | 532 ++++++++++++++++++----------------- src/physac.h | 58 ++-- src/raylib.h | 49 ++-- 6 files changed, 392 insertions(+), 513 deletions(-) delete mode 100644 examples/physics_rigidbody_force.c delete mode 100644 examples/physics_rigidbody_force.png (limited to 'src/raylib.h') diff --git a/examples/physics_basic_rigidbody.c b/examples/physics_basic_rigidbody.c index 6c354eb7..c604dd14 100644 --- a/examples/physics_basic_rigidbody.c +++ b/examples/physics_basic_rigidbody.c @@ -1,8 +1,8 @@ /******************************************************************************************* * -* raylib [physac] physics example - Basic rigidbody +* raylib [physac] example - Basic rigidbody * -* This example has been created using raylib 1.4 (www.raylib.com) +* This example has been created using raylib 1.5 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2016 Victor Fisac and Ramon Santamaria (@raysan5) @@ -11,8 +11,8 @@ #include "raylib.h" -#define OBJECT_SIZE 50 -#define PLAYER_INDEX 0 +#define MOVE_VELOCITY 5 +#define JUMP_VELOCITY 35 int main() { @@ -20,28 +20,45 @@ int main() //-------------------------------------------------------------------------------------- int screenWidth = 800; int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [physics] example - basic rigidbody"); - InitPhysics(3); // Initialize physics system with maximum physic objects + InitWindow(screenWidth, screenHeight, "raylib [physac] example - basic rigidbody"); + InitPhysics(); // Initialize physics module - // Object initialization - Transform player = (Transform){(Vector2){(screenWidth - OBJECT_SIZE) / 2, (screenHeight - OBJECT_SIZE) / 2}, 0.0f, (Vector2){OBJECT_SIZE, OBJECT_SIZE}}; - AddCollider(PLAYER_INDEX, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, 0}); - AddRigidbody(PLAYER_INDEX, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 1.0f}); + SetTargetFPS(60); - // Floor initialization - // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody) - Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}}; - AddCollider(PLAYER_INDEX + 1, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0}); + // Debug variables + bool isDebug = false; - // Object properties initialization - float moveSpeed = 6.0f; - float jumpForce = 5.0f; + // Player physic object + PhysicObject *player = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 }); + player->rigidbody.enabled = true; // Enable physic object rigidbody behaviour + player->rigidbody.applyGravity = true; + player->rigidbody.friction = 0.3f; + player->collider.enabled = true; // Enable physic object collisions detection - bool physicsDebug = false; + // Player physic object + PhysicObject *player2 = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 }); + player2->rigidbody.enabled = true; + player2->rigidbody.applyGravity = true; + player2->rigidbody.friction = 0.1f; + player2->collider.enabled = true; + + // Floor physic object + PhysicObject *floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 }); + floor->collider.enabled = true; // Enable just physic object collisions detection + + // Left wall physic object + PhysicObject *leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight }); + leftWall->collider.enabled = true; + + // Right wall physic object + PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight }); + rightWall->collider.enabled = true; + + // Platform physic objectdd + PhysicObject *platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 }); + platform->collider.enabled = true; - SetTargetFPS(60); //-------------------------------------------------------------------------------------- // Main game loop @@ -49,35 +66,22 @@ int main() { // Update //---------------------------------------------------------------------------------- + UpdatePhysics(); // Update all created physic objects - // Update object physics - // NOTE: all physics detections and reactions are calculated in ApplyPhysics() function (You will live happier :D) - ApplyPhysics(PLAYER_INDEX, &player.position); + // Check debug switch input + if (IsKeyPressed('P')) isDebug = !isDebug; - // Check jump button input - if (IsKeyDown(KEY_SPACE) && GetRigidbody(PLAYER_INDEX).isGrounded) - { - // Reset object Y velocity to avoid double jumping cases but keep the same X velocity that it already has - SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){GetRigidbody(PLAYER_INDEX).velocity.x, 0}); - - // Add jumping force in Y axis - AddRigidbodyForce(PLAYER_INDEX, (Vector2){0, jumpForce}); - } + // Check player movement inputs + if (IsKeyDown('W') && player->rigidbody.isGrounded) player->rigidbody.velocity.y = JUMP_VELOCITY; + + if (IsKeyDown('A')) player->rigidbody.velocity.x = -MOVE_VELOCITY; + else if (IsKeyDown('D')) player->rigidbody.velocity.x = MOVE_VELOCITY; - // Check movement buttons input - if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) - { - // Set rigidbody velocity in X based on moveSpeed value and apply the same Y velocity that it already has - SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); - } - else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) - { - // Set rigidbody velocity in X based on moveSpeed negative value and apply the same Y velocity that it already has - SetRigidbodyVelocity(PLAYER_INDEX, (Vector2){-moveSpeed, GetRigidbody(PLAYER_INDEX).velocity.y}); - } + // Check player 2 movement inputs + if (IsKeyDown(KEY_UP) && player2->rigidbody.isGrounded) player2->rigidbody.velocity.y = JUMP_VELOCITY; - // Check debug mode toggle button input - if (IsKeyPressed(KEY_P)) physicsDebug = !physicsDebug; + if (IsKeyDown(KEY_LEFT)) player2->rigidbody.velocity.x = -MOVE_VELOCITY; + else if (IsKeyDown(KEY_RIGHT)) player2->rigidbody.velocity.x = MOVE_VELOCITY; //---------------------------------------------------------------------------------- // Draw @@ -86,28 +90,28 @@ int main() ClearBackground(RAYWHITE); - // Draw information - DrawText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", (screenWidth - MeasureText("Use LEFT / RIGHT to MOVE and SPACE to JUMP", 20)) / 2, screenHeight * 0.20f, 20, LIGHTGRAY); - DrawText("Use P to switch DEBUG MODE", (screenWidth - MeasureText("Use P to switch DEBUG MODE", 20)) / 2, screenHeight * 0.3f, 20, LIGHTGRAY); - - // Check if debug mode is enabled - if (physicsDebug) + if (isDebug) { - // Draw every internal physics stored collider if it is active - for (int i = 0; i < 2; i++) - { - if (GetCollider(i).enabled) - { - DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN); - } - } + DrawRectangleLines(floor->collider.bounds.x, floor->collider.bounds.y, floor->collider.bounds.width, floor->collider.bounds.height, GREEN); + DrawRectangleLines(leftWall->collider.bounds.x, leftWall->collider.bounds.y, leftWall->collider.bounds.width, leftWall->collider.bounds.height, GREEN); + DrawRectangleLines(rightWall->collider.bounds.x, rightWall->collider.bounds.y, rightWall->collider.bounds.width, rightWall->collider.bounds.height, GREEN); + DrawRectangleLines(platform->collider.bounds.x, platform->collider.bounds.y, platform->collider.bounds.width, platform->collider.bounds.height, GREEN); + DrawRectangleLines(player->collider.bounds.x, player->collider.bounds.y, player->collider.bounds.width, player->collider.bounds.height, GREEN); + DrawRectangleLines(player2->collider.bounds.x, player2->collider.bounds.y, player2->collider.bounds.width, player2->collider.bounds.height, GREEN); } else { - // Draw player and floor - DrawRectangleRec((Rectangle){player.position.x, player.position.y, player.scale.x, player.scale.y}, GRAY); - DrawRectangleRec((Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, BLACK); + // Convert transform values to rectangle data type variable + DrawRectangleRec(TransformToRectangle(floor->transform), DARKGRAY); + DrawRectangleRec(TransformToRectangle(leftWall->transform), DARKGRAY); + DrawRectangleRec(TransformToRectangle(rightWall->transform), DARKGRAY); + DrawRectangleRec(TransformToRectangle(platform->transform), DARKGRAY); + DrawRectangleRec(TransformToRectangle(player->transform), RED); + DrawRectangleRec(TransformToRectangle(player2->transform), BLUE); } + + // Draw all physic object information in specific screen position and font size + // DrawPhysicObjectInfo(player, (Vector2){ 10.0f, 10.0f }, 10); EndDrawing(); //---------------------------------------------------------------------------------- @@ -115,8 +119,7 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - UnloadPhysics(); // Unload physic objects - + ClosePhysics(); // Unitialize physics module CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/examples/physics_rigidbody_force.c b/examples/physics_rigidbody_force.c deleted file mode 100644 index 74a88a97..00000000 --- a/examples/physics_rigidbody_force.c +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************************* -* -* raylib [physac] physics example - Rigidbody forces -* -* This example has been created using raylib 1.4 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Copyright (c) 2016 Victor Fisac and Ramon Santamaria (@raysan5) -* -********************************************************************************************/ - -#include "raylib.h" - -#define MAX_OBJECTS 5 -#define OBJECTS_OFFSET 150 - -#define FORCE_INTENSITY 250.0f // Customize by user -#define FORCE_RADIUS 100 // Customize by user - -int main() -{ - // Initialization - //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [physics] example - rigidbodies forces"); - - InitPhysics(MAX_OBJECTS + 1); // Initialize physics system with maximum physic objects - - // Physic Objects initialization - Transform objects[MAX_OBJECTS]; - - for (int i = 0; i < MAX_OBJECTS; i++) - { - objects[i] = (Transform){(Vector2){75 + OBJECTS_OFFSET * i, (screenHeight - 50) / 2}, 0.0f, (Vector2){50, 50}}; - AddCollider(i, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){objects[i].position.x, objects[i].position.y, objects[i].scale.x, objects[i].scale.y}, 0}); - AddRigidbody(i, (Rigidbody){true, 1.0f, (Vector2){0, 0}, (Vector2){0, 0}, false, false, true, 0.5f, 0.5f}); - } - - // Floor initialization - // NOTE: floor doesn't need a rigidbody because it's a static physic object, just a collider to collide with other dynamic colliders (with rigidbody) - Transform floor = (Transform){(Vector2){0, screenHeight * 0.8f}, 0.0f, (Vector2){screenWidth, screenHeight * 0.2f}}; - AddCollider(MAX_OBJECTS, (Collider){true, COLLIDER_RECTANGLE, (Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, 0}); - - bool physicsDebug = false; - - SetTargetFPS(60); - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - - // Update object physics - // NOTE: all physics detections and reactions are calculated in ApplyPhysics() function (You will live happier :D) - for (int i = 0; i < MAX_OBJECTS; i++) - { - ApplyPhysics(i, &objects[i].position); - } - - // Check foce button input - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - AddForceAtPosition(GetMousePosition(), FORCE_INTENSITY, FORCE_RADIUS); - } - - // Check debug mode toggle button input - if (IsKeyPressed(KEY_P)) physicsDebug = !physicsDebug; - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - // Check if debug mode is enabled - if (physicsDebug) - { - // Draw every internal physics stored collider if it is active (floor included) - for (int i = 0; i < MAX_OBJECTS; i++) - { - if (GetCollider(i).enabled) - { - // Draw collider bounds - DrawRectangleLines(GetCollider(i).bounds.x, GetCollider(i).bounds.y, GetCollider(i).bounds.width, GetCollider(i).bounds.height, GREEN); - - // Check if current collider is not floor - if (i < MAX_OBJECTS) - { - // Draw lines between mouse position and objects if they are in force range - if (CheckCollisionPointCircle(GetMousePosition(), (Vector2){GetCollider(i).bounds.x + GetCollider(i).bounds.width / 2, GetCollider(i).bounds.y + GetCollider(i).bounds.height / 2}, FORCE_RADIUS)) - { - DrawLineV(GetMousePosition(), (Vector2){GetCollider(i).bounds.x + GetCollider(i).bounds.width / 2, GetCollider(i).bounds.y + GetCollider(i).bounds.height / 2}, RED); - } - } - } - } - - // Draw radius circle - DrawCircleLines(GetMousePosition().x, GetMousePosition().y, FORCE_RADIUS, RED); - } - else - { - // Draw objects - for (int i = 0; i < MAX_OBJECTS; i++) - { - DrawRectangleRec((Rectangle){objects[i].position.x, objects[i].position.y, objects[i].scale.x, objects[i].scale.y}, GRAY); - } - - // Draw floor - DrawRectangleRec((Rectangle){floor.position.x, floor.position.y, floor.scale.x, floor.scale.y}, BLACK); - } - - - // Draw help messages - DrawText("Use LEFT MOUSE BUTTON to create a force in mouse position", (screenWidth - MeasureText("Use LEFT MOUSE BUTTON to create a force in mouse position", 20)) / 2, screenHeight * 0.20f, 20, LIGHTGRAY); - DrawText("Use P to switch DEBUG MODE", (screenWidth - MeasureText("Use P to switch DEBUG MODE", 20)) / 2, screenHeight * 0.3f, 20, LIGHTGRAY); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - UnloadPhysics(); // Unload physic objects - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/examples/physics_rigidbody_force.png b/examples/physics_rigidbody_force.png deleted file mode 100644 index 48afa91b..00000000 Binary files a/examples/physics_rigidbody_force.png and /dev/null differ diff --git a/src/physac.c b/src/physac.c index 4c50dd41..13247117 100644 --- a/src/physac.c +++ b/src/physac.c @@ -1,6 +1,6 @@ /********************************************************************************************** * -* [physac] raylib physics engine module - Basic functions to apply physics to 2D objects +* [physac] raylib physics module - Basic functions to apply physics to 2D objects * * Copyright (c) 2015 Victor Fisac and Ramon Santamaria * @@ -29,329 +29,343 @@ #include "raylib.h" #endif -#include -#include // Required for: malloc(), free() +#include // Declares malloc() and free() for memory management +#include // abs() and fminf() //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define DECIMAL_FIX 0.26f // Decimal margin for collision checks (avoid rigidbodies shake) +#define MAX_PHYSIC_OBJECTS 256 +#define PHYSICS_GRAVITY -9.81f/2 +#define PHYSICS_STEPS 450 +#define PHYSICS_ACCURACY 0.0001f // Velocity subtract operations round filter (friction) +#define PHYSICS_ERRORPERCENT 0.001f // Collision resolve position fix //---------------------------------------------------------------------------------- // Types and Structures Definition +// NOTE: Below types are required for PHYSAC_STANDALONE usage //---------------------------------------------------------------------------------- // ... //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Collider *colliders; // Colliders array, dynamically allocated at runtime -static Rigidbody *rigidbodies; // Rigitbody array, dynamically allocated at runtime -static bool collisionChecker; - -static int maxElements; // Max physic elements to compute -static bool enabled; // Physics enabled? (true by default) -static Vector2 gravity; // Gravity value used for physic calculations +static PhysicObject *physicObjects[MAX_PHYSIC_OBJECTS]; // Physic objects pool +static int physicObjectsCount; // Counts current enabled physic objects //---------------------------------------------------------------------------------- -// Module specific Functions Declarations +// Module specific Functions Declaration //---------------------------------------------------------------------------------- -static float Vector2Length(Vector2 vector); -static float Vector2Distance(Vector2 a, Vector2 b); -static void Vector2Normalize(Vector2 *vector); +static float Vector2DotProduct(Vector2 v1, Vector2 v2); // Returns the dot product of two Vector2 //---------------------------------------------------------------------------------- -// Module Functions Definitions +// Module Functions Definition //---------------------------------------------------------------------------------- -void InitPhysics(int maxPhysicElements) -{ - maxElements = maxPhysicElements; - - colliders = (Collider *)malloc(maxElements*sizeof(Collider)); - rigidbodies = (Rigidbody *)malloc(maxElements*sizeof(Rigidbody)); - - for (int i = 0; i < maxElements; i++) - { - colliders[i].enabled = false; - colliders[i].bounds = (Rectangle){ 0, 0, 0, 0 }; - colliders[i].radius = 0; - - rigidbodies[i].enabled = false; - rigidbodies[i].mass = 0.0f; - rigidbodies[i].velocity = (Vector2){ 0.0f, 0.0f }; - rigidbodies[i].acceleration = (Vector2){ 0.0f, 0.0f }; - rigidbodies[i].isGrounded = false; - rigidbodies[i].isContact = false; - rigidbodies[i].friction = 0.0f; - } - - collisionChecker = false; - enabled = true; - - // NOTE: To get better results, gravity needs to be 1:10 from original parameter - gravity = (Vector2){ 0.0f, -9.81f/10.0f }; // By default, standard gravity -} - -void UnloadPhysics() -{ - free(colliders); - free(rigidbodies); -} - -void AddCollider(int index, Collider collider) -{ - colliders[index] = collider; -} -void AddRigidbody(int index, Rigidbody rigidbody) +// Initializes pointers array (just pointers, fixed size) +void InitPhysics() { - rigidbodies[index] = rigidbody; + // Initialize physics variables + physicObjectsCount = 0; } -void ApplyPhysics(int index, Vector2 *position) +// Update physic objects, calculating physic behaviours and collisions detection +void UpdatePhysics() { - if (rigidbodies[index].enabled) + // Reset all physic objects is grounded state + for(int i = 0; i < physicObjectsCount; i++) { - // Apply friction to acceleration - if (rigidbodies[index].acceleration.x > DECIMAL_FIX) - { - rigidbodies[index].acceleration.x -= rigidbodies[index].friction; - } - else if (rigidbodies[index].acceleration.x < -DECIMAL_FIX) - { - rigidbodies[index].acceleration.x += rigidbodies[index].friction; - } - else - { - rigidbodies[index].acceleration.x = 0; - } - - if (rigidbodies[index].acceleration.y > DECIMAL_FIX / 2) - { - rigidbodies[index].acceleration.y -= rigidbodies[index].friction; - } - else if (rigidbodies[index].acceleration.y < -DECIMAL_FIX / 2) - { - rigidbodies[index].acceleration.y += rigidbodies[index].friction; - } - else - { - rigidbodies[index].acceleration.y = 0; - } - - // Apply friction to velocity - if (rigidbodies[index].isGrounded) - { - if (rigidbodies[index].velocity.x > DECIMAL_FIX) - { - rigidbodies[index].velocity.x -= rigidbodies[index].friction; - } - else if (rigidbodies[index].velocity.x < -DECIMAL_FIX) - { - rigidbodies[index].velocity.x += rigidbodies[index].friction; - } - else - { - rigidbodies[index].velocity.x = 0; - } - } - - if (rigidbodies[index].velocity.y > DECIMAL_FIX / 2) - { - rigidbodies[index].velocity.y -= rigidbodies[index].friction; - } - else if (rigidbodies[index].velocity.y < -DECIMAL_FIX / 2) - { - rigidbodies[index].velocity.y += rigidbodies[index].friction; - } - else - { - rigidbodies[index].velocity.y = 0; - } - - // Apply gravity - rigidbodies[index].velocity.y += gravity.y; - rigidbodies[index].velocity.x += gravity.x; - - // Apply acceleration - rigidbodies[index].velocity.y += rigidbodies[index].acceleration.y; - rigidbodies[index].velocity.x += rigidbodies[index].acceleration.x; - - // Update position vector - position->x += rigidbodies[index].velocity.x; - position->y -= rigidbodies[index].velocity.y; - - // Update collider bounds - colliders[index].bounds.x = position->x; - colliders[index].bounds.y = position->y; - - // Check collision with other colliders - collisionChecker = false; - rigidbodies[index].isContact = false; - for (int j = 0; j < maxElements; j++) + if(physicObjects[i]->rigidbody.enabled) physicObjects[i]->rigidbody.isGrounded = false; + } + + for(int steps = 0; steps < PHYSICS_STEPS; steps++) + { + for(int i = 0; i < physicObjectsCount; i++) { - if (index != j) + if(physicObjects[i]->enabled) { - if (colliders[index].enabled && colliders[j].enabled) + // Update physic behaviour + if(physicObjects[i]->rigidbody.enabled) { - if (colliders[index].type == COLLIDER_RECTANGLE) + // Apply friction to acceleration in X axis + if (physicObjects[i]->rigidbody.acceleration.x > PHYSICS_ACCURACY) physicObjects[i]->rigidbody.acceleration.x -= physicObjects[i]->rigidbody.friction/PHYSICS_STEPS; + else if (physicObjects[i]->rigidbody.acceleration.x < PHYSICS_ACCURACY) physicObjects[i]->rigidbody.acceleration.x += physicObjects[i]->rigidbody.friction/PHYSICS_STEPS; + else physicObjects[i]->rigidbody.acceleration.x = 0.0f; + + // Apply friction to velocity in X axis + if (physicObjects[i]->rigidbody.velocity.x > PHYSICS_ACCURACY) physicObjects[i]->rigidbody.velocity.x -= physicObjects[i]->rigidbody.friction/PHYSICS_STEPS; + else if (physicObjects[i]->rigidbody.velocity.x < PHYSICS_ACCURACY) physicObjects[i]->rigidbody.velocity.x += physicObjects[i]->rigidbody.friction/PHYSICS_STEPS; + else physicObjects[i]->rigidbody.velocity.x = 0.0f; + + // Apply gravity to velocity + if (physicObjects[i]->rigidbody.applyGravity) physicObjects[i]->rigidbody.velocity.y += PHYSICS_GRAVITY/PHYSICS_STEPS; + + // Apply acceleration to velocity + physicObjects[i]->rigidbody.velocity.x += physicObjects[i]->rigidbody.acceleration.x/PHYSICS_STEPS; + physicObjects[i]->rigidbody.velocity.y += physicObjects[i]->rigidbody.acceleration.y/PHYSICS_STEPS; + + // Apply velocity to position + physicObjects[i]->transform.position.x += physicObjects[i]->rigidbody.velocity.x/PHYSICS_STEPS; + physicObjects[i]->transform.position.y -= physicObjects[i]->rigidbody.velocity.y/PHYSICS_STEPS; + } + + // Update collision detection + if (physicObjects[i]->collider.enabled) + { + // Update collider bounds + physicObjects[i]->collider.bounds = TransformToRectangle(physicObjects[i]->transform); + + // Check collision with other colliders + for (int k = 0; k < physicObjectsCount; k++) { - if (colliders[j].type == COLLIDER_RECTANGLE) + if (physicObjects[k]->collider.enabled && i != k) { - if (CheckCollisionRecs(colliders[index].bounds, colliders[j].bounds)) + // Check if colliders are overlapped + if (CheckCollisionRecs(physicObjects[i]->collider.bounds, physicObjects[k]->collider.bounds)) { - collisionChecker = true; + // Resolve physic collision + // NOTE: collision resolve is generic for all directions and conditions (no axis separated cases behaviours) + // and it is separated in rigidbody attributes resolve (velocity changes by impulse) and position correction (position overlap) + + // 1. Calculate collision normal + // ------------------------------------------------------------------------------------------------------------------------------------- + + // Define collision ontact normal + Vector2 contactNormal = { 0.0f, 0.0f }; + + // Calculate direction vector from i to k + Vector2 direction; + direction.x = (physicObjects[k]->transform.position.x + physicObjects[k]->transform.scale.x/2) - (physicObjects[i]->transform.position.x + physicObjects[i]->transform.scale.x/2); + direction.y = (physicObjects[k]->transform.position.y + physicObjects[k]->transform.scale.y/2) - (physicObjects[i]->transform.position.y + physicObjects[i]->transform.scale.y/2); + + // Define overlapping and penetration attributes + Vector2 overlap; + float penetrationDepth = 0.0f; - if ((colliders[index].bounds.y + colliders[index].bounds.height <= colliders[j].bounds.y) == false) + // Calculate overlap on X axis + overlap.x = (physicObjects[i]->transform.scale.x + physicObjects[k]->transform.scale.x)/2 - abs(direction.x); + + // SAT test on X axis + if (overlap.x > 0.0f) { - rigidbodies[index].isContact = true; + // Calculate overlap on Y axis + overlap.y = (physicObjects[i]->transform.scale.y + physicObjects[k]->transform.scale.y)/2 - abs(direction.y); + + // SAT test on Y axis + if (overlap.y > 0.0f) + { + // Find out which axis is axis of least penetration + if (overlap.y > overlap.x) + { + // Point towards k knowing that direction points from i to k + if (direction.x < 0.0f) contactNormal = (Vector2){ -1.0f, 0.0f }; + else contactNormal = (Vector2){ 1.0f, 0.0f }; + + // Update penetration depth for position correction + penetrationDepth = overlap.x; + } + else + { + // Point towards k knowing that direction points from i to k + if (direction.y < 0.0f) contactNormal = (Vector2){ 0.0f, 1.0f }; + else contactNormal = (Vector2){ 0.0f, -1.0f }; + + // Update penetration depth for position correction + penetrationDepth = overlap.y; + } + } + } + + // Update rigidbody grounded state + if (physicObjects[i]->rigidbody.enabled) + { + if (contactNormal.y < 0.0f) physicObjects[i]->rigidbody.isGrounded = true; + } + + // 2. Calculate collision impulse + // ------------------------------------------------------------------------------------------------------------------------------------- + + // Calculate relative velocity + Vector2 relVelocity = { physicObjects[k]->rigidbody.velocity.x - physicObjects[i]->rigidbody.velocity.x, physicObjects[k]->rigidbody.velocity.y - physicObjects[i]->rigidbody.velocity.y }; + + // Calculate relative velocity in terms of the normal direction + float velAlongNormal = Vector2DotProduct(relVelocity, contactNormal); + + // Dot not resolve if velocities are separating + if (velAlongNormal <= 0.0f) + { + // Calculate minimum bounciness value from both objects + float e = fminf(physicObjects[i]->rigidbody.bounciness, physicObjects[k]->rigidbody.bounciness); + + // Calculate impulse scalar value + float j = -(1.0f + e) * velAlongNormal; + j /= 1.0f/physicObjects[i]->rigidbody.mass + 1.0f/physicObjects[k]->rigidbody.mass; + + // Calculate final impulse vector + Vector2 impulse = { j*contactNormal.x, j*contactNormal.y }; + + // Calculate collision mass ration + float massSum = physicObjects[i]->rigidbody.mass + physicObjects[k]->rigidbody.mass; + float ratio = 0.0f; + + // Apply impulse to current rigidbodies velocities if they are enabled + if (physicObjects[i]->rigidbody.enabled) + { + // Calculate inverted mass ration + ratio = physicObjects[i]->rigidbody.mass/massSum; + + // Apply impulse direction to velocity + physicObjects[i]->rigidbody.velocity.x -= impulse.x*ratio; + physicObjects[i]->rigidbody.velocity.y -= impulse.y*ratio; + } + + if (physicObjects[k]->rigidbody.enabled) + { + // Calculate inverted mass ration + ratio = physicObjects[k]->rigidbody.mass/massSum; + + // Apply impulse direction to velocity + physicObjects[k]->rigidbody.velocity.x += impulse.x*ratio; + physicObjects[k]->rigidbody.velocity.y += impulse.y*ratio; + } + + // 3. Correct colliders overlaping (transform position) + // --------------------------------------------------------------------------------------------------------------------------------- + + // Calculate transform position penetration correction + Vector2 posCorrection; + posCorrection.x = penetrationDepth/((1.0f/physicObjects[i]->rigidbody.mass) + (1.0f/physicObjects[k]->rigidbody.mass))*PHYSICS_ERRORPERCENT*contactNormal.x; + posCorrection.y = penetrationDepth/((1.0f/physicObjects[i]->rigidbody.mass) + (1.0f/physicObjects[k]->rigidbody.mass))*PHYSICS_ERRORPERCENT*contactNormal.y; + + // Fix transform positions + if (physicObjects[i]->rigidbody.enabled) + { + // Fix physic objects transform position + physicObjects[i]->transform.position.x -= 1.0f/physicObjects[i]->rigidbody.mass*posCorrection.x; + physicObjects[i]->transform.position.y += 1.0f/physicObjects[i]->rigidbody.mass*posCorrection.y; + + // Update collider bounds + physicObjects[i]->collider.bounds = TransformToRectangle(physicObjects[i]->transform); + + if (physicObjects[k]->rigidbody.enabled) + { + // Fix physic objects transform position + physicObjects[k]->transform.position.x += 1.0f/physicObjects[k]->rigidbody.mass*posCorrection.x; + physicObjects[k]->transform.position.y -= 1.0f/physicObjects[k]->rigidbody.mass*posCorrection.y; + + // Update collider bounds + physicObjects[k]->collider.bounds = TransformToRectangle(physicObjects[k]->transform); + } + } } - } - } - else - { - if (CheckCollisionCircleRec((Vector2){colliders[j].bounds.x, colliders[j].bounds.y}, colliders[j].radius, colliders[index].bounds)) - { - collisionChecker = true; - } - } - } - else - { - if (colliders[j].type == COLLIDER_RECTANGLE) - { - if (CheckCollisionCircleRec((Vector2){colliders[index].bounds.x, colliders[index].bounds.y}, colliders[index].radius, colliders[j].bounds)) - { - collisionChecker = true; - } - } - else - { - if (CheckCollisionCircles((Vector2){colliders[j].bounds.x, colliders[j].bounds.y}, colliders[j].radius, (Vector2){colliders[index].bounds.x, colliders[index].bounds.y}, colliders[index].radius)) - { - collisionChecker = true; } } } } } } - - // Update grounded rigidbody state - rigidbodies[index].isGrounded = collisionChecker; - - // Set grounded state if needed (fix overlap and set y velocity) - if (collisionChecker && rigidbodies[index].velocity.y != 0) - { - position->y += rigidbodies[index].velocity.y; - rigidbodies[index].velocity.y = -rigidbodies[index].velocity.y * rigidbodies[index].bounciness; - } - - if (rigidbodies[index].isContact) - { - position->x -= rigidbodies[index].velocity.x; - rigidbodies[index].velocity.x = rigidbodies[index].velocity.x; - } } } -void SetRigidbodyEnabled(int index, bool state) -{ - rigidbodies[index].enabled = state; -} - -void SetRigidbodyVelocity(int index, Vector2 velocity) -{ - rigidbodies[index].velocity.x = velocity.x; - rigidbodies[index].velocity.y = velocity.y; -} - -void SetRigidbodyAcceleration(int index, Vector2 acceleration) +// Unitialize all physic objects and empty the objects pool +void ClosePhysics() { - rigidbodies[index].acceleration.x = acceleration.x; - rigidbodies[index].acceleration.y = acceleration.y; + // Free all dynamic memory allocations + for (int i = 0; i < physicObjectsCount; i++) free(physicObjects[i]); + + // Reset enabled physic objects count + physicObjectsCount = 0; } -void AddRigidbodyForce(int index, Vector2 force) +// Create a new physic object dinamically, initialize it and add to pool +PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale) { - rigidbodies[index].acceleration.x = force.x / rigidbodies[index].mass; - rigidbodies[index].acceleration.y = force.y / rigidbodies[index].mass; + // Allocate dynamic memory + PhysicObject *obj = (PhysicObject *)malloc(sizeof(PhysicObject)); + + // Initialize physic object values with generic values + obj->id = physicObjectsCount; + obj->enabled = true; + + obj->transform = (Transform){ (Vector2){ position.x - scale.x/2, position.y - scale.y/2 }, rotation, scale }; + + obj->rigidbody.enabled = false; + obj->rigidbody.mass = 1.0f; + obj->rigidbody.acceleration = (Vector2){ 0.0f, 0.0f }; + obj->rigidbody.velocity = (Vector2){ 0.0f, 0.0f }; + obj->rigidbody.applyGravity = false; + obj->rigidbody.isGrounded = false; + obj->rigidbody.friction = 0.0f; + obj->rigidbody.bounciness = 0.0f; + + obj->collider.enabled = false; + obj->collider.type = COLLIDER_RECTANGLE; + obj->collider.bounds = TransformToRectangle(obj->transform); + obj->collider.radius = 0.0f; + + // Add new physic object to the pointers array + physicObjects[physicObjectsCount] = obj; + + // Increase enabled physic objects count + physicObjectsCount++; + + return obj; } -void AddForceAtPosition(Vector2 position, float intensity, float radius) +// Destroy a specific physic object and take it out of the list +void DestroyPhysicObject(PhysicObject *pObj) { - for(int i = 0; i < maxElements; i++) + // Free dynamic memory allocation + free(physicObjects[pObj->id]); + + // Remove *obj from the pointers array + for (int i = pObj->id; i < physicObjectsCount; i++) { - if(rigidbodies[i].enabled) + // Resort all the following pointers of the array + if ((i + 1) < physicObjectsCount) { - // Get position from its collider - Vector2 pos = {colliders[i].bounds.x, colliders[i].bounds.y}; - - // Get distance between rigidbody position and target position - float distance = Vector2Distance(position, pos); - - if(distance <= radius) - { - // Calculate force based on direction - Vector2 force = {colliders[i].bounds.x - position.x, colliders[i].bounds.y - position.y}; - - // Normalize the direction vector - Vector2Normalize(&force); - - // Invert y value - force.y *= -1; - - // Apply intensity and distance - force = (Vector2){force.x * intensity / distance, force.y * intensity / distance}; - - // Add calculated force to the rigidbodies - AddRigidbodyForce(i, force); - } + physicObjects[i] = physicObjects[i + 1]; + physicObjects[i]->id = physicObjects[i + 1]->id; } + else free(physicObjects[i]); } + + // Decrease enabled physic objects count + physicObjectsCount--; } -void SetColliderEnabled(int index, bool state) -{ - colliders[index].enabled = state; -} - -Collider GetCollider(int index) +// Convert Transform data type to Rectangle (position and scale) +Rectangle TransformToRectangle(Transform transform) { - return colliders[index]; + return (Rectangle){transform.position.x, transform.position.y, transform.scale.x, transform.scale.y}; } -Rigidbody GetRigidbody(int index) +// Draw physic object information at screen position +void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize) { - return rigidbodies[index]; + // Draw physic object ID + DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK); + + // Draw physic object transform values + DrawText(FormatText("\nTRANSFORM\nPosition: %f, %f\nRotation: %f\nScale: %f, %f", pObj->transform.position.x, pObj->transform.position.y, pObj->transform.rotation, pObj->transform.scale.x, pObj->transform.scale.y), position.x, position.y, fontSize, BLACK); + + // Draw physic object rigidbody values + DrawText(FormatText("\n\n\n\n\n\nRIGIDBODY\nEnabled: %i\nMass: %f\nAcceleration: %f, %f\nVelocity: %f, %f\nApplyGravity: %i\nIsGrounded: %i\nFriction: %f\nBounciness: %f", pObj->rigidbody.enabled, pObj->rigidbody.mass, pObj->rigidbody.acceleration.x, pObj->rigidbody.acceleration.y, + pObj->rigidbody.velocity.x, pObj->rigidbody.velocity.y, pObj->rigidbody.applyGravity, pObj->rigidbody.isGrounded, pObj->rigidbody.friction, pObj->rigidbody.bounciness), position.x, position.y, fontSize, BLACK); + + DrawText(FormatText("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCOLLIDER\nEnabled: %i\nBounds: %i, %i, %i, %i\nRadius: %i", pObj->collider.enabled, pObj->collider.bounds.x, pObj->collider.bounds.y, pObj->collider.bounds.width, pObj->collider.bounds.height, pObj->collider.radius), position.x, position.y, fontSize, BLACK); } //---------------------------------------------------------------------------------- -// Module specific Functions Definitions +// Module specific Functions Definition //---------------------------------------------------------------------------------- -static float Vector2Length(Vector2 vector) -{ - return sqrt((vector.x * vector.x) + (vector.y * vector.y)); -} -static float Vector2Distance(Vector2 a, Vector2 b) +// Returns the dot product of two Vector2 +static float Vector2DotProduct(Vector2 v1, Vector2 v2) { - Vector2 vector = {b.x - a.x, b.y - a.y}; - return sqrt((vector.x * vector.x) + (vector.y * vector.y)); -} + float result; -static void Vector2Normalize(Vector2 *vector) -{ - float length = Vector2Length(*vector); - - if (length != 0.0f) - { - vector->x /= length; - vector->y /= length; - } - else - { - vector->x = 0.0f; - vector->y = 0.0f; - } + result = v1.x*v2.x + v1.y*v2.y; + + return result; } diff --git a/src/physac.h b/src/physac.h index 9e1b0b88..b948e4ce 100644 --- a/src/physac.h +++ b/src/physac.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* [physac] raylib physics engine module - Basic functions to apply physics to 2D objects +* [physac] raylib physics module - Basic functions to apply physics to 2D objects * * Copyright (c) 2015 Victor Fisac and Ramon Santamaria * @@ -31,62 +31,64 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition +// NOTE: Below types are required for PHYSAC_STANDALONE usage //---------------------------------------------------------------------------------- -// Collider types + +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; + typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; -// Transform struct typedef struct Transform { Vector2 position; float rotation; Vector2 scale; } Transform; -// Rigidbody struct typedef struct Rigidbody { - bool enabled; + bool enabled; // Acts as kinematic state (collisions are calculated anyway) float mass; Vector2 acceleration; Vector2 velocity; - bool isGrounded; - bool isContact; // Avoid freeze player when touching floor bool applyGravity; - float friction; // 0.0f to 1.0f - float bounciness; // 0.0f to 1.0f + bool isGrounded; + float friction; // Normalized value + float bounciness; // Normalized value } Rigidbody; -// Collider struct typedef struct Collider { bool enabled; ColliderType type; - Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE - int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE + Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE + int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE } Collider; +typedef struct PhysicObject { + unsigned int id; + Transform transform; + Rigidbody rigidbody; + Collider collider; + bool enabled; +} PhysicObject; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif //---------------------------------------------------------------------------------- -// Module Functions Declarations +// Module Functions Declaration //---------------------------------------------------------------------------------- -void InitPhysics(int maxPhysicElements); // Initialize all internal physics values -void UnloadPhysics(); // Unload physic elements arrays - -void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot -void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot - -void ApplyPhysics(int index, Vector2 *position); // Apply physics to internal rigidbody, physics calculations are applied to position pointer parameter -void SetRigidbodyEnabled(int index, bool state); // Set enabled state to a defined rigidbody -void SetRigidbodyVelocity(int index, Vector2 velocity); // Set velocity of rigidbody (without considering of mass value) -void SetRigidbodyAcceleration(int index, Vector2 acceleration); // Set acceleration of rigidbody (without considering of mass value) -void AddRigidbodyForce(int index, Vector2 force); // Set rigidbody force (considering mass value) -void AddForceAtPosition(Vector2 position, float intensity, float radius); // Add a force to all enabled rigidbodies at a position +void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection +void ClosePhysics(); // Unitialize all physic objects and empty the objects pool -void SetColliderEnabled(int index, bool state); // Set enabled state to a defined collider +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 -Rigidbody GetRigidbody(int index); // Returns the internal rigidbody data defined by index parameter -Collider GetCollider(int index); // Returns the internal collider data defined by index parameter +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 #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index c598ec30..b9cf05a4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -465,37 +465,40 @@ typedef struct { // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; -// Collider types typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; -// Transform struct typedef struct Transform { Vector2 position; float rotation; Vector2 scale; } Transform; -// Rigidbody struct typedef struct Rigidbody { - bool enabled; + bool enabled; // Acts as kinematic state (collisions are calculated anyway) float mass; Vector2 acceleration; Vector2 velocity; - bool isGrounded; - bool isContact; // Avoid freeze player when touching floor bool applyGravity; - float friction; // 0.0f to 1.0f - float bounciness; // 0.0f to 1.0f + bool isGrounded; + float friction; // Normalized value + float bounciness; // Normalized value } Rigidbody; -// Collider struct typedef struct Collider { bool enabled; ColliderType type; - Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE - int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE + Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE + int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE } Collider; +typedef struct PhysicObject { + unsigned int id; + Transform transform; + Rigidbody rigidbody; + Collider collider; + bool enabled; +} PhysicObject; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -800,25 +803,17 @@ void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textur void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) //---------------------------------------------------------------------------------- -// Physics System Functions (engine-module: physac) +// Physics System Functions (Module: physac) //---------------------------------------------------------------------------------- -void InitPhysics(int maxPhysicElements); // Initialize all internal physics values -void UnloadPhysics(); // Unload physic elements arrays - -void AddRigidbody(int index, Rigidbody rigidbody); // Initialize a new rigidbody with parameters to internal index slot -void AddCollider(int index, Collider collider); // Initialize a new Collider with parameters to internal index slot - -void ApplyPhysics(int index, Vector2 *position); // Apply physics to internal rigidbody, physics calculations are applied to position pointer parameter -void SetRigidbodyEnabled(int index, bool state); // Set enabled state to a defined rigidbody -void SetRigidbodyVelocity(int index, Vector2 velocity); // Set velocity of rigidbody (without considering of mass value) -void SetRigidbodyAcceleration(int index, Vector2 acceleration); // Set acceleration of rigidbody (without considering of mass value) -void AddRigidbodyForce(int index, Vector2 force); // Set rigidbody force (considering mass value) -void AddForceAtPosition(Vector2 position, float intensity, float radius); // Add a force to all enabled rigidbodies at a position +void InitPhysics(); // Initializes pointers array (just pointers, fixed size) +void UpdatePhysics(); // Update physic objects, calculating physic behaviours and collisions detection +void ClosePhysics(); // Unitialize all physic objects and empty the objects pool -void SetColliderEnabled(int index, bool state); // Set enabled state to a defined collider +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 -Rigidbody GetRigidbody(int index); // Returns the internal rigidbody data defined by index parameter -Collider GetCollider(int index); // Returns the internal collider data defined by index parameter +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 //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) -- cgit v1.2.3 From c9d22c7a14a84b24a94f876c9e438c621b4bf420 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 6 Mar 2016 02:05:16 +0100 Subject: Redesign to use Material type -IN PROGRESS- Requires Shader access functions review --- src/models.c | 18 +---- src/raylib.h | 40 ++++------ src/rlgl.c | 240 +++++++++++++---------------------------------------------- src/rlgl.h | 24 ++++-- 4 files changed, 89 insertions(+), 233 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index ee5e57c7..a1590424 100644 --- a/src/models.c +++ b/src/models.c @@ -551,10 +551,7 @@ Model LoadModel(const char *fileName) // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - if (mesh.vertexCount == 0) - { - TraceLog(WARNING, "Model could not be loaded"); - } + if (mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); else { // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() @@ -627,17 +624,8 @@ void UnloadModel(Model model) // Link a texture to a model void SetModelTexture(Model *model, Texture2D texture) { - if (texture.id <= 0) - { - // Use default white texture (use mesh color) - model->texture.id = whiteTexture; // OpenGL 1.1 - model->shader.texDiffuseId = whiteTexture; // OpenGL 3.3 / ES 2.0 - } - else - { - model->texture = texture; - model->shader.texDiffuseId = texture.id; - } + if (texture.id <= 0) model->material.texDiffuse.id = whiteTexture; // Use default white texture + else model->material.texDiffuse = texture; } static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) diff --git a/src/raylib.h b/src/raylib.h index 83e41ac7..f448487e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -347,12 +347,7 @@ typedef struct Mesh { // Shader type (generic shader) typedef struct Shader { - unsigned int id; // Shader program id - - // TODO: This should be Texture2D objects - unsigned int texDiffuseId; // Diffuse texture id - unsigned int texNormalId; // Normal texture id - unsigned int texSpecularId; // Specular texture id + unsigned int id; // Shader program id // Variable attributes int vertexLoc; // Vertex attribute location point (vertex shader) @@ -370,20 +365,19 @@ typedef struct Shader { } Shader; // Material type -// TODO: Redesign material-shaders-textures system 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 + float normalDepth; // Normal map depth } Material; // 3d Model type @@ -391,9 +385,7 @@ typedef struct Material { typedef struct Model { Mesh mesh; Matrix transform; - Texture2D texture; // Only for OpenGL 1.1, on newer versions this should be in the shader - Shader shader; - //Material material; + Material material; } Model; // Ray type (useful for raycast) @@ -774,7 +766,7 @@ void SetModelTexture(Model *model, Texture2D texture); void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) -void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // 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); // Draw a model wires (with texture if set) with extended parameters void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture @@ -806,10 +798,10 @@ int GetShaderLocation(Shader shader, const char *uniformName); void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment -void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment -void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment -void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment +//void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment +//void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment +//void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment +//void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) diff --git a/src/rlgl.c b/src/rlgl.c index e1949274..d9761732 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1421,7 +1421,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro #if defined(GRAPHICS_API_OPENGL_11) glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, model.texture.id); + glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array @@ -1452,7 +1452,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(model.shader.id); + glUseProgram(model.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() @@ -1476,28 +1476,30 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro Matrix matMVP = MatrixMultiply(matModelView, matProjection); // Transform to screen-space coordinates // Send combined model-view-projection matrix to shader - glUniformMatrix4fv(model.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniformMatrix4fv(model.material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); // Apply color tinting to model // NOTE: Just update one uniform on fragment shader float vColor[4] = { (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255 }; - glUniform4fv(model.shader.tintColorLoc, 1, vColor); + glUniform4fv(model.material.shader.tintColorLoc, 1, vColor); // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, model.shader.texDiffuseId); - glUniform1i(model.shader.mapDiffuseLoc, 0); - - if (model.shader.texNormalId != 0) + glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); + glUniform1i(model.material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 + + if (model.material.texNormal.id != 0) { glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, model.shader.texNormalId); + glBindTexture(GL_TEXTURE_2D, model.material.texNormal.id); + glUniform1i(model.material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 } - if (model.shader.texSpecularId != 0) + if (model.material.texSpecular.id != 0) { glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, model.shader.texSpecularId); + glBindTexture(GL_TEXTURE_2D, model.material.texSpecular.id); + glUniform1i(model.material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 } if (vaoSupported) @@ -1508,19 +1510,19 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro { // Bind model VBOs data glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[0]); - glVertexAttribPointer(model.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.vertexLoc); + glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.vertexLoc); glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[1]); - glVertexAttribPointer(model.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.texcoordLoc); + glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.texcoordLoc); // Add normals support - if (model.shader.normalLoc != -1) + if (model.material.shader.normalLoc != -1) { glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]); - glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.normalLoc); + glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.normalLoc); } } @@ -1531,13 +1533,13 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro //glDisableVertexAttribArray(model.shader.texcoordLoc); //if (model.shader.normalLoc != -1) glDisableVertexAttribArray(model.shader.normalLoc); - if (model.shader.texNormalId != 0) + if (model.material.texNormal.id != 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); } - if (model.shader.texSpecularId != 0) + if (model.material.texSpecular.id != 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); @@ -1907,22 +1909,29 @@ Model rlglLoadModel(Mesh mesh) Model model; model.mesh = mesh; - model.transform = MatrixIdentity(); model.mesh.vaoId = 0; // Vertex Array Object - model.mesh.vboId[0] = 0; // Vertex position VBO - model.mesh.vboId[1] = 0; // Texcoords VBO - model.mesh.vboId[2] = 0; // Normals VBO + model.mesh.vboId[0] = 0; // Vertex positions VBO + model.mesh.vboId[1] = 0; // Vertex texcoords VBO + model.mesh.vboId[2] = 0; // Vertex normals VBO + + model.transform = MatrixIdentity(); #if defined(GRAPHICS_API_OPENGL_11) - model.texture.id = 0; // No texture required - model.shader.id = 0; // No shader used + model.material.texDiffuse.id = 0; // No texture required + model.material.shader.id = 0; // No shader used #elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model.texture.id = whiteTexture; // Default whiteTexture - model.texture.width = 1; // Default whiteTexture width - model.texture.height = 1; // Default whiteTexture height - model.texture.format = UNCOMPRESSED_R8G8B8A8; // Default whiteTexture format - model.shader = simpleShader; // Default model shader + model.material.shader = simpleShader; // Default model shader + + model.material.texDiffuse.id = whiteTexture; // Default whiteTexture + model.material.texDiffuse.width = 1; // Default whiteTexture width + model.material.texDiffuse.height = 1; // Default whiteTexture height + model.material.texDiffuse.format = UNCOMPRESSED_R8G8B8A8; // Default whiteTexture format + + model.material.texNormal.id = 0; // By default, no normal texture + model.material.texSpecular.id = 0; // By default, no specular texture + + // TODO: Fill default material properties (color, glossiness...) GLuint vaoModel = 0; // Vertex Array Objects (VAO) GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO) @@ -1940,20 +1949,20 @@ Model rlglLoadModel(Mesh mesh) // Enable vertex attributes: position glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW); - glVertexAttribPointer(model.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.vertexLoc); + glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.vertexLoc); // Enable vertex attributes: texcoords glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW); - glVertexAttribPointer(model.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.texcoordLoc); + glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.texcoordLoc); // Enable vertex attributes: normals glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW); - glVertexAttribPointer(model.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.shader.normalLoc); + glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(model.material.shader.normalLoc); model.mesh.vboId[0] = vertexBuffer[0]; // Vertex position VBO model.mesh.vboId[1] = vertexBuffer[1]; // Texcoords VBO @@ -2153,11 +2162,6 @@ Shader LoadShader(char *vsFileName, char *fsFileName) if (shader.id != 0) { TraceLog(INFO, "[SHDR ID %i] Custom shader loaded successfully", shader.id); - - // Set shader textures ids (all 0 by default) - shader.texDiffuseId = 0; - shader.texNormalId = 0; - shader.texSpecularId = 0; // Get handles to GLSL input attibute locations //------------------------------------------------------------------- @@ -2314,28 +2318,7 @@ void SetCustomShader(Shader shader) if (currentShader.id != shader.id) { rlglDraw(); - currentShader = shader; -/* - if (vaoSupported) glBindVertexArray(vaoQuads); - - // Enable vertex attributes: position - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); - glEnableVertexAttribArray(currentShader.vertexLoc); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: texcoords - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); - glEnableVertexAttribArray(currentShader.texcoordLoc); - glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: colors - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); - glEnableVertexAttribArray(currentShader.colorLoc); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO -*/ } #endif } @@ -2358,7 +2341,7 @@ void SetPostproShader(Shader shader) texture.width = screenWidth; texture.height = screenHeight; - SetShaderMapDiffuse(&postproQuad.shader, texture); + postproQuad.material.texDiffuse = texture; //TraceLog(DEBUG, "Postproquad texture id: %i", postproQuad.texture.id); //TraceLog(DEBUG, "Postproquad shader diffuse map id: %i", postproQuad.shader.texDiffuseId); @@ -2386,7 +2369,7 @@ void SetDefaultShader(void) void SetModelShader(Model *model, Shader shader) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model->shader = shader; + model->material.shader = shader; if (vaoSupported) glBindVertexArray(model->mesh.vaoId); @@ -2406,9 +2389,7 @@ void SetModelShader(Model *model, Shader shader) glVertexAttribPointer(shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); if (vaoSupported) glBindVertexArray(0); // Unbind VAO - - // NOTE: If SetModelTexture() is called previously, texture is not assigned to new shader - if (model->texture.id > 0) model->shader.texDiffuseId = model->texture.id; + #elif (GRAPHICS_API_OPENGL_11) TraceLog(WARNING, "Shaders not supported on OpenGL 1.1"); #endif @@ -2480,104 +2461,6 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) #endif } -// Default diffuse shader map texture assignment -void SetShaderMapDiffuse(Shader *shader, Texture2D texture) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader->texDiffuseId = texture.id; - - glUseProgram(shader->id); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shader->texDiffuseId); - - glUniform1i(shader->mapDiffuseLoc, 0); // Texture fits in active texture unit 0 - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glUseProgram(0); -#endif -} - -// Normal map texture shader assignment -void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader->mapNormalLoc = glGetUniformLocation(shader->id, uniformName); - - if (shader->mapNormalLoc == -1) TraceLog(WARNING, "[SHDR ID %i] Shader location for %s could not be found", shader->id, uniformName); - else - { - shader->texNormalId = texture.id; - - glUseProgram(shader->id); - - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, shader->texNormalId); - - glUniform1i(shader->mapNormalLoc, 1); // Texture fits in active texture unit 1 - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glUseProgram(0); - } -#endif -} - -// Specular map texture shader assignment -void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader->mapSpecularLoc = glGetUniformLocation(shader->id, uniformName); - - if (shader->mapSpecularLoc == -1) TraceLog(WARNING, "[SHDR ID %i] Shader location for %s could not be found", shader->id, uniformName); - else - { - shader->texSpecularId = texture.id; - - glUseProgram(shader->id); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, shader->texSpecularId); - - glUniform1i(shader->mapSpecularLoc, 2); // Texture fits in active texture unit 2 - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glUseProgram(0); - } -#endif -} - -// Generic shader maps assignment -// TODO: Trying to find a generic shader to allow any kind of map -// NOTE: mapLocation should be retrieved by user with GetShaderLocation() -// ISSUE: mapTextureId: Shader should contain a reference to map texture and corresponding textureUnit, -// so it can be automatically checked and used in rlglDrawModel() -void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit) -{ -/* -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (mapLocation == -1) TraceLog(WARNING, "[SHDR ID %i] Map location could not be found", shader->id); - else - { - shader->mapTextureId = texture.id; - - glUseProgram(shader->id); - - glActiveTexture(GL_TEXTURE0 + textureUnit); - glBindTexture(GL_TEXTURE_2D, shader->mapTextureId); - - glUniform1i(mapLocation, textureUnit); // Texture fits in active textureUnit - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glUseProgram(0); - } -#endif -*/ -} - // Set blending mode (alpha, additive, multiplied) // NOTE: Only 3 blending modes predefined void SetBlendMode(int mode) @@ -2652,15 +2535,11 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in } // Load Shader (Vertex and Fragment) -// NOTE: This shader program is used only for batch buffers (lines, triangles, quads) +// NOTE: This shader program is used for batch buffers (lines, triangles, quads) static Shader LoadDefaultShader(void) { Shader shader; - // NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2 - // NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+ - // Just defined #version 330 despite shader is #version 110 - // Vertex shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) char vShaderStr[] = "#version 330 \n" @@ -2668,7 +2547,7 @@ static Shader LoadDefaultShader(void) "in vec2 vertexTexCoord; \n" "in vec4 vertexColor; \n" "out vec2 fragTexCoord; \n" - "out vec4 fragTintColor; \n" + "out vec4 fragTintColor; \n" #elif defined(GRAPHICS_API_OPENGL_ES2) char vShaderStr[] = "#version 100 \n" "attribute vec3 vertexPosition; \n" @@ -2677,7 +2556,7 @@ static Shader LoadDefaultShader(void) "varying vec2 fragTexCoord; \n" "varying vec4 fragTintColor; \n" #endif - "uniform mat4 mvpMatrix; \n" + "uniform mat4 mvpMatrix; \n" "void main() \n" "{ \n" " fragTexCoord = vertexTexCoord; \n" @@ -2689,7 +2568,7 @@ static Shader LoadDefaultShader(void) #if defined(GRAPHICS_API_OPENGL_33) char fShaderStr[] = "#version 330 \n" "in vec2 fragTexCoord; \n" - "in vec4 fragTintColor; \n" + "in vec4 fragTintColor; \n" #elif defined(GRAPHICS_API_OPENGL_ES2) char fShaderStr[] = "#version 100 \n" "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) @@ -2724,10 +2603,6 @@ static Shader LoadDefaultShader(void) shader.mapDiffuseLoc = glGetUniformLocation(shader.id, "texture0"); shader.mapNormalLoc = -1; // It can be set later shader.mapSpecularLoc = -1; // It can be set later - - shader.texDiffuseId = whiteTexture; // Default white texture - shader.texNormalId = 0; - shader.texSpecularId = 0; //-------------------------------------------------------------------- return shader; @@ -2739,10 +2614,6 @@ static Shader LoadSimpleShader(void) { Shader shader; - // NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2 - // NOTE: Detected an error on ATI cards if defined #version 110 while OpenGL 3.3+ - // Just defined #version 330 despite shader is #version 110 - // Vertex shader directly defined, no external file required #if defined(GRAPHICS_API_OPENGL_33) char vShaderStr[] = "#version 330 \n" @@ -2802,10 +2673,6 @@ static Shader LoadSimpleShader(void) shader.mapDiffuseLoc = glGetUniformLocation(shader.id, "texture0"); shader.mapNormalLoc = -1; // It can be set later shader.mapSpecularLoc = -1; // It can be set later - - shader.texDiffuseId = whiteTexture; // Default white texture - shader.texNormalId = 0; - shader.texSpecularId = 0; //-------------------------------------------------------------------- return shader; @@ -2878,7 +2745,6 @@ static void InitializeBuffers(void) quads.indices = (unsigned short *)malloc(sizeof(short)*6*MAX_QUADS_BATCH); // 6 int by quad (indices) #endif - for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0f; for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0f; for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0; diff --git a/src/rlgl.h b/src/rlgl.h index 9e0aaaaa..69640feb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -154,11 +154,6 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; typedef struct Shader { unsigned int id; // Shader program id - // TODO: This should be Texture2D objects - unsigned int texDiffuseId; // Diffuse texture id - unsigned int texNormalId; // Normal texture id - unsigned int texSpecularId; // Specular texture id - // Variable attributes int vertexLoc; // Vertex attribute location point (vertex shader) int texcoordLoc; // Texcoord attribute location point (vertex shader) @@ -184,12 +179,27 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; int format; // Data format (TextureFormat) } Texture2D; + // Material type + typedef struct Material { + Shader shader; + + Texture2D texDiffuse; // Diffuse texture + Texture2D texNormal; // Normal texture + Texture2D texSpecular; // Specular texture + + Color colDiffuse; + Color colAmbient; + Color colSpecular; + + float glossiness; + float normalDepth; + } Material; + // 3d Model type typedef struct Model { Mesh mesh; Matrix transform; - Texture2D texture; - Shader shader; + Material material; } Model; // Color blending modes (pre-defined) -- cgit v1.2.3 From d0e7195a16c50b23fd82e7ca7869cc07773ddba2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 6 Mar 2016 19:28:58 +0100 Subject: Added new functions to draw text on image --- src/raylib.h | 4 +++- src/textures.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index f448487e..527d0cb9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -697,9 +697,11 @@ Image ImageCopy(Image image); void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) -void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) +void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image +void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) +void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, int fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) void ImageFlipVertical(Image *image); // Flip image vertically void ImageFlipHorizontal(Image *image); // Flip image horizontally void ImageColorTint(Image *image, Color color); // Modify image color: tint diff --git a/src/textures.c b/src/textures.c index cb3113dc..e649df57 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1090,6 +1090,25 @@ Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, return imText; } +// Draw text (default font) within an image (destination) +void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) +{ + ImageDrawTextEx(dst, position, GetDefaultFont(), text, fontSize, 0, color); +} + +// Draw text (custom sprite font) within an image (destination) +void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, int fontSize, int spacing, Color color) +{ + Image imText = ImageTextEx(font, text, fontSize, spacing, color); + + Rectangle srcRec = { 0, 0, imText.width, imText.height }; + Rectangle dstRec = { (int)position.x, (int)position.y, imText.width, imText.height }; + + ImageDraw(dst, imText, srcRec, dstRec); + + UnloadImage(imText); +} + // Flip image vertically void ImageFlipVertical(Image *image) { -- cgit v1.2.3 From 0caf925d5dc32e03852e3bf3d5fc5e31bc065f03 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Wed, 16 Mar 2016 12:48:30 +0100 Subject: Updated headers --- src/physac.h | 4 ++-- src/raylib.h | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/physac.h b/src/physac.h index 852a7e4a..c70dbbe2 100644 --- a/src/physac.h +++ b/src/physac.h @@ -62,8 +62,8 @@ typedef struct Rigidbody { typedef struct Collider { bool enabled; ColliderType type; - Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE - int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE + Rectangle bounds; // Used for COLLIDER_RECTANGLE + int radius; // Used for COLLIDER_CIRCLE } Collider; typedef struct PhysicObject { diff --git a/src/raylib.h b/src/raylib.h index 527d0cb9..ddfccea7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -466,7 +466,7 @@ typedef struct { // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; -typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE, COLLIDER_CAPSULE } ColliderType; +typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType; typedef struct Transform { Vector2 position; @@ -482,14 +482,14 @@ typedef struct Rigidbody { bool applyGravity; bool isGrounded; float friction; // Normalized value - float bounciness; // Normalized value + float bounciness; } Rigidbody; typedef struct Collider { bool enabled; ColliderType type; - Rectangle bounds; // Used for COLLIDER_RECTANGLE and COLLIDER_CAPSULE - int radius; // Used for COLLIDER_CIRCLE and COLLIDER_CAPSULE + Rectangle bounds; // Used for COLLIDER_RECTANGLE + int radius; // Used for COLLIDER_CIRCLE } Collider; typedef struct PhysicObject { @@ -810,13 +810,16 @@ void SetBlendMode(int mode); // Set blend //---------------------------------------------------------------------------------- // Physics System Functions (Module: physac) //---------------------------------------------------------------------------------- -void InitPhysics(); // Initializes pointers array (just pointers, fixed size) +void InitPhysics(Vector2 gravity); // Initializes pointers array (just pointers, fixed size) 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 +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 -- cgit v1.2.3 From db4585b3e23cd3c5aa87da21aedc36fd8be21739 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 16 Mar 2016 17:52:09 +0100 Subject: Improved gamepad support Now it works ok also in RaspberryPi --- src/core.c | 46 ++++++++++++++-------------------------------- src/raylib.h | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 34 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 6b2321c2..5bb59faa 100644 --- a/src/core.c +++ b/src/core.c @@ -127,6 +127,7 @@ #define MOUSE_SENSITIVITY 0.8f #define MAX_GAMEPAD_BUTTONS 11 + #define MAX_GAMEPAD_AXIS 5 #endif //---------------------------------------------------------------------------------- @@ -168,8 +169,7 @@ static bool gamepadReady = false; // Flag to know if gamepad is re pthread_t gamepadThreadId; // Gamepad reading thread id int gamepadButtons[MAX_GAMEPAD_BUTTONS]; -int gamepadAxisX = 0; -int gamepadAxisY = 0; +float gamepadAxisValues[MAX_GAMEPAD_AXIS]; #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -1177,30 +1177,22 @@ bool IsGamepadAvailable(int gamepad) } // Return axis movement vector for a gamepad -Vector2 GetGamepadMovement(int gamepad) +float GetGamepadAxisMovement(int gamepad, int axis) { - Vector2 vec = { 0, 0 }; - - const float *axes; - int axisCount = 0; + float value = 0; #if defined(PLATFORM_RPI) - // TODO: Get gamepad axis information - // Use gamepadAxisX, gamepadAxisY + if (axis < MAX_GAMEPAD_AXIS) value = gamepadAxisValues[axis]; #else + const float *axes; + int axisCount = 0; + axes = glfwGetJoystickAxes(gamepad, &axisCount); -#endif - if (axisCount >= 2) - { - vec.x = axes[0]; // Left joystick X - vec.y = axes[1]; // Left joystick Y - - //vec.x = axes[2]; // Right joystick X - //vec.x = axes[3]; // Right joystick Y - } + if (axis < axisCount) value = axes[axis]; +#endif - return vec; + return value; } // Detect if a gamepad button has been pressed once @@ -2484,10 +2476,6 @@ static void *GamepadThread(void *arg) unsigned char number; // event axis/button number }; - // These values are sensible on Logitech Dual Action Rumble and Xbox360 controller - const int joystickAxisX = 0; - const int joystickAxisY = 1; - // Read gamepad event struct js_event gamepadEvent; @@ -2512,17 +2500,11 @@ static void *GamepadThread(void *arg) { TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); - if (gamepadEvent.number == joystickAxisX) gamepadAxisX = (int)gamepadEvent.value; - if (gamepadEvent.number == joystickAxisY) gamepadAxisY = (int)gamepadEvent.value; - /* - switch (gamepadEvent.number) + if (gamepadEvent.number < MAX_GAMEPAD_AXIS) { - case 0: // 1st Axis X - case 1: // 1st Axis Y - case 2: // 2st Axis X - case 3: // 2st Axis Y + // NOTE: Scaling of gamepadEvent.value to get values between -1..1 + gamepadAxisValues[gamepadEvent.number] = (float)gamepadEvent.value/32768; } - */ } } } diff --git a/src/raylib.h b/src/raylib.h index ddfccea7..d891467e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -190,7 +190,35 @@ #define GAMEPAD_BUTTON_SELECT 9 #define GAMEPAD_BUTTON_START 10 -// TODO: Review Xbox360 USB Controller Buttons +// Xbox360 USB Controller Buttons +#define GAMEPAD_XBOX_BUTTON_A 0 +#define GAMEPAD_XBOX_BUTTON_B 1 +#define GAMEPAD_XBOX_BUTTON_X 2 +#define GAMEPAD_XBOX_BUTTON_Y 3 +#define GAMEPAD_XBOX_BUTTON_LB 4 +#define GAMEPAD_XBOX_BUTTON_RB 5 +#define GAMEPAD_XBOX_BUTTON_SELECT 6 +#define GAMEPAD_XBOX_BUTTON_START 7 + +#if defined(PLATFORM_RPI) + #define GAMEPAD_XBOX_AXIS_DPAD_X 32 + #define GAMEPAD_XBOX_AXIS_DPAD_Y 64 + #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 + #define GAMEPAD_XBOX_AXIS_LT 2 + #define GAMEPAD_XBOX_AXIS_RT 5 +#else + #define GAMEPAD_XBOX_BUTTON_UP 10 + #define GAMEPAD_XBOX_BUTTON_DOWN 12 + #define GAMEPAD_XBOX_BUTTON_LEFT 13 + #define GAMEPAD_XBOX_BUTTON_RIGHT 11 + #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 + #define GAMEPAD_XBOX_AXIS_LT_RT 2 +#endif + +#define GAMEPAD_XBOX_AXIS_LEFT_X 0 +#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // Android Physic Buttons #define ANDROID_BACK 4 @@ -592,7 +620,7 @@ void DisableCursor(void); // Disables cursor bool IsCursorHidden(void); // Returns true if cursor is not visible bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available -Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad +float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once -- cgit v1.2.3 From 49df957058b2f602c7e6873fec0007fcd7a4dc4c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 17 Mar 2016 12:54:36 +0100 Subject: Add support for multiple gamepads on RPI --- src/core.c | 102 +++++++++++++++++++++++++++++++++++------------------------ src/raylib.h | 8 ++--- 2 files changed, 65 insertions(+), 45 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 5bb59faa..7d229324 100644 --- a/src/core.c +++ b/src/core.c @@ -116,9 +116,9 @@ #if defined(PLATFORM_RPI) // Old device inputs system - #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input - #define DEFAULT_MOUSE_DEV "/dev/input/mouse0" - #define DEFAULT_GAMEPAD_DEV "/dev/input/js0" + #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input + #define DEFAULT_MOUSE_DEV "/dev/input/mouse0" // Mouse input + #define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...) // New device input events (evdev) (must be detected) //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" @@ -126,8 +126,10 @@ //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN" #define MOUSE_SENSITIVITY 0.8f - #define MAX_GAMEPAD_BUTTONS 11 - #define MAX_GAMEPAD_AXIS 5 + + #define MAX_GAMEPADS 2 // Max number of gamepads supported + #define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) + #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #endif //---------------------------------------------------------------------------------- @@ -164,12 +166,12 @@ static bool mouseReady = false; // Flag to know if mouse is read pthread_t mouseThreadId; // Mouse reading thread id // Gamepad input variables -static int gamepadStream = -1; // Gamepad device file descriptor -static bool gamepadReady = false; // Flag to know if gamepad is ready -pthread_t gamepadThreadId; // Gamepad reading thread id +static int gamepadStream[MAX_GAMEPADS] = { -1 }; // Gamepad device file descriptor (two gamepads supported) +static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready (two gamepads supported) +pthread_t gamepadThreadId; // Gamepad reading thread id -int gamepadButtons[MAX_GAMEPAD_BUTTONS]; -float gamepadAxisValues[MAX_GAMEPAD_AXIS]; +int gamepadButtons[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Gamepad buttons state +float gamepadAxisValues[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -1168,7 +1170,7 @@ bool IsGamepadAvailable(int gamepad) bool result = false; #if defined(PLATFORM_RPI) - if (gamepadReady && (gamepad == 0)) result = true; + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; #else if (glfwJoystickPresent(gamepad) == 1) result = true; #endif @@ -1182,7 +1184,10 @@ float GetGamepadAxisMovement(int gamepad, int axis) float value = 0; #if defined(PLATFORM_RPI) - if (axis < MAX_GAMEPAD_AXIS) value = gamepadAxisValues[axis]; + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) + { + if (axis < MAX_GAMEPAD_AXIS) value = gamepadAxisValues[gamepad][axis]; + } #else const float *axes; int axisCount = 0; @@ -1219,7 +1224,7 @@ bool IsGamepadButtonDown(int gamepad, int button) #if defined(PLATFORM_RPI) // Get gamepad buttons information - if ((gamepad == 0) && (gamepadButtons[button] == 1)) result = true; + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (gamepadButtons[gamepad][button] == 1)) result = true; else result = false; #else const unsigned char *buttons; @@ -1258,7 +1263,7 @@ bool IsGamepadButtonUp(int gamepad, int button) #if defined(PLATFORM_RPI) // Get gamepad buttons information - if ((gamepad == 0) && (gamepadButtons[button] == 0)) result = true; + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (gamepadButtons[gamepad][button] == 0)) result = true; else result = false; #else const unsigned char *buttons; @@ -2447,19 +2452,31 @@ static void *MouseThread(void *arg) // Init gamepad system static void InitGamepad(void) { - if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) - { - TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); - } - else + char gamepadDev[128] = ""; + + for (int i = 0; i < MAX_GAMEPADS; i++) { - gamepadReady = true; + sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i); + + if ((gamepadStream[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0) + { + // NOTE: Only show message for first gamepad + if (i == 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); + } + else + { + gamepadReady[i] = true; - int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL); + // NOTE: Only create one thread + if (i == 0) + { + int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL); - if (error != 0) TraceLog(WARNING, "Error creating gamepad input event thread"); - else TraceLog(INFO, "Gamepad device initialized successfully"); - } + if (error != 0) TraceLog(WARNING, "Error creating gamepad input event thread"); + else TraceLog(INFO, "Gamepad device initialized successfully"); + } + } + } } // Process Gamepad (/dev/input/js0) @@ -2481,29 +2498,32 @@ static void *GamepadThread(void *arg) while (1) { - if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) + for (int i = 0; i < MAX_GAMEPADS; i++) { - gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events - - // Process gamepad events by type - if (gamepadEvent.type == JS_EVENT_BUTTON) + if (read(gamepadStream[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) { - TraceLog(DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events - if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) + // Process gamepad events by type + if (gamepadEvent.type == JS_EVENT_BUTTON) { - // 1 - button pressed, 0 - button released - gamepadButtons[gamepadEvent.number] = (int)gamepadEvent.value; + TraceLog(DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) + { + // 1 - button pressed, 0 - button released + gamepadButtons[i][gamepadEvent.number] = (int)gamepadEvent.value; + } } - } - else if (gamepadEvent.type == JS_EVENT_AXIS) - { - TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); - - if (gamepadEvent.number < MAX_GAMEPAD_AXIS) + else if (gamepadEvent.type == JS_EVENT_AXIS) { - // NOTE: Scaling of gamepadEvent.value to get values between -1..1 - gamepadAxisValues[gamepadEvent.number] = (float)gamepadEvent.value/32768; + TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); + + if (gamepadEvent.number < MAX_GAMEPAD_AXIS) + { + // NOTE: Scaling of gamepadEvent.value to get values between -1..1 + gamepadAxisValues[i][gamepadEvent.number] = (float)gamepadEvent.value/32768; + } } } } diff --git a/src/raylib.h b/src/raylib.h index d891467e..a87b58da 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -174,8 +174,8 @@ // Gamepad Number #define GAMEPAD_PLAYER1 0 #define GAMEPAD_PLAYER2 1 -#define GAMEPAD_PLAYER3 2 -#define GAMEPAD_PLAYER4 3 +#define GAMEPAD_PLAYER3 2 // Not supported +#define GAMEPAD_PLAYER4 3 // Not supported // Gamepad Buttons // NOTE: Adjusted for a PS3 USB Controller @@ -201,8 +201,8 @@ #define GAMEPAD_XBOX_BUTTON_START 7 #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_DPAD_X 32 - #define GAMEPAD_XBOX_AXIS_DPAD_Y 64 + #define GAMEPAD_XBOX_AXIS_DPAD_X 7 + #define GAMEPAD_XBOX_AXIS_DPAD_Y 6 #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 #define GAMEPAD_XBOX_AXIS_LT 2 -- cgit v1.2.3 From 60223a358b691c2769c362597c49e124b045209c Mon Sep 17 00:00:00 2001 From: victorfisac Date: Wed, 23 Mar 2016 15:50:41 +0100 Subject: Physac redesign (3/3) Finally, physics update is handled in main thread using steps to get accuracy in collisions detection instead of moving it to a new thread. Examples are finished as simple and clear as I could. Finally, physac module is MORE simpler than in the first version, calculation everything by the same way for both types of physic objects. I tryed to add rotated physics a couple of times but I didn't get anything good to get a base to improve it. Maybe for the next version... No bugs or strange behaviours found during testing. --- examples/physics_basic_rigidbody.c | 9 ++++--- examples/physics_basic_rigidbody.png | Bin 18144 -> 15294 bytes examples/physics_forces.c | 40 +++++++++++++++++++++------- examples/physics_forces.png | Bin 0 -> 17935 bytes src/physac.c | 49 +++++++++++++++++++---------------- src/physac.h | 6 ++--- src/raylib.h | 4 +-- 7 files changed, 68 insertions(+), 40 deletions(-) create mode 100644 examples/physics_forces.png (limited to 'src/raylib.h') diff --git a/examples/physics_basic_rigidbody.c b/examples/physics_basic_rigidbody.c index f0edba72..917813ad 100644 --- a/examples/physics_basic_rigidbody.c +++ b/examples/physics_basic_rigidbody.c @@ -65,7 +65,7 @@ int main() if (IsKeyDown('A')) rectangle->rigidbody.velocity.x = -MOVE_VELOCITY; else if (IsKeyDown('D')) rectangle->rigidbody.velocity.x = MOVE_VELOCITY; - // Check player 2 movement inputs + // Check square movement inputs if (IsKeyDown(KEY_UP) && square->rigidbody.isGrounded) square->rigidbody.velocity.y = JUMP_VELOCITY; if (IsKeyDown(KEY_LEFT)) square->rigidbody.velocity.x = -MOVE_VELOCITY; else if (IsKeyDown(KEY_RIGHT)) square->rigidbody.velocity.x = MOVE_VELOCITY; @@ -80,17 +80,20 @@ int main() ClearBackground(RAYWHITE); - // Convert transform values to rectangle data type variable - DrawRectangleRec(TransformToRectangle(floor->transform), DARKGRAY); + // Draw floor, roof and walls rectangles + DrawRectangleRec(TransformToRectangle(floor->transform), DARKGRAY); // Convert transform values to rectangle data type variable DrawRectangleRec(TransformToRectangle(leftWall->transform), DARKGRAY); DrawRectangleRec(TransformToRectangle(rightWall->transform), DARKGRAY); DrawRectangleRec(TransformToRectangle(roof->transform), DARKGRAY); + // Draw middle platform rectangle DrawRectangleRec(TransformToRectangle(platform->transform), DARKGRAY); + // Draw physic objects DrawRectangleRec(TransformToRectangle(rectangle->transform), RED); DrawRectangleRec(TransformToRectangle(square->transform), BLUE); + // Draw collider lines if debug is enabled if (isDebug) { DrawRectangleLines(floor->collider.bounds.x, floor->collider.bounds.y, floor->collider.bounds.width, floor->collider.bounds.height, GREEN); diff --git a/examples/physics_basic_rigidbody.png b/examples/physics_basic_rigidbody.png index 3d691637..52f265ac 100644 Binary files a/examples/physics_basic_rigidbody.png and b/examples/physics_basic_rigidbody.png differ diff --git a/examples/physics_forces.c b/examples/physics_forces.c index 2afd14ee..74b40d57 100644 --- a/examples/physics_forces.c +++ b/examples/physics_forces.c @@ -12,9 +12,12 @@ #include "raylib.h" #include "math.h" -#define FORCE_AMOUNT 5.0f -#define FORCE_RADIUS 150 -#define LINE_LENGTH 100 +#define FORCE_AMOUNT 5.0f +#define FORCE_RADIUS 150 +#define LINE_LENGTH 75 +#define TRIANGLE_LENGTH 12 + +void DrawRigidbodyCircle(PhysicObject *obj, Color color); int main() { @@ -42,6 +45,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]; for (int i = 0; i < 3; i++) { @@ -111,14 +115,23 @@ int main() // Draw force radius DrawCircleLines(mousePosition.x, mousePosition.y, FORCE_RADIUS, BLACK); - // Draw direction line + // Draw direction lines if (CheckCollisionPointCircle((Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 }, mousePosition, FORCE_RADIUS)) { Vector2 direction = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 - mousePosition.x, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 - mousePosition.y }; float angle = atan2l(direction.y, direction.x); - DrawLineV((Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 }, - (Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 + (cos(angle)*LINE_LENGTH), rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 + (sin(angle)*LINE_LENGTH) }, BLACK); + // Calculate arrow start and end positions + Vector2 startPosition = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 }; + Vector2 endPosition = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 + (cos(angle)*LINE_LENGTH), rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 + (sin(angle)*LINE_LENGTH) }; + + // Draw arrow line + DrawLineV(startPosition, endPosition, BLACK); + + // Draw arrow triangle + DrawTriangleLines((Vector2){ endPosition.x - cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y - sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH }, + (Vector2){ endPosition.x + cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y + sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH }, + (Vector2){ endPosition.x + cos(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2, endPosition.y + sin(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2 }, BLACK); } } @@ -131,14 +144,23 @@ int main() // Draw force radius DrawCircleLines(mousePosition.x, mousePosition.y, FORCE_RADIUS, BLACK); - // Draw direction line + // Draw direction lines if (CheckCollisionPointCircle((Vector2){ circles[i]->transform.position.x, circles[i]->transform.position.y }, mousePosition, FORCE_RADIUS)) { Vector2 direction = { circles[i]->transform.position.x - mousePosition.x, circles[i]->transform.position.y - mousePosition.y }; float angle = atan2l(direction.y, direction.x); - DrawLineV((Vector2){ circles[i]->transform.position.x, circles[i]->transform.position.y }, - (Vector2){ circles[i]->transform.position.x + (cos(angle)*LINE_LENGTH), circles[i]->transform.position.y + (sin(angle)*LINE_LENGTH) }, BLACK); + // Calculate arrow start and end positions + Vector2 startPosition = { circles[i]->transform.position.x, circles[i]->transform.position.y }; + Vector2 endPosition = { circles[i]->transform.position.x + (cos(angle)*LINE_LENGTH), circles[i]->transform.position.y + (sin(angle)*LINE_LENGTH) }; + + // Draw arrow line + DrawLineV(startPosition, endPosition, BLACK); + + // Draw arrow triangle + DrawTriangleLines((Vector2){ endPosition.x - cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y - sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH }, + (Vector2){ endPosition.x + cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y + sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH }, + (Vector2){ endPosition.x + cos(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2, endPosition.y + sin(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2 }, BLACK); } } diff --git a/examples/physics_forces.png b/examples/physics_forces.png new file mode 100644 index 00000000..832bdbd9 Binary files /dev/null and b/examples/physics_forces.png differ diff --git a/src/physac.c b/src/physac.c index 718a06bb..e3f956ba 100644 --- a/src/physac.c +++ b/src/physac.c @@ -2,7 +2,7 @@ * * [physac] raylib physics module - Basic functions to apply physics to 2D objects * -* Copyright (c) 2015 Victor Fisac and Ramon Santamaria +* Copyright (c) 2016 Victor Fisac and Ramon Santamaria * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -75,10 +75,7 @@ void InitPhysics(Vector2 gravity) void UpdatePhysics() { // Reset all physic objects is grounded state - for (int i = 0; i < physicObjectsCount; i++) - { - if (physicObjects[i]->rigidbody.enabled) physicObjects[i]->rigidbody.isGrounded = false; - } + for (int i = 0; i < physicObjectsCount; i++) physicObjects[i]->rigidbody.isGrounded = false; for (int steps = 0; steps < PHYSICS_STEPS; steps++) { @@ -537,26 +534,32 @@ void ApplyForceAtPosition(Vector2 position, float force, float radius) { for(int i = 0; i < physicObjectsCount; i++) { - // Calculate direction and distance between force and physic object pposition - Vector2 distance = (Vector2){ physicObjects[i]->transform.position.x - position.x, physicObjects[i]->transform.position.y - position.y }; - - if(physicObjects[i]->collider.type == COLLIDER_RECTANGLE) + if(physicObjects[i]->rigidbody.enabled) { - distance.x += physicObjects[i]->transform.scale.x/2; - distance.y += physicObjects[i]->transform.scale.y/2; - } - - float distanceLength = Vector2Length(distance); - - // Check if physic object is in force range - if(distanceLength <= radius) - { - // Normalize force direction - distance.x /= distanceLength; - distance.y /= -distanceLength; + // Calculate direction and distance between force and physic object pposition + Vector2 distance = (Vector2){ physicObjects[i]->transform.position.x - position.x, physicObjects[i]->transform.position.y - position.y }; + + if(physicObjects[i]->collider.type == COLLIDER_RECTANGLE) + { + distance.x += physicObjects[i]->transform.scale.x/2; + distance.y += physicObjects[i]->transform.scale.y/2; + } + + float distanceLength = Vector2Length(distance); - // Apply force to the physic object - ApplyForce(physicObjects[i], (Vector2){ distance.x*force, distance.y*force }); + // Check if physic object is in force range + if(distanceLength <= radius) + { + // Normalize force direction + distance.x /= distanceLength; + distance.y /= -distanceLength; + + // Calculate final force + Vector2 finalForce = { distance.x*force, distance.y*force }; + + // Apply force to the physic object + ApplyForce(physicObjects[i], finalForce); + } } } } diff --git a/src/physac.h b/src/physac.h index c70dbbe2..37544686 100644 --- a/src/physac.h +++ b/src/physac.h @@ -2,7 +2,7 @@ * * [physac] raylib physics module - Basic functions to apply physics to 2D objects * -* Copyright (c) 2015 Victor Fisac and Ramon Santamaria +* Copyright (c) 2016 Victor Fisac and Ramon Santamaria * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -44,8 +44,8 @@ typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType; typedef struct Transform { Vector2 position; - float rotation; - Vector2 scale; + float rotation; // Radians (not used) + Vector2 scale; // Just for rectangle physic objects, for circle physic objects use collider radius and keep scale as { 0, 0 } } Transform; typedef struct Rigidbody { diff --git a/src/raylib.h b/src/raylib.h index a87b58da..1782fef3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -498,8 +498,8 @@ typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType; typedef struct Transform { Vector2 position; - float rotation; - Vector2 scale; + float rotation; // Radians (not used) + Vector2 scale; // Just for rectangle physic objects, for circle physic objects use collider radius and keep scale as { 0, 0 } } Transform; typedef struct Rigidbody { -- cgit v1.2.3 From 8b7ca8b670a0f338fef85125311522833b945bf7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 27 Mar 2016 18:32:36 +0200 Subject: Review comments --- src/raylib.h | 20 ++++++++++---------- src/textures.c | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 1782fef3..2b65df9e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raylib 1.4.0 (www.raylib.com) +* raylib 1.5.0 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * @@ -345,8 +345,8 @@ typedef struct Camera { // Camera2D type, defines a 2d camera typedef struct Camera2D { - Vector2 position; // Camera position - Vector2 origin; // Camera origin (for rotation and zoom) + Vector2 offset; // Camera offset (displacement from target) + Vector2 target; // Camera target (for rotation and zoom) float rotation; // Camera rotation in degrees float zoom; // Camera zoom (scaling), should be 1.0f by default } Camera2D; @@ -375,7 +375,7 @@ typedef struct Mesh { // Shader type (generic shader) typedef struct Shader { - unsigned int id; // Shader program id + unsigned int id; // Shader program id // Variable attributes int vertexLoc; // Vertex attribute location point (vertex shader) @@ -411,9 +411,9 @@ typedef struct Material { // 3d Model type // TODO: Replace shader/testure by material typedef struct Model { - Mesh mesh; - Matrix transform; - Material material; + Mesh mesh; // Vertex data buffers (RAM and VRAM) + Matrix transform; // Local transform matrix + Material material; // Shader and textures data } Model; // Ray type (useful for raycast) @@ -432,8 +432,8 @@ typedef struct Sound { typedef struct Wave { void *data; // Buffer data pointer unsigned int dataSize; // Data size in bytes - unsigned int sampleRate; - short bitsPerSample; + unsigned int sampleRate; // Samples per second to be played + short bitsPerSample; // Sample size in bits short channels; } Wave; @@ -484,7 +484,7 @@ typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; // Gesture events // NOTE: MAX_TOUCH_POINTS fixed to 2 -typedef struct { +typedef struct GestureEvent { int touchAction; int pointCount; int pointerId[MAX_TOUCH_POINTS]; diff --git a/src/textures.c b/src/textures.c index e649df57..9d0d13b6 100644 --- a/src/textures.c +++ b/src/textures.c @@ -29,21 +29,21 @@ #include "raylib.h" -#include // Declares malloc() and free() for memory management -#include // Required for strcmp(), strrchr(), strncmp() +#include // Declares malloc() and free() for memory management +#include // Required for strcmp(), strrchr(), strncmp() -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 - // Required: rlglLoadTexture() rlDeleteTextures(), - // rlglGenerateMipmaps(), some funcs for DrawTexturePro() +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 + // Required: rlglLoadTexture() rlDeleteTextures(), + // rlglGenerateMipmaps(), some funcs for DrawTexturePro() -#include "utils.h" // rRES data decompression utility function - // NOTE: Includes Android fopen function map +#include "utils.h" // rRES data decompression utility function + // NOTE: Includes Android fopen function map #define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" // Used to read image data (multiple formats support) +#include "stb_image.h" // Used to read image data (multiple formats support) #define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "stb_image_resize.h" +#include "stb_image_resize.h" // Used on image scaling function: ImageResize() //---------------------------------------------------------------------------------- // Defines and Macros @@ -130,6 +130,7 @@ Image LoadImage(const char *fileName) } // Load image data from Color array data (RGBA - 32bit) +// NOTE: Creates a copy of pixels data array Image LoadImageEx(Color *pixels, int width, int height) { Image image; -- cgit v1.2.3 From 66b096d97848eb096a043781f1f305e7189f2a00 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 30 Mar 2016 20:09:16 +0200 Subject: Added support for render to texture (use RenderTexture2D) Now it's possible to render to texture, old postprocessing system will be removed on next raylib version. --- examples/resources/shaders/base.vs | 3 + examples/resources/shaders/bloom.fs | 3 +- examples/shaders_postprocessing.c | 36 ++++++++--- src/core.c | 22 ++++++- src/raylib.h | 11 ++++ src/rlgl.c | 118 +++++++++++++++++++++++++++++++++++- src/rlgl.h | 11 ++++ src/textures.c | 19 ++++++ 8 files changed, 210 insertions(+), 13 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/resources/shaders/base.vs b/examples/resources/shaders/base.vs index b0f930b7..9b8cca69 100644 --- a/examples/resources/shaders/base.vs +++ b/examples/resources/shaders/base.vs @@ -3,8 +3,10 @@ in vec3 vertexPosition; in vec2 vertexTexCoord; in vec3 vertexNormal; +in vec4 vertexColor; out vec2 fragTexCoord; +out vec4 fragTintColor; uniform mat4 mvpMatrix; @@ -13,6 +15,7 @@ uniform mat4 mvpMatrix; void main() { fragTexCoord = vertexTexCoord; + fragTintColor = vertexColor; gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); } \ No newline at end of file diff --git a/examples/resources/shaders/bloom.fs b/examples/resources/shaders/bloom.fs index 2833ce33..0a73161a 100644 --- a/examples/resources/shaders/bloom.fs +++ b/examples/resources/shaders/bloom.fs @@ -1,11 +1,12 @@ #version 330 in vec2 fragTexCoord; +in vec4 fragTintColor; out vec4 fragColor; uniform sampler2D texture0; -uniform vec4 fragTintColor; +//uniform vec4 fragTintColor; // NOTE: Add here your custom variables diff --git a/examples/shaders_postprocessing.c b/examples/shaders_postprocessing.c index 44829648..fabf5131 100644 --- a/examples/shaders_postprocessing.c +++ b/examples/shaders_postprocessing.c @@ -41,7 +41,11 @@ int main() Shader shader = LoadShader("resources/shaders/base.vs", "resources/shaders/bloom.fs"); // Load postpro shader - SetPostproShader(shader); // Set fullscreen postprocessing shader + // NOTE: Old postprocessing system is not flexible enough despite being very easy to use + //SetPostproShader(shader); // Set fullscreen postprocessing shader + + // New postprocessing system let the user create multiple RenderTexture2D and perform multiple render passes + RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); // Setup orbital camera SetCameraMode(CAMERA_ORBITAL); // Set an orbital camera mode @@ -65,15 +69,26 @@ int main() ClearBackground(RAYWHITE); - Begin3dMode(camera); + BeginTextureMode(target); // Enable render to texture RenderTexture2D + + Begin3dMode(camera); - DrawModel(dwarf, position, 2.0f, WHITE); // Draw 3d model with texture + DrawModel(dwarf, position, 2.0f, WHITE); // Draw 3d model with texture - DrawGrid(10, 1.0f); // Draw a grid + DrawGrid(10, 1.0f); // Draw a grid - End3dMode(); + End3dMode(); + + DrawText("HELLO TEXTURE!!!", 120, 200, 60, RED); + + EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) + + SetCustomShader(shader); + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + DrawTextureRec(target.texture, (Rectangle){ 0, target.texture.height, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); + SetDefaultShader(); - DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, BLACK); + DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, DARKGRAY); DrawFPS(10, 10); @@ -83,11 +98,12 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - UnloadShader(shader); // Unload shader - UnloadTexture(texture); // Unload texture - UnloadModel(dwarf); // Unload model + UnloadShader(shader); // Unload shader + UnloadTexture(texture); // Unload texture + UnloadModel(dwarf); // Unload model + UnloadRenderTexture(target); // Unload render texture - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/src/core.c b/src/core.c index 5150389c..5a794376 100644 --- a/src/core.c +++ b/src/core.c @@ -545,7 +545,7 @@ void BeginDrawing(void) if (IsPosproShaderEnabled()) rlEnablePostproFBO(); - rlClearScreenBuffers(); + rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -656,6 +656,26 @@ void End3dMode(void) rlDisableDepthTest(); // Disable DEPTH_TEST for 2D } +// Initializes render texture for drawing +void BeginTextureMode(RenderTexture2D target) +{ + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + rlEnableRenderTexture(target.id); + + rlClearScreenBuffers(); // Clear render texture buffers + + rlLoadIdentity(); // Reset current matrix (MODELVIEW) +} + +// Ends drawing to render texture +void EndTextureMode(void) +{ + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + rlDisableRenderTexture(); +} + // Set target FPS for the game void SetTargetFPS(int fps) { diff --git a/src/raylib.h b/src/raylib.h index 2b65df9e..c8f2c2a2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -324,6 +324,13 @@ typedef struct Texture2D { int format; // Data format (TextureFormat) } Texture2D; +// RenderTexture2D type, for texture rendering +typedef struct RenderTexture2D { + unsigned int id; // Render texture (fbo) id + Texture2D texture; // Color buffer attachment texture + Texture2D depth; // Depth buffer attachment texture +} RenderTexture2D; + // SpriteFont type, includes texture and charSet array data typedef struct SpriteFont { Texture2D texture; // Font texture @@ -565,6 +572,8 @@ void EndDrawing(void); // End canvas drawin void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode +void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing +void EndTextureMode(void); // Ends drawing to render texture Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position Vector2 WorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position @@ -714,8 +723,10 @@ Texture2D LoadTexture(const char *fileName); Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) Texture2D LoadTextureFromImage(Image image); // Load a texture from image data +RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadTexture(Texture2D texture); // Unload texture from GPU memory +void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory Color *GetImageData(Image image); // Get pixel data from image as a Color struct array Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) diff --git a/src/rlgl.c b/src/rlgl.c index 39a34095..2153221e 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -785,6 +785,20 @@ void rlDisableTexture(void) #endif } +void rlEnableRenderTexture(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindFramebuffer(GL_FRAMEBUFFER, id); +#endif +} + +void rlDisableRenderTexture(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + // Enable depth test void rlEnableDepthTest(void) { @@ -803,6 +817,16 @@ void rlDeleteTextures(unsigned int id) glDeleteTextures(1, &id); } +// Unload render texture from GPU memory +void rlDeleteRenderTextures(RenderTexture2D target) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteFramebuffers(1, &target.id); + glDeleteTextures(1, &target.texture.id); + glDeleteTextures(1, &target.depth.id); +#endif +} + // Enable rendering to postprocessing FBO void rlEnablePostproFBO() { @@ -1163,7 +1187,7 @@ FBO rlglLoadFBO(int width, int height) glDeleteTextures(1, &fbo.colorTextureId); glDeleteTextures(1, &fbo.depthTextureId); } - else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo); + else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo.id); glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif @@ -1833,6 +1857,98 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma return id; } +// Load a texture to be used for rendering (fbo with color and depth attachments) +RenderTexture2D rlglLoadRenderTexture(int width, int height) +{ + RenderTexture2D target; + + target.id = 0; + + target.texture.id = 0; + target.texture.width = width; + target.texture.height = height; + target.texture.format = UNCOMPRESSED_R8G8B8; + target.texture.mipmaps = 1; + + target.depth.id = 0; + target.depth.width = width; + target.depth.height = height; + target.depth.format = 19; //DEPTH_COMPONENT_16BIT + target.depth.mipmaps = 1; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Create the texture that will serve as the color attachment for the framebuffer + glGenTextures(1, &target.texture.id); + glBindTexture(GL_TEXTURE_2D, target.texture.id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); + +#define USE_DEPTH_RENDERBUFFER +#if defined(USE_DEPTH_RENDERBUFFER) + // Create the renderbuffer that will serve as the depth attachment for the framebuffer. + glGenRenderbuffers(1, &target.depth.id); + glBindRenderbuffer(GL_RENDERBUFFER, target.depth.id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + +#elif defined(USE_DEPTH_TEXTURE) + // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extension required) + // A renderbuffer is simpler than a texture and could offer better performance on embedded devices + glGenTextures(1, &target.depth.id); + glBindTexture(GL_TEXTURE_2D, target.depth.id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, 0); +#endif + + // Create the framebuffer object + glGenFramebuffers(1, &target.id); + glBindFramebuffer(GL_FRAMEBUFFER, target.id); + + // Attach color texture and depth renderbuffer to FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target.texture.id, 0); +#if defined(USE_DEPTH_RENDERBUFFER) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, target.depth.id); +#elif defined(USE_DEPTH_TEXTURE) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target.depth.id, 0); +#endif + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + TraceLog(WARNING, "Framebuffer object could not be created..."); + + switch(status) + { + case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break; +#if defined(GRAPHICS_API_OPENGL_ES2) + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TraceLog(WARNING, "Framebuffer incomplete dimensions"); break; +#endif + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break; + default: break; + } + + glDeleteTextures(1, &target.texture.id); + glDeleteTextures(1, &target.depth.id); + glDeleteFramebuffers(1, &target.id); + } + else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", target.id); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif + + return target; +} + +// Update already loaded texture in GPU with new data void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data) { glBindTexture(GL_TEXTURE_2D, id); diff --git a/src/rlgl.h b/src/rlgl.h index 1a5260eb..679cb590 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -183,6 +183,13 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; int format; // Data format (TextureFormat) } Texture2D; + // RenderTexture2D type, for texture rendering + typedef struct RenderTexture2D { + unsigned int id; // Render texture (fbo) id + Texture2D texture; // Color buffer attachment texture + Texture2D depth; // Depth buffer attachment texture + } RenderTexture2D; + // Material type typedef struct Material { Shader shader; @@ -248,9 +255,12 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) //------------------------------------------------------------------------------------ void rlEnableTexture(unsigned int id); // Enable texture usage void rlDisableTexture(void); // Disable texture usage +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 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 void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory @@ -268,6 +278,7 @@ void rlglDraw(void); // Draw VAO/VBO void rlglInitGraphics(int offsetX, int offsetY, int width, int height); // Initialize Graphics (OpenGL stuff) unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU +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 diff --git a/src/textures.c b/src/textures.c index 9d0d13b6..67264afb 100644 --- a/src/textures.c +++ b/src/textures.c @@ -389,6 +389,14 @@ Texture2D LoadTextureFromImage(Image image) return texture; } +// Load a texture to be used for rendering +RenderTexture2D LoadRenderTexture(int width, int height) +{ + RenderTexture2D target = rlglLoadRenderTexture(width, height); + + return target; +} + // Unload image from CPU memory (RAM) void UnloadImage(Image image) { @@ -409,6 +417,17 @@ void UnloadTexture(Texture2D texture) } } +// Unload render texture from GPU memory +void UnloadRenderTexture(RenderTexture2D target) +{ + if (target.id != 0) + { + rlDeleteRenderTextures(target); + + TraceLog(INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id); + } +} + // Get pixel data from image in the form of Color struct array Color *GetImageData(Image image) { -- cgit v1.2.3 From 06a8d7eb06e1573d5cce991ca39f6cb1067ea6fb Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 1 Apr 2016 10:39:33 +0200 Subject: Remove old postprocessing system --- examples/shaders_custom_uniform.c | 7 +- examples/shaders_postprocessing.c | 7 +- src/core.c | 9 +- src/raylib.h | 2 - src/rlgl.c | 244 ++------------------------------------ src/rlgl.h | 6 - 6 files changed, 13 insertions(+), 262 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/shaders_custom_uniform.c b/examples/shaders_custom_uniform.c index 05e4dcfd..af59dc3c 100644 --- a/examples/shaders_custom_uniform.c +++ b/examples/shaders_custom_uniform.c @@ -47,10 +47,7 @@ int main() float swirlCenter[2] = { (float)screenWidth/2, (float)screenHeight/2 }; - // NOTE: Old postprocessing system is not flexible enough despite being very easy to use - //SetPostproShader(shader); // Set fullscreen postprocessing shader - - // New postprocessing system let the user create multiple RenderTexture2D and perform multiple render passes + // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); // Setup orbital camera @@ -83,7 +80,7 @@ int main() ClearBackground(RAYWHITE); - BeginTextureMode(target); // Enable render to texture RenderTexture2D + BeginTextureMode(target); // Enable drawing to texture Begin3dMode(camera); diff --git a/examples/shaders_postprocessing.c b/examples/shaders_postprocessing.c index fabf5131..0bcd5156 100644 --- a/examples/shaders_postprocessing.c +++ b/examples/shaders_postprocessing.c @@ -41,10 +41,7 @@ int main() Shader shader = LoadShader("resources/shaders/base.vs", "resources/shaders/bloom.fs"); // Load postpro shader - // NOTE: Old postprocessing system is not flexible enough despite being very easy to use - //SetPostproShader(shader); // Set fullscreen postprocessing shader - - // New postprocessing system let the user create multiple RenderTexture2D and perform multiple render passes + // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); // Setup orbital camera @@ -69,7 +66,7 @@ int main() ClearBackground(RAYWHITE); - BeginTextureMode(target); // Enable render to texture RenderTexture2D + BeginTextureMode(target); // Enable drawing to texture Begin3dMode(camera); diff --git a/src/core.c b/src/core.c index 5a794376..ae6f4cad 100644 --- a/src/core.c +++ b/src/core.c @@ -543,12 +543,8 @@ void BeginDrawing(void) updateTime = currentTime - previousTime; previousTime = currentTime; - if (IsPosproShaderEnabled()) rlEnablePostproFBO(); - rlClearScreenBuffers(); // Clear current framebuffers - rlLoadIdentity(); // Reset current matrix (MODELVIEW) - rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here //rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL 1.1 @@ -578,7 +574,7 @@ void BeginDrawingPro(int blendMode, Shader shader, Matrix transform) BeginDrawing(); SetBlendMode(blendMode); - SetPostproShader(shader); + SetCustomShader(shader); rlMultMatrixf(MatrixToFloat(transform)); } @@ -588,12 +584,11 @@ void EndDrawing(void) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - if (IsPosproShaderEnabled()) rlglDrawPostpro(); // Draw postprocessing effect (shader) - SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events + // Frame time control system currentTime = GetTime(); drawTime = currentTime - previousTime; previousTime = currentTime; diff --git a/src/raylib.h b/src/raylib.h index c8f2c2a2..22fcb4ac 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -829,11 +829,9 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shaders strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory -void SetPostproShader(Shader shader); // Set fullscreen postproduction shader void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw void SetModelShader(Model *model, Shader shader); // Link a shader to a model -bool IsPosproShaderEnabled(void); // Check if postprocessing shader is enabled int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) diff --git a/src/rlgl.c b/src/rlgl.c index 2153221e..809077e3 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -176,24 +176,6 @@ typedef struct { // TODO: Store draw state -> blending mode, shader } DrawCall; -// pixel type (same as Color type) -// NOTE: Used exclusively in mipmap generation functions -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -} pixel; - -// Framebuffer Object type -typedef struct { - GLuint id; - int width; - int height; - GLuint colorTextureId; - GLuint depthTextureId; -} FBO; - #if defined(RLGL_STANDALONE) typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; #endif @@ -248,13 +230,6 @@ 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 - -// Framebuffer object and texture -static FBO postproFbo; -static Model postproQuad; - -// Shaders related variables -static bool enabledPostpro = false; #endif // Compressed textures support flags @@ -269,9 +244,6 @@ static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays; //static PFNGLISVERTEXARRAYOESPROC glIsVertexArray; // NOTE: Fails in WebGL, omitted #endif -// Save screen size data (render size), required for postpro quad -static int screenWidth, screenHeight; - static int blendMode = 0; // White texture useful for plain color polys (required by shader) @@ -290,14 +262,11 @@ static void UpdateBuffers(void); static char *TextFileRead(char *fn); static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat); - -FBO rlglLoadFBO(int width, int height); -void rlglUnloadFBO(FBO fbo); #endif #if defined(GRAPHICS_API_OPENGL_11) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); -static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight); +static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); #endif #if defined(RLGL_STANDALONE) @@ -827,14 +796,6 @@ void rlDeleteRenderTextures(RenderTexture2D target) #endif } -// Enable rendering to postprocessing FBO -void rlEnablePostproFBO() -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindFramebuffer(GL_FRAMEBUFFER, postproFbo.id); -#endif -} - // Unload shader from GPU memory void rlDeleteShader(unsigned int id) { @@ -1088,125 +1049,6 @@ void rlglInit(void) #endif } -// Init postpro system -// NOTE: Uses global variables screenWidth and screenHeight -// Modifies global variables: postproFbo, postproQuad -void rlglInitPostpro(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - postproFbo = rlglLoadFBO(screenWidth, screenHeight); - - if (postproFbo.id > 0) - { - // Create a simple quad model to render fbo texture - Mesh quad; - - quad.vertexCount = 6; - - float w = (float)postproFbo.width; - float h = (float)postproFbo.height; - - float quadPositions[6*3] = { w, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, h, 0.0f, 0.0f, h, 0.0f, w, h, 0.0f, w, 0.0f, 0.0f }; - float quadTexcoords[6*2] = { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; - float quadNormals[6*3] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f }; - unsigned char quadColors[6*4] = { 255 }; - - quad.vertices = quadPositions; - quad.texcoords = quadTexcoords; - quad.normals = quadNormals; - quad.colors = quadColors; - - postproQuad = rlglLoadModel(quad); - - // NOTE: postproFbo.colorTextureId must be assigned to postproQuad model shader - } -#endif -} - -// Load a framebuffer object -FBO rlglLoadFBO(int width, int height) -{ - FBO fbo; - fbo.id = 0; - fbo.width = width; - fbo.height = height; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Create the texture that will serve as the color attachment for the framebuffer - glGenTextures(1, &fbo.colorTextureId); - glBindTexture(GL_TEXTURE_2D, fbo.colorTextureId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - - // Create the renderbuffer that will serve as the depth attachment for the framebuffer. - glGenRenderbuffers(1, &fbo.depthTextureId); - glBindRenderbuffer(GL_RENDERBUFFER, fbo.depthTextureId); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); - - // NOTE: We can also use a texture for depth buffer (GL_ARB_depth_texture/GL_OES_depth_texture extensions) - // A renderbuffer is simpler than a texture and could offer better performance on embedded devices -/* - glGenTextures(1, &fbo.depthTextureId); - glBindTexture(GL_TEXTURE_2D, fbo.depthTextureId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); -*/ - // Create the framebuffer object - glGenFramebuffers(1, &fbo.id); - glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); - - // Attach color texture and depth renderbuffer to FBO - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.colorTextureId, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo.depthTextureId); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - TraceLog(WARNING, "Framebuffer object could not be created..."); - - switch(status) - { - case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break; -#if defined(GRAPHICS_API_OPENGL_ES2) - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TraceLog(WARNING, "Framebuffer incomplete dimensions"); break; -#endif - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break; - default: break; - } - - glDeleteTextures(1, &fbo.colorTextureId); - glDeleteTextures(1, &fbo.depthTextureId); - } - else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", fbo.id); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif - - return fbo; -} - -// Unload framebuffer object -void rlglUnloadFBO(FBO fbo) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteFramebuffers(1, &fbo.id); - glDeleteTextures(1, &fbo.colorTextureId); - glDeleteTextures(1, &fbo.depthTextureId); - - TraceLog(INFO, "[FBO ID %i] Unloaded framebuffer object successfully", fbo.id); -#endif -} - // Vertex Buffer Object deinitialization (memory free) void rlglClose(void) { @@ -1263,20 +1105,6 @@ void rlglClose(void) glDeleteTextures(1, &whiteTexture); TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); - if (postproFbo.id != 0) - { - rlglUnloadFBO(postproFbo); - - // Unload postpro quad model data - rlDeleteBuffers(postproQuad.mesh.vboId[0]); - rlDeleteBuffers(postproQuad.mesh.vboId[1]); - rlDeleteBuffers(postproQuad.mesh.vboId[2]); - - rlDeleteVertexArrays(postproQuad.mesh.vaoId); - - TraceLog(INFO, "Unloaded postprocessing data"); - } - free(draws); #endif } @@ -1443,16 +1271,6 @@ void rlglDraw(void) #endif } -// Draw with postprocessing shader -void rlglDrawPostpro(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - rlglDrawModel(postproQuad, (Vector3){ 0.0f, 0.0f, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, 0.0f, (Vector3){1.0f, 1.0f, 1.0f}, (Color){ 255, 255, 255, 255 }, false); -#endif -} - // Draw a 3d model // NOTE: Model transform can come within model struct void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires) @@ -1606,12 +1424,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro // Initialize Graphics Device (OpenGL stuff) // NOTE: Stores global variables screenWidth and screenHeight void rlglInitGraphics(int offsetX, int offsetY, int width, int height) -{ - // Save screen size data (global vars), required on postpro quad - // NOTE: Size represents render size, it could differ from screen size! - screenWidth = width; - screenHeight = height; - +{ // NOTE: Required! viewport must be recalculated if screen resized! glViewport(offsetX/2, offsetY/2, width - offsetX, height - offsetY); // Set viewport width and height @@ -2458,44 +2271,11 @@ void SetCustomShader(Shader shader) #endif } -// Set postprocessing shader -void SetPostproShader(Shader shader) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (!enabledPostpro) - { - enabledPostpro = true; - rlglInitPostpro(); // Lazy initialization on postprocessing usage - } - - SetModelShader(&postproQuad, shader); - - Texture2D texture; - texture.id = postproFbo.colorTextureId; - texture.width = postproFbo.width; - texture.height = postproFbo.height; - - postproQuad.material.texDiffuse = texture; - - //TraceLog(DEBUG, "Postproquad texture id: %i", postproQuad.texture.id); - //TraceLog(DEBUG, "Postproquad shader diffuse map id: %i", postproQuad.shader.texDiffuseId); - //TraceLog(DEBUG, "Shader diffuse map id: %i", shader.texDiffuseId); -#elif defined(GRAPHICS_API_OPENGL_11) - TraceLog(WARNING, "Shaders not supported on OpenGL 1.1"); -#endif -} - // Set default shader to be used in batch draw void SetDefaultShader(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) SetCustomShader(defaultShader); - - if (enabledPostpro) - { - SetPostproShader(defaultShader); - enabledPostpro = false; - } #endif } @@ -2529,16 +2309,6 @@ void SetModelShader(Model *model, Shader shader) #endif } -// Check if postprocessing is enabled (used in module: core) -bool IsPosproShaderEnabled(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - return enabledPostpro; -#elif defined(GRAPHICS_API_OPENGL_11) - return false; -#endif -} - // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName) { @@ -3120,8 +2890,8 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) // Generate mipmaps // NOTE: Every mipmap data is stored after data - pixel *image = (pixel *)malloc(width*height*sizeof(pixel)); - pixel *mipmap = NULL; + Color *image = (Color *)malloc(width*height*sizeof(Color)); + Color *mipmap = NULL; int offset = 0; int j = 0; @@ -3169,15 +2939,15 @@ static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight) } // Manual mipmap generation (basic scaling algorithm) -static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight) +static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) { int x2, y2; - pixel prow, pcol; + Color prow, pcol; int width = srcWidth/2; int height = srcHeight/2; - pixel *mipmap = (pixel *)malloc(width*height*sizeof(pixel)); + Color *mipmap = (Color *)malloc(width*height*sizeof(Color)); // Scaling algorithm works perfectly (box-filter) for (int y = 0; y < height; y++) diff --git a/src/rlgl.h b/src/rlgl.h index 679cb590..714961e1 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -267,7 +267,6 @@ void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth) int rlGetVersion(void); // Returns current OpenGL version -void rlEnablePostproFBO(void); // Enable rendering to postprocessing FBO //------------------------------------------------------------------------------------ // Functions Declaration - rlgl functionality @@ -285,9 +284,6 @@ void rlglGenerateMipmaps(Texture2D texture); // Gene // NOTE: There is a set of shader related functions that are available to end user, // to avoid creating function wrappers through core module, they have been directly declared in raylib.h -void rlglInitPostpro(void); // Initialize postprocessing system -void rlglDrawPostpro(void); // Draw with postprocessing shader - Model rlglLoadModel(Mesh mesh); // Upload vertex data into GPU and provided VAO/VBO ids void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires); @@ -309,11 +305,9 @@ void PrintModelviewMatrix(void); // DEBUG: Print modelview matrix Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory -void SetPostproShader(Shader shader); // Set fullscreen postproduction shader void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw void SetModelShader(Model *model, Shader shader); // Link a shader to a model -bool IsPosproShaderEnabled(void); // Check if postprocessing shader is enabled int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -- cgit v1.2.3 From c1e49d2b13c75da2c532079d454fad32f9ceccd4 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 8 Apr 2016 12:00:29 +0200 Subject: Removed function I decided it is redundant and could be confusing (when mixed with 3D drawing). It's not KISS. --- src/core.c | 11 ----------- src/raylib.h | 1 - 2 files changed, 12 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index ae6f4cad..e01f3969 100644 --- a/src/core.c +++ b/src/core.c @@ -568,17 +568,6 @@ void BeginDrawingEx(Camera2D camera) rlMultMatrixf(MatrixToFloat(matTransform)); } -// Setup drawing canvas with pro parameters -void BeginDrawingPro(int blendMode, Shader shader, Matrix transform) -{ - BeginDrawing(); - - SetBlendMode(blendMode); - SetCustomShader(shader); - - rlMultMatrixf(MatrixToFloat(transform)); -} - // End canvas drawing and Swap Buffers (Double Buffering) void EndDrawing(void) { diff --git a/src/raylib.h b/src/raylib.h index 22fcb4ac..52a5e73c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -567,7 +567,6 @@ int GetScreenHeight(void); // Get current scree void ClearBackground(Color color); // Sets Background Color void BeginDrawing(void); // Setup drawing canvas to start drawing void BeginDrawingEx(Camera2D camera); // Setup drawing canvas with 2d camera -void BeginDrawingPro(int blendMode, Shader shader, Matrix transform); // Setup drawing canvas with pro parameters void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) -- cgit v1.2.3 From 6b5e18e6bfe9940987cc38dcf40e2e903fe3b235 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 17 Apr 2016 11:19:32 +0200 Subject: Make mouse inputs available on Android for... ... easy code porting, transalating them to touches and gestures internally. Removed function SetCustomCursor(), it can be managed by the user. --- src/core.c | 245 ++++++++++++++++++++++++++++++++--------------------------- src/raylib.h | 35 ++++----- 2 files changed, 148 insertions(+), 132 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index e01f3969..294936fb 100644 --- a/src/core.c +++ b/src/core.c @@ -195,26 +195,19 @@ static int renderOffsetY = 0; // Offset Y from render area (must b static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) -static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... - -static bool customCursor = false; // Tracks if custom cursor has been set static bool cursorOnScreen = false; // Tracks if cursor is inside client area -static Texture2D cursor; // Cursor texture - -static Vector2 mousePosition; // Mouse position on screen static char previousKeyState[512] = { 0 }; // Required to check if key pressed/released once static char currentKeyState[512] = { 0 }; // Required to check if key pressed/released once -static char previousMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once -static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once - static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once static char currentGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once +static char previousMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once +static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once + static int previousMouseWheelY = 0; // Required to track mouse wheel variation static int currentMouseWheelY = 0; // Required to track mouse wheel variation @@ -224,6 +217,9 @@ static int lastKeyPressed = -1; // Register last key pressed static bool cursorHidden; // Track if cursor is hidden #endif +static Vector2 mousePosition; // Mouse position on screen +static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen + #if defined(PLATFORM_DESKTOP) static char **dropFilesPath; // Store dropped files paths as strings static int dropFilesCount = 0; // Count stored strings @@ -494,29 +490,6 @@ void ToggleFullscreen(void) #endif } -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -// Set a custom cursor icon/image -void SetCustomCursor(const char *cursorImage) -{ - if (customCursor) UnloadTexture(cursor); - - cursor = LoadTexture(cursorImage); - -#if defined(PLATFORM_DESKTOP) - // NOTE: emscripten not implemented - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#endif - customCursor = true; -} - -// Set a custom key to exit program -// NOTE: default exitKey is ESCAPE -void SetExitKey(int key) -{ - exitKey = key; -} -#endif - // Get current screen width int GetScreenWidth(void) { @@ -1032,78 +1005,11 @@ int GetKeyPressed(void) return lastKeyPressed; } -// Detect if a mouse button has been pressed once -bool IsMouseButtonPressed(int button) -{ - bool pressed = false; - - if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; - else pressed = false; - - return pressed; -} - -// Detect if a mouse button is being pressed -bool IsMouseButtonDown(int button) -{ - if (GetMouseButtonStatus(button) == 1) return true; - else return false; -} - -// Detect if a mouse button has been released once -bool IsMouseButtonReleased(int button) -{ - bool released = false; - - if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true; - else released = false; - - return released; -} - -// Detect if a mouse button is NOT being pressed -bool IsMouseButtonUp(int button) -{ - if (GetMouseButtonStatus(button) == 0) return true; - else return false; -} - -// Returns mouse position X -int GetMouseX(void) -{ - return (int)mousePosition.x; -} - -// Returns mouse position Y -int GetMouseY(void) -{ - return (int)mousePosition.y; -} - -// Returns mouse position XY -Vector2 GetMousePosition(void) -{ - return mousePosition; -} - -// Set mouse position XY -void SetMousePosition(Vector2 position) -{ - mousePosition = position; -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - // NOTE: emscripten not implemented - glfwSetCursorPos(window, position.x, position.y); -#endif -} - -// Returns mouse wheel movement Y -int GetMouseWheelMove(void) +// Set a custom key to exit program +// NOTE: default exitKey is ESCAPE +void SetExitKey(int key) { -#if defined(PLATFORM_WEB) - return previousMouseWheelY/100; -#else - return previousMouseWheelY; -#endif + exitKey = key; } // Hide mouse cursor @@ -1280,6 +1186,111 @@ bool IsGamepadButtonUp(int gamepad, int button) } #endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) + +// Detect if a mouse button has been pressed once +bool IsMouseButtonPressed(int button) +{ + bool pressed = false; + +#if defined(PLATFORM_ANDROID) + if (IsGestureDetected() && (GetGestureType() == GESTURE_TAP)) pressed = true; +#else + if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; +#endif + + return pressed; +} + +// Detect if a mouse button is being pressed +bool IsMouseButtonDown(int button) +{ + bool down = false; + +#if defined(PLATFORM_ANDROID) + if (IsGestureDetected() && (GetGestureType() == GESTURE_HOLD)) down = true; +#else + if (GetMouseButtonStatus(button) == 1) down = true; +#endif + + return down; +} + +// Detect if a mouse button has been released once +bool IsMouseButtonReleased(int button) +{ + bool released = false; + +#if !defined(PLATFORM_ANDROID) + if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true; +#endif + + return released; +} + +// Detect if a mouse button is NOT being pressed +bool IsMouseButtonUp(int button) +{ + bool up = false; + +#if !defined(PLATFORM_ANDROID) + if (GetMouseButtonStatus(button) == 0) up = true; +#endif + + return up; +} + +// Returns mouse position X +int GetMouseX(void) +{ +#if defined(PLATFORM_ANDROID) + return (int)touchPosition[0].x; +#else + return (int)mousePosition.x; +#endif +} + +// Returns mouse position Y +int GetMouseY(void) +{ +#if defined(PLATFORM_ANDROID) + return (int)touchPosition[0].x; +#else + return (int)mousePosition.y; +#endif +} + +// Returns mouse position XY +Vector2 GetMousePosition(void) +{ +#if defined(PLATFORM_ANDROID) + return GetTouchPosition(0); +#else + return mousePosition; +#endif +} + +// Set mouse position XY +void SetMousePosition(Vector2 position) +{ + mousePosition = position; +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + // NOTE: emscripten not implemented + glfwSetCursorPos(window, position.x, position.y); +#endif +} + +// Returns mouse wheel movement Y +int GetMouseWheelMove(void) +{ +#if defined(PLATFORM_ANDROID) + return 0; +#elif defined(PLATFORM_WEB) + return previousMouseWheelY/100; +#else + return previousMouseWheelY; +#endif +} + // Returns touch position X int GetTouchX(void) { @@ -1376,7 +1387,7 @@ static void InitDisplay(int width, int height) // Downscale matrix is required in case desired screen area is bigger than display area downscaleView = MatrixIdentity(); - + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) glfwSetErrorCallback(ErrorCallback); @@ -1393,10 +1404,12 @@ static void InitDisplay(int width, int height) // Screen size security check if (screenWidth <= 0) screenWidth = displayWidth; if (screenHeight <= 0) screenHeight = displayHeight; -#elif defined(PLATFORM_WEB) +#endif // defined(PLATFORM_DESKTOP) + +#if defined(PLATFORM_WEB) displayWidth = screenWidth; displayHeight = screenHeight; -#endif +#endif // defined(PLATFORM_WEB) glfwDefaultWindowHints(); // Set default windows hints @@ -1447,7 +1460,7 @@ static void InitDisplay(int width, int height) // TODO: Check modes[i]->width; // TODO: Check modes[i]->height; } - + window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); } else @@ -1543,8 +1556,9 @@ static void InitDisplay(int width, int height) } //glfwGetFramebufferSize(window, &renderWidth, &renderHeight); // Get framebuffer size of current window +#endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) -#elif defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) +#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) fullscreen = true; // Screen size security check @@ -1629,8 +1643,9 @@ static void InitDisplay(int width, int height) //ANativeWindow_setBuffersGeometry(app->window, 0, 0, displayFormat); // Force use of native display size surface = eglCreateWindowSurface(display, config, app->window, NULL); +#endif // defined(PLATFORM_ANDROID) -#elif defined(PLATFORM_RPI) +#if defined(PLATFORM_RPI) graphics_get_display_size(0, &displayWidth, &displayHeight); // At this point we need to manage render size vs screen size @@ -1668,7 +1683,7 @@ static void InitDisplay(int width, int height) surface = eglCreateWindowSurface(display, config, &nativeWindow, NULL); //--------------------------------------------------------------------------------- -#endif +#endif // defined(PLATFORM_RPI) // There must be at least one frame displayed before the buffers are swapped //eglSwapInterval(display, 1); @@ -1688,13 +1703,17 @@ static void InitDisplay(int width, int height) TraceLog(INFO, "Screen size: %i x %i", screenWidth, screenHeight); TraceLog(INFO, "Viewport offsets: %i, %i", renderOffsetX, renderOffsetY); } -#endif +#endif // defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) } // Initialize OpenGL graphics static void InitGraphics(void) { rlglInit(); // Init rlgl + +#if defined(PLATFORM_OCULUS) + //rlglInitOculus(); // Init rlgl for Oculus Rift (required textures) +#endif rlglInitGraphics(renderOffsetX, renderOffsetY, renderWidth, renderHeight); // Init graphics (OpenGL stuff) @@ -2153,7 +2172,7 @@ static bool GetMouseButtonStatus(int button) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetMouseButton(window, button); #elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual keyboard + // TODO: Check for virtual mouse return false; #elif defined(PLATFORM_RPI) // NOTE: Mouse buttons states are filled in PollInputEvents() diff --git a/src/raylib.h b/src/raylib.h index 52a5e73c..2fe29cc8 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -557,13 +557,15 @@ void CloseWindow(void); // Close Window and bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) -void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image -void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -#endif int GetScreenWidth(void); // Get current screen width int GetScreenHeight(void); // Get current screen height +void ShowCursor(void); // Shows cursor +void HideCursor(void); // Hides cursor +bool IsCursorHidden(void); // Returns true if cursor is not visible +void EnableCursor(void); // Enables cursor +void DisableCursor(void); // Disables cursor + void ClearBackground(Color color); // Sets Background Color void BeginDrawing(void); // Setup drawing canvas to start drawing void BeginDrawingEx(Camera2D camera); // Setup drawing canvas with 2d camera @@ -610,6 +612,15 @@ bool IsKeyDown(int key); // Detect if a key is be bool IsKeyReleased(int key); // Detect if a key has been released once bool IsKeyUp(int key); // Detect if a key is NOT being pressed int GetKeyPressed(void); // Get latest key pressed +void SetExitKey(int key); // Set a custom key to exit program (default is ESC) + +bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis +bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once +bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed +bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once +bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed +#endif bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed @@ -621,20 +632,6 @@ Vector2 GetMousePosition(void); // Returns mouse positio void SetMousePosition(Vector2 position); // Set mouse position XY int GetMouseWheelMove(void); // Returns mouse wheel movement Y -void ShowCursor(void); // Shows cursor -void HideCursor(void); // Hides cursor -void EnableCursor(void); // Enables cursor -void DisableCursor(void); // Disables cursor -bool IsCursorHidden(void); // Returns true if cursor is not visible - -bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available -float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis -bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once -bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed -bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once -bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed -#endif - int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) @@ -649,7 +646,7 @@ bool IsButtonReleased(int button); // Detect if an android // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures -void UpdateGestures(void); // Update gestures detected (must be called every frame) +void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) bool IsGestureDetected(void); // Check if a gesture have been detected int GetGestureType(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -- cgit v1.2.3 From 17eefed08fa052b39c9ee4c4cb486794a8551c92 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 17 Apr 2016 11:36:40 +0200 Subject: Improved gestures system --- examples/core_gestures_detection.c | 8 +++----- src/core.c | 4 ++-- src/gestures.c | 6 +++--- src/gestures.h | 4 ++-- src/raylib.h | 4 ++-- 5 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_gestures_detection.c b/examples/core_gestures_detection.c index a5cf8e69..63a1e6bd 100644 --- a/examples/core_gestures_detection.c +++ b/examples/core_gestures_detection.c @@ -43,12 +43,11 @@ int main() // Update //---------------------------------------------------------------------------------- lastGesture = currentGesture; + currentGesture = GetGestureDetected(); touchPosition = GetTouchPosition(0); - - if (CheckCollisionPointRec(touchPosition, touchArea) && IsGestureDetected()) + + if (CheckCollisionPointRec(touchPosition, touchArea) && (currentGesture != GESTURE_NONE)) { - currentGesture = GetGestureType(); - if (currentGesture != lastGesture) { // Store gesture string @@ -78,7 +77,6 @@ int main() } } } - else currentGesture = GESTURE_NONE; //---------------------------------------------------------------------------------- // Draw diff --git a/src/core.c b/src/core.c index 294936fb..7b1d5960 100644 --- a/src/core.c +++ b/src/core.c @@ -1193,7 +1193,7 @@ bool IsMouseButtonPressed(int button) bool pressed = false; #if defined(PLATFORM_ANDROID) - if (IsGestureDetected() && (GetGestureType() == GESTURE_TAP)) pressed = true; + if (IsGestureDetected(GESTURE_TAP)) pressed = true; #else if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true; #endif @@ -1207,7 +1207,7 @@ bool IsMouseButtonDown(int button) bool down = false; #if defined(PLATFORM_ANDROID) - if (IsGestureDetected() && (GetGestureType() == GESTURE_HOLD)) down = true; + if (IsGestureDetected(GESTURE_HOLD)) down = true; #else if (GetMouseButtonStatus(button) == 1) down = true; #endif diff --git a/src/gestures.c b/src/gestures.c index b0a80084..d72aaf4e 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -292,14 +292,14 @@ void UpdateGestures(void) } // Check if a gesture have been detected -bool IsGestureDetected(void) +bool IsGestureDetected(int gesture) { - if ((enabledGestures & currentGesture) != GESTURE_NONE) return true; + if ((enabledGestures & currentGesture) == gesture) return true; else return false; } // Check gesture type -int GetGestureType(void) +int GetGestureDetected(void) { // Get current gesture only if enabled return (enabledGestures & currentGesture); diff --git a/src/gestures.h b/src/gestures.h index 5468eb54..f2bdaba4 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -92,8 +92,8 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) -bool IsGestureDetected(void); // Check if a gesture have been detected -int GetGestureType(void); // Get latest detected gesture +bool IsGestureDetected(int gesture); // Check if a gesture have been detected +int GetGestureDetected(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags int GetTouchPointsCount(void); // Get touch points count diff --git a/src/raylib.h b/src/raylib.h index 2fe29cc8..0c80b957 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -647,8 +647,8 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) -bool IsGestureDetected(void); // Check if a gesture have been detected -int GetGestureType(void); // Get latest detected gesture +bool IsGestureDetected(int gesture); // Check if a gesture have been detected +int GetGestureDetected(void); // Get latest detected gesture void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags int GetTouchPointsCount(void); // Get touch points count -- cgit v1.2.3 From f12754b01f107913b722c80f0d957bdcdfb68c81 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Mon, 25 Apr 2016 18:40:19 -0700 Subject: quick fix Boolean errors --- src/audio.c | 20 ++++++++++---------- src/jar_xm.h | 3 ++- src/raylib.h | 3 ++- 3 files changed, 14 insertions(+), 12 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 93b83599..5953cd40 100644 --- a/src/audio.c +++ b/src/audio.c @@ -42,9 +42,6 @@ #include // Required for strcmp() #include // Used for .WAV loading -#define JAR_XM_IMPLEMENTATION -#include "jar_xm.h" // For playing .xm files - #if defined(AUDIO_STANDALONE) #include // Used for functions with variable number of parameters (TraceLog()) #else @@ -53,7 +50,10 @@ #endif //#define STB_VORBIS_HEADER_ONLY -#include "stb_vorbis.h" // OGG loading functions +#include "stb_vorbis.h" // OGG loading functions + +#define JAR_XM_IMPLEMENTATION +#include "jar_xm.h" // For playing .xm files //---------------------------------------------------------------------------------- // Defines and Macros @@ -576,11 +576,11 @@ void PlayMusicStream(char *fileName) currentMusic.loop = true; // only stereo/float is supported for xm - if(info.channels == 2 && !jar_xm_create_context_from_file(¤tMusic.chipctx, currentMusic.sampleRate, fileName)) + if(!jar_xm_create_context_from_file(¤tMusic.chipctx, currentMusic.sampleRate, fileName)) { - currentMusic.format = AL_FORMAT_STEREO_FLOAT32; - jar_xm_set_max_loop_count(currentMusic.chipctx, 0); //infinite number of loops - //currentMusic.totalSamplesLeft = ; // Unsure of how to calculate this + currentMusic.format = AL_FORMAT_STEREO16; // AL_FORMAT_STEREO_FLOAT32; + jar_xm_set_max_loop_count(currentMusic.chipctx, 0); // infinite number of loops + currentMusic.totalSamplesLeft = jar_xm_get_remaining_samples(currentMusic.chipctx); musicEnabled = true; } } @@ -712,8 +712,8 @@ static bool BufferMusicStream(ALuint buffer) { if (currentMusic.chipTune) { - jar_xm_generate_samples(currentMusic.chipctx, pcm + size, (MUSIC_BUFFER_SIZE - size) / 2); - streamedBytes = (MUSIC_BUFFER_SIZE - size)/2; // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. + jar_xm_generate_samples_16bit(currentMusic.chipctx, pcm + size, (MUSIC_BUFFER_SIZE - size) / 2); + streamedBytes = (MUSIC_BUFFER_SIZE - size) * 2; // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. } else { diff --git a/src/jar_xm.h b/src/jar_xm.h index 4fda948b..062b88da 100644 --- a/src/jar_xm.h +++ b/src/jar_xm.h @@ -59,10 +59,11 @@ #include #include #include -#include #include #include + + //------------------------------------------------------------------------------- #ifdef __cplusplus extern "C" { diff --git a/src/raylib.h b/src/raylib.h index 0c80b957..de157087 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -261,7 +261,8 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type -typedef enum { false, true } bool; +#include +//typedef enum { false, true } bool; #endif // byte type -- cgit v1.2.3 From f707c1ca468ef3243808ec87a0b6a891f6c6a130 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 27 Apr 2016 00:02:11 -0700 Subject: this should work --- src/audio.c | 2 +- src/raylib.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 2b8c6d48..0be257d9 100644 --- a/src/audio.c +++ b/src/audio.c @@ -820,7 +820,7 @@ void UpdateMusicStream(void) // Add refilled buffer to queue again... don't let the music stop! alSourceQueueBuffers(currentMusic.source, 1, &buffer); - if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data..."); + if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); processed--; } diff --git a/src/raylib.h b/src/raylib.h index de157087..699fbbdb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -261,8 +261,9 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type -#include -//typedef enum { false, true } bool; + #ifndef true + typedef enum { false, true } bool; + #endif #endif // byte type -- cgit v1.2.3 From 91f1f324c0ee3bd57ed778b39fd54d97330dba32 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Fri, 29 Apr 2016 23:00:12 -0700 Subject: First stage of audio API update Look over changes and give feedback please. --- src/audio.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/audio.h | 25 +++++++++++++++++++++++-- src/raylib.h | 19 +++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 0be257d9..ededf4ae 100644 --- a/src/audio.c +++ b/src/audio.c @@ -97,9 +97,10 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- +static bool mixChannelsActive_g[4]; // 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 Music currentMusic; // Current music loaded + // NOTE: Only one music file playing at a time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -164,6 +165,53 @@ void CloseAudioDevice(void) alcCloseDevice(device); } +// True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool AudioDeviceReady(void) +{ + ALCcontext *context = alcGetCurrentContext(); + if (context == NULL) return false; + else{ + ALCdevice *device = alcGetContextsDevice(context); + if (device == NULL) return false; + else return true; + } +} + +//---------------------------------------------------------------------------------- +// 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 mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. +// exmple usage is InitAudioContext(48000, 16, mixA, stereo); +AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels) +{ + if(!AudioDeviceReady()) InitAudioDevice(); + else StopMusicStream(); + + if(!mixChannelsActive_g[mixChannel]){ + AudioContext *ac = malloc(sizeof(AudioContext)); + ac->sampleRate = sampleRate; + ac->bitsPerSample = bitsPerSample; + ac->mixChannel = mixChannel; + ac->channels = channels; + mixChannelsActive_g[mixChannel] = true; + return ac; + } + return NULL; +} + +// Frees buffer in audio context +void CloseAudioContext(AudioContext *ctx) +{ + if(ctx){ + mixChannelsActive_g[ctx->mixChannel] = false; + free(ctx); + } +} + + + //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- diff --git a/src/audio.h b/src/audio.h index ed156532..401edc3e 100644 --- a/src/audio.h +++ b/src/audio.h @@ -41,8 +41,12 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type -typedef enum { false, true } bool; + #ifndef true + typedef enum { false, true } bool; + #endif #endif +typedef enum { silence, mono, stereo } channel_t; +typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio streams // Sound source type typedef struct Sound { @@ -59,6 +63,16 @@ 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 struct AudioContext { + unsigned short sampleRate; // default is 48000 + unsigned char bitsPerSample; // 16 is default + mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream + channel_t channels; // 1=mono, 2=stereo +} AudioContext; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -73,6 +87,13 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) +bool AudioDeviceReady(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 mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. +// exmple usage is InitAudioContext(48000, 16, mixA, stereo); +AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +void CloseAudioContext(AudioContext *ctx); // Frees audio context Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -92,7 +113,7 @@ void PauseMusicStream(void); // Pause music p void ResumeMusicStream(void); // Resume playing paused music bool MusicIsPlaying(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 GetMusicTimeLength(void); // Get music time length (in seconds) float GetMusicTimePlayed(void); // Get current music time played (in seconds) #ifdef __cplusplus diff --git a/src/raylib.h b/src/raylib.h index 699fbbdb..1721c009 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -265,6 +265,8 @@ typedef enum { false, true } bool; #endif #endif +typedef enum { silence, mono, stereo } channel_t; +typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio streams // byte type typedef unsigned char byte; @@ -446,6 +448,16 @@ 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 struct AudioContext { + unsigned short sampleRate; // default is 48000 + unsigned char bitsPerSample; // 16 is default + mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream + channel_t channels; // 1=mono, 2=stereo +} AudioContext; + // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -863,6 +875,13 @@ void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize); //------------------------------------------------------------------------------------ void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) +bool AudioDeviceReady(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 mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. +// exmple usage is InitAudioContext(48000, 16, mixA, stereo); +AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +void CloseAudioContext(AudioContext *ctx); // Frees audio context Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data -- cgit v1.2.3 From 5f1e8b827822ded6d24d71f75e1f1d0d301dbb2d Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Fri, 29 Apr 2016 23:43:21 -0700 Subject: hide struct from user Hiding the struct from user should protect from accidentally modifying the mix channel. This could cause serious errors down the road. --- src/audio.c | 37 +++++++++++++++++++++++++++---------- src/audio.h | 12 ++++-------- src/raylib.h | 12 ++++-------- 3 files changed, 35 insertions(+), 26 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index ededf4ae..2c0ed3de 100644 --- a/src/audio.c +++ b/src/audio.c @@ -90,6 +90,16 @@ typedef struct Music { 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. +typedef struct AudioContext_t { + unsigned short sampleRate; // default is 48000 + unsigned char bitsPerSample; // 16 is default + mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream + channel_t channels; // 1=mono, 2=stereo +} AudioContext_t; + #if defined(AUDIO_STANDALONE) typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; #endif @@ -97,10 +107,10 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static bool mixChannelsActive_g[4]; // What mix channels are currently active +static AudioContext_t* mixChannelsActive_g[4]; // 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 Music currentMusic; // Current music loaded + // NOTE: Only one music file playing at a time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -184,32 +194,39 @@ bool AudioDeviceReady(void) // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. // exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels) +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels) { if(!AudioDeviceReady()) InitAudioDevice(); else StopMusicStream(); if(!mixChannelsActive_g[mixChannel]){ - AudioContext *ac = malloc(sizeof(AudioContext)); + AudioContext_t *ac = malloc(sizeof(AudioContext_t)); ac->sampleRate = sampleRate; ac->bitsPerSample = bitsPerSample; ac->mixChannel = mixChannel; ac->channels = channels; - mixChannelsActive_g[mixChannel] = true; + mixChannelsActive_g[mixChannel] = ac; return ac; } return NULL; } // Frees buffer in audio context -void CloseAudioContext(AudioContext *ctx) +void CloseAudioContext(AudioContext ctx) { - if(ctx){ - mixChannelsActive_g[ctx->mixChannel] = false; - free(ctx); + AudioContext_t *context = (AudioContext_t*)ctx; + if(context){ + mixChannelsActive_g[context->mixChannel] = NULL; + free(context); } } +// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in +void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength) +{ + ; +} + //---------------------------------------------------------------------------------- diff --git a/src/audio.h b/src/audio.h index 401edc3e..cadf2bc1 100644 --- a/src/audio.h +++ b/src/audio.h @@ -66,12 +66,7 @@ typedef struct 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 struct AudioContext { - unsigned short sampleRate; // default is 48000 - unsigned char bitsPerSample; // 16 is default - mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream - channel_t channels; // 1=mono, 2=stereo -} AudioContext; +typedef void* AudioContext; #ifdef __cplusplus extern "C" { // Prevents name mangling of functions @@ -92,8 +87,9 @@ bool AudioDeviceReady(void); // True if call // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. // exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); -void CloseAudioContext(AudioContext *ctx); // Frees audio context +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +void CloseAudioContext(AudioContext ctx); // Frees audio context +void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data diff --git a/src/raylib.h b/src/raylib.h index 1721c009..5b7b34fd 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -451,12 +451,7 @@ typedef struct 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 struct AudioContext { - unsigned short sampleRate; // default is 48000 - unsigned char bitsPerSample; // 16 is default - mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream - channel_t channels; // 1=mono, 2=stereo -} AudioContext; +typedef void* AudioContext; // Texture formats // NOTE: Support depends on OpenGL version and platform @@ -880,8 +875,9 @@ bool AudioDeviceReady(void); // True if call // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. // exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext* InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); -void CloseAudioContext(AudioContext *ctx); // Frees audio context +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +void CloseAudioContext(AudioContext ctx); // Frees audio context +void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data -- cgit v1.2.3 From a1038f61b60ad21c936af783facc91fe01607be3 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Sat, 30 Apr 2016 15:41:46 -0700 Subject: BPS type added to ensure consistency --- src/audio.c | 42 ++++++++++++++++++++++++++++++++++++++---- src/audio.h | 7 ++++--- src/raylib.h | 7 ++++--- 3 files changed, 46 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 2c0ed3de..9d1aa014 100644 --- a/src/audio.c +++ b/src/audio.c @@ -95,9 +95,12 @@ typedef struct Music { // a dedicated mix channel. typedef struct AudioContext_t { unsigned short sampleRate; // default is 48000 - unsigned char bitsPerSample; // 16 is default + BPS bitsPerSample; // 16 is default mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream channel_t channels; // 1=mono, 2=stereo + ALenum alFormat; // openAL format specifier + ALuint alSource; // openAL source + ALuint alBuffer[2]; // openAL sample buffer } AudioContext_t; #if defined(AUDIO_STANDALONE) @@ -193,8 +196,8 @@ bool AudioDeviceReady(void) // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. -// exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels) +// exmple usage is InitAudioContext(48000, sixteenBPS, mixA, stereo); +AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels) { if(!AudioDeviceReady()) InitAudioDevice(); else StopMusicStream(); @@ -206,6 +209,30 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSa ac->mixChannel = mixChannel; ac->channels = channels; mixChannelsActive_g[mixChannel] = ac; + + // setup openAL format + if (channels == mono) + { + if (bitsPerSample == eightBPS ) ac->alFormat = AL_FORMAT_MONO8; + else if (bitsPerSample == sixteenBPS) ac->alFormat = AL_FORMAT_MONO16; + } + else if (channels == stereo) + { + if (bitsPerSample == eightBPS ) ac->alFormat = AL_FORMAT_STEREO8; + else if (bitsPerSample == sixteenBPS) ac->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); + + // Create Buffer + alGenBuffers(2, &ac->alBuffer); + + return ac; } return NULL; @@ -216,15 +243,22 @@ void CloseAudioContext(AudioContext ctx) { AudioContext_t *context = (AudioContext_t*)ctx; if(context){ + alDeleteSources(1, &context->alSource); + alDeleteBuffers(2, &context->alBuffer); mixChannelsActive_g[context->mixChannel] = NULL; free(context); + ctx = NULL; } } // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength) { - ; + AudioContext_t *context = (AudioContext_t*)ctx; + if(!musicEnabled && context && mixChannelsActive_g[context->mixChannel] == context) + { + ; + } } diff --git a/src/audio.h b/src/audio.h index cadf2bc1..28fe4b3c 100644 --- a/src/audio.h +++ b/src/audio.h @@ -45,8 +45,9 @@ typedef enum { false, true } bool; #endif #endif -typedef enum { silence, mono, stereo } channel_t; -typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio streams +typedef enum { silence, mono, stereo } channel_t; // number of audio sources per sample +typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio samples +typedef enum { eightBPS, sixteenBPS } BPS; // Either 8 or 16 bit quality samples // Sound source type typedef struct Sound { @@ -87,7 +88,7 @@ bool AudioDeviceReady(void); // True if call // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. // exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels); void CloseAudioContext(AudioContext ctx); // Frees audio context void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in diff --git a/src/raylib.h b/src/raylib.h index 5b7b34fd..83f58a51 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -265,8 +265,9 @@ typedef enum { false, true } bool; #endif #endif -typedef enum { silence, mono, stereo } channel_t; -typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio streams +typedef enum { silence, mono, stereo } channel_t; // number of audio sources per sample +typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio samples +typedef enum { eightBPS, sixteenBPS } BPS; // Either 8 or 16 bit quality samples // byte type typedef unsigned char byte; @@ -875,7 +876,7 @@ bool AudioDeviceReady(void); // True if call // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing // The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. // exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, mix_t mixChannel, channel_t channels); +AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels); void CloseAudioContext(AudioContext ctx); // Frees audio context void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in -- cgit v1.2.3 From 34e5fcf47e99deecc9954fd848130c61119e2e93 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Sat, 30 Apr 2016 16:05:43 -0700 Subject: removed enums --- src/audio.c | 36 +++++++++++++++++++----------------- src/audio.h | 13 +++++-------- src/raylib.h | 13 +++++-------- 3 files changed, 29 insertions(+), 33 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 9d1aa014..8a8ca4ef 100644 --- a/src/audio.c +++ b/src/audio.c @@ -59,6 +59,7 @@ // Defines and Macros //---------------------------------------------------------------------------------- #define MUSIC_STREAM_BUFFERS 2 +#define MAX_AUDIO_CONTEXTS 4 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) // NOTE: On RPI and Android should be lower to avoid frame-stalls @@ -95,9 +96,9 @@ typedef struct Music { // a dedicated mix channel. typedef struct AudioContext_t { unsigned short sampleRate; // default is 48000 - BPS bitsPerSample; // 16 is default - mix_t mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream - channel_t channels; // 1=mono, 2=stereo + unsigned char bitsPerSample; // 16 is default + unsigned char mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream + unsigned char channels; // 1=mono, 2=stereo ALenum alFormat; // openAL format specifier ALuint alSource; // openAL source ALuint alBuffer[2]; // openAL sample buffer @@ -110,10 +111,10 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static AudioContext_t* mixChannelsActive_g[4]; // What mix channels are currently active +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 Music currentMusic; // Current music loaded + // NOTE: Only one music file playing at a time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -179,7 +180,7 @@ void CloseAudioDevice(void) } // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet -bool AudioDeviceReady(void) +bool IsAudioDeviceReady(void) { ALCcontext *context = alcGetCurrentContext(); if (context == NULL) return false; @@ -195,11 +196,12 @@ bool AudioDeviceReady(void) //---------------------------------------------------------------------------------- // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing -// The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. -// exmple usage is InitAudioContext(48000, sixteenBPS, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels) +// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time. +// exmple usage is InitAudioContext(48000, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels) { - if(!AudioDeviceReady()) InitAudioDevice(); + if(mixChannel > MAX_AUDIO_CONTEXTS) return NULL; + if(!IsAudioDeviceReady()) InitAudioDevice(); else StopMusicStream(); if(!mixChannelsActive_g[mixChannel]){ @@ -211,15 +213,15 @@ AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_ mixChannelsActive_g[mixChannel] = ac; // setup openAL format - if (channels == mono) + if (channels == 1) { - if (bitsPerSample == eightBPS ) ac->alFormat = AL_FORMAT_MONO8; - else if (bitsPerSample == sixteenBPS) ac->alFormat = AL_FORMAT_MONO16; + if (bitsPerSample == 8 ) ac->alFormat = AL_FORMAT_MONO8; + else if (bitsPerSample == 16) ac->alFormat = AL_FORMAT_MONO16; } - else if (channels == stereo) + else if (channels == 2) { - if (bitsPerSample == eightBPS ) ac->alFormat = AL_FORMAT_STEREO8; - else if (bitsPerSample == sixteenBPS) ac->alFormat = AL_FORMAT_STEREO16; + if (bitsPerSample == 8 ) ac->alFormat = AL_FORMAT_STEREO8; + else if (bitsPerSample == 16) ac->alFormat = AL_FORMAT_STEREO16; } // Create an audio source diff --git a/src/audio.h b/src/audio.h index 28fe4b3c..9c681044 100644 --- a/src/audio.h +++ b/src/audio.h @@ -45,9 +45,6 @@ typedef enum { false, true } bool; #endif #endif -typedef enum { silence, mono, stereo } channel_t; // number of audio sources per sample -typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio samples -typedef enum { eightBPS, sixteenBPS } BPS; // Either 8 or 16 bit quality samples // Sound source type typedef struct Sound { @@ -83,13 +80,13 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool AudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing -// The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. -// exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels); -void CloseAudioContext(AudioContext ctx); // Frees audio context +// 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, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels); +void CloseAudioContext(AudioContext ctx); // Frees audio context void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in Sound LoadSound(char *fileName); // Load sound to memory diff --git a/src/raylib.h b/src/raylib.h index 83f58a51..8390d176 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -265,9 +265,6 @@ typedef enum { false, true } bool; #endif #endif -typedef enum { silence, mono, stereo } channel_t; // number of audio sources per sample -typedef enum { mixA, mixB, mixC, mixD } mix_t; // Used for mixing/muxing up to four diferent audio samples -typedef enum { eightBPS, sixteenBPS } BPS; // Either 8 or 16 bit quality samples // byte type typedef unsigned char byte; @@ -871,13 +868,13 @@ void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize); //------------------------------------------------------------------------------------ void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool AudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet // Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing -// The mix_t is what mix channel you want to operate on, mixA->mixD are the ones available. Each mix channel can only be used one at a time. -// exmple usage is InitAudioContext(48000, 16, mixA, stereo); -AudioContext InitAudioContext(unsigned short sampleRate, BPS bitsPerSample, mix_t mixChannel, channel_t channels); -void CloseAudioContext(AudioContext ctx); // Frees audio context +// 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, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels); +void CloseAudioContext(AudioContext ctx); // Frees audio context void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in Sound LoadSound(char *fileName); // Load sound to memory -- cgit v1.2.3 From 0e6d1cb272435c670a991169f413c98516dce15d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 May 2016 00:16:32 +0200 Subject: Working on materials system... --- src/raylib.h | 21 +++++++++------------ src/rlgl.c | 14 +++++--------- 2 files changed, 14 insertions(+), 21 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 8390d176..8af13cb4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -355,7 +355,7 @@ typedef struct Camera { // Camera2D type, defines a 2d camera typedef struct Camera2D { Vector2 offset; // Camera offset (displacement from target) - Vector2 target; // Camera target (for rotation and zoom) + Vector2 target; // Camera target (rotation and zoom origin) float rotation; // Camera rotation in degrees float zoom; // Camera zoom (scaling), should be 1.0f by default } Camera2D; @@ -386,16 +386,17 @@ typedef struct Mesh { typedef struct Shader { unsigned int id; // Shader program id - // Variable attributes + // Variable attributes locations int vertexLoc; // Vertex attribute location point (vertex shader) int texcoordLoc; // Texcoord attribute location point (vertex shader) int normalLoc; // Normal attribute location point (vertex shader) int colorLoc; // Color attibute location point (vertex shader) - // Uniforms + // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int tintColorLoc; // Color uniform location point (fragment shader) + // Texture map locations int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) int mapNormalLoc; // Normal map texture uniform location point (fragment shader) int mapSpecularLoc; // Specular map texture uniform location point (fragment shader) @@ -832,18 +833,14 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shaders strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory -void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw +void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetModelShader(Model *model, Shader shader); // Link a shader to a model -int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) -void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -//void SetShaderMapDiffuse(Shader *shader, Texture2D texture); // Default diffuse shader map texture assignment -//void SetShaderMapNormal(Shader *shader, const char *uniformName, Texture2D texture); // Normal map texture shader assignment -//void SetShaderMapSpecular(Shader *shader, const char *uniformName, Texture2D texture); // Specular map texture shader assignment -//void SetShaderMap(Shader *shader, int mapLocation, Texture2D texture, int textureUnit); // TODO: Generic shader map assignment +int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location +void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) +void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) diff --git a/src/rlgl.c b/src/rlgl.c index 5b181a86..b1b020ec 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1350,14 +1350,14 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); glUniform1i(model.material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 - if (model.material.texNormal.id != 0) + if ((model.material.texNormal.id != 0) && (model.material.shader.mapNormalLoc != -1)) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, model.material.texNormal.id); glUniform1i(model.material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 } - if (model.material.texSpecular.id != 0) + if ((model.material.texSpecular.id != 0) && (model.material.shader.mapSpecularLoc != -1)) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, model.material.texSpecular.id); @@ -2125,17 +2125,13 @@ Shader LoadShader(char *vsFileName, char *fsFileName) // After shader loading, we try to load default location names if (shader.id != 0) LoadDefaultShaderLocations(&shader); - else - { - TraceLog(WARNING, "Custom shader could not be loaded"); - shader = defaultShader; - } // Shader strings must be freed free(vShaderStr); free(fShaderStr); } - else + + if (shader.id == 0) { TraceLog(WARNING, "Custom shader could not be loaded"); shader = defaultShader; @@ -2494,7 +2490,7 @@ static Shader LoadDefaultShader(void) if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Default shader loaded successfully", shader.id); else TraceLog(WARNING, "[SHDR ID %i] Default shader could not be loaded", shader.id); - LoadDefaultShaderLocations(&shader); + if (shader.id != 0) LoadDefaultShaderLocations(&shader); return shader; } -- cgit v1.2.3 From fa98289ddb5fc190a100249c667d5e9814f4d864 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 2 May 2016 00:37:33 +0200 Subject: Added 2D camera mode functions Removed BeginDrawingEx() Added Begin2dMode() and End2dMode() --- src/core.c | 44 +++++++++++++++++++++++++++----------------- src/raylib.h | 3 ++- 2 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 7b1d5960..dd904692 100644 --- a/src/core.c +++ b/src/core.c @@ -524,23 +524,6 @@ void BeginDrawing(void) // NOTE: Not required with OpenGL 3.3+ } -// Setup drawing canvas with 2d camera -void BeginDrawingEx(Camera2D camera) -{ - BeginDrawing(); - - // Camera rotation and scaling is always relative to target - Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); - Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); - Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); - - Matrix matTranslation = MatrixTranslate(camera.offset.x + camera.target.x, camera.offset.y + camera.target.y, 0.0f); - - Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); - - rlMultMatrixf(MatrixToFloat(matTransform)); -} - // End canvas drawing and Swap Buffers (Double Buffering) void EndDrawing(void) { @@ -569,6 +552,33 @@ void EndDrawing(void) } } +// Initialize 2D mode with custom camera +void Begin2dMode(Camera2D camera) +{ + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + rlLoadIdentity(); // Reset current matrix (MODELVIEW) + + // Camera rotation and scaling is always relative to target + Matrix matOrigin = MatrixTranslate(-camera.target.x, -camera.target.y, 0.0f); + Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); + Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); + + Matrix matTranslation = MatrixTranslate(camera.offset.x + camera.target.x, camera.offset.y + camera.target.y, 0.0f); + + Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); + + rlMultMatrixf(MatrixToFloat(matTransform)); +} + +// Ends 2D mode custom camera usage +void End2dMode(void) +{ + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + rlLoadIdentity(); // Reset current matrix (MODELVIEW) +} + // Initializes 3D mode for drawing (Camera setup) void Begin3dMode(Camera camera) { diff --git a/src/raylib.h b/src/raylib.h index 8af13cb4..337b9813 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -576,9 +576,10 @@ void DisableCursor(void); // Disables cursor void ClearBackground(Color color); // Sets Background Color void BeginDrawing(void); // Setup drawing canvas to start drawing -void BeginDrawingEx(Camera2D camera); // Setup drawing canvas with 2d camera void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) +void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera +void End2dMode(void); // Ends 2D mode custom camera usage void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing -- cgit v1.2.3 From a2a3d3aeb60dd117b02fc8c7c85ec428175a5f83 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Sun, 1 May 2016 18:53:40 -0700 Subject: new silence generator --- src/audio.c | 74 ++++++++++++++++++++++++++++++++++++++++++------------------ src/audio.h | 7 +++--- src/raylib.h | 7 +++--- 3 files changed, 60 insertions(+), 28 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 8a8ca4ef..7100a6c1 100644 --- a/src/audio.c +++ b/src/audio.c @@ -37,6 +37,7 @@ #include "AL/al.h" // OpenAL basic header #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) +#include "AL/alext.h" // extensions for other format types #include // Declares malloc() and free() for memory management #include // Required for strcmp() @@ -93,12 +94,10 @@ typedef struct 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. +// a dedicated mix channel. All audio is 32bit floating point in stereo. typedef struct AudioContext_t { unsigned short sampleRate; // default is 48000 - unsigned char bitsPerSample; // 16 is default unsigned char mixChannel; // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream - unsigned char channels; // 1=mono, 2=stereo ALenum alFormat; // openAL format specifier ALuint alSource; // openAL source ALuint alBuffer[2]; // openAL sample buffer @@ -126,6 +125,9 @@ 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 +// fill buffer with zeros +static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer); + #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) @@ -197,8 +199,9 @@ bool IsAudioDeviceReady(void) // 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, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels) +// exmple usage is InitAudioContext(48000, 0); // mixchannel 1, 48khz +// all samples are floating point stereo by default +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel) { if(mixChannel > MAX_AUDIO_CONTEXTS) return NULL; if(!IsAudioDeviceReady()) InitAudioDevice(); @@ -207,22 +210,11 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSa if(!mixChannelsActive_g[mixChannel]){ AudioContext_t *ac = malloc(sizeof(AudioContext_t)); ac->sampleRate = sampleRate; - ac->bitsPerSample = bitsPerSample; ac->mixChannel = mixChannel; - ac->channels = channels; mixChannelsActive_g[mixChannel] = ac; // setup openAL format - if (channels == 1) - { - if (bitsPerSample == 8 ) ac->alFormat = AL_FORMAT_MONO8; - else if (bitsPerSample == 16) ac->alFormat = AL_FORMAT_MONO16; - } - else if (channels == 2) - { - if (bitsPerSample == 8 ) ac->alFormat = AL_FORMAT_STEREO8; - else if (bitsPerSample == 16) ac->alFormat = AL_FORMAT_STEREO16; - } + ac->alFormat = AL_FORMAT_STEREO_FLOAT32; // Create an audio source alGenSources(1, &ac->alSource); @@ -232,7 +224,14 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSa alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0); // Create Buffer - alGenBuffers(2, &ac->alBuffer); + alGenBuffers(2, ac->alBuffer); + + //fill buffers + FillAlBufferWithSilence(ac, ac->alBuffer[0]); + FillAlBufferWithSilence(ac, ac->alBuffer[1]); + alSourceQueueBuffers(ac->alSource, 2, ac->alBuffer); + alSourcei(ac->alSource, AL_LOOPING, AL_FALSE); // this could cause errors + alSourcePlay(ac->alSource); return ac; @@ -245,8 +244,20 @@ void CloseAudioContext(AudioContext ctx) { AudioContext_t *context = (AudioContext_t*)ctx; if(context){ + alSourceStop(context->alSource); + + //flush out all queued buffers + ALuint buffer = 0; + int queued = 0; + alGetSourcei(context->alSource, AL_BUFFERS_QUEUED, &queued); + while (queued > 0) + { + alSourceUnqueueBuffers(context->alSource, 1, &buffer); + queued--; + } + alDeleteSources(1, &context->alSource); - alDeleteBuffers(2, &context->alBuffer); + alDeleteBuffers(2, context->alBuffer); mixChannelsActive_g[context->mixChannel] = NULL; free(context); ctx = NULL; @@ -254,15 +265,34 @@ void CloseAudioContext(AudioContext ctx) } // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in -void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength) +// Call "UpdateAudioContext(ctx, NULL, 0)" every game tick if you want to pause the audio +void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) { AudioContext_t *context = (AudioContext_t*)ctx; - if(!musicEnabled && context && mixChannelsActive_g[context->mixChannel] == context) + if (context && mixChannelsActive_g[context->mixChannel] == context) { - ; + ALint processed = 0; + ALuint buffer = 0; + alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any) + + if (!data || !dataLength)// play silence + while (processed > 0) + { + alSourceUnqueueBuffers(context->alSource, 1, &buffer); + FillAlBufferWithSilence(context, buffer); + alSourceQueueBuffers(context->alSource, 1, &buffer); + processed--; + } } } +// fill buffer with zeros +static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer) +{ + float pcm[MUSIC_BUFFER_SIZE] = {0.f}; + alBufferData(buffer, ac->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), ac->sampleRate); +} + //---------------------------------------------------------------------------------- diff --git a/src/audio.h b/src/audio.h index 9c681044..9037a843 100644 --- a/src/audio.h +++ b/src/audio.h @@ -84,10 +84,11 @@ bool IsAudioDeviceReady(void); // True if call // 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, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels); +// exmple usage is InitAudioContext(48000, 0); // mixchannel 1, 48khz +// all samples are floating point stereo by default +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel); void CloseAudioContext(AudioContext ctx); // Frees audio context -void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in +void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 diff --git a/src/raylib.h b/src/raylib.h index 8390d176..f4ea875e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -872,10 +872,11 @@ bool IsAudioDeviceReady(void); // True if call // 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, 16, 0, 2); // stereo, mixchannel 1, 16bit, 48khz -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char bitsPerSample, unsigned char mixChannel, unsigned char channels); +// exmple usage is InitAudioContext(48000, 0); // mixchannel 1, 48khz +// all samples are floating point stereo by default +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel); void CloseAudioContext(AudioContext ctx); // Frees audio context -void UpdateAudioContext(AudioContext ctx, void *data, unsigned short *dataLength); // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in +void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 -- cgit v1.2.3 From 790bc7280685d714ddce3e1ee0afa11cee0c5e06 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Sun, 1 May 2016 23:07:02 -0700 Subject: bool return for failed update --- src/audio.c | 9 +++++++-- src/audio.h | 2 +- src/raylib.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 7100a6c1..7b42b089 100644 --- a/src/audio.c +++ b/src/audio.c @@ -256,6 +256,7 @@ void CloseAudioContext(AudioContext ctx) queued--; } + //delete source and buffers alDeleteSources(1, &context->alSource); alDeleteBuffers(2, context->alBuffer); mixChannelsActive_g[context->mixChannel] = NULL; @@ -266,7 +267,8 @@ void CloseAudioContext(AudioContext ctx) // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in // Call "UpdateAudioContext(ctx, NULL, 0)" every game tick if you want to pause the audio -void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) +// Returns true if data was pushed onto queue, otherwise if queue is full then no data is added and false is returned +bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) { AudioContext_t *context = (AudioContext_t*)ctx; if (context && mixChannelsActive_g[context->mixChannel] == context) @@ -274,7 +276,9 @@ void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength ALint processed = 0; ALuint buffer = 0; alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any) - + + if(!processed) return false;//nothing to process, queue is still full + if (!data || !dataLength)// play silence while (processed > 0) { @@ -283,6 +287,7 @@ void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength alSourceQueueBuffers(context->alSource, 1, &buffer); processed--; } + return true; } } diff --git a/src/audio.h b/src/audio.h index 9037a843..4a198c59 100644 --- a/src/audio.h +++ b/src/audio.h @@ -88,7 +88,7 @@ bool IsAudioDeviceReady(void); // True if call // all samples are floating point stereo by default AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel); void CloseAudioContext(AudioContext ctx); // Frees audio context -void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 diff --git a/src/raylib.h b/src/raylib.h index ade581d3..9c5a8258 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -874,7 +874,7 @@ bool IsAudioDeviceReady(void); // True if call // all samples are floating point stereo by default AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel); void CloseAudioContext(AudioContext ctx); // Frees audio context -void UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 -- cgit v1.2.3 From 9ef0240e99e7e6a626fdb8fee4f8a81eea21f3e2 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Mon, 2 May 2016 01:24:24 -0700 Subject: resamples added Ease of use considered in api and channels are more convenient as unsigned char type. --- src/audio.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ src/audio.h | 6 +++--- src/raylib.h | 6 +++--- 3 files changed, 49 insertions(+), 12 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 7b42b089..d935b6c7 100644 --- a/src/audio.c +++ b/src/audio.c @@ -97,6 +97,7 @@ typedef struct Music { // a dedicated mix channel. All audio is 32bit floating point in stereo. typedef struct AudioContext_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 ALenum alFormat; // openAL format specifier ALuint alSource; // openAL source @@ -125,8 +126,9 @@ 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 -// fill buffer with zeros -static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer); +static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer);// fill buffer with zeros +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 #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename @@ -199,9 +201,9 @@ bool IsAudioDeviceReady(void) // 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); // mixchannel 1, 48khz -// all samples are floating point stereo by default -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel) +// exmple usage is InitAudioContext(48000, 0, 2); // mixchannel 1, 48khz, stereo +// all samples are floating point by default +AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels) { if(mixChannel > MAX_AUDIO_CONTEXTS) return NULL; if(!IsAudioDeviceReady()) InitAudioDevice(); @@ -210,11 +212,15 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChanne if(!mixChannelsActive_g[mixChannel]){ AudioContext_t *ac = malloc(sizeof(AudioContext_t)); ac->sampleRate = sampleRate; + ac->channels = channels; ac->mixChannel = mixChannel; mixChannelsActive_g[mixChannel] = ac; // setup openAL format - ac->alFormat = AL_FORMAT_STEREO_FLOAT32; + if(channels == 1) + ac->alFormat = AL_FORMAT_MONO_FLOAT32; + else + ac->alFormat = AL_FORMAT_STEREO_FLOAT32; // Create an audio source alGenSources(1, &ac->alSource); @@ -289,6 +295,7 @@ bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength } return true; } + return false; } // fill buffer with zeros @@ -298,6 +305,36 @@ static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer) alBufferData(buffer, ac->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), ac->sampleRate); } +// example usage: +// short sh[3] = {1,2,3};float fl[3]; +// ResampleShortToFloat(sh,fl,3); +static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len) +{ + int x; + for(x=0;x Date: Mon, 2 May 2016 14:37:00 -0700 Subject: number remaining buffer transfer for updateAudioContext updateAudioContext is almost done --- src/audio.c | 39 +++++++++++++++++++++++++++++++-------- src/audio.h | 2 +- src/raylib.h | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index d935b6c7..ff4f2858 100644 --- a/src/audio.c +++ b/src/audio.c @@ -273,17 +273,20 @@ void CloseAudioContext(AudioContext ctx) // Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in // Call "UpdateAudioContext(ctx, NULL, 0)" every game tick if you want to pause the audio -// Returns true if data was pushed onto queue, otherwise if queue is full then no data is added and false is returned -bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) +// Returns number of floats that where processed +unsigned short UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) { + unsigned short numberProcessed = 0; + unsigned short numberRemaining = dataLength; AudioContext_t *context = (AudioContext_t*)ctx; + if (context && mixChannelsActive_g[context->mixChannel] == context) { ALint processed = 0; ALuint buffer = 0; alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any) - if(!processed) return false;//nothing to process, queue is still full + if(!processed) return 0;//nothing to process, queue is still full if (!data || !dataLength)// play silence while (processed > 0) @@ -292,17 +295,37 @@ bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength FillAlBufferWithSilence(context, buffer); alSourceQueueBuffers(context->alSource, 1, &buffer); processed--; + numberProcessed+=MUSIC_BUFFER_SIZE; + } + if(numberRemaining)// buffer data stream in increments of MUSIC_BUFFER_SIZE + while (processed > 0) + { + alSourceUnqueueBuffers(context->alSource, 1, &buffer); + if(numberRemaining >= MUSIC_BUFFER_SIZE) + { + float pcm[MUSIC_BUFFER_SIZE]; + memcpy(pcm, &data[numberProcessed], MUSIC_BUFFER_SIZE); + alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), context->sampleRate); + alSourceQueueBuffers(context->alSource, 1, &buffer); + numberProcessed+=MUSIC_BUFFER_SIZE; + numberRemaining-=MUSIC_BUFFER_SIZE; + } + else // less than MUSIC_BUFFER_SIZE number of samples left to buffer, the remaining data is padded with zeros + { + float pcm[MUSIC_BUFFER_SIZE] = {0.f}; // pad with zeros + } + + processed--; } - return true; } - return false; + return numberProcessed; } // fill buffer with zeros -static void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer) +static void FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer) { float pcm[MUSIC_BUFFER_SIZE] = {0.f}; - alBufferData(buffer, ac->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), ac->sampleRate); + alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), context->sampleRate); } // example usage: @@ -322,7 +345,7 @@ static void ResampleShortToFloat(short *shorts, float *floats, unsigned short le // example usage: // char ch[3] = {1,2,3};float fl[3]; -// ResampleShortToFloat(ch,fl,3); +// ResampleByteToFloat(ch,fl,3); static void ResampleByteToFloat(char *chars, float *floats, unsigned short len) { int x; diff --git a/src/audio.h b/src/audio.h index d723ef1b..2b36b3f0 100644 --- a/src/audio.h +++ b/src/audio.h @@ -88,7 +88,7 @@ bool IsAudioDeviceReady(void); // True if call // all samples are floating point by default AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels); void CloseAudioContext(AudioContext ctx); // Frees audio context -bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +unsigned short UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 diff --git a/src/raylib.h b/src/raylib.h index 3fa20116..5c727b61 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -874,7 +874,7 @@ bool IsAudioDeviceReady(void); // True if call // all samples are floating point by default AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels); void CloseAudioContext(AudioContext ctx); // Frees audio context -bool UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +unsigned short UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength); // 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 -- cgit v1.2.3 From 9d09ada33b26704a7f5d285d2f0d115e41df41bf Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Mon, 2 May 2016 21:59:55 -0700 Subject: new boolean floatingPoint option Now floating point is either on or off. This simplifies the use of 16bit vs float. --- src/audio.c | 132 +++++++++++++++++++++++++++++++++++++---------------------- src/audio.h | 7 ++-- src/raylib.h | 7 ++-- 3 files changed, 88 insertions(+), 58 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index ff4f2858..dc063796 100644 --- a/src/audio.c +++ b/src/audio.c @@ -59,15 +59,17 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MUSIC_STREAM_BUFFERS 2 -#define MAX_AUDIO_CONTEXTS 4 +#define MAX_STREAM_BUFFERS 2 +#define MAX_AUDIO_CONTEXTS 4 // Number of open AL sources #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) // NOTE: On RPI and Android should be lower to avoid frame-stalls - #define MUSIC_BUFFER_SIZE 4096*2 // PCM data buffer (short) - 16Kb (RPI) + #define MUSIC_BUFFER_SIZE_SHORT 4096*2 // PCM data buffer (short) - 16Kb (RPI) + #define MUSIC_BUFFER_SIZE_FLOAT 4096 // PCM data buffer (float) - 16Kb (RPI) #else // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care... - #define MUSIC_BUFFER_SIZE 4096*8 // PCM data buffer (short) - 64Kb + #define MUSIC_BUFFER_SIZE_SHORT 4096*8 // PCM data buffer (short) - 64Kb + #define MUSIC_BUFFER_SIZE_FLOAT 4096*4 // PCM data buffer (float) - 64Kb #endif //---------------------------------------------------------------------------------- @@ -80,7 +82,7 @@ typedef struct Music { stb_vorbis *stream; jar_xm_context_t *chipctx; // Stores jar_xm context - ALuint buffers[MUSIC_STREAM_BUFFERS]; + ALuint buffers[MAX_STREAM_BUFFERS]; ALuint source; ALenum format; @@ -96,12 +98,13 @@ typedef struct Music { // no more than 4 concurrent audio contexts in use. This is due to each active context being tied to // a dedicated mix channel. All audio is 32bit floating point in stereo. typedef struct AudioContext_t { - unsigned short sampleRate; // default is 48000 - unsigned 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 - ALenum alFormat; // openAL format specifier - ALuint alSource; // openAL source - ALuint alBuffer[2]; // openAL sample buffer + 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 + ALenum alFormat; // openAL format specifier + ALuint alSource; // openAL source + ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer } AudioContext_t; #if defined(AUDIO_STANDALONE) @@ -126,7 +129,7 @@ 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 void FillAlBufferWithSilence(AudioContext_t *ac, ALuint buffer);// fill buffer with zeros +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 @@ -201,11 +204,10 @@ bool IsAudioDeviceReady(void) // 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); // mixchannel 1, 48khz, stereo -// all samples are floating point by default -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels) +// 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) { - if(mixChannel > MAX_AUDIO_CONTEXTS) return NULL; + if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL; if(!IsAudioDeviceReady()) InitAudioDevice(); else StopMusicStream(); @@ -214,13 +216,24 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChanne ac->sampleRate = sampleRate; ac->channels = channels; ac->mixChannel = mixChannel; + ac->floatingPoint = floatingPoint; mixChannelsActive_g[mixChannel] = ac; // setup openAL format if(channels == 1) - ac->alFormat = AL_FORMAT_MONO_FLOAT32; - else - ac->alFormat = AL_FORMAT_STEREO_FLOAT32; + { + if(floatingPoint) + ac->alFormat = AL_FORMAT_MONO_FLOAT32; + else + ac->alFormat = AL_FORMAT_MONO16; + } + else if(channels == 2) + { + if(floatingPoint) + ac->alFormat = AL_FORMAT_STEREO_FLOAT32; + else + ac->alFormat = AL_FORMAT_STEREO16; + } // Create an audio source alGenSources(1, &ac->alSource); @@ -230,16 +243,17 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChanne alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0); // Create Buffer - alGenBuffers(2, ac->alBuffer); + alGenBuffers(MAX_STREAM_BUFFERS, ac->alBuffer); //fill buffers - FillAlBufferWithSilence(ac, ac->alBuffer[0]); - FillAlBufferWithSilence(ac, ac->alBuffer[1]); - alSourceQueueBuffers(ac->alSource, 2, ac->alBuffer); + int x; + for(x=0;xalBuffer[x]); + + alSourceQueueBuffers(ac->alSource, MAX_STREAM_BUFFERS, ac->alBuffer); alSourcei(ac->alSource, AL_LOOPING, AL_FALSE); // this could cause errors alSourcePlay(ac->alSource); - return ac; } return NULL; @@ -264,20 +278,22 @@ void CloseAudioContext(AudioContext ctx) //delete source and buffers alDeleteSources(1, &context->alSource); - alDeleteBuffers(2, context->alBuffer); + alDeleteBuffers(MAX_STREAM_BUFFERS, context->alBuffer); mixChannelsActive_g[context->mixChannel] = NULL; free(context); ctx = NULL; } } -// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in -// Call "UpdateAudioContext(ctx, NULL, 0)" every game tick if you want to pause the audio -// Returns number of floats that where processed -unsigned short UpdateAudioContext(AudioContext ctx, float *data, unsigned short dataLength) +// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in. +// Call "UpdateAudioContext(ctx, NULL, 0)" every game tick if you want to pause the audio. +// @Returns number of samples that where processed. +// All data streams should be of a length that is evenly divisible by MUSIC_BUFFER_SIZE, +// otherwise the remaining data will not be pushed. +unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements) { unsigned short numberProcessed = 0; - unsigned short numberRemaining = dataLength; + unsigned short numberRemaining = numberElements; AudioContext_t *context = (AudioContext_t*)ctx; if (context && mixChannelsActive_g[context->mixChannel] == context) @@ -288,44 +304,60 @@ unsigned short UpdateAudioContext(AudioContext ctx, float *data, unsigned short if(!processed) return 0;//nothing to process, queue is still full - if (!data || !dataLength)// play silence + if (!data || !numberElements)// play silence + { while (processed > 0) { alSourceUnqueueBuffers(context->alSource, 1, &buffer); - FillAlBufferWithSilence(context, buffer); + numberProcessed += FillAlBufferWithSilence(context, buffer); alSourceQueueBuffers(context->alSource, 1, &buffer); processed--; - numberProcessed+=MUSIC_BUFFER_SIZE; } + } if(numberRemaining)// buffer data stream in increments of MUSIC_BUFFER_SIZE + { while (processed > 0) { - alSourceUnqueueBuffers(context->alSource, 1, &buffer); - if(numberRemaining >= MUSIC_BUFFER_SIZE) + if(context->floatingPoint && numberRemaining >= MUSIC_BUFFER_SIZE_FLOAT) // process float buffers { - float pcm[MUSIC_BUFFER_SIZE]; - memcpy(pcm, &data[numberProcessed], MUSIC_BUFFER_SIZE); - alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), context->sampleRate); + float *ptr = (float*)data; + alSourceUnqueueBuffers(context->alSource, 1, &buffer); + alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate); alSourceQueueBuffers(context->alSource, 1, &buffer); - numberProcessed+=MUSIC_BUFFER_SIZE; - numberRemaining-=MUSIC_BUFFER_SIZE; + numberProcessed+=MUSIC_BUFFER_SIZE_FLOAT; + numberRemaining-=MUSIC_BUFFER_SIZE_FLOAT; } - else // less than MUSIC_BUFFER_SIZE number of samples left to buffer, the remaining data is padded with zeros + else if(!context->floatingPoint && numberRemaining >= MUSIC_BUFFER_SIZE_SHORT) // process short buffers { - float pcm[MUSIC_BUFFER_SIZE] = {0.f}; // pad with zeros + short *ptr = (short*)data; + alSourceUnqueueBuffers(context->alSource, 1, &buffer); + alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_SHORT*sizeof(short), context->sampleRate); + alSourceQueueBuffers(context->alSource, 1, &buffer); + numberProcessed+=MUSIC_BUFFER_SIZE_SHORT; + numberRemaining-=MUSIC_BUFFER_SIZE_SHORT; } processed--; } + } } return numberProcessed; } -// fill buffer with zeros -static void FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer) +// fill buffer with zeros, returns number processed +static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer) { - float pcm[MUSIC_BUFFER_SIZE] = {0.f}; - alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE*sizeof(float), context->sampleRate); + if(context->floatingPoint){ + float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f}; + alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->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); + return MUSIC_BUFFER_SIZE_SHORT; + } } // example usage: @@ -920,7 +952,7 @@ float GetMusicTimePlayed(void) // Fill music buffers with new data from music stream static bool BufferMusicStream(ALuint buffer) { - short pcm[MUSIC_BUFFER_SIZE]; + short pcm[MUSIC_BUFFER_SIZE_SHORT]; int size = 0; // Total size of data steamed (in bytes) int streamedBytes = 0; // samples of data obtained, channels are not included in calculation @@ -930,15 +962,15 @@ static bool BufferMusicStream(ALuint buffer) { 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 / 2; + int readlen = MUSIC_BUFFER_SIZE_SHORT / 2; jar_xm_generate_samples_16bit(currentMusic.chipctx, pcm, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location size += readlen * currentMusic.channels; // Not sure if this is what it needs } else { - while (size < MUSIC_BUFFER_SIZE) + while (size < MUSIC_BUFFER_SIZE_SHORT) { - streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE - size); + 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; } diff --git a/src/audio.h b/src/audio.h index 2b36b3f0..9d6fa5d0 100644 --- a/src/audio.h +++ b/src/audio.h @@ -84,11 +84,10 @@ bool IsAudioDeviceReady(void); // True if call // 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); // mixchannel 1, 48khz, stereo -// all samples are floating point by default -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels); +// 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, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +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 diff --git a/src/raylib.h b/src/raylib.h index 5c727b61..c9ba5b38 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -870,11 +870,10 @@ bool IsAudioDeviceReady(void); // True if call // 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); // mixchannel 1, 48khz, stereo -// all samples are floating point by default -AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels); +// 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, float *data, unsigned short dataLength); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played +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 -- cgit v1.2.3 From 5f73850fa675530d6933d85a6d80684106beff69 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 3 May 2016 18:04:21 +0200 Subject: Renamed functions for consistency --- src/audio.c | 4 ++-- src/audio.h | 4 ++-- src/raylib.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 39d1ee8b..09c91785 100644 --- a/src/audio.c +++ b/src/audio.c @@ -585,7 +585,7 @@ void StopSound(Sound sound) } // Check if a sound is playing -bool SoundIsPlaying(Sound sound) +bool IsSoundPlaying(Sound sound) { bool playing = false; ALint state; @@ -764,7 +764,7 @@ void ResumeMusicStream(void) } // Check if music is playing -bool MusicIsPlaying(void) +bool IsMusicPlaying(void) { bool playing = false; ALint state; diff --git a/src/audio.h b/src/audio.h index 9c681044..73f60ab1 100644 --- a/src/audio.h +++ b/src/audio.h @@ -96,7 +96,7 @@ void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound void PauseSound(Sound sound); // Pause a sound void StopSound(Sound sound); // Stop playing a sound -bool SoundIsPlaying(Sound sound); // Check if a sound is currently playing +bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing 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) @@ -105,7 +105,7 @@ void UpdateMusicStream(void); // Updates buffe void StopMusicStream(void); // Stop music playing (close stream) void PauseMusicStream(void); // Pause music playing void ResumeMusicStream(void); // Resume playing paused music -bool MusicIsPlaying(void); // Check if music is playing +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) diff --git a/src/raylib.h b/src/raylib.h index 337b9813..bc98181b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -882,7 +882,7 @@ void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound void PauseSound(Sound sound); // Pause a sound void StopSound(Sound sound); // Stop playing a sound -bool SoundIsPlaying(Sound sound); // Check if a sound is currently playing +bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing 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) @@ -891,7 +891,7 @@ void UpdateMusicStream(void); // Updates buffe void StopMusicStream(void); // Stop music playing (close stream) void PauseMusicStream(void); // Pause music playing void ResumeMusicStream(void); // Resume playing paused music -bool MusicIsPlaying(void); // Check if music is playing +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) -- cgit v1.2.3 From fd67e31f630476980eb09e49177958703db5b3d3 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 3 May 2016 19:27:06 +0200 Subject: Renamed function for consistency --- examples/core_world_screen.c | 2 +- src/core.c | 4 ++-- src/raylib.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_world_screen.c b/examples/core_world_screen.c index d89a296b..f3798830 100644 --- a/examples/core_world_screen.c +++ b/examples/core_world_screen.c @@ -43,7 +43,7 @@ int main() UpdateCamera(&camera); // Update internal camera and our camera // Calculate cube screen space position (with a little offset to be in top) - cubeScreenPosition = WorldToScreen((Vector3){cubePosition.x, cubePosition.y + 2.5f, cubePosition.z}, camera); + cubeScreenPosition = GetWorldToScreen((Vector3){cubePosition.x, cubePosition.y + 2.5f, cubePosition.z}, camera); //---------------------------------------------------------------------------------- // Draw diff --git a/src/core.c b/src/core.c index b27712a7..669010f9 100644 --- a/src/core.c +++ b/src/core.c @@ -905,7 +905,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) Vector3 farPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); #else // OPTION 2: Compute unprojection directly here - + // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it Matrix matProjView = MatrixMultiply(matProj, matView); MatrixInvert(&matProjView); @@ -935,7 +935,7 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) } // Returns the screen space position from a 3d world space position -Vector2 WorldToScreen(Vector3 position, Camera camera) +Vector2 GetWorldToScreen(Vector3 position, Camera camera) { // Calculate projection matrix (from perspective instead of frustum Matrix matProj = MatrixPerspective(camera.fovy, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0); diff --git a/src/raylib.h b/src/raylib.h index bc98181b..8af7d2fb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -586,7 +586,7 @@ void BeginTextureMode(RenderTexture2D target); // Initializes rende void EndTextureMode(void); // Ends drawing to render texture Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position -Vector2 WorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position +Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) void SetTargetFPS(int fps); // Set target FPS (maximum) -- cgit v1.2.3 From 7ab008878afa202b4f2e579567be7a7d87242661 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 7 May 2016 18:07:15 +0200 Subject: Library redesign to accomodate materials system --- src/models.c | 164 ++++++++-- src/raylib.h | 31 +- src/rlgl.c | 989 +++++++++++++++++++++++++++++------------------------------ src/rlgl.h | 15 +- 4 files changed, 641 insertions(+), 558 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 0bb2b8d6..9b139120 100644 --- a/src/models.c +++ b/src/models.c @@ -55,7 +55,9 @@ extern unsigned int whiteTexture; //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- -static Mesh LoadOBJ(const char *fileName); +static Mesh LoadOBJ(const char *fileName); // Load OBJ mesh data +static Material LoadMTL(const char *fileName); // Load MTL material data + static Mesh GenMeshHeightmap(Image image, Vector3 size); static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); @@ -542,24 +544,19 @@ void DrawGizmo(Vector3 position) Model LoadModel(const char *fileName) { Model model = { 0 }; - Mesh mesh = { 0 }; - // NOTE: Initialize default data for model in case loading fails, maybe a cube? + // TODO: Initialize default data for model in case loading fails, maybe a cube? - if (strcmp(GetExtension(fileName),"obj") == 0) mesh = LoadOBJ(fileName); + if (strcmp(GetExtension(fileName),"obj") == 0) model.mesh = LoadOBJ(fileName); else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName); - // NOTE: At this point we have all vertex, texcoord, normal data for the model in mesh struct - - if (mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); + if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded"); else { - // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() - model = rlglLoadModel(mesh); // Upload vertex data to GPU - - // NOTE: Now that vertex data is uploaded to GPU VRAM, we can free arrays from CPU RAM - // We don't need CPU vertex data on OpenGL 3.3 or ES2... for static meshes... - // ...but we could keep CPU vertex data in case we need to update the mesh + rlglLoadMesh(&model.mesh); // Upload vertex data to GPU + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); } return model; @@ -568,12 +565,12 @@ Model LoadModel(const char *fileName) // Load a 3d model (from vertex data) Model LoadModelEx(Mesh data) { - Model model; + Model model = { 0 }; - // NOTE: model properties (transform, texture, shader) are initialized inside rlglLoadModel() - model = rlglLoadModel(data); // Upload vertex data to GPU + rlglLoadMesh(&data); // Upload vertex data to GPU - // NOTE: Vertex data is managed externally, must be deallocated manually + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -582,8 +579,14 @@ Model LoadModelEx(Mesh data) // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) { - Mesh mesh = GenMeshHeightmap(heightmap, size); - Model model = rlglLoadModel(mesh); + Model model = { 0 }; + + model.mesh = GenMeshHeightmap(heightmap, size); + + rlglLoadMesh(&model.mesh); + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -591,8 +594,14 @@ Model LoadHeightmap(Image heightmap, Vector3 size) // Load a map image as a 3d model (cubes based) Model LoadCubicmap(Image cubicmap) { - Mesh mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); - Model model = rlglLoadModel(mesh); + Model model = { 0 }; + + model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f }); + + rlglLoadMesh(&model.mesh); + + model.transform = MatrixIdentity(); + model.material = LoadDefaultMaterial(); return model; } @@ -613,13 +622,44 @@ void UnloadModel(Model model) rlDeleteBuffers(model.mesh.vboId[0]); // vertex rlDeleteBuffers(model.mesh.vboId[1]); // texcoords rlDeleteBuffers(model.mesh.vboId[2]); // normals - //rlDeleteBuffers(model.mesh.vboId[3]); // texcoords2 (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[3]); // colors (NOT USED) //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // colors (NOT USED) + //rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 (NOT USED) rlDeleteVertexArrays(model.mesh.vaoId); } +// Load material data (from file) +Material LoadMaterial(const char *fileName) +{ + Material material = { 0 }; + + if (strcmp(GetExtension(fileName),"mtl") == 0) material = LoadMTL(fileName); + else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName); + + return material; +} + +// Load default material (uses default models shader) +Material LoadDefaultMaterial(void) +{ + Material material = { 0 }; + + material.shader = GetDefaultShader(); + material.texDiffuse = GetDefaultTexture(); // White texture (1x1 pixel) + //material.texNormal; // NOTE: By default, not set + //material.texSpecular; // NOTE: By default, not set + + material.colDiffuse = WHITE; // Diffuse color + material.colAmbient = WHITE; // Ambient color + material.colSpecular = WHITE; // Specular color + + material.glossiness = 100.0f; // Glossiness level + material.normalDepth = 1.0f; // Normal map depth + + return material; +} + // Link a texture to a model void SetModelTexture(Model *model, Texture2D texture) { @@ -1100,31 +1140,59 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint) { Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - + DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); } // Draw a model with extended parameters void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { - // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, false); + // 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); + + // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) + //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, false); } // Draw a model wires (with texture if set) -void DrawModelWires(Model model, Vector3 position, float scale, Color color) +void DrawModelWires(Model model, Vector3 position, float scale, Color tint) { Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - rlglDrawModel(model, position, rotationAxis, 0.0f, vScale, color, true); + // Calculate transformation matrix from function parameters + // Get transform matrix (rotation -> scale -> translation) + Matrix matRotation = MatrixRotate(rotationAxis, 0.0f); + Matrix matScale = MatrixScale(vScale.x, vScale.y, vScale.z); + Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, true); } // 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) { - // NOTE: Rotation must be provided in degrees, it's converted to radians inside rlglDrawModel() - rlglDrawModel(model, position, rotationAxis, rotationAngle, scale, tint, true); + // 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); + + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); + model.material.colDiffuse = tint; + + rlglDrawEx(model.mesh, model.material, model.transform, true); } // Draw a billboard @@ -1856,3 +1924,39 @@ static Mesh LoadOBJ(const char *fileName) return mesh; } + +// Load MTL material data +static Material LoadMTL(const char *fileName) +{ + Material material = { 0 }; + + // TODO: Load mtl file + + char dataType; + char comments[200]; + + FILE *mtlFile; + + mtlFile = fopen(fileName, "rt"); + + if (mtlFile == NULL) + { + TraceLog(WARNING, "[%s] MTL file could not be opened", fileName); + return material; + } + + // 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(mtlFile)) + { + fscanf(mtlFile, "%c", &dataType); + } + + fclose(mtlFile); + + // NOTE: At this point we have all material data + TraceLog(INFO, "[%s] Material loaded successfully", fileName); + + return material; +} diff --git a/src/raylib.h b/src/raylib.h index 8af7d2fb..c88a60f4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -387,10 +387,10 @@ typedef struct Shader { unsigned int id; // Shader program id // Variable attributes locations - int vertexLoc; // Vertex attribute location point (vertex shader) - int texcoordLoc; // Texcoord attribute location point (vertex shader) - int normalLoc; // Normal attribute location point (vertex shader) - int colorLoc; // Color attibute location point (vertex shader) + int vertexLoc; // Vertex attribute location point (default-location = 0) + int texcoordLoc; // Texcoord attribute location point (default-location = 1) + int normalLoc; // Normal attribute location point (default-location = 2) + int colorLoc; // Color attibute location point (default-location = 3) // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) @@ -801,17 +801,20 @@ 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 LoadModelFromRES(const char *rresName, int resId); // TODO: 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) -void UnloadModel(Model model); // Unload 3d model from memory -void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model +Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) +Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) +//Model LoadModelFromRES(const char *rresName, int resId); // TODO: 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) +void UnloadModel(Model model); // Unload 3d model from memory +void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model + +Material LoadMaterial(const char *fileName); // Load material data (from file) +Material LoadDefaultMaterial(void); // Load default material (uses default models shader) void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters -void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) +void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) @@ -832,11 +835,11 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shaders strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory void SetDefaultShader(void); // Set default shader to be used in batch draw void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw -void SetModelShader(Model *model, Shader shader); // Link a shader to a model +Shader GetDefaultShader(void); // Get default shader +Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) diff --git a/src/rlgl.c b/src/rlgl.c index 9112e47e..02649e30 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -255,14 +255,16 @@ unsigned int whiteTexture; //---------------------------------------------------------------------------------- #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat); +static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id -static Shader LoadDefaultShader(void); -static void LoadDefaultShaderLocations(Shader *shader); -static void UnloadDefaultShader(void); +static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring) +static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms) +static void UnloadDefaultShader(void); // Unload default shader -static void LoadDefaultBuffers(void); -static void UpdateDefaultBuffers(void); -static void UnloadDefaultBuffers(void); +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 char *ReadTextFile(const char *fileName); #endif @@ -1061,167 +1063,12 @@ void rlglDraw(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UpdateDefaultBuffers(); - - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) - { - glUseProgram(currentShader.id); - - Matrix matMVP = MatrixMultiply(modelview, projection); // Create modelview-projection matrix - - glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform1i(currentShader.mapDiffuseLoc, 0); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); - } - - // NOTE: We draw in this order: lines, triangles, quads - - if (lines.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(vaoLines); - } - else - { - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - } - - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - if (triangles.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); - - if (vaoSupported) - { - glBindVertexArray(vaoTriangles); - } - else - { - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - } - - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } - - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; - - if (vaoSupported) - { - glBindVertexArray(vaoQuads); - } - else - { - // Enable vertex attributes - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); - glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.texcoordLoc); - - if (currentShader.colorLoc != -1) - { - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); - } - - //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); - - for (int i = 0; i < drawsCounter; i++) - { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad - - //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - - glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - - // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process -#if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); -#elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset)); -#endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! - - indicesOffset += draws[i].vertexCount/4*6; - } - - if (!vaoSupported) - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures - } - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO - - glUseProgram(0); // Unbind shader program - - // Reset draws counter - drawsCounter = 1; - draws[0].textureId = whiteTexture; - draws[0].vertexCount = 0; - - // Reset vertex counters for next frame - lines.vCounter = 0; - lines.cCounter = 0; - - triangles.vCounter = 0; - triangles.cCounter = 0; - - quads.vCounter = 0; - quads.tcCounter = 0; - quads.cCounter = 0; - - // Reset depth for next draw - currentDepth = -1.0f; + DrawDefaultBuffers(); #endif } -// Draw a 3d model -// NOTE: Model transform can come within model struct -void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires) +// 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 @@ -1230,27 +1077,21 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro #if defined(GRAPHICS_API_OPENGL_11) glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, model.material.texDiffuse.id); + 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 glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array - glVertexPointer(3, GL_FLOAT, 0, model.mesh.vertices); // Pointer to vertex coords array - glTexCoordPointer(2, GL_FLOAT, 0, model.mesh.texcoords); // Pointer to texture coords array - glNormalPointer(GL_FLOAT, 0, model.mesh.normals); // Pointer to normals array - //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.mesh.colors); // Pointer to colors array (NOT USED) + glVertexPointer(3, GL_FLOAT, 0, mesh.vertices); // Pointer to vertex coords array + glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array + glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array + //glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array (NOT USED) - rlPushMatrix(); - rlTranslatef(position.x, position.y, position.z); - rlScalef(scale.x, scale.y, scale.z); - rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - - rlColor4ub(color.r, color.g, color.b, color.a); - - glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); - rlPopMatrix(); + rlMultMatrixf(MatrixToFloat(transform)); + + glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array @@ -1261,97 +1102,83 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float ro #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(model.material.shader.id); + 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 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); - Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); - - // Combine model internal transformation matrix (model.transform) with matrix generated by function parameters (matTransform) - Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates - + // Calculate model-view matrix combining matModel and matView - Matrix matModelView = MatrixMultiply(matModel, matView); // Transform to camera-space coordinates + 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(model.material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - // Apply color tinting to model + // Apply color tinting (material.colDiffuse) // NOTE: Just update one uniform on fragment shader - float vColor[4] = { (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255 }; - glUniform4fv(model.material.shader.tintColorLoc, 1, vColor); + 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, model.material.texDiffuse.id); - glUniform1i(model.material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 + glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id); + glUniform1i(material.shader.mapDiffuseLoc, 0); // Texture fits in active texture unit 0 - if ((model.material.texNormal.id != 0) && (model.material.shader.mapNormalLoc != -1)) + if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1)) { glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, model.material.texNormal.id); - glUniform1i(model.material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 + glBindTexture(GL_TEXTURE_2D, material.texNormal.id); + glUniform1i(material.shader.mapNormalLoc, 1); // Texture fits in active texture unit 1 } - if ((model.material.texSpecular.id != 0) && (model.material.shader.mapSpecularLoc != -1)) + if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1)) { glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, model.material.texSpecular.id); - glUniform1i(model.material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 + glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); + glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 } if (vaoSupported) { - glBindVertexArray(model.mesh.vaoId); + glBindVertexArray(mesh.vaoId); } else { - // Bind model VBO data: vertex position - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[0]); - glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.vertexLoc); + // 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 model VBO data: vertex texcoords - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[1]); - glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.texcoordLoc); + // 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 model VBO data: vertex normals (if available) - if (model.material.shader.normalLoc != -1) + // Bind mesh VBO data: vertex normals (shader-location = 2, if available) + if (material.shader.normalLoc != -1) { - glBindBuffer(GL_ARRAY_BUFFER, model.mesh.vboId[2]); - glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.normalLoc); + glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]); + glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(material.shader.normalLoc); } - // TODO: Bind model VBO data: colors, tangents, texcoords2 (if available) + // TODO: Bind mesh VBO data: colors, tangents, texcoords2 (if available) } // Draw call! - glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount); - - //glDisableVertexAttribArray(model.shader.vertexLoc); - //glDisableVertexAttribArray(model.shader.texcoordLoc); - //if (model.shader.normalLoc != -1) glDisableVertexAttribArray(model.shader.normalLoc); + glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); - if (model.material.texNormal.id != 0) + if (material.texNormal.id != 0) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); } - if (model.material.texSpecular.id != 0) + if (material.texSpecular.id != 0) { glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); @@ -1808,95 +1635,75 @@ void rlglGenerateMipmaps(Texture2D texture) glBindTexture(GL_TEXTURE_2D, 0); } -// Load vertex data into a VAO (if supported) and VBO -Model rlglLoadModel(Mesh mesh) +// Upload vertex data into a VAO (if supported) and VBO +void rlglLoadMesh(Mesh *mesh) { - Model model; - - model.mesh = mesh; - model.mesh.vaoId = 0; // Vertex Array Object - model.mesh.vboId[0] = 0; // Vertex positions VBO - model.mesh.vboId[1] = 0; // Vertex texcoords VBO - model.mesh.vboId[2] = 0; // Vertex normals VBO + mesh->vaoId = 0; // Vertex Array Object + mesh->vboId[0] = 0; // Vertex positions VBO + mesh->vboId[1] = 0; // Vertex texcoords VBO + mesh->vboId[2] = 0; // Vertex normals VBO + mesh->vboId[3] = 0; // Vertex color VBO + mesh->vboId[4] = 0; // Vertex tangent VBO + mesh->vboId[5] = 0; // Vertex texcoord2 VBO // TODO: Consider attributes: color, texcoords2, tangents (if available) - model.transform = MatrixIdentity(); - -#if defined(GRAPHICS_API_OPENGL_11) - model.material.texDiffuse.id = 0; // No texture required - model.material.shader.id = 0; // No shader used - -#elif defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model.material.shader = defaultShader; // Default model shader - - model.material.texDiffuse.id = whiteTexture; // Default whiteTexture - model.material.texDiffuse.width = 1; // Default whiteTexture width - model.material.texDiffuse.height = 1; // Default whiteTexture height - model.material.texDiffuse.format = UNCOMPRESSED_R8G8B8A8; // Default whiteTexture format - - model.material.texNormal.id = 0; // By default, no normal texture - model.material.texSpecular.id = 0; // By default, no specular texture - - // TODO: Fill default material properties (color, glossiness...) - - GLuint vaoModel = 0; // Vertex Array Objects (VAO) - GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO) +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLuint vaoId = 0; // Vertex Array Objects (VAO) + GLuint vboId[3]; // Vertex Buffer Objects (VBOs) if (vaoSupported) { // Initialize Quads VAO (Buffer A) - glGenVertexArrays(1, &vaoModel); - glBindVertexArray(vaoModel); + glGenVertexArrays(1, &vaoId); + glBindVertexArray(vaoId); } // Create buffers for our vertex data (positions, texcoords, normals) - glGenBuffers(3, vertexBuffer); - - // NOTE: Default shader is assigned to model, so vbo buffers are properly linked to vertex attribs - // If model shader is changed, vbo buffers must be re-assigned to new location points (previously loaded) - - // Enable vertex attributes: position - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.vertexLoc); - - // Enable vertex attributes: texcoords - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.texcoordLoc); - - // Enable vertex attributes: normals - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW); - glVertexAttribPointer(model.material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(model.material.shader.normalLoc); - - glVertexAttrib4f(model.material.shader.colorLoc, 1.0f, 1.0f, 1.0f, 1.0f); // Color vertex attribute set to default: WHITE - glDisableVertexAttribArray(model.material.shader.colorLoc); + glGenBuffers(3, vboId); + + // NOTE: Attributes must be uploaded considering default locations points + + // Enable vertex attributes: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(0); + + // Enable vertex attributes: texcoords (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, vboId[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, GL_STATIC_DRAW); + glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(1); + + // Enable vertex attributes: normals (shader-location = 2) + glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(2); + + // Default color vertex attribute (shader-location = 3) + glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); // Color vertex attribute set to default: WHITE + glDisableVertexAttribArray(3); - model.mesh.vboId[0] = vertexBuffer[0]; // Vertex position VBO - model.mesh.vboId[1] = vertexBuffer[1]; // Texcoords VBO - model.mesh.vboId[2] = vertexBuffer[2]; // Normals VBO + mesh->vboId[0] = vboId[0]; // Vertex position VBO + mesh->vboId[1] = vboId[1]; // Texcoords VBO + mesh->vboId[2] = vboId[2]; // Normals VBO if (vaoSupported) { - if (vaoModel > 0) + if (vaoId > 0) { - model.mesh.vaoId = vaoModel; - TraceLog(INFO, "[VAO ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel); + mesh->vaoId = vaoId; + TraceLog(INFO, "[VAO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vaoId); } - else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)"); + else TraceLog(WARNING, "Mesh could not be uploaded to VRAM (GPU)"); } else { - TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Model uploaded successfully to VRAM (GPU)", model.mesh.vboId[0], model.mesh.vboId[1], model.mesh.vboId[2]); + TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vboId[0], mesh->vboId[1], mesh->vboId[2]); } #endif - - return model; } // Read screen pixel data (color buffer) @@ -2090,36 +1897,202 @@ Shader LoadShader(char *vsFileName, char *fsFileName) return shader; } -// Load custom shader strings and return program id -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) +// Unload a custom shader from memory +void UnloadShader(Shader shader) +{ + if (shader.id != 0) + { + rlDeleteShader(shader.id); + TraceLog(INFO, "[SHDR ID %i] Unloaded shader program data", shader.id); + } +} + +// Set custom shader to be used on batch draw +void SetCustomShader(Shader shader) { - unsigned int program = 0; - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - GLuint vertexShader; - GLuint fragmentShader; + if (currentShader.id != shader.id) + { + rlglDraw(); + currentShader = shader; + } +#endif +} - vertexShader = glCreateShader(GL_VERTEX_SHADER); - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); +// Set default shader to be used in batch draw +void SetDefaultShader(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + SetCustomShader(defaultShader); +#endif +} - const char *pvs = vShaderStr; - const char *pfs = fShaderStr; +// Get default shader +Shader GetDefaultShader(void) +{ + return defaultShader; +} - glShaderSource(vertexShader, 1, &pvs, NULL); - glShaderSource(fragmentShader, 1, &pfs, NULL); +// Get shader uniform location +int GetShaderLocation(Shader shader, const char *uniformName) +{ + int location = -1; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + location = glGetUniformLocation(shader.id, uniformName); + + if (location == -1) TraceLog(WARNING, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName); +#endif + return location; +} - GLint success = 0; +// Set shader uniform value (float) +void SetShaderValue(Shader shader, int uniformLoc, float *value, int size) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUseProgram(shader.id); - glCompileShader(vertexShader); + if (size == 1) glUniform1fv(uniformLoc, 1, value); // Shader uniform type: float + else if (size == 2) glUniform2fv(uniformLoc, 1, value); // Shader uniform type: vec2 + else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3 + else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4 + else TraceLog(WARNING, "Shader value float array size not supported"); + + glUseProgram(0); +#endif +} - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); +// Set shader uniform value (int) +void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUseProgram(shader.id); - if (success != GL_TRUE) - { - TraceLog(WARNING, "[VSHDR ID %i] Failed to compile vertex shader...", vertexShader); + if (size == 1) glUniform1iv(uniformLoc, 1, value); // Shader uniform type: int + else if (size == 2) glUniform2iv(uniformLoc, 1, value); // Shader uniform type: ivec2 + else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3 + else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4 + else TraceLog(WARNING, "Shader value int array size not supported"); + + glUseProgram(0); +#endif +} - int maxLength = 0; - int length; +// Set shader uniform value (matrix 4x4) +void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUseProgram(shader.id); + + glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); + + glUseProgram(0); +#endif +} + +// Set blending mode (alpha, additive, multiplied) +// NOTE: Only 3 blending modes predefined +void SetBlendMode(int mode) +{ + if ((blendMode != mode) && (mode < 3)) + { + rlglDraw(); + + switch (mode) + { + case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; + case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE); + case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; + default: break; + } + + blendMode = mode; + } +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Convert image data to OpenGL texture (returns OpenGL valid Id) +// NOTE: Expected compressed image data and POT image +static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat) +{ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + int blockSize = 0; // Bytes every block + int offset = 0; + + if ((compressedFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) || + (compressedFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || +#if defined(GRAPHICS_API_OPENGL_ES2) + (compressedFormat == GL_ETC1_RGB8_OES) || +#endif + (compressedFormat == GL_COMPRESSED_RGB8_ETC2)) blockSize = 8; + else blockSize = 16; + + // Load the mipmap levels + for (int level = 0; level < mipmapCount && (width || height); level++) + { + unsigned int size = 0; + + size = ((width + 3)/4)*((height + 3)/4)*blockSize; + + glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset); + + offset += size; + width /= 2; + height /= 2; + + // Security check for NPOT textures + if (width < 1) width = 1; + if (height < 1) height = 1; + } +} + +Texture2D GetDefaultTexture(void) +{ + Texture2D texture; + + texture.id = whiteTexture; + texture.width = 1; + texture.height = 1; + texture.mipmaps = 1; + texture.format = UNCOMPRESSED_R8G8B8A8; + + return texture; +} + +// Load custom shader strings and return program id +static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) +{ + unsigned int program = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLuint vertexShader; + GLuint fragmentShader; + + vertexShader = glCreateShader(GL_VERTEX_SHADER); + fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + + const char *pvs = vShaderStr; + const char *pfs = fShaderStr; + + glShaderSource(vertexShader, 1, &pvs, NULL); + glShaderSource(fragmentShader, 1, &pfs, NULL); + + GLint success = 0; + + glCompileShader(vertexShader); + + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); + + if (success != GL_TRUE) + { + TraceLog(WARNING, "[VSHDR ID %i] Failed to compile vertex shader...", vertexShader); + + int maxLength = 0; + int length; glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength); @@ -2156,7 +2129,17 @@ unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); - + + // NOTE: Default attribute shader locations must be binded before linking + glBindAttribLocation(program, 0, "vertexPosition"); + glBindAttribLocation(program, 1, "vertexTexCoord"); + glBindAttribLocation(program, 2, "vertexNormal"); + glBindAttribLocation(program, 3, "vertexColor"); + glBindAttribLocation(program, 4, "vertexTangent"); + glBindAttribLocation(program, 5, "vertexTexCoord2"); + + // NOTE: If some attrib name is no found on the shader, it locations becomes -1 + glLinkProgram(program); // NOTE: All uniform variables are intitialised to 0 when a program links @@ -2190,184 +2173,8 @@ unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) return program; } -// Unload a custom shader from memory -void UnloadShader(Shader shader) -{ - if (shader.id != 0) - { - rlDeleteShader(shader.id); - TraceLog(INFO, "[SHDR ID %i] Unloaded shader program data", shader.id); - } -} - -// Set custom shader to be used on batch draw -void SetCustomShader(Shader shader) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (currentShader.id != shader.id) - { - rlglDraw(); - currentShader = shader; - } -#endif -} - -// Set default shader to be used in batch draw -void SetDefaultShader(void) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - SetCustomShader(defaultShader); -#endif -} - -// Link shader to model -void SetModelShader(Model *model, Shader shader) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - model->material.shader = shader; - - if (vaoSupported) glBindVertexArray(model->mesh.vaoId); - - // Enable vertex attributes: position - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[0]); - glEnableVertexAttribArray(shader.vertexLoc); - glVertexAttribPointer(shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: texcoords - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[1]); - glEnableVertexAttribArray(shader.texcoordLoc); - glVertexAttribPointer(shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - - // Enable vertex attributes: normals - glBindBuffer(GL_ARRAY_BUFFER, model->mesh.vboId[2]); - glEnableVertexAttribArray(shader.normalLoc); - glVertexAttribPointer(shader.normalLoc, 3, GL_FLOAT, 0, 0, 0); - - if (vaoSupported) glBindVertexArray(0); // Unbind VAO - -#elif (GRAPHICS_API_OPENGL_11) - TraceLog(WARNING, "Shaders not supported on OpenGL 1.1"); -#endif -} - -// Get shader uniform location -int GetShaderLocation(Shader shader, const char *uniformName) -{ - int location = -1; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetUniformLocation(shader.id, uniformName); - - if (location == -1) TraceLog(WARNING, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName); -#endif - return location; -} - -// Set shader uniform value (float) -void SetShaderValue(Shader shader, int uniformLoc, float *value, int size) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - if (size == 1) glUniform1fv(uniformLoc, 1, value); // Shader uniform type: float - else if (size == 2) glUniform2fv(uniformLoc, 1, value); // Shader uniform type: vec2 - else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3 - else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4 - else TraceLog(WARNING, "Shader value float array size not supported"); - - glUseProgram(0); -#endif -} - -// Set shader uniform value (int) -void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - if (size == 1) glUniform1iv(uniformLoc, 1, value); // Shader uniform type: int - else if (size == 2) glUniform2iv(uniformLoc, 1, value); // Shader uniform type: ivec2 - else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3 - else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4 - else TraceLog(WARNING, "Shader value int array size not supported"); - - glUseProgram(0); -#endif -} - -// Set shader uniform value (matrix 4x4) -void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glUseProgram(shader.id); - - glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); - - glUseProgram(0); -#endif -} - -// Set blending mode (alpha, additive, multiplied) -// NOTE: Only 3 blending modes predefined -void SetBlendMode(int mode) -{ - if ((blendMode != mode) && (mode < 3)) - { - rlglDraw(); - - switch (mode) - { - case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; - case BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; // Alternative: glBlendFunc(GL_ONE, GL_ONE); - case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; - default: break; - } - - blendMode = mode; - } -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -// Convert image data to OpenGL texture (returns OpenGL valid Id) -// NOTE: Expected compressed image data and POT image -static void LoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compressedFormat) -{ - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - int blockSize = 0; // Bytes every block - int offset = 0; - - if ((compressedFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) || - (compressedFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || -#if defined(GRAPHICS_API_OPENGL_ES2) - (compressedFormat == GL_ETC1_RGB8_OES) || -#endif - (compressedFormat == GL_COMPRESSED_RGB8_ETC2)) blockSize = 8; - else blockSize = 16; - - // Load the mipmap levels - for (int level = 0; level < mipmapCount && (width || height); level++) - { - unsigned int size = 0; - - size = ((width + 3)/4)*((height + 3)/4)*blockSize; - - glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset); - offset += size; - width /= 2; - height /= 2; - - // Security check for NPOT textures - if (width < 1) width = 1; - if (height < 1) height = 1; - } -} - -// Load default shader (Vertex and Fragment) +// Load default shader (just vertex positioning and texture coloring) // NOTE: This shader program is used for batch buffers (lines, triangles, quads) static Shader LoadDefaultShader(void) { @@ -2436,6 +2243,12 @@ static Shader LoadDefaultShader(void) // NOTE: If any location is not found, loc point becomes -1 static void LoadDefaultShaderLocations(Shader *shader) { + // NOTE: Default shader attrib locations have been fixed before linking: + // vertex position location = 0 + // vertex texcoord location = 1 + // vertex normal location = 2 + // vertex color location = 3 + // Get handles to GLSL input attibute locations shader->vertexLoc = glGetAttribLocation(shader->id, "vertexPosition"); shader->texcoordLoc = glGetAttribLocation(shader->id, "vertexTexCoord"); @@ -2470,7 +2283,7 @@ static void LoadDefaultBuffers(void) // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads) //-------------------------------------------------------------------------------------------- - // Initialize lines arrays (vertex position and color data) + // Lines - Initialize arrays (vertex position and color data) lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line @@ -2480,7 +2293,7 @@ static void LoadDefaultBuffers(void) lines.vCounter = 0; lines.cCounter = 0; - // Initialize triangles arrays (vertex position and color data) + // Triangles - Initialize arrays (vertex position and color data) triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle @@ -2490,7 +2303,7 @@ static void LoadDefaultBuffers(void) triangles.vCounter = 0; triangles.cCounter = 0; - // Initialize quads arrays (vertex position, texcoord and color data... and indexes) + // Quads - Initialize arrays (vertex position, texcoord, color data and indexes) quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad @@ -2523,7 +2336,7 @@ static void LoadDefaultBuffers(void) quads.tcCounter = 0; quads.cCounter = 0; - TraceLog(INFO, "Default buffers initialized successfully in CPU (lines, triangles, quads)"); + TraceLog(INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)"); //-------------------------------------------------------------------------------------------- // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads) @@ -2541,20 +2354,21 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(2, linesBuffer); - // Lines - Vertex positions buffer binding and attributes enable + // Lines - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - // Lines - colors buffer + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (lines) VAO initialized successfully", vaoLines); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (lines) VBOs initialized successfully", linesBuffer[0], linesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", vaoLines); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", linesBuffer[0], linesBuffer[1]); // Upload and link triangles vertex buffers if (vaoSupported) @@ -2567,19 +2381,21 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(2, trianglesBuffer); - // Enable vertex attributes + // Triangles - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (triangles) VAO initialized successfully", vaoTriangles); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers (triangles) VBOs initialized successfully", trianglesBuffer[0], trianglesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", vaoTriangles); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully(triangles)", trianglesBuffer[0], trianglesBuffer[1]); // Upload and link quads vertex buffers if (vaoSupported) @@ -2592,17 +2408,20 @@ static void LoadDefaultBuffers(void) // Create buffers for our vertex data glGenBuffers(4, quadsBuffer); - // Enable vertex attributes + // Quads - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + // Vertex texcoord buffer (shader-location = 1) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.texcoordLoc); glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + // Vertex color buffer (shader-location = 3) glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); @@ -2616,15 +2435,15 @@ static void LoadDefaultBuffers(void) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); #endif - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers (quads) VAO initialized successfully", vaoQuads); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers (quads) VBOs initialized successfully", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", vaoQuads); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]); // Unbind the current VAO if (vaoSupported) glBindVertexArray(0); //-------------------------------------------------------------------------------------------- } -// Update default buffers (VAOs/VBOs) with vertex array data +// Update default internal buffers (VAOs/VBOs) with vertex array data // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) static void UpdateDefaultBuffers(void) @@ -2695,7 +2514,165 @@ static void UpdateDefaultBuffers(void) if (vaoSupported) glBindVertexArray(0); } -// Unload default buffers vertex data from CPU and GPU +// Draw default internal buffers vertex data +// NOTE: We draw in this order: lines, triangles, quads +static void DrawDefaultBuffers(void) +{ + // Set current shader and upload current MVP matrix + if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) + { + glUseProgram(currentShader.id); + + // Create modelview-projection matrix + Matrix matMVP = MatrixMultiply(modelview, projection); + + glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniform1i(currentShader.mapDiffuseLoc, 0); + glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + } + + // Draw lines buffers + if (lines.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); + + if (vaoSupported) + { + glBindVertexArray(vaoLines); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } + + glDrawArrays(GL_LINES, 0, lines.vCounter); + + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + // Draw triangles buffers + if (triangles.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); + + if (vaoSupported) + { + glBindVertexArray(vaoTriangles); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } + + glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); + + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + // Draw quads buffers + if (quads.vCounter > 0) + { + int quadsCount = 0; + int numIndicesToProcess = 0; + int indicesOffset = 0; + + if (vaoSupported) + { + glBindVertexArray(vaoQuads); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: texcoord (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); + glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.texcoordLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); + } + + //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); + + for (int i = 0; i < drawsCounter; i++) + { + quadsCount = draws[i].vertexCount/4; + numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad + + //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); + + glBindTexture(GL_TEXTURE_2D, draws[i].textureId); + + // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process +#if defined(GRAPHICS_API_OPENGL_33) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); +#elif defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset)); +#endif + //GLenum err; + //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! + + indicesOffset += draws[i].vertexCount/4*6; + } + + if (!vaoSupported) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } + + if (vaoSupported) glBindVertexArray(0); // Unbind VAO + + glUseProgram(0); // Unbind shader program + + // Reset draws counter + drawsCounter = 1; + draws[0].textureId = whiteTexture; + draws[0].vertexCount = 0; + + // Reset vertex counters for next frame + lines.vCounter = 0; + lines.cCounter = 0; + triangles.vCounter = 0; + triangles.cCounter = 0; + quads.vCounter = 0; + quads.tcCounter = 0; + quads.cCounter = 0; + + // Reset depth for next draw + currentDepth = -1.0f; +} + +// Unload default internal buffers vertex data from CPU and GPU static void UnloadDefaultBuffers(void) { // Unbind everything diff --git a/src/rlgl.h b/src/rlgl.h index cd8e6d1d..afc2ab96 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -280,29 +280,28 @@ 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 - -// NOTE: There is a set of shader related functions that are available to end user, -// to avoid creating function wrappers through core module, they have been directly declared in raylib.h - -Model rlglLoadModel(Mesh mesh); // Upload vertex data into GPU and provided VAO/VBO ids -void rlglDrawModel(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color color, bool wires); +void rlglLoadMesh(Mesh *mesh); // Upload vertex data into GPU and provided VAO/VBO ids +void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires); Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data +// NOTE: There is a set of shader related functions that are available to end user, +// to avoid creating function wrappers through core module, they have been directly declared in raylib.h + #if defined(RLGL_STANDALONE) //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr); // Load custom shader strings and return program id void UnloadShader(Shader shader); // Unload a custom shader from memory void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw void SetDefaultShader(void); // Set default shader to be used in batch draw -void SetModelShader(Model *model, Shader shader); // Link a shader to a model +Shader GetDefaultShader(void); // Get default shader +Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -- cgit v1.2.3 From 0bcb873cbb3758d67b1d263fafb6be818ddbf067 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 8 May 2016 15:24:02 +0200 Subject: Improved mesh support Depending on mesh data, it can be loaded and default vertex attribute location points are set, including colors, tangents and texcoords2 --- src/models.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++------------- src/raylib.h | 6 +-- src/rlgl.c | 90 ++++++++++++++++++++++++++++++++++++-------- 3 files changed, 171 insertions(+), 45 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 9b139120..4aff7216 100644 --- a/src/models.c +++ b/src/models.c @@ -575,6 +575,89 @@ Model LoadModelEx(Mesh data) return model; } +// Load a 3d model from rRES file (raylib Resource) +Model LoadModelFromRES(const char *rresName, int resId) +{ + Model model = { 0 }; + bool found = false; + + char id[4]; // rRES file identifier + unsigned char version; // rRES file version and subversion + char useless; // rRES header reserved data + short numRes; + + ResInfoHeader infoHeader; + + FILE *rresFile = fopen(rresName, "rb"); + + if (rresFile == NULL) + { + TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); + } + else + { + // Read rres file (basic file check - id) + fread(&id[0], sizeof(char), 1, rresFile); + fread(&id[1], sizeof(char), 1, rresFile); + fread(&id[2], sizeof(char), 1, rresFile); + fread(&id[3], sizeof(char), 1, rresFile); + fread(&version, sizeof(char), 1, rresFile); + fread(&useless, sizeof(char), 1, rresFile); + + if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) + { + TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); + } + else + { + // Read number of resources embedded + fread(&numRes, sizeof(short), 1, rresFile); + + for (int i = 0; i < numRes; i++) + { + fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); + + if (infoHeader.id == resId) + { + found = true; + + // Check data is of valid MODEL type + if (infoHeader.type == 8) + { + // TODO: Load model data + } + else + { + TraceLog(WARNING, "[%s] Required resource do not seem to be a valid MODEL resource", rresName); + } + } + else + { + // Depending on type, skip the right amount of parameters + switch (infoHeader.type) + { + case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters + case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters + case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) + case 3: break; // TEXT: No parameters + case 4: break; // RAW: No parameters + default: break; + } + + // Jump DATA to read next infoHeader + fseek(rresFile, infoHeader.size, SEEK_CUR); + } + } + } + + fclose(rresFile); + } + + if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); + + return model; +} + // Load a heightmap image as a 3d model // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) @@ -613,18 +696,18 @@ void UnloadModel(Model model) free(model.mesh.vertices); free(model.mesh.texcoords); free(model.mesh.normals); - free(model.mesh.colors); - //if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2); // Not used - //if (model.mesh.tangents != NULL) free(model.mesh.tangents); // Not used + 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); 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 (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[4]); // tangents (NOT USED) - //rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 (NOT USED) + rlDeleteBuffers(model.mesh.vboId[3]); // colors + rlDeleteBuffers(model.mesh.vboId[4]); // tangents + rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 rlDeleteVertexArrays(model.mesh.vaoId); } @@ -672,7 +755,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) { #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) - Mesh mesh; + Mesh mesh = { 0 }; int mapX = heightmap.width; int mapZ = heightmap.height; @@ -687,7 +770,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used... + mesh.colors = NULL; int vCounter = 0; // Used to count vertices float by float int tcCounter = 0; // Used to count texcoords float by float @@ -770,16 +853,12 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) free(pixels); - // Fill color data - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; - return mesh; } static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) { - Mesh mesh; + Mesh mesh = { 0 }; Color *cubicmapPixels = GetImageData(cubicmap); @@ -1088,11 +1167,7 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); // Not used... - - // Fill color data - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; + mesh.colors = NULL; int fCounter = 0; @@ -1810,7 +1885,7 @@ static Mesh LoadOBJ(const char *fileName) mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); - mesh.colors = (unsigned char *)malloc(mesh.vertexCount*4*sizeof(unsigned char)); + mesh.colors = NULL; int vCounter = 0; // Used to count vertices float by float int tcCounter = 0; // Used to count texcoords float by float @@ -1909,10 +1984,6 @@ static Mesh LoadOBJ(const char *fileName) // Security check, just in case no normals or no texcoords defined in OBJ if (numTexCoords == 0) for (int i = 0; i < (2*mesh.vertexCount); i++) mesh.texcoords[i] = 0.0f; - - // NOTE: We set all vertex colors to white - // NOTE: Not used any more... just one plain color defined at DrawModel() - for (int i = 0; i < (4*mesh.vertexCount); i++) mesh.colors[i] = 255; // Now we can free temp mid* arrays free(midVertices); @@ -1945,9 +2016,6 @@ static Material LoadMTL(const char *fileName) return material; } - // 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(mtlFile)) { fscanf(mtlFile, "%c", &dataType); diff --git a/src/raylib.h b/src/raylib.h index c88a60f4..60384444 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -386,7 +386,7 @@ typedef struct Mesh { typedef struct Shader { unsigned int id; // Shader program id - // Variable attributes locations + // Vertex attributes locations (default locations) int vertexLoc; // Vertex attribute location point (default-location = 0) int texcoordLoc; // Texcoord attribute location point (default-location = 1) int normalLoc; // Normal attribute location point (default-location = 2) @@ -803,14 +803,14 @@ void DrawGizmo(Vector3 position); //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) Model LoadModelEx(Mesh data); // Load a 3d model (from mesh data) -//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) +Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource) Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) void UnloadModel(Model model); // Unload 3d model from memory void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model Material LoadMaterial(const char *fileName); // Load material data (from file) -Material LoadDefaultMaterial(void); // Load default material (uses default models shader) +Material LoadDefaultMaterial(void); // Load default material (uses default models shader) void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters diff --git a/src/rlgl.c b/src/rlgl.c index 462ccdec..6ffcb8a5 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -811,9 +811,11 @@ void rlDeleteVertexArrays(unsigned int id) void rlDeleteBuffers(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteBuffers(1, &id); - - if (!vaoSupported) TraceLog(INFO, "[VBO ID %i] Unloaded model vertex data from VRAM (GPU)", id); + if (id != 0) + { + glDeleteBuffers(1, &id); + if (!vaoSupported) TraceLog(INFO, "[VBO ID %i] Unloaded model vertex data from VRAM (GPU)", id); + } #endif } @@ -1638,6 +1640,7 @@ void rlglGenerateMipmaps(Texture2D texture) } // Upload vertex data into a VAO (if supported) and VBO +// TODO: Consider attributes: color, texcoords2, tangents (if available) void rlglLoadMesh(Mesh *mesh) { mesh->vaoId = 0; // Vertex Array Object @@ -1648,11 +1651,10 @@ void rlglLoadMesh(Mesh *mesh) mesh->vboId[4] = 0; // Vertex tangent VBO mesh->vboId[5] = 0; // Vertex texcoord2 VBO - // TODO: Consider attributes: color, texcoords2, tangents (if available) - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLuint vaoId = 0; // Vertex Array Objects (VAO) - GLuint vboId[3]; // Vertex Buffer Objects (VBOs) + GLuint vboId[6]; // Vertex Buffer Objects (VBOs) if (vaoSupported) { @@ -1661,36 +1663,92 @@ void rlglLoadMesh(Mesh *mesh) glBindVertexArray(vaoId); } - // Create buffers for our vertex data (positions, texcoords, normals) - glGenBuffers(3, vboId); - // NOTE: Attributes must be uploaded considering default locations points // 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); 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); glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(1); // Enable vertex attributes: normals (shader-location = 2) - glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); - glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); - glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(2); + if (mesh->normals != NULL) + { + glGenBuffers(1, &vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[2]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(2); + } + else + { + // Default color vertex attribute set to WHITE + glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f); + glDisableVertexAttribArray(2); + } // Default color vertex attribute (shader-location = 3) - glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); // Color vertex attribute set to default: WHITE - glDisableVertexAttribArray(3); + if (mesh->colors != NULL) + { + 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); + glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(3); + } + else + { + // Default color vertex attribute set to WHITE + glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); + glDisableVertexAttribArray(3); + } + + // Default tangent vertex attribute (shader-location = 4) + if (mesh->tangents != NULL) + { + glGenBuffers(1, &vboId[4]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[4]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, GL_STATIC_DRAW); + glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(4); + } + else + { + // Default tangents vertex attribute + glVertexAttrib3f(4, 0.0f, 0.0f, 0.0f); + glDisableVertexAttribArray(4); + } + + // Default texcoord2 vertex attribute (shader-location = 5) + if (mesh->texcoords2 != NULL) + { + glGenBuffers(1, &vboId[5]); + glBindBuffer(GL_ARRAY_BUFFER, vboId[5]); + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, GL_STATIC_DRAW); + glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(5); + } + else + { + // Default tangents vertex attribute + glVertexAttrib2f(5, 0.0f, 0.0f); + glDisableVertexAttribArray(5); + } mesh->vboId[0] = vboId[0]; // Vertex position VBO mesh->vboId[1] = vboId[1]; // Texcoords VBO mesh->vboId[2] = vboId[2]; // Normals VBO + mesh->vboId[3] = vboId[3]; // Colors VBO + mesh->vboId[4] = vboId[4]; // Tangents VBO + mesh->vboId[5] = vboId[5]; // Texcoords2 VBO if (vaoSupported) { @@ -1703,7 +1761,7 @@ void rlglLoadMesh(Mesh *mesh) } else { - TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i] Mesh uploaded successfully to VRAM (GPU)", mesh->vboId[0], mesh->vboId[1], mesh->vboId[2]); + TraceLog(INFO, "[VBOs] Mesh uploaded successfully to VRAM (GPU)"); } #endif } -- cgit v1.2.3 From f7d4951165e8bece5ae58cd4c92b08e4f29cbef7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 8 May 2016 23:50:35 +0200 Subject: Improved vertex attribs support for models --- src/models.c | 2 +- src/raylib.h | 14 ++++++++------ src/rlgl.c | 45 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 45 insertions(+), 16 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 4aff7216..ee04b449 100644 --- a/src/models.c +++ b/src/models.c @@ -695,7 +695,7 @@ void UnloadModel(Model model) // Unload mesh data free(model.mesh.vertices); free(model.mesh.texcoords); - free(model.mesh.normals); + 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); diff --git a/src/raylib.h b/src/raylib.h index 60384444..1258bffc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -369,12 +369,12 @@ typedef struct BoundingBox { // Vertex data definning a mesh typedef struct Mesh { int vertexCount; // num vertices - float *vertices; // vertex position (XYZ - 3 components per vertex) - float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) - float *texcoords2; // vertex second texture coordinates (useful for lightmaps) - float *normals; // vertex normals (XYZ - 3 components per vertex) - float *tangents; // vertex tangents (XYZ - 3 components per vertex) - unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) + float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) + float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) BoundingBox bounds; // mesh limits defined by min and max points @@ -391,6 +391,8 @@ typedef struct Shader { int texcoordLoc; // Texcoord attribute location point (default-location = 1) int normalLoc; // Normal attribute location point (default-location = 2) int colorLoc; // Color attibute location point (default-location = 3) + int tangentLoc; // Tangent attribute location point (default-location = 4) + int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) diff --git a/src/rlgl.c b/src/rlgl.c index 6ffcb8a5..2e4601df 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1084,12 +1084,13 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) // 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 - glEnableClientState(GL_NORMAL_ARRAY); // Enable normals 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 - glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array - //glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array (NOT USED) + 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)); @@ -1099,7 +1100,8 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array - glDisableClientState(GL_NORMAL_ARRAY); // Disable normals 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); @@ -1170,7 +1172,29 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glEnableVertexAttribArray(material.shader.normalLoc); } - // TODO: Bind mesh VBO data: colors, tangents, texcoords2 (if available) + // 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); + } } // Draw call! @@ -1640,16 +1664,15 @@ void rlglGenerateMipmaps(Texture2D texture) } // Upload vertex data into a VAO (if supported) and VBO -// TODO: Consider attributes: color, texcoords2, tangents (if available) void rlglLoadMesh(Mesh *mesh) { mesh->vaoId = 0; // Vertex Array Object mesh->vboId[0] = 0; // Vertex positions VBO mesh->vboId[1] = 0; // Vertex texcoords VBO mesh->vboId[2] = 0; // Vertex normals VBO - mesh->vboId[3] = 0; // Vertex color VBO - mesh->vboId[4] = 0; // Vertex tangent VBO - mesh->vboId[5] = 0; // Vertex texcoord2 VBO + mesh->vboId[3] = 0; // Vertex colors VBO + mesh->vboId[4] = 0; // Vertex tangents VBO + mesh->vboId[5] = 0; // Vertex texcoords2 VBO #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -2314,12 +2337,16 @@ static void LoadDefaultShaderLocations(Shader *shader) // vertex texcoord location = 1 // vertex normal location = 2 // vertex color location = 3 + // vertex tangent location = 4 + // 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"); // Get handles to GLSL uniform locations (vertex shader) shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); -- cgit v1.2.3 From 1ddf594d15f31f1502eeb18f0f0c8039799fff01 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 10 May 2016 18:24:28 +0200 Subject: Added support for indexed mesh data --- src/models.c | 21 +++++++++++++++++---- src/raylib.h | 7 +++++-- src/rlgl.c | 39 ++++++++++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 17 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 7d24e383..41150179 100644 --- a/src/models.c +++ b/src/models.c @@ -553,7 +553,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); // Upload vertex data to GPU model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); @@ -567,7 +567,9 @@ Model LoadModelEx(Mesh data) { Model model = { 0 }; - rlglLoadMesh(&data); // Upload vertex data to GPU + model.mesh = data; + + rlglLoadMesh(&model.mesh); // Upload vertex data to GPU model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); @@ -693,12 +695,13 @@ Model LoadCubicmap(Image cubicmap) void UnloadModel(Model model) { // Unload mesh data - free(model.mesh.vertices); - free(model.mesh.texcoords); + 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)"); @@ -708,8 +711,11 @@ void UnloadModel(Model model) rlDeleteBuffers(model.mesh.vboId[3]); // colors rlDeleteBuffers(model.mesh.vboId[4]); // tangents rlDeleteBuffers(model.mesh.vboId[5]); // texcoords2 + rlDeleteBuffers(model.mesh.vboId[6]); // indices rlDeleteVertexArrays(model.mesh.vaoId); + + UnloadMaterial(model.material); } // Load material data (from file) @@ -743,6 +749,13 @@ Material LoadDefaultMaterial(void) return material; } +void UnloadMaterial(Material material) +{ + rlDeleteTextures(material.texDiffuse.id); + rlDeleteTextures(material.texNormal.id); + rlDeleteTextures(material.texSpecular.id); +} + // Link a texture to a model void SetModelTexture(Model *model, Texture2D texture) { diff --git a/src/raylib.h b/src/raylib.h index 1258bffc..05463325 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -368,18 +368,20 @@ typedef struct BoundingBox { // Vertex data definning a mesh typedef struct Mesh { - int vertexCount; // num vertices + int vertexCount; // number of vertices stored in arrays float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices; // vertex indices (in case vertex data comes indexed) + int trianglesCount; // number of triangles to draw BoundingBox bounds; // mesh limits defined by min and max points unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[6]; // OpenGL Vertex Buffer Objects id (6 types of vertex data) + unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) } Mesh; // Shader type (generic shader) @@ -813,6 +815,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) +void UnloadMaterial(Material material); // Unload material textures from VRAM void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters diff --git a/src/rlgl.c b/src/rlgl.c index 33f12deb..8364c4f1 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -783,16 +783,16 @@ void rlDisableDepthTest(void) // Unload texture from GPU memory void rlDeleteTextures(unsigned int id) { - glDeleteTextures(1, &id); + if (id != 0) glDeleteTextures(1, &id); } // Unload render texture from GPU memory void rlDeleteRenderTextures(RenderTexture2D target) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteFramebuffers(1, &target.id); - glDeleteTextures(1, &target.texture.id); - glDeleteTextures(1, &target.depth.id); + if (target.id != 0) glDeleteFramebuffers(1, &target.id); + if (target.texture.id != 0) glDeleteTextures(1, &target.texture.id); + if (target.depth.id != 0) glDeleteTextures(1, &target.depth.id); #endif } @@ -800,7 +800,7 @@ void rlDeleteRenderTextures(RenderTexture2D target) void rlDeleteShader(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDeleteProgram(id); + if (id != 0) glDeleteProgram(id); #endif } @@ -810,7 +810,7 @@ void rlDeleteVertexArrays(unsigned int id) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if (vaoSupported) { - glDeleteVertexArrays(1, &id); + if (id != 0) glDeleteVertexArrays(1, &id); TraceLog(INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", id); } #endif @@ -1204,10 +1204,13 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(material.shader.texcoord2Loc); } + + if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); } // Draw call! - glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); + if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.trianglesCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw + else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount); if (material.texNormal.id != 0) { @@ -1225,7 +1228,11 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures if (vaoSupported) glBindVertexArray(0); // Unbind VAO - else glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs + else + { + glBindBuffer(GL_ARRAY_BUFFER, 0); // Unbind VBOs + if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } glUseProgram(0); // Unbind shader program #endif @@ -1682,11 +1689,12 @@ void rlglLoadMesh(Mesh *mesh) mesh->vboId[3] = 0; // Vertex colors VBO mesh->vboId[4] = 0; // Vertex tangents VBO mesh->vboId[5] = 0; // Vertex texcoords2 VBO + mesh->vboId[6] = 0; // Vertex indices VBO #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLuint vaoId = 0; // Vertex Array Objects (VAO) - GLuint vboId[6]; // Vertex Buffer Objects (VBOs) + GLuint vboId[7]; // Vertex Buffer Objects (VBOs) if (vaoSupported) { @@ -1775,12 +1783,21 @@ void rlglLoadMesh(Mesh *mesh) glDisableVertexAttribArray(5); } + if (mesh->indices != NULL) + { + glGenBuffers(1, &vboId[6]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId[6]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*mesh->trianglesCount*3, mesh->indices, GL_STATIC_DRAW); + } + + mesh->vboId[0] = vboId[0]; // Vertex position VBO mesh->vboId[1] = vboId[1]; // Texcoords VBO mesh->vboId[2] = vboId[2]; // Normals VBO mesh->vboId[3] = vboId[3]; // Colors VBO mesh->vboId[4] = vboId[4]; // Tangents VBO mesh->vboId[5] = vboId[5]; // Texcoords2 VBO + mesh->vboId[6] = vboId[6]; // Indices VBO if (vaoSupported) { @@ -2733,9 +2750,9 @@ static void DrawDefaultBuffers(void) // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process #if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset)); + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); #elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesOffset)); + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); #endif //GLenum err; //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! -- cgit v1.2.3 From 5c112ff5425356a81920d907caf25a40c9ba71df Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 10 May 2016 19:24:25 +0200 Subject: Corrected tipo --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 05463325..ecfce9fc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -376,7 +376,7 @@ typedef struct Mesh { float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices; // vertex indices (in case vertex data comes indexed) - int trianglesCount; // number of triangles to draw + int triangleCount; // number of triangles to draw BoundingBox bounds; // mesh limits defined by min and max points -- cgit v1.2.3 From 6db44500b75097a581587cba15ce703963d2ced8 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 11 May 2016 00:37:10 -0700 Subject: adding multiple music streams --- src/audio.c | 181 ++++++++++++++++++++++++++--------------------------------- src/audio.h | 9 +-- src/raylib.h | 9 +-- 3 files changed, 91 insertions(+), 108 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index fbf53df6..39be4eeb 100644 --- a/src/audio.c +++ b/src/audio.c @@ -61,6 +61,7 @@ //---------------------------------------------------------------------------------- #define MAX_STREAM_BUFFERS 2 #define MAX_AUDIO_CONTEXTS 4 // Number of open AL sources +#define MAX_MUSIC_STREAMS 2 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) // NOTE: On RPI and Android should be lower to avoid frame-stalls @@ -81,13 +82,8 @@ 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; + AudioContext_t *ctx; // audio context + int totalSamplesLeft; float totalLengthSeconds; bool loop; @@ -117,8 +113,8 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- 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 Music currentMusic[2]; // Current music loaded, up to two can play at the same time + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -769,151 +765,129 @@ void SetSoundPitch(Sound sound, float pitch) // Start music playing (open stream) void PlayMusicStream(char *fileName) { + int musicIndex; + int mixIndex; + for(musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot + { + if(currentMusic[musicIndex].stream == NULL && !currentMusic[musicIndex].chipTune) break; + else if(musicIndex = MAX_MUSIC_STREAMS - 1) return; + } + for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot + { + if(mixChannelsActive_g[mixIndex] == NULL) break; + else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return; + } + + 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); } 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; + if (info.channels == 2){ + currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false); + } + else{ + currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false); + } - currentMusic.loop = true; // We loop by default + currentMusic[musicIndex].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) * currentMusic[musicIndex].channels; + currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream); } } 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); + 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) / ((float)currentMusic[musicIndex].sampleRate); musicEnabled = true; - TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic.totalSamplesLeft); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic.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); + 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); - // NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream() + currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true); } 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) +// Stop music playing for individual music index of currentMusic array (close stream) +void StopMusicStream(int index) { - if (musicEnabled) + if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx) { - alSourceStop(currentMusic.source); - EmptyMusicStream(); // Empty music buffers - alDeleteSources(1, ¤tMusic.source); - alDeleteBuffers(2, currentMusic.buffers); + CloseAudioContext(currentMusic[index].ctx); - if (currentMusic.chipTune) + if (currentMusic[index].chipTune) { - jar_xm_free_context(currentMusic.chipctx); + jar_xm_free_context(currentMusic[index].chipctx); } else { - stb_vorbis_close(currentMusic.stream); + stb_vorbis_close(currentMusic[index].stream); } + + if(!getMusicStreamCount()) musicEnabled = false; } +} - musicEnabled = false; +//get number of music channels active at this time, this does not mean they are playing +int getMusicStreamCount(void) +{ + int musicCount; + 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) { TraceLog(INFO, "Pausing music stream"); - alSourcePause(currentMusic.source); + UpdateAudioContext(currentMusic[index].ctx, NULL, 0); // pushing null data auto pauses stream musicEnabled = 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(currentMusic[musicIndex].ctx){ + alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PAUSED) + { + TraceLog(INFO, "Resuming music stream"); + alSourcePlay(currentMusic[musicIndex].ctx->alSource); + musicEnabled = true; + } } } @@ -922,17 +896,24 @@ bool IsMusicPlaying(void) { bool playing = false; ALint state; - - alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); - if (state == AL_PLAYING) playing = true; + + for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) + { + if(currentMusic[musicIndex].ctx){ + alGetSourcei(currentMusic[musicIndex].ctx->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(currentMusic[musicIndex].ctx){ + alSourcef(currentMusic[musicIndex].ctx->alSource, AL_GAIN, volume); + } } // Get current music time length (in seconds) diff --git a/src/audio.h b/src/audio.h index afd881b7..a1602bd9 100644 --- a/src/audio.h +++ b/src/audio.h @@ -102,13 +102,14 @@ void SetSoundPitch(Sound sound, float pitch); // Set pitch for 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 +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(void); // Check if music is playing -void SetMusicVolume(float volume); // Set volume for music (1.0 is max level) +void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level) float GetMusicTimeLength(void); // Get music time length (in seconds) float GetMusicTimePlayed(void); // Get current music time played (in seconds) +int getMusicStreamCount(void); #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index d464c8e9..0c49a085 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -893,13 +893,14 @@ void SetSoundPitch(Sound sound, float pitch); // Set pitch for 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 +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(void); // Check if music is playing -void SetMusicVolume(float volume); // Set volume for music (1.0 is max level) +void SetMusicVolume(int index, float volume); // Set volume for music (1.0 is max level) float GetMusicTimeLength(void); // Get current music time length (in seconds) float GetMusicTimePlayed(void); // Get current music time played (in seconds) +int getMusicStreamCount(void); #ifdef __cplusplus } -- cgit v1.2.3 From ad3d270c429844462f3fd62fa12257760fac24b5 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 11 May 2016 18:14:59 -0700 Subject: added set pitch for music streams --- src/audio.c | 40 ++++++++++++++++++++++------------------ src/audio.h | 3 ++- src/raylib.h | 3 ++- 3 files changed, 26 insertions(+), 20 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 39be4eeb..f89be8bf 100644 --- a/src/audio.c +++ b/src/audio.c @@ -113,7 +113,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS]; // What mix channels are currently active static bool musicEnabled = false; -static Music currentMusic[2]; // Current music loaded, up to two can play at the same time +static Music currentMusic[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -797,18 +797,18 @@ void PlayMusicStream(char *fileName) TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels); TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); + currentMusic[musicIndex].loop = true; // We loop by default + musicEnabled = true; + + 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].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false); } else{ currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false); } - - currentMusic[musicIndex].loop = true; // We loop by default - musicEnabled = true; - - currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * currentMusic[musicIndex].channels; - currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream); } } else if (strcmp(GetExtension(fileName),"xm") == 0) @@ -820,7 +820,7 @@ void PlayMusicStream(char *fileName) 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) / ((float)currentMusic[musicIndex].sampleRate); + currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f; musicEnabled = true; TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft); @@ -891,18 +891,15 @@ void ResumeMusicStream(int index) } } -// Check if music is playing -bool IsMusicPlaying(void) +// Check if any music is playing +bool IsMusicPlaying(int index) { bool playing = false; ALint state; - for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) - { - if(currentMusic[musicIndex].ctx){ - alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state); - if (state == AL_PLAYING) playing = true; - } + if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ + alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) playing = true; } return playing; @@ -911,8 +908,15 @@ bool IsMusicPlaying(void) // Set volume for music void SetMusicVolume(int index, float volume) { - if(currentMusic[musicIndex].ctx){ - alSourcef(currentMusic[musicIndex].ctx->alSource, AL_GAIN, volume); + if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ + alSourcef(currentMusic[index].ctx->alSource, AL_GAIN, volume); + } +} + +void SetMusicPitch(int index, float pitch) +{ + if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ + alSourcef(currentMusic[index].ctx->alSource, AL_PITCH, pitch); } } diff --git a/src/audio.h b/src/audio.h index a1602bd9..fef85b4f 100644 --- a/src/audio.h +++ b/src/audio.h @@ -105,11 +105,12 @@ void UpdateMusicStream(void); // Updates buffe 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(void); // Check if music is playing +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(void); // Get music time length (in seconds) float GetMusicTimePlayed(void); // Get current music time played (in seconds) int getMusicStreamCount(void); +void SetMusicPitch(int index, float pitch); #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index 0c49a085..b9390d31 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -896,11 +896,12 @@ void UpdateMusicStream(void); // Updates buffe 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(void); // Check if music is playing +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(void); // Get current music time length (in seconds) float GetMusicTimePlayed(void); // Get current music time played (in seconds) int getMusicStreamCount(void); +void SetMusicPitch(int index, float pitch); #ifdef __cplusplus } -- cgit v1.2.3 From 9737c58054d5d0cc636fca0c998b31a69d501970 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 11 May 2016 20:15:37 -0700 Subject: PlayMusicStream now uses index --- src/audio.c | 29 +++++++++++++++++++---------- src/audio.h | 2 +- src/raylib.h | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index f89be8bf..6a8d251e 100644 --- a/src/audio.c +++ b/src/audio.c @@ -763,19 +763,18 @@ 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 musicIndex; + int musicIndex = index; int mixIndex; - for(musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot - { - if(currentMusic[musicIndex].stream == NULL && !currentMusic[musicIndex].chipTune) break; - else if(musicIndex = MAX_MUSIC_STREAMS - 1) return; - } + + if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) return 1; // error + for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot { if(mixChannelsActive_g[mixIndex] == NULL) break; - else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return; + else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error } @@ -787,6 +786,7 @@ void PlayMusicStream(char *fileName) if (currentMusic[musicIndex].stream == NULL) { TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); + return 3; // error } else { @@ -828,9 +828,18 @@ void PlayMusicStream(char *fileName) currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true); } - else TraceLog(WARNING, "[%s] XM file could not be opened", fileName); + else + { + TraceLog(WARNING, "[%s] XM file could not be opened", fileName); + return 4; // error + } + } + else + { + TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); + return 5; // error } - else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); + return 0; // normal return } // Stop music playing for individual music index of currentMusic array (close stream) diff --git a/src/audio.h b/src/audio.h index fef85b4f..d09c4acc 100644 --- a/src/audio.h +++ b/src/audio.h @@ -100,7 +100,7 @@ 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) +int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) void UpdateMusicStream(void); // Updates buffers for music streaming void StopMusicStream(int index); // Stop music playing (close stream) void PauseMusicStream(int index); // Pause music playing diff --git a/src/raylib.h b/src/raylib.h index a6507906..cb17aa78 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -894,7 +894,7 @@ 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) +int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) void UpdateMusicStream(void); // Updates buffers for music streaming void StopMusicStream(int index); // Stop music playing (close stream) void PauseMusicStream(int index); // Pause music playing -- cgit v1.2.3 From f0ada8c40d7887654d05c62f980a0a5473c1d8a7 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 11 May 2016 22:37:53 -0700 Subject: apply index to remaining functions --- src/audio.c | 108 +++++++++++++++++++++++++++++++---------------------------- src/audio.h | 6 ++-- src/raylib.h | 6 ++-- 3 files changed, 62 insertions(+), 58 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 6a8d251e..94729566 100644 --- a/src/audio.c +++ b/src/audio.c @@ -118,12 +118,12 @@ static Music currentMusic[MAX_MUSIC_STREAMS]; // Current //---------------------------------------------------------------------------------- // 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, ALuint buffer); // 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 @@ -766,7 +766,6 @@ void SetSoundPitch(Sound sound, float pitch) // returns 0 on success int PlayMusicStream(int musicIndex, char *fileName) { - int musicIndex = index; int mixIndex; if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) return 1; // error @@ -930,36 +929,36 @@ void SetMusicPitch(int index, float 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) + if (currentMusic[index].chipTune) { 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 + jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples); + secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value } 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); + int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels; + int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft; + secondsPlayed = (float)samplesPlayed / (currentMusic[index].ctx->sampleRate * currentMusic[index].ctx->channels); } @@ -971,9 +970,10 @@ float GetMusicTimePlayed(void) //---------------------------------------------------------------------------------- // Fill music buffers with new data from music stream -static bool BufferMusicStream(ALuint buffer) +static bool BufferMusicStream(int index, ALuint buffer) { 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 @@ -981,93 +981,97 @@ static bool BufferMusicStream(ALuint buffer) if (musicEnabled) { - if (currentMusic.chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. + if (currentMusic[index].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 + int readlen = MUSIC_BUFFER_SIZE_FLOAT / 2; + jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location + size += readlen * currentMusic[index].ctx->channels; // Not sure if this is what it needs + + alBufferData(buffer, currentMusic[index].ctx->alFormat, pcmf, size*sizeof(float), 48000); + currentMusic[index].totalSamplesLeft -= size; + if(currentMusic[index].totalSamplesLeft <= 0) active = false; } else { while (size < MUSIC_BUFFER_SIZE_SHORT) { - 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); + streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size); + if (streamedBytes > 0) size += (streamedBytes*currentMusic[index].ctx->channels); else break; } + + if (size > 0) + { + alBufferData(buffer, currentMusic[index].ctx->alFormat, pcm, size*sizeof(short), currentMusic[index].ctx->sampleRate); + currentMusic[index].totalSamplesLeft -= size; + + if(currentMusic[index].totalSamplesLeft <= 0) active = false; // end if no more samples left + } + else + { + active = false; + TraceLog(WARNING, "No more data obtained from stream"); + } } 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"); - } - 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].source, AL_BUFFERS_QUEUED, &queued); while (queued > 0) { - alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); + alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer); queued--; } } // Update (re-fill) music buffers if data already processed -void UpdateMusicStream(void) +void UpdateMusicStream(int index) { ALuint buffer = 0; ALint processed = 0; bool active = true; - if (musicEnabled) + if (index < MAX_MUSIC_STREAMS && musicEnabled) { // Get the number of already processed buffers (if any) - alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(currentMusic[index].source, AL_BUFFERS_PROCESSED, &processed); while (processed > 0) { // Recover processed buffer for refill - alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); + alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer); // Refill buffer active = BufferMusicStream(buffer); // If no more data to stream, restart music (if loop) - if ((!active) && (currentMusic.loop)) + if ((!active) && (currentMusic[index].loop)) { - if(currentMusic.chipTune) + if(currentMusic[index].chipTune) { - currentMusic.totalSamplesLeft = currentMusic.totalLengthSeconds * currentMusic.sampleRate; + currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate; } else { - stb_vorbis_seek_start(currentMusic.stream); - currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream)*currentMusic.channels; + stb_vorbis_seek_start(currentMusic[index].stream); + currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream)*currentMusic[index].ctx->channels; } active = BufferMusicStream(buffer); } // Add refilled buffer to queue again... don't let the music stop! - alSourceQueueBuffers(currentMusic.source, 1, &buffer); + alSourceQueueBuffers(currentMusic[index].source, 1, &buffer); if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); @@ -1075,9 +1079,9 @@ void UpdateMusicStream(void) } ALenum state; - alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); + alGetSourcei(currentMusic[index].source, AL_SOURCE_STATE, &state); - if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source); + if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].source); if (!active) StopMusicStream(); } diff --git a/src/audio.h b/src/audio.h index d09c4acc..63c1c136 100644 --- a/src/audio.h +++ b/src/audio.h @@ -101,14 +101,14 @@ void SetSoundVolume(Sound sound, float volume); // Set volume fo void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) -void UpdateMusicStream(void); // Updates buffers for music streaming +void UpdateMusicStream(int index); // Updates buffers for music streaming void StopMusicStream(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(void); // Get music time length (in seconds) -float GetMusicTimePlayed(void); // Get current music time played (in seconds) +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); diff --git a/src/raylib.h b/src/raylib.h index cb17aa78..05c945f7 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -895,14 +895,14 @@ void SetSoundVolume(Sound sound, float volume); // Set volume fo void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) -void UpdateMusicStream(void); // Updates buffers for music streaming +void UpdateMusicStream(int index); // Updates buffers for music streaming void StopMusicStream(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(void); // Get current music time length (in seconds) -float GetMusicTimePlayed(void); // Get current music time played (in seconds) +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); -- cgit v1.2.3 From 075f51e0a3abfd9ebdfc66ee862f933a993105ca Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 12 May 2016 12:20:23 +0200 Subject: Simplified internal (default) dynamic buffers --- src/raylib.h | 2 +- src/rlgl.c | 200 ++++++++++++++++++++++++----------------------------------- src/rlgl.h | 2 +- 3 files changed, 84 insertions(+), 120 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 634ab143..911fd8b5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -376,7 +376,7 @@ typedef struct Mesh { float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices; // vertex indices (in case vertex data comes indexed) - int triangleCount; // number of triangles to draw + int triangleCount; // number of triangles stored (indexed or not) BoundingBox bounds; // mesh limits defined by min and max points diff --git a/src/rlgl.c b/src/rlgl.c index 3c0d9e79..0c0da221 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -128,54 +128,23 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -// Vertex buffer (position + color arrays) -// NOTE: Used for lines and triangles VAOs +// Dynamic vertex buffers (position + texcoords + colors + indices arrays) typedef struct { - int vCounter; - int cCounter; - float *vertices; // 3 components per vertex - unsigned char *colors; // 4 components per vertex -} VertexPositionColorBuffer; - -// Vertex buffer (position + texcoords + color arrays) -// NOTE: Not used -typedef struct { - int vCounter; - int tcCounter; - int cCounter; - float *vertices; // 3 components per vertex - float *texcoords; // 2 components per vertex - unsigned char *colors; // 4 components per vertex -} VertexPositionColorTextureBuffer; - -// Vertex buffer (position + texcoords + normals arrays) -// NOTE: Not used -typedef struct { - int vCounter; - int tcCounter; - int nCounter; - float *vertices; // 3 components per vertex - float *texcoords; // 2 components per vertex - float *normals; // 3 components per vertex - //short *normals; // NOTE: Less data load... but padding issues and normalizing required! -} VertexPositionTextureNormalBuffer; - -// Vertex buffer (position + texcoords + colors + indices arrays) -// NOTE: Used for quads VAO -typedef struct { - int vCounter; - int tcCounter; - int cCounter; - float *vertices; // 3 components per vertex - float *texcoords; // 2 components per vertex - unsigned char *colors; // 4 components per vertex + int vCounter; // vertex position counter to process (and draw) from full buffer + int tcCounter; // vertex texcoord counter to process (and draw) from full buffer + int cCounter; // vertex color counter to process (and draw) from full buffer + float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) - unsigned int *indices; // 6 indices per quad (could be int) + unsigned int *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad) #elif defined(GRAPHICS_API_OPENGL_ES2) - unsigned short *indices; // 6 indices per quad (must be short) + unsigned short *indices; // vertex indices (in case vertex data comes indexed) (6 indices per quad) // NOTE: 6*2 byte = 12 byte, not alignment problem! #endif -} VertexPositionColorTextureIndexBuffer; + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int vboId[4]; // OpenGL Vertex Buffer Objects id (4 types of vertex data) +} DynamicBuffer; // Draw call type // NOTE: Used to track required draw-calls, organized by texture @@ -205,18 +174,9 @@ static DrawMode currentDrawMode; static float currentDepth = -1.0f; -// Default vertex buffers for lines, triangles and quads -static VertexPositionColorBuffer lines; // No texture support -static VertexPositionColorBuffer triangles; // No texture support -static VertexPositionColorTextureIndexBuffer quads; - -// Default vertex buffers VAOs (if supported) -static GLuint vaoLines, vaoTriangles, vaoQuads; - -// Default vertex buffers VBOs -static GLuint linesBuffer[2]; // Lines buffers (position, color) -static GLuint trianglesBuffer[2]; // Triangles buffers (position, color) -static GLuint quadsBuffer[4]; // Quads buffers (position, texcoord, color, index) +static DynamicBuffer lines; +static DynamicBuffer triangles; +static DynamicBuffer quads; // Default buffers draw calls static DrawCall *draws; @@ -1207,7 +1167,7 @@ void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires) glEnableVertexAttribArray(material.shader.texcoord2Loc); } - if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); + if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); } // Draw call! @@ -1692,7 +1652,6 @@ 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 - #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLuint vaoId = 0; // Vertex Array Objects (VAO) @@ -2407,22 +2366,28 @@ static void LoadDefaultBuffers(void) // Lines - Initialize arrays (vertex position and color data) lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line + lines.texcoords = NULL; + lines.indices = NULL; for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0f; for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0; lines.vCounter = 0; lines.cCounter = 0; + lines.tcCounter = 0; // Triangles - Initialize arrays (vertex position and color data) triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle + triangles.texcoords = NULL; + triangles.indices = NULL; for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0f; for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0; triangles.vCounter = 0; triangles.cCounter = 0; + triangles.tcCounter = 0; // Quads - Initialize arrays (vertex position, texcoord, color data and indexes) quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad @@ -2468,96 +2433,95 @@ static void LoadDefaultBuffers(void) if (vaoSupported) { // Initialize Lines VAO - glGenVertexArrays(1, &vaoLines); - glBindVertexArray(vaoLines); + glGenVertexArrays(1, &lines.vaoId); + glBindVertexArray(lines.vaoId); } - // Create buffers for our vertex data - glGenBuffers(2, linesBuffer); - // Lines - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); + glGenBuffers(2, &lines.vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); // Vertex color buffer (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); + glGenBuffers(2, &lines.vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", vaoLines); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", linesBuffer[0], linesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (lines)", lines.vaoId); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (lines)", lines.vboId[0], lines.vboId[1]); // Upload and link triangles vertex buffers if (vaoSupported) { // Initialize Triangles VAO - glGenVertexArrays(1, &vaoTriangles); - glBindVertexArray(vaoTriangles); + glGenVertexArrays(1, &triangles.vaoId); + glBindVertexArray(triangles.vaoId); } - // Create buffers for our vertex data - glGenBuffers(2, trianglesBuffer); - // Triangles - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); + glGenBuffers(1, &triangles.vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); // Vertex color buffer (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); + glGenBuffers(1, &triangles.vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", vaoTriangles); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully(triangles)", trianglesBuffer[0], trianglesBuffer[1]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (triangles)", triangles.vaoId); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully(triangles)", triangles.vboId[0], triangles.vboId[1]); // Upload and link quads vertex buffers if (vaoSupported) { // Initialize Quads VAO - glGenVertexArrays(1, &vaoQuads); - glBindVertexArray(vaoQuads); + glGenVertexArrays(1, &quads.vaoId); + glBindVertexArray(quads.vaoId); } - // Create buffers for our vertex data - glGenBuffers(4, quadsBuffer); - // Quads - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); + glGenBuffers(1, &quads.vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.vertexLoc); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); // Vertex texcoord buffer (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); + glGenBuffers(1, &quads.vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.texcoordLoc); glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); // Vertex color buffer (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); + glGenBuffers(1, &quads.vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(currentShader.colorLoc); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); // Fill index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); + glGenBuffers(1, &quads.vboId[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); #if defined(GRAPHICS_API_OPENGL_33) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); #elif defined(GRAPHICS_API_OPENGL_ES2) glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW); #endif - if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", vaoQuads); - else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quadsBuffer[0], quadsBuffer[1], quadsBuffer[2], quadsBuffer[3]); + if (vaoSupported) TraceLog(INFO, "[VAO ID %i] Default buffers VAO initialized successfully (quads)", quads.vaoId); + else TraceLog(INFO, "[VBO ID %i][VBO ID %i][VBO ID %i][VBO ID %i] Default buffers VBOs initialized successfully (quads)", quads.vboId[0], quads.vboId[1], quads.vboId[2], quads.vboId[3]); // Unbind the current VAO if (vaoSupported) glBindVertexArray(0); @@ -2573,15 +2537,15 @@ static void UpdateDefaultBuffers(void) if (lines.vCounter > 0) { // Activate Lines VAO - if (vaoSupported) glBindVertexArray(vaoLines); + if (vaoSupported) glBindVertexArray(lines.vaoId); // Lines - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*lines.vCounter, lines.vertices); // target - offset (in bytes) - size (in bytes) - data pointer // Lines - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*lines.cCounter, lines.colors); } @@ -2590,15 +2554,15 @@ static void UpdateDefaultBuffers(void) if (triangles.vCounter > 0) { // Activate Triangles VAO - if (vaoSupported) glBindVertexArray(vaoTriangles); + if (vaoSupported) glBindVertexArray(triangles.vaoId); // Triangles - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*triangles.vCounter, triangles.vertices); // Triangles - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*triangles.cCounter, triangles.colors); } @@ -2607,20 +2571,20 @@ static void UpdateDefaultBuffers(void) if (quads.vCounter > 0) { // Activate Quads VAO - if (vaoSupported) glBindVertexArray(vaoQuads); + if (vaoSupported) glBindVertexArray(quads.vaoId); // Quads - vertex positions buffer - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices); // Quads - texture coordinates buffer - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords); // Quads - colors buffer - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*quads.vCounter, quads.colors); @@ -2659,17 +2623,17 @@ static void DrawDefaultBuffers(void) if (vaoSupported) { - glBindVertexArray(vaoLines); + glBindVertexArray(lines.vaoId); } else { // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.vertexLoc); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(currentShader.colorLoc); } @@ -2687,17 +2651,17 @@ static void DrawDefaultBuffers(void) if (vaoSupported) { - glBindVertexArray(vaoTriangles); + glBindVertexArray(triangles.vaoId); } else { // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.vertexLoc); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(currentShader.colorLoc); } @@ -2717,26 +2681,26 @@ static void DrawDefaultBuffers(void) if (vaoSupported) { - glBindVertexArray(vaoQuads); + glBindVertexArray(quads.vaoId); } else { // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.vertexLoc); // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); glEnableVertexAttribArray(currentShader.texcoordLoc); // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]); + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(currentShader.colorLoc); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); } //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); @@ -2806,21 +2770,21 @@ static void UnloadDefaultBuffers(void) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Delete VBOs from GPU (VRAM) - glDeleteBuffers(1, &linesBuffer[0]); - glDeleteBuffers(1, &linesBuffer[1]); - glDeleteBuffers(1, &trianglesBuffer[0]); - glDeleteBuffers(1, &trianglesBuffer[1]); - glDeleteBuffers(1, &quadsBuffer[0]); - glDeleteBuffers(1, &quadsBuffer[1]); - glDeleteBuffers(1, &quadsBuffer[2]); - glDeleteBuffers(1, &quadsBuffer[3]); + glDeleteBuffers(1, &lines.vboId[0]); + glDeleteBuffers(1, &lines.vboId[1]); + glDeleteBuffers(1, &triangles.vboId[0]); + glDeleteBuffers(1, &triangles.vboId[1]); + glDeleteBuffers(1, &quads.vboId[0]); + glDeleteBuffers(1, &quads.vboId[1]); + glDeleteBuffers(1, &quads.vboId[2]); + glDeleteBuffers(1, &quads.vboId[3]); if (vaoSupported) { // Delete VAOs from GPU (VRAM) - glDeleteVertexArrays(1, &vaoLines); - glDeleteVertexArrays(1, &vaoTriangles); - glDeleteVertexArrays(1, &vaoQuads); + glDeleteVertexArrays(1, &lines.vaoId); + glDeleteVertexArrays(1, &triangles.vaoId); + glDeleteVertexArrays(1, &quads.vaoId); } // Free vertex arrays memory from CPU (RAM) diff --git a/src/rlgl.h b/src/rlgl.h index 6e694dae..7b88bc9e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -147,7 +147,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices; // vertex indices (in case vertex data comes indexed) - int triangleCount; // number of triangles to draw + int triangleCount; // number of triangles stored (indexed or not) BoundingBox bounds; // mesh limits defined by min and max points -- cgit v1.2.3 From 76ff4d220ee735b8b86bd4dae776665cf68e4fb4 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Sun, 15 May 2016 19:37:15 -0700 Subject: renamed everything so it is obvious what it does --- src/audio.c | 380 ++++++++++++++++++++++++++++------------------------------- src/audio.h | 15 +-- src/raylib.h | 15 +-- 3 files changed, 190 insertions(+), 220 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index cc5ca1a2..584d3ad1 100644 --- a/src/audio.c +++ b/src/audio.c @@ -77,10 +77,10 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -// 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 @@ -89,14 +89,14 @@ typedef struct AudioContext_t { 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... +// 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 context - AudioContext_t *ctx; // audio context + jar_xm_context_t *chipctx; // Stores jar_xm mixc + MixChannel_t *mixc; // mix channel int totalSamplesLeft; float totalLengthSeconds; @@ -111,9 +111,9 @@ 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 MixChannel_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS]; // 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 +static Music currentMusic[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -122,13 +122,17 @@ 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(int index); // Fill music buffers with data -static void EmptyMusicStream(int index); // 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 bool isMusicStreamReady(int index); // Checks if music buffer is ready to be refilled + +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 unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses +static unsigned short 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 @@ -139,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 @@ -155,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)); @@ -171,14 +175,14 @@ void CloseAudioDevice(void) { for(int index=0; index= MAX_AUDIO_CONTEXTS) return NULL; if(!IsAudioDeviceReady()) InitAudioDevice(); 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;xalBuffer[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 unsigned short 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); + } + else // process short buffers + { + short *ptr = (short*)data; + alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate); } - return 0; + alSourceQueueBuffers(mixc->alSource, 1, &buffer); + + return numberElements; } // fill buffer with zeros, returns number processed -static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer) +static unsigned short 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,28 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len) } } +// used to output raw audio streams, returns negative numbers on error +RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint) +{ + int mixIndex; + for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot + { + if(mixChannelsActive_g[mixIndex] == NULL) break; + else if(mixIndex = MAX_AUDIO_CONTEXTS - 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]); +} + //---------------------------------------------------------------------------------- @@ -807,14 +788,14 @@ int PlayMusicStream(int musicIndex, char *fileName) currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream); if (info.channels == 2){ - currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false); - currentMusic[musicIndex].ctx->playing = true; + currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); + currentMusic[musicIndex].mixc->playing = true; } else{ - currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false); - currentMusic[musicIndex].ctx->playing = true; + currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); + currentMusic[musicIndex].mixc->playing = true; } - if(!currentMusic[musicIndex].ctx) return 4; // error + if(!currentMusic[musicIndex].mixc) return 4; // error } } else if (strcmp(GetExtension(fileName),"xm") == 0) @@ -832,9 +813,9 @@ int PlayMusicStream(int musicIndex, char *fileName) 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); - currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true); - if(!currentMusic[musicIndex].ctx) return 5; // error - currentMusic[musicIndex].ctx->playing = true; + currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); + if(!currentMusic[musicIndex].mixc) return 5; // error + currentMusic[musicIndex].mixc->playing = true; } else { @@ -853,9 +834,9 @@ int PlayMusicStream(int musicIndex, char *fileName) // Stop music playing for individual music index of currentMusic array (close stream) void StopMusicStream(int index) { - if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx) + if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc) { - CloseAudioContext(currentMusic[index].ctx); + CloseMixChannel(currentMusic[index].mixc); if (currentMusic[index].chipTune) { @@ -889,11 +870,11 @@ int getMusicStreamCount(void) void PauseMusicStream(int index) { // Pause music stream if music available! - if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx && musicEnabled_g) + if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc && musicEnabled_g) { TraceLog(INFO, "Pausing music stream"); - alSourcePause(currentMusic[index].ctx->alSource); - currentMusic[index].ctx->playing = false; + alSourcePause(currentMusic[index].mixc->alSource); + currentMusic[index].mixc->playing = false; } } @@ -902,13 +883,13 @@ void ResumeMusicStream(int index) { // Resume music playing... if music available! ALenum state; - if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ - alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state); + if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){ + alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) { TraceLog(INFO, "Resuming music stream"); - alSourcePlay(currentMusic[index].ctx->alSource); - currentMusic[index].ctx->playing = true; + alSourcePlay(currentMusic[index].mixc->alSource); + currentMusic[index].mixc->playing = true; } } } @@ -919,8 +900,8 @@ bool IsMusicPlaying(int index) bool playing = false; ALint state; - if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ - alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state); + if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){ + alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) playing = true; } @@ -930,15 +911,15 @@ bool IsMusicPlaying(int index) // Set volume for music void SetMusicVolume(int index, float volume) { - if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){ - alSourcef(currentMusic[index].ctx->alSource, 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].ctx){ - alSourcef(currentMusic[index].ctx->alSource, AL_PITCH, pitch); + if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){ + alSourcef(currentMusic[index].mixc->alSource, AL_PITCH, pitch); } } @@ -962,19 +943,19 @@ float GetMusicTimeLength(int index) float GetMusicTimePlayed(int index) { float secondsPlayed; - if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx) + if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc) { if (currentMusic[index].chipTune) { uint64_t samples; jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples); - secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value + 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].ctx->channels; + 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].ctx->sampleRate * currentMusic[index].ctx->channels); + secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels); } } @@ -987,32 +968,32 @@ float GetMusicTimePlayed(int index) //---------------------------------------------------------------------------------- // Fill music buffers with new data from music stream -static bool BufferMusicStream(int index) +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 L+R samples + 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 (!currentMusic[index].ctx->playing && currentMusic[index].totalSamplesLeft > 0) - { - UpdateAudioContext(currentMusic[index].ctx, NULL, 0); - return true; // it is still active but it is paused - } - 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[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT / 2) - size = MUSIC_BUFFER_SIZE_FLOAT / 2; + if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) + size = MUSIC_BUFFER_SIZE_SHORT / 2; else size = currentMusic[index].totalSamplesLeft / 2; - - jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location - UpdateAudioContext(currentMusic[index].ctx, pcmf, size * 2); - currentMusic[index].totalSamplesLeft -= size * 2; + + for(int x=0; xchannels, pcm, size); - UpdateAudioContext(currentMusic[index].ctx, pcm, streamedBytes * currentMusic[index].ctx->channels); - currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].ctx->channels; + for(int x=0; xchannels, 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; + } + } } - - TraceLog(DEBUG, "Buffering index:%i, chiptune:%i", index, (int)currentMusic[index].chipTune); - if(currentMusic[index].totalSamplesLeft <= 0) active = false; return active; } @@ -1038,25 +1024,22 @@ static void EmptyMusicStream(int index) ALuint buffer = 0; int queued = 0; - alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued); while (queued > 0) { - alSourceUnqueueBuffers(currentMusic[index].ctx->alSource, 1, &buffer); + alSourceUnqueueBuffers(currentMusic[index].mixc->alSource, 1, &buffer); queued--; } } //determine if a music stream is ready to be written to -static bool isMusicStreamReady(int index) +static int IsMusicStreamReadyForBuffering(int index) { ALint processed = 0; - alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_PROCESSED, &processed); - - if(processed) return true; - - return false; + alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + return processed; } // Update (re-fill) music buffers if data already processed @@ -1064,21 +1047,22 @@ void UpdateMusicStream(int index) { ALenum state; bool active = true; - - if (index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].ctx && isMusicStreamReady(index)) + int numBuffers = IsMusicStreamReadyForBuffering(index); + + if (currentMusic[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].mixc && numBuffers) { - active = BufferMusicStream(index); + active = BufferMusicStream(index, numBuffers); - if (!active && currentMusic[index].loop && currentMusic[index].ctx->playing) + if (!active && currentMusic[index].loop) { if (currentMusic[index].chipTune) { - currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate; + currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * 48000; } else { stb_vorbis_seek_start(currentMusic[index].stream); - currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels; + currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels; } active = true; } @@ -1086,9 +1070,9 @@ void UpdateMusicStream(int index) if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); - alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state); + alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state); - if (state != AL_PLAYING && active && currentMusic[index].ctx->playing) alSourcePlay(currentMusic[index].ctx->alSource); + if (state != AL_PLAYING && active) alSourcePlay(currentMusic[index].mixc->alSource); if (!active) StopMusicStream(index); diff --git a/src/audio.h b/src/audio.h index 63c1c136..d3276bf6 100644 --- a/src/audio.h +++ b/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) @@ -112,6 +102,9 @@ float GetMusicTimePlayed(int index); // Get current m int getMusicStreamCount(void); void SetMusicPitch(int index, float pitch); +RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint); +void CloseRawAudioContext(RawAudioContext ctx); + #ifdef __cplusplus } #endif diff --git a/src/raylib.h b/src/raylib.h index ea9fbfcb..6efde710 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -451,10 +451,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 @@ -876,13 +873,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) @@ -906,6 +896,9 @@ float GetMusicTimePlayed(int index); // Get current m int getMusicStreamCount(void); void SetMusicPitch(int index, float pitch); +RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint); // used to output raw audio streams, returns negative numbers on error +void CloseRawAudioContext(RawAudioContext ctx); + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 41c5f3a0178027e9b74e563ab102f603a53e35bf Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Thu, 19 May 2016 20:44:09 -0700 Subject: Buffer for raw audio --- src/audio.c | 22 ++++++++++++++++++---- src/audio.h | 4 ++++ src/raylib.h | 6 +++++- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 6d8f876c..43e8be14 100644 --- a/src/audio.c +++ b/src/audio.c @@ -128,8 +128,8 @@ static void EmptyMusicStream(int index); // Empty music buffers 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 unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses -static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed +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 @@ -292,7 +292,7 @@ static void CloseMixChannel(MixChannel_t* mixc) // 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. -static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements) +static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements) { if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples @@ -331,7 +331,7 @@ static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numbe } // fill buffer with zeros, returns number processed -static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer) +static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer) { if(mixc->floatingPoint){ float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f}; @@ -377,6 +377,7 @@ 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; @@ -398,6 +399,19 @@ void CloseRawAudioContext(RawAudioContext 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; +} + + + //---------------------------------------------------------------------------------- diff --git a/src/audio.h b/src/audio.h index d3276bf6..1140a60a 100644 --- a/src/audio.h +++ b/src/audio.h @@ -102,8 +102,12 @@ float GetMusicTimePlayed(int index); // Get current m 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 } diff --git a/src/raylib.h b/src/raylib.h index 6efde710..986dc7bf 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -896,8 +896,12 @@ float GetMusicTimePlayed(int index); // Get current m int getMusicStreamCount(void); void SetMusicPitch(int index, float pitch); -RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint); // used to output raw audio streams, returns negative numbers on error +// 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 } -- cgit v1.2.3 From 7d1d9ff143cd7c6c55d3fd891b43e143431ea15f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 20 May 2016 09:36:02 +0200 Subject: Support DYNAMIC_DRAW mesh loading --- src/models.c | 10 +++++----- src/raylib.h | 2 +- src/rlgl.c | 17 ++++++++++------- src/rlgl.h | 2 +- 4 files changed, 17 insertions(+), 14 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index bb2d56c2..6d72d1e3 100644 --- a/src/models.c +++ b/src/models.c @@ -553,7 +553,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 +563,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 +668,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 +683,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(); diff --git a/src/raylib.h b/src/raylib.h index 986dc7bf..8a46ec35 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -803,7 +803,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) diff --git a/src/rlgl.c b/src/rlgl.c index 888a9313..cc2b8942 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1500,7 +1500,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 @@ -1510,6 +1510,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) @@ -1527,14 +1530,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); @@ -1543,7 +1546,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); } @@ -1559,7 +1562,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); } @@ -1575,7 +1578,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); } @@ -1591,7 +1594,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); } diff --git a/src/rlgl.h b/src/rlgl.h index a33e3a0a..a557ffa2 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -280,7 +280,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a textur 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 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 -- cgit v1.2.3 From 03cc031d00ab97ab46b61b66a6281a175c33541f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 20 May 2016 09:40:48 +0200 Subject: Remove TODO comments (already done) --- src/raylib.h | 1 - src/shapes.c | 1 - 2 files changed, 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 8a46ec35..32cd54a6 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -423,7 +423,6 @@ typedef struct Material { } Material; // 3d Model type -// TODO: Replace shader/testure by material typedef struct Model { Mesh mesh; // Vertex data buffers (RAM and VRAM) Matrix transform; // Local transform matrix diff --git a/src/shapes.c b/src/shapes.c index 14d11315..5b66e5ef 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -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 }; -- cgit v1.2.3 From c9e30f77540e9693ddecffc353964eb71e854842 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 20 May 2016 10:53:31 +0200 Subject: Review struct typedef to avoid pointers for users --- examples/physics_basic_rigidbody.c | 17 +++++++++-------- examples/physics_forces.c | 14 +++++++------- src/physac.c | 12 ++++++------ src/raylib.h | 12 ++++++------ 4 files changed, 28 insertions(+), 27 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/physics_basic_rigidbody.c b/examples/physics_basic_rigidbody.c index 917813ad..cd09f070 100644 --- a/examples/physics_basic_rigidbody.c +++ b/examples/physics_basic_rigidbody.c @@ -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 //-------------------------------------------------------------------------------------- diff --git a/examples/physics_forces.c b/examples/physics_forces.c index 74b40d57..f4eefa05 100644 --- a/examples/physics_forces.c +++ b/examples/physics_forces.c @@ -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 }); //-------------------------------------------------------------------------------------- diff --git a/src/physac.c b/src/physac.c index ed707474..181488ac 100644 --- a/src/physac.c +++ b/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); diff --git a/src/raylib.h b/src/raylib.h index 32cd54a6..fc1914bb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -535,13 +535,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 @@ -856,14 +856,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) -- cgit v1.2.3 From dcf5f45f687f2a534286aecd5e6471a0440b0c21 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 20 May 2016 12:28:07 +0200 Subject: Add lighting system -IN PROGRESS- Improved materials --- src/models.c | 12 +++++ src/raylib.h | 30 ++++++++++- src/rlgl.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/rlgl.h | 25 +++++++++ 4 files changed, 228 insertions(+), 6 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 6d72d1e3..44e30390 100644 --- a/src/models.c +++ b/src/models.c @@ -732,6 +732,18 @@ Material LoadDefaultMaterial(void) return material; } +// Load standard material (uses standard models 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); diff --git a/src/raylib.h b/src/raylib.h index fc1914bb..d98a0797 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -422,13 +422,38 @@ typedef struct Material { float normalDepth; // Normal map depth } Material; -// 3d Model type +// 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 +// TODO: Review contained data to support different light types and features +typedef struct LightData { + int id; + int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; + + Vector3 position; + Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) + float attenuation; // Lost of light intensity with distance (use radius?) + + Color diffuse; // Use Vector3 diffuse (including intensities)? + float intensity; + + Color specular; + //float specFactor; // Specular intensity ? + + //Color ambient; // Required? + + float coneAngle; // SpotLight +} LightData, *Light; + +// Light types +typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + // Ray type (useful for raycast) typedef struct Ray { Vector3 position; @@ -849,6 +874,9 @@ 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 DestroyLight(Light light); // Destroy a light and take it out of the list + //---------------------------------------------------------------------------------- // Physics System Functions (Module: physac) //---------------------------------------------------------------------------------- diff --git a/src/rlgl.c b/src/rlgl.c index cc2b8942..e971d747 100644 --- a/src/rlgl.c +++ b/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 @@ -199,6 +201,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,6 +233,7 @@ 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 @@ -235,6 +242,8 @@ static void UpdateDefaultBuffers(void); // Update default internal buffers ( 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 @@ -1749,11 +1758,19 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // 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); - + // Setup shader uniforms for material related data + // TODO: Check if using standard shader to get location points + + // 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); + + // TODO: Upload to shader material.colAmbient + // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); + + // TODO: Upload to shader material.colSpecular + // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); + // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id); @@ -1764,6 +1781,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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)) @@ -1771,7 +1791,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 + + // TODO: Upload to shader glossiness + //glUniform1f(???, material.glossiness); } + + // Setup shader uniforms for lights + SetShaderLights(material.shader); if (vaoSupported) { @@ -2198,6 +2224,55 @@ void SetBlendMode(int mode) } } +// Create a new light, initialize it and add to pool +// TODO: Review creation parameters (only generic ones) +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->direction = (Vector3){ 0.0f, 0.0f, 0.0f }; + light->intensity = 1.0f; + light->diffuse = diffuse; + light->specular = WHITE; + + // Add new light to the array + lights[lightsCount] = light; + + // Increase enabled lights count + lightsCount++; + + return light; +} + +// 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 //---------------------------------------------------------------------------------- @@ -2415,6 +2490,32 @@ static Shader LoadDefaultShader(void) return shader; } +// Load standard shader +// NOTE: This shader supports: +// - Up to 3 different maps: diffuse, normal, specular +// - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth +// - Up to 8 lights: Point, Directional or Spot +static Shader LoadStandardShader(void) +{ + Shader shader; + + char *vShaderStr; + char *fShaderStr; + + // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330) + + // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs) + + shader.id = LoadShaderProgram(vShaderStr, fShaderStr); + + 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); // TODO: Review locations fetching + + 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) @@ -2900,6 +3001,62 @@ 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 +// TODO: Review memcpy() and parameters pass +static void SetShaderLights(Shader shader) +{ + /* + // NOTE: Standard Shader must include the following data: + + // Shader Light struct + struct Light { + vec3 position; + vec3 direction; + + vec3 diffuse; + float intensity; + } + + const int maxLights = 8; + uniform int lightsCount; // Number of lights + uniform Light lights[maxLights]; + */ + + int locPoint; + char locName[32] = "lights[x].position\0"; + + glUseProgram(shader.id); + + locPoint = glGetUniformLocation(shader.id, "lightsCount"); + glUniform1i(locPoint, lightsCount); + + for (int i = 0; i < lightsCount; i++) + { + locName[7] = '0' + i; + + memcpy(&locName[10], "position\0", strlen("position\0")); + locPoint = glGetUniformLocation(shader.id, locName); + glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + + memcpy(&locName[10], "direction\0", strlen("direction\0")); + locPoint = glGetUniformLocation(shader.id, locName); + glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z); + + memcpy(&locName[10], "diffuse\0", strlen("diffuse\0")); + 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); + + // TODO: Pass to the shader any other required data from LightData struct + } + + glUseProgram(0); +} + // Read text data from file // NOTE: text chars array should be freed manually static char *ReadTextFile(const char *fileName) diff --git a/src/rlgl.h b/src/rlgl.h index a557ffa2..39941b33 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -209,6 +209,28 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; float glossiness; float normalDepth; } Material; + + // Light type + // TODO: Review contained data to support different light types and features + typedef struct LightData { + int id; + int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; + + Vector3 position; + Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) + float attenuation; // Lost of light intensity with distance (use radius?) + + Color diffuse; // Use Vector3 diffuse (including intensities)? + float intensity; + + Color specular; + //float specFactor; // Specular intensity ? + + //Color ambient; // Required? + + float coneAngle; // SpotLight + } LightData, *Light; // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; @@ -311,6 +333,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 -- cgit v1.2.3 From 30c8058fca39e4d6566b2fc06ae2498c48c00717 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Fri, 20 May 2016 17:18:07 +0200 Subject: Add standard lighting (1/3) - Ambient and lambert lighting added. - Ambient and diffuse colors linked to standard shader. - Single light linked to standard shader. - LoadStandardMaterial() and depending functions added. --- src/models.c | 6 +-- src/raylib.h | 9 ++-- src/rlgl.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 131 insertions(+), 33 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 414f6716..2629dffd 100644 --- a/src/models.c +++ b/src/models.c @@ -732,13 +732,13 @@ Material LoadDefaultMaterial(void) return material; } -// Load standard material (uses standard models shader) +// 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(); + material.shader = GetStandardShader(); return material; } @@ -1240,7 +1240,7 @@ 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; rlglDrawMesh(model.mesh, model.material, model.transform); } diff --git a/src/raylib.h b/src/raylib.h index d98a0797..48534fd6 100644 --- a/src/raylib.h +++ b/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) @@ -444,11 +444,8 @@ typedef struct LightData { float intensity; Color specular; - //float specFactor; // Specular intensity ? - - //Color ambient; // Required? - float coneAngle; // SpotLight + float coneAngle; // SpotLight } LightData, *Light; // Light types @@ -836,6 +833,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) @@ -865,6 +863,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 diff --git a/src/rlgl.c b/src/rlgl.c index c5048aff..e2195e4d 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -191,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 @@ -236,6 +237,7 @@ static Shader LoadDefaultShader(void); // Load default shader (just vertex 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 @@ -1018,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) @@ -1046,6 +1049,7 @@ void rlglClose(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UnloadDefaultShader(); + UnloadStandardShader(); UnloadDefaultBuffers(); // Delete default white texture @@ -1757,19 +1761,30 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Send combined model-view-projection matrix to shader glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - - // Setup shader uniforms for material related data - // TODO: Check if using standard shader to get location points // 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)); + + // 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); - // TODO: Upload to shader material.colAmbient - // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255); - - // TODO: Upload to shader material.colSpecular - // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); + // TODO: Upload to shader glossiness + //glUniform1f(???, material.glossiness); + } // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); @@ -1791,13 +1806,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); glUniform1i(material.shader.mapSpecularLoc, 2); // Texture fits in active texture unit 2 - - // TODO: Upload to shader glossiness - //glUniform1f(???, material.glossiness); } - - // Setup shader uniforms for lights - //SetShaderLights(material.shader); if (vaoSupported) { @@ -2148,6 +2157,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) { @@ -2499,13 +2519,75 @@ static Shader LoadStandardShader(void) { Shader shader; - char *vShaderStr; - char *fShaderStr; - - // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330) - - // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs) - + // Vertex shader directly defined, no external file required +#if defined(GRAPHICS_API_OPENGL_33) + char vShaderStr[] = "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec3 vertexNormal; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" + "out vec3 fragNormal; \n" +#elif defined(GRAPHICS_API_OPENGL_ES2) + char vShaderStr[] = "#version 100 \n" + "attribute vec3 vertexPosition; \n" + "attribute vec3 vertexNormal; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "varying vec3 fragNormal; \n" +#endif + "uniform mat4 mvpMatrix; \n" + "uniform mat4 modelMatrix; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); \n" + " fragNormal = normalize(normalMatrix*vertexNormal); \n" + " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot) + // Fragment shader directly defined, no external file required +#if defined(GRAPHICS_API_OPENGL_33) + char fShaderStr[] = "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "in vec3 fragNormal; \n" + "out vec4 finalColor; \n" +#elif defined(GRAPHICS_API_OPENGL_ES2) + char fShaderStr[] = "#version 100 \n" + "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "varying vec3 fragNormal; \n" +#endif + "uniform sampler2D texture0; \n" + "uniform vec4 fragTintColor; \n" + "uniform vec4 colAmbient; \n" + "uniform vec4 colSpecular; \n" + "uniform vec3 lightDir; \n" + "vec3 LambertLighting(in vec3 n, in vec3 l) \n" + "{ \n" + " return clamp(dot(n, l), 0, 1)*fragTintColor.rgb; \n" + "} \n" + + "void main() \n" + "{ \n" + " vec3 n = normalize(fragNormal); \n" + " vec3 l = normalize(lightDir); \n" +#if defined(GRAPHICS_API_OPENGL_33) + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a); \n" // Stupid specular color operation to avoid shader location errors +#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" +#endif + "} \n"; + shader.id = LoadShaderProgram(vShaderStr, fShaderStr); if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id); @@ -2554,10 +2636,23 @@ static void UnloadDefaultShader(void) //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) { @@ -3006,6 +3101,9 @@ static void UnloadDefaultBuffers(void) // TODO: Review memcpy() and parameters pass static void SetShaderLights(Shader shader) { + // Note: currently working with one light (index 0) + // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights) + /* // NOTE: Standard Shader must include the following data: @@ -3023,7 +3121,7 @@ static void SetShaderLights(Shader shader) uniform Light lights[maxLights]; */ - int locPoint; + /*int locPoint; char locName[32] = "lights[x].position\0"; glUseProgram(shader.id); @@ -3052,9 +3150,10 @@ static void SetShaderLights(Shader shader) glUniform1f(locPoint, lights[i]->intensity); // TODO: Pass to the shader any other required data from LightData struct - } + }*/ - glUseProgram(0); + int locPoint = GetShaderLocation(shader, "lightDir"); + glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z); } // Read text data from file -- cgit v1.2.3 From c320a21f2b0e96f7605624e84048ccab9700b516 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Sat, 21 May 2016 18:16:39 +0200 Subject: Add standard lighting (2/3) - 3 light types added (point, directional, spot). - DrawLights() function added using line shapes. - Standard lighting example added. - Removed useless struct variables from material and light. - Fixed light attributes dynamic locations errors. - Standard vertex and fragment shaders temporally added until rewrite it as char pointers in rlgl. TODO: - Add normal and specular maps calculations in standard shader. - Add control structs to handle which attributes needs to be calculated (textures, specular...). - Adapt standard shader to version 110. - Rewrite standard shader as char pointers in rlgl. --- examples/resources/shaders/standard.fs | 136 +++++++++++++++++++++ examples/resources/shaders/standard.vs | 23 ++++ examples/shaders_standard_lighting.c | 118 ++++++++++++++++++ src/raylib.h | 15 ++- src/rlgl.c | 213 ++++++++++++++------------------- src/rlgl.h | 32 ++--- 6 files changed, 388 insertions(+), 149 deletions(-) create mode 100644 examples/resources/shaders/standard.fs create mode 100644 examples/resources/shaders/standard.vs create mode 100644 examples/shaders_standard_lighting.c (limited to 'src/raylib.h') diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs new file mode 100644 index 00000000..30c841d2 --- /dev/null +++ b/examples/resources/shaders/standard.fs @@ -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); +} diff --git a/examples/resources/shaders/standard.vs b/examples/resources/shaders/standard.vs new file mode 100644 index 00000000..fc0a5ff4 --- /dev/null +++ b/examples/resources/shaders/standard.vs @@ -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); +} \ No newline at end of file diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c new file mode 100644 index 00000000..7a9cc086 --- /dev/null +++ b/examples/shaders_standard_lighting.c @@ -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; +} \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index 48534fd6..9cd02fd8 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -418,7 +418,7 @@ 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; @@ -430,22 +430,19 @@ typedef struct Model { } Model; // Light type -// TODO: Review contained data to support different light types and features typedef struct LightData { int id; int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; Vector3 position; - Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) - float attenuation; // Lost of light intensity with distance (use radius?) + 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 (including intensities)? + Color diffuse; // Use Vector3 diffuse float intensity; - Color specular; - - float coneAngle; // SpotLight + float coneAngle; // Spot light max angle } LightData, *Light; // Light types @@ -805,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 @@ -874,6 +872,7 @@ 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 //---------------------------------------------------------------------------------- diff --git a/src/rlgl.c b/src/rlgl.c index e2195e4d..55677f3e 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1773,6 +1773,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // 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); @@ -1782,8 +1785,8 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // 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); - // TODO: Upload to shader glossiness - //glUniform1f(???, material.glossiness); + // Upload to shader glossiness + glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness); } // Set shader textures (diffuse, normal, specular) @@ -2245,7 +2248,6 @@ void SetBlendMode(int mode) } // Create a new light, initialize it and add to pool -// TODO: Review creation parameters (only generic ones) Light CreateLight(int type, Vector3 position, Color diffuse) { // Allocate dynamic memory @@ -2257,10 +2259,9 @@ Light CreateLight(int type, Vector3 position, Color diffuse) light->enabled = true; light->position = position; - light->direction = (Vector3){ 0.0f, 0.0f, 0.0f }; + light->target = (Vector3){ 0.0f, 0.0f, 0.0f }; light->intensity = 1.0f; light->diffuse = diffuse; - light->specular = WHITE; // Add new light to the array lights[lightsCount] = light; @@ -2271,6 +2272,31 @@ Light CreateLight(int type, Vector3 position, Color diffuse) 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)); + } + 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) { @@ -2488,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"; @@ -2513,87 +2539,17 @@ static Shader LoadDefaultShader(void) // Load standard shader // NOTE: This shader supports: // - Up to 3 different maps: diffuse, normal, specular -// - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth +// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth // - Up to 8 lights: Point, Directional or Spot static Shader LoadStandardShader(void) { - Shader shader; - - // Vertex shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char vShaderStr[] = "#version 330 \n" - "in vec3 vertexPosition; \n" - "in vec3 vertexNormal; \n" - "in vec2 vertexTexCoord; \n" - "in vec4 vertexColor; \n" - "out vec2 fragTexCoord; \n" - "out vec4 fragColor; \n" - "out vec3 fragNormal; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - char vShaderStr[] = "#version 100 \n" - "attribute vec3 vertexPosition; \n" - "attribute vec3 vertexNormal; \n" - "attribute vec2 vertexTexCoord; \n" - "attribute vec4 vertexColor; \n" - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" - "varying vec3 fragNormal; \n" -#endif - "uniform mat4 mvpMatrix; \n" - "uniform mat4 modelMatrix; \n" - "void main() \n" - "{ \n" - " fragTexCoord = vertexTexCoord; \n" - " fragColor = vertexColor; \n" - " mat3 normalMatrix = transpose(inverse(mat3(modelMatrix))); \n" - " fragNormal = normalize(normalMatrix*vertexNormal); \n" - " gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" - "} \n"; - - // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot) - // Fragment shader directly defined, no external file required -#if defined(GRAPHICS_API_OPENGL_33) - char fShaderStr[] = "#version 330 \n" - "in vec2 fragTexCoord; \n" - "in vec4 fragColor; \n" - "in vec3 fragNormal; \n" - "out vec4 finalColor; \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) - char fShaderStr[] = "#version 100 \n" - "precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) - "varying vec2 fragTexCoord; \n" - "varying vec4 fragColor; \n" - "varying vec3 fragNormal; \n" -#endif - "uniform sampler2D texture0; \n" - "uniform vec4 fragTintColor; \n" - "uniform vec4 colAmbient; \n" - "uniform vec4 colSpecular; \n" - "uniform vec3 lightDir; \n" - "vec3 LambertLighting(in vec3 n, in vec3 l) \n" - "{ \n" - " return clamp(dot(n, l), 0, 1)*fragTintColor.rgb; \n" - "} \n" - - "void main() \n" - "{ \n" - " vec3 n = normalize(fragNormal); \n" - " vec3 l = normalize(lightDir); \n" -#if defined(GRAPHICS_API_OPENGL_33) - " vec4 texelColor = texture(texture0, fragTexCoord); \n" - " finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a); \n" // Stupid specular color operation to avoid shader location errors -#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" -#endif - "} \n"; - - shader.id = LoadShaderProgram(vShaderStr, fShaderStr); + // 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); // TODO: Review locations fetching + if (shader.id != 0) LoadDefaultShaderLocations(&shader); return shader; } @@ -2622,7 +2578,7 @@ static void LoadDefaultShaderLocations(Shader *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"); @@ -3098,62 +3054,75 @@ static void UnloadDefaultBuffers(void) // 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 -// TODO: Review memcpy() and parameters pass static void SetShaderLights(Shader shader) { - // Note: currently working with one light (index 0) - // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights) - - /* - // NOTE: Standard Shader must include the following data: - - // Shader Light struct - struct Light { - vec3 position; - vec3 direction; - - vec3 diffuse; - float intensity; - } - - const int maxLights = 8; - uniform int lightsCount; // Number of lights - uniform Light lights[maxLights]; - */ + int locPoint = glGetUniformLocation(shader.id, "lightsCount"); + glUniform1i(locPoint, lightsCount); - /*int locPoint; char locName[32] = "lights[x].position\0"; - - glUseProgram(shader.id); - - locPoint = glGetUniformLocation(shader.id, "lightsCount"); - glUniform1i(locPoint, lightsCount); for (int i = 0; i < lightsCount; i++) { locName[7] = '0' + i; - memcpy(&locName[10], "position\0", strlen("position\0")); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform1i(locPoint, lights[i]->enabled); - memcpy(&locName[10], "direction\0", strlen("direction\0")); - locPoint = glGetUniformLocation(shader.id, locName); - glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z); - - memcpy(&locName[10], "diffuse\0", strlen("diffuse\0")); + 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 ); + 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 - }*/ - - int locPoint = GetShaderLocation(shader, "lightDir"); - glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z); + } } // Read text data from file diff --git a/src/rlgl.h b/src/rlgl.h index 39941b33..0765a8a7 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -196,40 +196,34 @@ 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 - // TODO: Review contained data to support different light types and features typedef struct LightData { int id; int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; Vector3 position; - Vector3 direction; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction) - float attenuation; // Lost of light intensity with distance (use radius?) + 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 (including intensities)? + Color diffuse; // Use Vector3 diffuse float intensity; - Color specular; - //float specFactor; // Specular intensity ? - - //Color ambient; // Required? - - float coneAngle; // SpotLight + float coneAngle; // Spot light max angle } LightData, *Light; // Color blending modes (pre-defined) -- cgit v1.2.3 From 3d6696f6c981a7a8f523d631926380eced475733 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 25 May 2016 16:21:13 +0200 Subject: Renamed shader variables (more generic names) --- src/raylib.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 9cd02fd8..d0231be2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -369,6 +369,7 @@ typedef struct BoundingBox { // Vertex data definning a mesh typedef struct Mesh { int vertexCount; // number of vertices stored in arrays + int triangleCount; // number of triangles stored (indexed or not) float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) @@ -376,8 +377,7 @@ typedef struct Mesh { float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) unsigned short *indices; // vertex indices (in case vertex data comes indexed) - int triangleCount; // number of triangles stored (indexed or not) - + BoundingBox bounds; // mesh limits defined by min and max points unsigned int vaoId; // OpenGL Vertex Array Object id @@ -389,30 +389,30 @@ typedef struct Shader { unsigned int id; // Shader program id // Vertex attributes locations (default locations) - int vertexLoc; // Vertex attribute location point (default-location = 0) - int texcoordLoc; // Texcoord attribute location point (default-location = 1) - int normalLoc; // Normal attribute location point (default-location = 2) - int colorLoc; // Color attibute location point (default-location = 3) - int tangentLoc; // Tangent attribute location point (default-location = 4) + int vertexLoc; // Vertex attribute location point (default-location = 0) + int texcoordLoc; // Texcoord attribute location point (default-location = 1) int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) + int normalLoc; // Normal attribute location point (default-location = 2) + int tangentLoc; // Tangent attribute location point (default-location = 4) + int colorLoc; // Color attibute location point (default-location = 3) // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int tintColorLoc; // Diffuse color uniform location point (fragment shader) - // Texture map locations - int mapDiffuseLoc; // Diffuse map texture uniform location point (fragment shader) - int mapNormalLoc; // Normal map texture uniform location point (fragment shader) - int mapSpecularLoc; // Specular map texture uniform location point (fragment shader) + // Texture map locations (generic for any kind of map) + int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) + int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) + int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) } Shader; // Material type typedef struct Material { - Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular) + Shader shader; // Standard shader (supports 3 map textures) - Texture2D texDiffuse; // Diffuse texture - Texture2D texNormal; // Normal texture - Texture2D texSpecular; // Specular texture + Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc) + Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) + Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color @@ -439,8 +439,8 @@ typedef struct LightData { 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; + Color diffuse; // Light color + float intensity; // Light intensity level float coneAngle; // Spot light max angle } LightData, *Light; -- cgit v1.2.3 From 2e26ce235d00fdc633559f9404ddd8ec70c96df7 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Mon, 30 May 2016 19:18:11 +0200 Subject: Add Draw3DCircle function and update raylib and rlgl header Draw3DCircle is useful to draw point lights radius. --- src/models.c | 19 +++++++++++++++++++ src/raylib.h | 3 ++- src/rlgl.h | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 07dee720..6ffb561e 100644 --- a/src/models.c +++ b/src/models.c @@ -75,6 +75,25 @@ void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color) rlEnd(); } +// Draw a circle in 3D world space +void Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color) +{ + rlPushMatrix(); + rlTranslatef(center.x, center.y, center.z); + rlRotatef(rotationAngle, rotation.x, rotation.y, rotation.z); + + rlBegin(RL_LINES); + for (int i = 0; i < 360; i += 10) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex3f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius, 0.0f); + rlVertex3f(sin(DEG2RAD*(i + 10)) * radius, cos(DEG2RAD*(i + 10)) * radius, 0.0f); + } + rlEnd(); + rlPopMatrix(); +} + // Draw cube // NOTE: Cube position is the center position void DrawCube(Vector3 position, float width, float height, float length, Color color) diff --git a/src/raylib.h b/src/raylib.h index d0231be2..0af7ef31 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -437,7 +437,7 @@ typedef struct LightData { Vector3 position; Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float attenuation; // Lost of light intensity with distance (world distance) + float radius; // Lost of light intensity with distance (world distance) Color diffuse; // Light color float intensity; // Light intensity level @@ -803,6 +803,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 Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle 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 diff --git a/src/rlgl.h b/src/rlgl.h index a3ba6cd5..d4a2dabe 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -218,7 +218,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; Vector3 position; Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float attenuation; // Lost of light intensity with distance (world distance) + float radius; // Lost of light intensity with distance (world distance) Color diffuse; // Use Vector3 diffuse float intensity; -- cgit v1.2.3 From f2d61d4043850e89b2d2cb7bacffe628aef0b981 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Mon, 30 May 2016 19:43:35 +0200 Subject: Remove normal depth Scaling normal depth (y axis) makes disappear the specular of fragments... So I think it can be removed, it is not a very useful/important attribute. --- src/models.c | 1 - src/raylib.h | 1 - src/rlgl.c | 5 +---- src/rlgl.h | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 6ffb561e..90b752fd 100644 --- a/src/models.c +++ b/src/models.c @@ -756,7 +756,6 @@ Material LoadDefaultMaterial(void) material.colSpecular = WHITE; // Specular color material.glossiness = 100.0f; // Glossiness level - material.normalDepth = 1.0f; // Normal map depth return material; } diff --git a/src/raylib.h b/src/raylib.h index 0af7ef31..73a36a16 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -419,7 +419,6 @@ typedef struct Material { Color colSpecular; // Specular color float glossiness; // Glossiness level (Ranges from 0 to 1000) - float normalDepth; // Normal map depth } Material; // Model type diff --git a/src/rlgl.c b/src/rlgl.c index d781b755..b4569207 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1816,9 +1816,6 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, material.texNormal.id); glUniform1i(material.shader.mapTexture1Loc, 1); // Normal texture fits in active texture unit 1 - - // TODO: Upload to shader normalDepth - //glUniform1f(???, material.normalDepth); } if ((material.texSpecular.id != 0) && (material.shader.mapTexture2Loc != -1)) @@ -2565,7 +2562,7 @@ static Shader LoadDefaultShader(void) // Load standard shader // NOTE: This shader supports: // - Up to 3 different maps: diffuse, normal, specular -// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth +// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness // - Up to 8 lights: Point, Directional or Spot static Shader LoadStandardShader(void) { diff --git a/src/rlgl.h b/src/rlgl.h index d4a2dabe..dc16e807 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -207,7 +207,6 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; Color colSpecular; // Specular color float glossiness; // Glossiness level (Ranges from 0 to 1000) - float normalDepth; // Normal map depth } Material; // Light type -- cgit v1.2.3 From b0a0c5d4312d05d460cdd12f6af12321b0a55e66 Mon Sep 17 00:00:00 2001 From: victorfisac Date: Mon, 30 May 2016 19:55:13 +0200 Subject: Added tint color attribute to material data type It tints all fragments, ignores lighting. Useful for some features like feedback (damage color, ...). --- src/models.c | 3 ++- src/raylib.h | 1 + src/rlgl.c | 3 +++ src/rlgl.h | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 90b752fd..092a43fc 100644 --- a/src/models.c +++ b/src/models.c @@ -751,6 +751,7 @@ Material LoadDefaultMaterial(void) //material.texNormal; // NOTE: By default, not set //material.texSpecular; // NOTE: By default, not set + material.colTint = WHITE; // Tint color material.colDiffuse = WHITE; // Diffuse color material.colAmbient = WHITE; // Ambient color material.colSpecular = WHITE; // Specular color @@ -1268,7 +1269,7 @@ 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.colTint = tint; rlglDrawMesh(model.mesh, model.material, model.transform); } diff --git a/src/raylib.h b/src/raylib.h index 73a36a16..dfec956d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -414,6 +414,7 @@ typedef struct Material { Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) + Color colTint; // Tint color Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color diff --git a/src/rlgl.c b/src/rlgl.c index b4569207..0f68953e 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1793,6 +1793,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Setup shader uniforms for lights SetShaderLights(material.shader); + // Upload to shader material.colSpecular + glUniform4f(glGetUniformLocation(material.shader.id, "colTint"), (float)material.colTint.r/255, (float)material.colTint.g/255, (float)material.colTint.b/255, (float)material.colTint.a/255); + // 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); diff --git a/src/rlgl.h b/src/rlgl.h index dc16e807..23ad29fb 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -202,6 +202,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; Texture2D texNormal; // Normal texture Texture2D texSpecular; // Specular texture + Color colTint; // Tint color Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color -- cgit v1.2.3 From 9f2fc81df2ad6731b521bd7dfd523ee10f63be90 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Mon, 30 May 2016 15:34:29 -0700 Subject: update to openal --- CMakeLists.txt | 4 +- external/openal_soft/include/AL/alext.h | 87 ++++++++++++++++++++++- external/openal_soft/include/AL/efx-presets.h | 2 +- external/openal_soft/lib/win32/libOpenAL32.dll.a | Bin 0 -> 100246 bytes external/openal_soft/lib/win32/libopenal32.a | Bin 95688 -> 0 bytes external/openal_soft/openal32.dll | Bin 402553 -> 845045 bytes src/audio.c | 2 +- src/audio.h | 2 +- src/raylib.h | 2 +- 9 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 external/openal_soft/lib/win32/libOpenAL32.dll.a delete mode 100644 external/openal_soft/lib/win32/libopenal32.a (limited to 'src/raylib.h') diff --git a/CMakeLists.txt b/CMakeLists.txt index 8689e9ad..eb0052d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_C_FLAGS "-O1 -Wall -std=gnu99 -fgnu89-inline") IF(${PLATFORM_TO_USE} MATCHES "PLATFORM_DESKTOP") add_definitions(-DPLATFORM_DESKTOP, -DGRAPHICS_API_OPENGL_33) - include_directories("." "src/" "external/openal_soft/include" "external/glew/include" "external/glfw3/include") + include_directories("." "src/" "external/openal_soft/include" "external/glfw3/include") ENDIF() @@ -22,7 +22,7 @@ ENDIF() IF(${PLATFORM_TO_USE} MATCHES "PLATFORM_WEB") add_definitions(-DPLATFORM_WEB, -GRAPHICS_API_OPENGL_ES2) - include_directories("." "src/" "external/openal_soft/include" "external/glew/include" "external/glfw3/include") + include_directories("." "src/" "external/openal_soft/include" "external/glfw3/include") ENDIF() diff --git a/external/openal_soft/include/AL/alext.h b/external/openal_soft/include/AL/alext.h index 0447f2bb..6af581aa 100644 --- a/external/openal_soft/include/AL/alext.h +++ b/external/openal_soft/include/AL/alext.h @@ -13,8 +13,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ @@ -348,6 +348,89 @@ AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64 #endif #endif +#ifndef ALC_EXT_DEFAULT_FILTER_ORDER +#define ALC_EXT_DEFAULT_FILTER_ORDER 1 +#define ALC_DEFAULT_FILTER_ORDER 0x1100 +#endif + +#ifndef AL_SOFT_deferred_updates +#define AL_SOFT_deferred_updates 1 +#define AL_DEFERRED_UPDATES_SOFT 0xC002 +typedef ALvoid (AL_APIENTRY*LPALDEFERUPDATESSOFT)(void); +typedef ALvoid (AL_APIENTRY*LPALPROCESSUPDATESSOFT)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void); +AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void); +#endif +#endif + +#ifndef AL_SOFT_block_alignment +#define AL_SOFT_block_alignment 1 +#define AL_UNPACK_BLOCK_ALIGNMENT_SOFT 0x200C +#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D +#endif + +#ifndef AL_SOFT_MSADPCM +#define AL_SOFT_MSADPCM 1 +#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302 +#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303 +#endif + +#ifndef AL_SOFT_source_length +#define AL_SOFT_source_length 1 +/*#define AL_BYTE_LENGTH_SOFT 0x2009*/ +/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/ +/*#define AL_SEC_LENGTH_SOFT 0x200B*/ +#endif + +#ifndef ALC_SOFT_pause_device +#define ALC_SOFT_pause_device 1 +typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device); +typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device); +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); +#endif +#endif + +#ifndef AL_EXT_BFORMAT +#define AL_EXT_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_8 0x20021 +#define AL_FORMAT_BFORMAT2D_16 0x20022 +#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 +#define AL_FORMAT_BFORMAT3D_8 0x20031 +#define AL_FORMAT_BFORMAT3D_16 0x20032 +#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 +#endif + +#ifndef AL_EXT_MULAW_BFORMAT +#define AL_EXT_MULAW_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 +#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 +#endif + +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + #ifdef __cplusplus } #endif diff --git a/external/openal_soft/include/AL/efx-presets.h b/external/openal_soft/include/AL/efx-presets.h index 86dcbda2..8539fd51 100644 --- a/external/openal_soft/include/AL/efx-presets.h +++ b/external/openal_soft/include/AL/efx-presets.h @@ -345,7 +345,7 @@ typedef struct { /* Driving Presets */ #define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ - { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } #define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } diff --git a/external/openal_soft/lib/win32/libOpenAL32.dll.a b/external/openal_soft/lib/win32/libOpenAL32.dll.a new file mode 100644 index 00000000..1c4c63c8 Binary files /dev/null and b/external/openal_soft/lib/win32/libOpenAL32.dll.a differ diff --git a/external/openal_soft/lib/win32/libopenal32.a b/external/openal_soft/lib/win32/libopenal32.a deleted file mode 100644 index 5f7352ac..00000000 Binary files a/external/openal_soft/lib/win32/libopenal32.a and /dev/null differ diff --git a/external/openal_soft/openal32.dll b/external/openal_soft/openal32.dll index 71ced6a2..1e3bddd5 100644 Binary files a/external/openal_soft/openal32.dll and b/external/openal_soft/openal32.dll differ diff --git a/src/audio.c b/src/audio.c index 0c61c0fa..c72b32aa 100644 --- a/src/audio.c +++ b/src/audio.c @@ -399,7 +399,7 @@ void CloseRawAudioContext(RawAudioContext ctx) CloseMixChannel(mixChannelsActive_g[ctx]); } -int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements) +int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short numberElements) { int numBuffered = 0; if(ctx >= 0) diff --git a/src/audio.h b/src/audio.h index 1140a60a..ec00f7b5 100644 --- a/src/audio.h +++ b/src/audio.h @@ -107,7 +107,7 @@ void SetMusicPitch(int index, float pitch); 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 +int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short numberElements); // returns number of elements buffered #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index d0231be2..a0cfc7a0 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -926,7 +926,7 @@ void SetMusicPitch(int index, float pitch); 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 +int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short numberElements); // returns number of elements buffered #ifdef __cplusplus } -- cgit v1.2.3 From caa7bc366b949310fbb9c7eafbb9fa7050e1514a Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 31 May 2016 00:51:55 +0200 Subject: Reviewed DrawLight() function and some tweaks --- examples/shaders_standard_lighting.c | 12 ++++++------ src/models.c | 29 +++++++++++++++++++++++++++ src/raylib.h | 18 ++++++++--------- src/rlgl.c | 38 +++++++----------------------------- 4 files changed, 51 insertions(+), 46 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c index 6b5cd9f5..10416f7f 100644 --- a/examples/shaders_standard_lighting.c +++ b/examples/shaders_standard_lighting.c @@ -33,12 +33,12 @@ int main() 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 + Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Material material = LoadStandardMaterial(); - material.texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture - material.texNormal = LoadTexture("resources/model/dwarf_normal.png"); // Load model normal texture + material.texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture + material.texNormal = LoadTexture("resources/model/dwarf_normal.png"); // Load model normal texture material.texSpecular = LoadTexture("resources/model/dwarf_specular.png"); // Load model specular texture material.colDiffuse = (Color){255, 255, 255, 255}; material.colAmbient = (Color){0, 0, 10, 255}; @@ -46,8 +46,6 @@ int main() material.glossiness = 50.0f; dwarf.material = material; // Apply material to model - - Model dwarf2 = LoadModel("resources/model/dwarf.obj"); // Load OBJ 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}; @@ -91,7 +89,9 @@ int main() DrawModel(dwarf, position, 2.0f, WHITE); // Draw 3d model with texture - DrawLights(); // Draw all created lights in 3D world + DrawLight(spotLight); // Draw spot light + DrawLight(dirLight); // Draw directional light + DrawLight(pointLight); // Draw point light DrawGrid(10, 1.0f); // Draw a grid diff --git a/src/models.c b/src/models.c index 092a43fc..8c5ed914 100644 --- a/src/models.c +++ b/src/models.c @@ -569,6 +569,35 @@ void DrawGizmo(Vector3 position) rlPopMatrix(); } + +// Draw light in 3D world +void DrawLight(Light light) +{ + switch (light->type) + { + case LIGHT_POINT: + { + DrawSphereWires(light->position, 0.3f*light->intensity, 4, 8, (light->enabled ? light->diffuse : BLACK)); + Draw3DCircle(light->position, light->radius, 0.0f, (Vector3){ 0, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); + Draw3DCircle(light->position, light->radius, 90.0f, (Vector3){ 1, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); + Draw3DCircle(light->position, light->radius, 90.0f, (Vector3){ 0, 1, 0 }, (light->enabled ? light->diffuse : BLACK)); + } break; + case LIGHT_DIRECTIONAL: + { + Draw3DLine(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); + DrawSphereWires(light->position, 0.3f*light->intensity, 4, 8, (light->enabled ? light->diffuse : BLACK)); + DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); + } break; + case LIGHT_SPOT: + { + Draw3DLine(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); + DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : BLACK)); + DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); + } break; + default: break; + } +} + // Load a 3d model (from file) Model LoadModel(const char *fileName) { diff --git a/src/raylib.h b/src/raylib.h index dfec956d..cba73e52 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -431,18 +431,18 @@ typedef struct Model { // Light type typedef struct LightData { - int id; - int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - bool enabled; + unsigned int id; // Light id + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; // Light enabled - Vector3 position; - Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Lost of light intensity with distance (world distance) + Vector3 position; // Light position + Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float radius; // Light attenuation radius light intensity reduced with distance (world distance) - Color diffuse; // Light color + Color diffuse; // Light diffuse color float intensity; // Light intensity level - float coneAngle; // Spot light max angle + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; // Light types @@ -817,6 +817,7 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Color color); void DrawRay(Ray ray, Color color); // Draw a ray line void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) void DrawGizmo(Vector3 position); // Draw simple gizmo +void DrawLight(Light light); // Draw light in 3D world //DrawTorus(), DrawTeapot() are useless... //------------------------------------------------------------------------------------ @@ -873,7 +874,6 @@ 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 //---------------------------------------------------------------------------------- diff --git a/src/rlgl.c b/src/rlgl.c index 0f68953e..97a92a4d 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1069,6 +1069,13 @@ void rlglClose(void) // Delete default white texture glDeleteTextures(1, &whiteTexture); TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); + + // Unload lights + if (lightsCount > 0) + { + for (int i = 0; i < lightsCount; i++) free(lights[i]); + lightsCount = 0; + } free(draws); #endif @@ -2292,37 +2299,6 @@ Light CreateLight(int type, Vector3 position, Color diffuse) 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)); - Draw3DCircle(lights[i]->position, lights[i]->radius, 0.0f, (Vector3){ 0, 0, 0 }, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); - Draw3DCircle(lights[i]->position, lights[i]->radius, 90.0f, (Vector3){ 1, 0, 0 }, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); - Draw3DCircle(lights[i]->position, lights[i]->radius, 90.0f, (Vector3){ 0, 1, 0 }, (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) { -- cgit v1.2.3 From cac2a66debd0f2d3ef8195940f8e2744d539d19a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 31 May 2016 17:11:02 +0200 Subject: Improved library consistency Functions renamed to improve library consistency --- examples/shaders_custom_uniform.c | 12 +++++++----- examples/shaders_postprocessing.c | 12 +++++++----- examples/shaders_shapes_textures.c | 18 +++++++++--------- examples/textures_particles_trail_blending.c | 24 +++++++++++++----------- src/raylib.h | 8 +++++--- src/rlgl.c | 18 ++++++++++++------ src/rlgl.h | 9 ++++++--- 7 files changed, 59 insertions(+), 42 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/shaders_custom_uniform.c b/examples/shaders_custom_uniform.c index 74077143..516d5087 100644 --- a/examples/shaders_custom_uniform.c +++ b/examples/shaders_custom_uniform.c @@ -33,7 +33,7 @@ int main() Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model - Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture + Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture (diffuse map) SetModelTexture(&dwarf, texture); // Bind texture to model Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position @@ -94,10 +94,12 @@ int main() EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) - SetCustomShader(shader); - // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) - DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); - SetDefaultShader(); + BeginShaderMode(shader); + + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); + + EndShaderMode(); DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, GRAY); diff --git a/examples/shaders_postprocessing.c b/examples/shaders_postprocessing.c index e9fafe15..5e8b5a80 100644 --- a/examples/shaders_postprocessing.c +++ b/examples/shaders_postprocessing.c @@ -33,7 +33,7 @@ int main() Camera camera = {{ 3.0f, 3.0f, 3.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f }; Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model - Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture + Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture (diffuse map) SetModelTexture(&dwarf, texture); // Bind texture to model Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position @@ -80,10 +80,12 @@ int main() EndTextureMode(); // End drawing to texture (now we have a texture available for next passes) - SetCustomShader(shader); - // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) - DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); - SetDefaultShader(); + BeginShaderMode(shader); + + // NOTE: Render texture must be y-flipped due to default OpenGL coordinates (left-bottom) + DrawTextureRec(target.texture, (Rectangle){ 0, 0, target.texture.width, -target.texture.height }, (Vector2){ 0, 0 }, WHITE); + + EndShaderMode(); DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, DARKGRAY); diff --git a/examples/shaders_shapes_textures.c b/examples/shaders_shapes_textures.c index 1b1142fa..0a14469f 100644 --- a/examples/shaders_shapes_textures.c +++ b/examples/shaders_shapes_textures.c @@ -65,16 +65,16 @@ int main() // Activate our custom shader to be applied on next shapes/textures drawings - SetCustomShader(shader); + BeginShaderMode(shader); - DrawText("USING CUSTOM SHADER", 190, 40, 10, RED); + DrawText("USING CUSTOM SHADER", 190, 40, 10, RED); - DrawRectangle(250 - 60, 90, 120, 60, RED); - DrawRectangleGradient(250 - 90, 170, 180, 130, MAROON, GOLD); - DrawRectangleLines(250 - 40, 320, 80, 60, ORANGE); + DrawRectangle(250 - 60, 90, 120, 60, RED); + DrawRectangleGradient(250 - 90, 170, 180, 130, MAROON, GOLD); + DrawRectangleLines(250 - 40, 320, 80, 60, ORANGE); // Activate our default shader for next drawings - SetDefaultShader(); + EndShaderMode(); DrawText("USING DEFAULT SHADER", 370, 40, 10, RED); @@ -89,12 +89,12 @@ int main() DrawPoly((Vector2){430, 320}, 6, 80, 0, BROWN); // Activate our custom shader to be applied on next shapes/textures drawings - SetCustomShader(shader); + BeginShaderMode(shader); - DrawTexture(sonic, 380, -10, WHITE); // Using custom shader + DrawTexture(sonic, 380, -10, WHITE); // Using custom shader // Activate our default shader for next drawings - SetDefaultShader(); + EndShaderMode(); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/textures_particles_trail_blending.c b/examples/textures_particles_trail_blending.c index 76cd0423..0b47c790 100644 --- a/examples/textures_particles_trail_blending.c +++ b/examples/textures_particles_trail_blending.c @@ -102,20 +102,22 @@ int main() ClearBackground(DARKGRAY); - SetBlendMode(blending); + BeginBlendMode(blending); - // Draw active particles - for (int i = 0; i < MAX_PARTICLES; i++) - { - if (mouseTail[i].active) DrawTexturePro(smoke, (Rectangle){ 0, 0, smoke.width, smoke.height }, - (Rectangle){ mouseTail[i].position.x, mouseTail[i].position.y, smoke.width*mouseTail[i].size, smoke.height*mouseTail[i].size }, - (Vector2){ smoke.width*mouseTail[i].size/2, smoke.height*mouseTail[i].size/2 }, mouseTail[i].rotation, - Fade(mouseTail[i].color, mouseTail[i].alpha)); - } + // Draw active particles + for (int i = 0; i < MAX_PARTICLES; i++) + { + if (mouseTail[i].active) DrawTexturePro(smoke, (Rectangle){ 0, 0, smoke.width, smoke.height }, + (Rectangle){ mouseTail[i].position.x, mouseTail[i].position.y, smoke.width*mouseTail[i].size, smoke.height*mouseTail[i].size }, + (Vector2){ smoke.width*mouseTail[i].size/2, smoke.height*mouseTail[i].size/2 }, mouseTail[i].rotation, + Fade(mouseTail[i].color, mouseTail[i].alpha)); + } + + EndBlendMode(); - DrawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, RAYWHITE); + DrawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, BLACK); - if (blending == BLEND_ALPHA) DrawText("ALPHA BLENDING", 290, screenHeight - 40, 20, RAYWHITE); + if (blending == BLEND_ALPHA) DrawText("ALPHA BLENDING", 290, screenHeight - 40, 20, BLACK); else DrawText("ADDITIVE BLENDING", 280, screenHeight - 40, 20, RAYWHITE); EndDrawing(); diff --git a/src/raylib.h b/src/raylib.h index cba73e52..5bef3698 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -860,8 +860,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations void UnloadShader(Shader shader); // Unload a custom shader from memory -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 @@ -871,7 +870,10 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // S void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) +void BeginShaderMode(Shader shader); // Begin custom shader drawing +void EndShaderMode(void); // End custom shader drawing (use default shader) +void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) +void EndBlendMode(void); // End blending mode (reset to default: alpha blending) 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 diff --git a/src/rlgl.c b/src/rlgl.c index 97a92a4d..5c4c9c01 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2157,7 +2157,7 @@ void UnloadShader(Shader shader) } // Set custom shader to be used on batch draw -void SetCustomShader(Shader shader) +void BeginShaderMode(Shader shader) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if (currentShader.id != shader.id) @@ -2169,10 +2169,10 @@ void SetCustomShader(Shader shader) } // Set default shader to be used in batch draw -void SetDefaultShader(void) +void EndShaderMode(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - SetCustomShader(defaultShader); + BeginShaderMode(defaultShader); #endif } @@ -2254,9 +2254,9 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) #endif } -// Set blending mode (alpha, additive, multiplied) -// NOTE: Only 3 blending modes predefined -void SetBlendMode(int mode) +// Begin blending mode (alpha, additive, multiplied) +// NOTE: Only 3 blending modes supported, default blend mode is alpha +void BeginBlendMode(int mode) { if ((blendMode != mode) && (mode < 3)) { @@ -2274,6 +2274,12 @@ void SetBlendMode(int mode) } } +// End blending mode (reset to default: alpha blending) +void EndBlendMode(void) +{ + BeginBlendMode(BLEND_ALPHA); +} + // Create a new light, initialize it and add to pool Light CreateLight(int type, Vector3 position, Color diffuse) { diff --git a/src/rlgl.h b/src/rlgl.h index 23ad29fb..ccf2b36a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -317,9 +317,9 @@ void *rlglReadTexturePixels(Texture2D texture); // Read text //------------------------------------------------------------------------------------ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations void UnloadShader(Shader shader); // Unload a custom shader from memory -void SetCustomShader(Shader shader); // Set custom shader to be used in batch draw -void SetDefaultShader(void); // Set default 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 @@ -327,7 +327,10 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // S void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetBlendMode(int mode); // Set blending mode (alpha, additive, multiplied) +void BeginShaderMode(Shader shader); // Begin custom shader drawing +void EndShaderMode(void); // End custom shader drawing (use default shader) +void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) +void EndBlendMode(void); // End blending mode (reset to default: alpha blending) 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 -- cgit v1.2.3 From 302ec438dd8a5483e4fcf81d4bd80ac7d09e6a61 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 31 May 2016 18:15:53 +0200 Subject: Removed colTint, tint color is colDiffuse Tint color could be applied to colDiffuse... but what's the best way? Replace it? Multiply by? A point to think about... --- examples/resources/shaders/glsl330/grayscale.fs | 4 ++-- examples/resources/shaders/standard.fs | 7 +++---- examples/shaders_standard_lighting.c | 4 ++-- src/models.c | 5 ++--- src/raylib.h | 1 - src/rlgl.c | 3 --- src/rlgl.h | 21 ++++++++++----------- 7 files changed, 19 insertions(+), 26 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/resources/shaders/glsl330/grayscale.fs b/examples/resources/shaders/glsl330/grayscale.fs index d4a8824f..5b3e11be 100644 --- a/examples/resources/shaders/glsl330/grayscale.fs +++ b/examples/resources/shaders/glsl330/grayscale.fs @@ -6,7 +6,7 @@ in vec4 fragColor; // Input uniform values uniform sampler2D texture0; -uniform vec4 fragTintColor; +uniform vec4 colDiffuse; // Output fragment color out vec4 finalColor; @@ -16,7 +16,7 @@ out vec4 finalColor; void main() { // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor; + vec4 texelColor = texture(texture0, fragTexCoord)*colDiffuse*fragColor; // Convert texel color to grayscale using NTSC conversion weights float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114)); diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs index bb9e6865..e5916031 100644 --- a/examples/resources/shaders/standard.fs +++ b/examples/resources/shaders/standard.fs @@ -11,7 +11,6 @@ uniform sampler2D texture0; uniform sampler2D texture1; uniform sampler2D texture2; -uniform vec4 colTint; uniform vec4 colAmbient; uniform vec4 colDiffuse; uniform vec4 colSpecular; @@ -55,7 +54,7 @@ vec3 CalcPointLight(Light l, vec3 n, vec3 v, float s) spec = pow(dot(n, h), 3 + glossiness)*s; } - return (diff*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb); + return (diff*l.diffuse.rgb + spec*colSpecular.rgb); } vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v, float s) @@ -74,7 +73,7 @@ vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v, float s) } // Combine results - return (diff*l.intensity*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb); + return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb); } vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s) @@ -150,5 +149,5 @@ void main() } // Calculate final fragment color - finalColor = vec4(texelColor.rgb*lighting*colTint.rgb, texelColor.a*colTint.a); + finalColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); } diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c index 10416f7f..ccbe74ca 100644 --- a/examples/shaders_standard_lighting.c +++ b/examples/shaders_standard_lighting.c @@ -40,9 +40,9 @@ int main() material.texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture material.texNormal = LoadTexture("resources/model/dwarf_normal.png"); // Load model normal texture material.texSpecular = LoadTexture("resources/model/dwarf_specular.png"); // Load model specular texture - material.colDiffuse = (Color){255, 255, 255, 255}; + material.colDiffuse = WHITE; material.colAmbient = (Color){0, 0, 10, 255}; - material.colSpecular = (Color){255, 255, 255, 255}; + material.colSpecular = WHITE; material.glossiness = 50.0f; dwarf.material = material; // Apply material to model diff --git a/src/models.c b/src/models.c index 8c5ed914..962a6470 100644 --- a/src/models.c +++ b/src/models.c @@ -779,8 +779,7 @@ Material LoadDefaultMaterial(void) material.texDiffuse = GetDefaultTexture(); // White texture (1x1 pixel) //material.texNormal; // NOTE: By default, not set //material.texSpecular; // NOTE: By default, not set - - material.colTint = WHITE; // Tint color + material.colDiffuse = WHITE; // Diffuse color material.colAmbient = WHITE; // Ambient color material.colSpecular = WHITE; // Specular color @@ -1298,7 +1297,7 @@ 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.colTint = tint; + model.material.colDiffuse = tint; // TODO: Multiply tint color by diffuse color? rlglDrawMesh(model.mesh, model.material, model.transform); } diff --git a/src/raylib.h b/src/raylib.h index 5bef3698..271c0e42 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -414,7 +414,6 @@ typedef struct Material { Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) - Color colTint; // Tint color Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color diff --git a/src/rlgl.c b/src/rlgl.c index 5c4c9c01..6a2adeb2 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1800,9 +1800,6 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Setup shader uniforms for lights SetShaderLights(material.shader); - // Upload to shader material.colSpecular - glUniform4f(glGetUniformLocation(material.shader.id, "colTint"), (float)material.colTint.r/255, (float)material.colTint.g/255, (float)material.colTint.b/255, (float)material.colTint.a/255); - // 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); diff --git a/src/rlgl.h b/src/rlgl.h index ccf2b36a..336f6019 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -201,8 +201,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; Texture2D texDiffuse; // Diffuse texture Texture2D texNormal; // Normal texture Texture2D texSpecular; // Specular texture - - Color colTint; // Tint color + Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color @@ -212,18 +211,18 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; // Light type typedef struct LightData { - int id; - int type; // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - bool enabled; + unsigned int id; // Light id + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; // Light enabled - Vector3 position; - Vector3 target; // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Lost of light intensity with distance (world distance) + Vector3 position; // Light position + Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float radius; // Light attenuation radius light intensity reduced with distance (world distance) - Color diffuse; // Use Vector3 diffuse - float intensity; + Color diffuse; // Light diffuse color + float intensity; // Light intensity level - float coneAngle; // Spot light max angle + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; // Color blending modes (pre-defined) -- cgit v1.2.3 From d17a0cee1aa53978387e68be58d901bffd1ac0a9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 31 May 2016 19:12:37 +0200 Subject: Review text formatting (spacing, tabs...) --- examples/resources/shaders/standard.fs | 8 ++- src/core.c | 18 +++--- src/raylib.h | 96 +++++++++++++++--------------- src/raymath.h | 2 +- src/rlgl.c | 2 +- src/rlgl.h | 103 +++++++++++++++++---------------- src/shapes.c | 2 +- 7 files changed, 117 insertions(+), 114 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs index e5916031..e5a6d1bc 100644 --- a/examples/resources/shaders/standard.fs +++ b/examples/resources/shaders/standard.fs @@ -88,8 +88,10 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s) // 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 @@ -103,7 +105,7 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s) spec = pow(dot(n, h), 3 + glossiness)*s; } - return falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb); + return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb)); } void main() @@ -122,7 +124,7 @@ void main() vec3 lighting = colAmbient.rgb; // Calculate normal texture color fetching or set to maximum normal value by default - if(useNormal == 1) + if (useNormal == 1) { n *= texture(texture1, fragTexCoord).rgb; n = normalize(n); @@ -130,7 +132,7 @@ void main() // Calculate specular texture color fetching or set to maximum specular value by default float spec = 1.0; - if(useSpecular == 1) spec *= normalize(texture(texture2, fragTexCoord).r); + if (useSpecular == 1) spec *= normalize(texture(texture2, fragTexCoord).r); for (int i = 0; i < lightsCount; i++) { diff --git a/src/core.c b/src/core.c index 70dfa7a5..7bd44c81 100644 --- a/src/core.c +++ b/src/core.c @@ -2078,10 +2078,10 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int gestureEvent.position[0] = GetMousePosition(); // Normalize gestureEvent.position[0] for screenWidth and screenHeight - gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - - // Gesture data is sent to gestures system for processing + + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); #endif } @@ -2223,10 +2223,10 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // Load default font for convenience // NOTE: External function (defined in module: text) LoadDefaultFont(); - + // TODO: GPU assets reload in case of lost focus (lost context) // NOTE: This problem has been solved just unbinding and rebinding context from display - /* + /* if (assetsReloadRequired) { for (int i = 0; i < assetsCount; i++) @@ -2759,9 +2759,9 @@ static void *GamepadThread(void *arg) }; // Read gamepad event - struct js_event gamepadEvent; + struct js_event gamepadEvent; - while (1) + while (1) { for (int i = 0; i < MAX_GAMEPADS; i++) { @@ -2792,8 +2792,8 @@ static void *GamepadThread(void *arg) } } } - } - + } + return NULL; } #endif diff --git a/src/raylib.h b/src/raylib.h index 271c0e42..1ef0a98e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -349,7 +349,7 @@ typedef struct Camera { Vector3 position; // Camera position Vector3 target; // Camera target it looks-at Vector3 up; // Camera up vector (rotation over its axis) - float fovy; // Field-Of-View apperture in Y (degrees) + float fovy; // Camera field-of-view apperture in Y (degrees) } Camera; // Camera2D type, defines a 2d camera @@ -362,86 +362,84 @@ typedef struct Camera2D { // Bounding box type typedef struct BoundingBox { - Vector3 min; - Vector3 max; + Vector3 min; // minimum vertex box-corner + Vector3 max; // maximum vertex box-corner } BoundingBox; // Vertex data definning a mesh typedef struct Mesh { - int vertexCount; // number of vertices stored in arrays - int triangleCount; // number of triangles stored (indexed or not) - float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) - float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) - float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) - float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) - unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - unsigned short *indices; // vertex indices (in case vertex data comes indexed) - - BoundingBox bounds; // mesh limits defined by min and max points - - unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) + int vertexCount; // number of vertices stored in arrays + int triangleCount; // number of triangles stored (indexed or not) + float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) + float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices;// vertex indices (in case vertex data comes indexed) + + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) } Mesh; // Shader type (generic shader) typedef struct Shader { - unsigned int id; // Shader program id + unsigned int id; // Shader program id // Vertex attributes locations (default locations) - int vertexLoc; // Vertex attribute location point (default-location = 0) - int texcoordLoc; // Texcoord attribute location point (default-location = 1) - int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) - int normalLoc; // Normal attribute location point (default-location = 2) - int tangentLoc; // Tangent attribute location point (default-location = 4) - int colorLoc; // Color attibute location point (default-location = 3) + int vertexLoc; // Vertex attribute location point (default-location = 0) + int texcoordLoc; // Texcoord attribute location point (default-location = 1) + int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) + int normalLoc; // Normal attribute location point (default-location = 2) + int tangentLoc; // Tangent attribute location point (default-location = 4) + int colorLoc; // Color attibute location point (default-location = 3) // Uniform locations - int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Diffuse color uniform location point (fragment shader) + int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) + int tintColorLoc; // Diffuse color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) - int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) - int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) - int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) + int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) + int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) + int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) } Shader; // Material type typedef struct Material { - Shader shader; // Standard shader (supports 3 map textures) + Shader shader; // Standard shader (supports 3 map textures) - Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc) - Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) - Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) + Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc) + Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) + Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) - Color colDiffuse; // Diffuse color - Color colAmbient; // Ambient color - Color colSpecular; // Specular color + Color colDiffuse; // Diffuse color + Color colAmbient; // Ambient color + Color colSpecular; // Specular color - float glossiness; // Glossiness level (Ranges from 0 to 1000) + float glossiness; // Glossiness level (Ranges from 0 to 1000) } 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 + 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 { - unsigned int id; // Light id - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - bool enabled; // Light enabled + unsigned int id; // Light unique id + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; // Light enabled - Vector3 position; // Light position - Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Light attenuation radius light intensity reduced with distance (world distance) + Vector3 position; // Light position + Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float radius; // Light attenuation radius light intensity reduced with distance (world distance) - Color diffuse; // Light diffuse color - float intensity; // Light intensity level + Color diffuse; // Light diffuse color + float intensity; // Light intensity level - float coneAngle; // Light cone max angle: LIGHT_SPOT + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; // Light types diff --git a/src/raymath.h b/src/raymath.h index 59d66e56..2e055e9f 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -73,7 +73,7 @@ //---------------------------------------------------------------------------------- #if defined(RAYMATH_STANDALONE) - // Vector2 type + // Vector2 type typedef struct Vector2 { float x; float y; diff --git a/src/rlgl.c b/src/rlgl.c index 6a2adeb2..89361f46 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2369,7 +2369,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr) { unsigned int program = 0; - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) GLuint vertexShader; GLuint fragmentShader; diff --git a/src/rlgl.h b/src/rlgl.h index 336f6019..e8e754b4 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -130,51 +130,43 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; COMPRESSED_ASTC_4x4_RGBA, // 8 bpp COMPRESSED_ASTC_8x8_RGBA // 2 bpp } TextureFormat; - - // Bounding box type - typedef struct BoundingBox { - Vector3 min; - Vector3 max; - } BoundingBox; // Vertex data definning a mesh typedef struct Mesh { - int vertexCount; // number of vertices stored in arrays - float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) - float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) - float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) - float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) - float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) - unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) - unsigned short *indices; // vertex indices (in case vertex data comes indexed) - int triangleCount; // number of triangles stored (indexed or not) - - BoundingBox bounds; // mesh limits defined by min and max points - - unsigned int vaoId; // OpenGL Vertex Array Object id - unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) + int vertexCount; // number of vertices stored in arrays + int triangleCount; // number of triangles stored (indexed or not) + float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5) + float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4) + unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices;// vertex indices (in case vertex data comes indexed) + + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data) } Mesh; // Shader type (generic shader) typedef struct Shader { - unsigned int id; // Shader program id + unsigned int id; // Shader program id // Vertex attributes locations (default locations) - int vertexLoc; // Vertex attribute location point (default-location = 0) - int texcoordLoc; // Texcoord attribute location point (default-location = 1) - int normalLoc; // Normal attribute location point (default-location = 2) - int colorLoc; // Color attibute location point (default-location = 3) - int tangentLoc; // Tangent attribute location point (default-location = 4) - int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) + int vertexLoc; // Vertex attribute location point (default-location = 0) + int texcoordLoc; // Texcoord attribute location point (default-location = 1) + int normalLoc; // Normal attribute location point (default-location = 2) + int colorLoc; // Color attibute location point (default-location = 3) + int tangentLoc; // Tangent attribute location point (default-location = 4) + int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5) // Uniform locations - int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Color uniform location point (fragment shader) + int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) + int tintColorLoc; // Color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) - int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) - int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) - int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) + int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) + int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) + int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2) } Shader; // Texture2D type @@ -196,35 +188,46 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion; // Material type typedef struct Material { - Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular) + 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; // Diffuse color - Color colAmbient; // Ambient color - Color colSpecular; // Specular color + Color colDiffuse; // Diffuse color + Color colAmbient; // Ambient color + Color colSpecular; // Specular color - float glossiness; // Glossiness level (Ranges from 0 to 1000) + float glossiness; // Glossiness level (Ranges from 0 to 1000) } Material; + // Camera type, defines a camera position/orientation in 3d space + typedef struct Camera { + Vector3 position; // Camera position + Vector3 target; // Camera target it looks-at + Vector3 up; // Camera up vector (rotation over its axis) + float fovy; // Camera field-of-view apperture in Y (degrees) + } Camera; + // Light type typedef struct LightData { - unsigned int id; // Light id - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - bool enabled; // Light enabled + unsigned int id; // Light unique id + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + bool enabled; // Light enabled - Vector3 position; // Light position - Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Light attenuation radius light intensity reduced with distance (world distance) + Vector3 position; // Light position + Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float radius; // Light attenuation radius light intensity reduced with distance (world distance) - Color diffuse; // Light diffuse color - float intensity; // Light intensity level + Color diffuse; // Light diffuse color + float intensity; // Light intensity level - float coneAngle; // Light cone max angle: LIGHT_SPOT + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; - + + // Light types + typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; #endif diff --git a/src/shapes.c b/src/shapes.c index 5b66e5ef..7129ac17 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -489,7 +489,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) retRec.height = rec2.height - dyy; } } - + if (rec1.width > rec2.width) { if (retRec.width >= rec2.width) retRec.width = rec2.width; -- cgit v1.2.3 From 90e1ed2b5e54a9b6c69be3dd2b71d1e4f3632c33 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Wed, 1 Jun 2016 20:09:00 -0700 Subject: mod player added --- src/audio.c | 85 +++- src/audio.h | 3 +- src/jar_mod.h | 1583 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/raylib.h | 3 +- 4 files changed, 1652 insertions(+), 22 deletions(-) create mode 100644 src/jar_mod.h (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index c72b32aa..ceec5577 100644 --- a/src/audio.c +++ b/src/audio.c @@ -56,6 +56,9 @@ #define JAR_XM_IMPLEMENTATION #include "jar_xm.h" // For playing .xm files +#define JAR_MOD_IMPLEMENTATION +#include "jar_mod.h" // For playing .mod files + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -95,10 +98,11 @@ typedef struct MixChannel_t { // 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 + jar_xm_context_t *xmctx; // Stores jar_xm mixc, XM chiptune context + modcontext modctx; // Stores mod chiptune context MixChannel_t *mixc; // mix channel - int totalSamplesLeft; + unsigned int totalSamplesLeft; float totalLengthSeconds; bool loop; bool chipTune; // True if chiptune is loaded @@ -399,6 +403,8 @@ void CloseRawAudioContext(RawAudioContext ctx) CloseMixChannel(mixChannelsActive_g[ctx]); } +// if 0 is returned, the buffers are still full and you need to keep trying with same data until a number is returned. +// any other number returned is the number that was processed and passed into buffer. int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short numberElements) { int numBuffered = 0; @@ -767,7 +773,7 @@ int PlayMusicStream(int musicIndex, char *fileName) { int mixIndex; - if(currentMusic[musicIndex].stream || currentMusic[musicIndex].chipctx) return 1; // error + if(currentMusic[musicIndex].stream || currentMusic[musicIndex].xmctx) return 1; // error for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { @@ -798,7 +804,7 @@ int PlayMusicStream(int musicIndex, char *fileName) musicEnabled_g = true; - currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels; + currentMusic[musicIndex].totalSamplesLeft = (unsigned int)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){ @@ -815,12 +821,12 @@ int PlayMusicStream(int musicIndex, char *fileName) else if (strcmp(GetExtension(fileName),"xm") == 0) { // only stereo is supported for xm - if(!jar_xm_create_context_from_file(¤tMusic[musicIndex].chipctx, 48000, fileName)) + if(!jar_xm_create_context_from_file(¤tMusic[musicIndex].xmctx, 48000, fileName)) { 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); + jar_xm_set_max_loop_count(currentMusic[musicIndex].xmctx, 0); // infinite number of loops + currentMusic[musicIndex].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(currentMusic[musicIndex].xmctx); currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f; musicEnabled_g = true; @@ -837,10 +843,34 @@ int PlayMusicStream(int musicIndex, char *fileName) return 6; // error } } + else if (strcmp(GetExtension(fileName),"mod") == 0) + { + jar_mod_init(¤tMusic[musicIndex].modctx); + if(jar_mod_load_file(¤tMusic[musicIndex].modctx, fileName)) + { + currentMusic[musicIndex].chipTune = true; + currentMusic[musicIndex].loop = true; + currentMusic[musicIndex].totalSamplesLeft = (unsigned int)jar_mod_max_samples(¤tMusic[musicIndex].modctx); + currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f; + musicEnabled_g = true; + + TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft); + TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds); + + currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); + if(!currentMusic[musicIndex].mixc) return 7; // error + currentMusic[musicIndex].mixc->playing = true; + } + else + { + TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); + return 8; // error + } + } else { TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); - return 7; // error + return 9; // error } return 0; // normal return } @@ -852,9 +882,14 @@ void StopMusicStream(int index) { CloseMixChannel(currentMusic[index].mixc); - if (currentMusic[index].chipTune) + if (currentMusic[index].chipTune && currentMusic[index].xmctx) { - jar_xm_free_context(currentMusic[index].chipctx); + jar_xm_free_context(currentMusic[index].xmctx); + currentMusic[index].xmctx = 0; + } + else if(currentMusic[index].chipTune && currentMusic[index].modctx.mod_loaded) + { + jar_mod_unload(¤tMusic[index].modctx); } else { @@ -862,10 +897,10 @@ void StopMusicStream(int index) } if(!getMusicStreamCount()) musicEnabled_g = false; - if(currentMusic[index].stream || currentMusic[index].chipctx) + if(currentMusic[index].stream || currentMusic[index].xmctx) { currentMusic[index].stream = NULL; - currentMusic[index].chipctx = NULL; + currentMusic[index].xmctx = NULL; } } } @@ -937,13 +972,13 @@ void SetMusicPitch(int index, float pitch) } } -// Get current music time length (in seconds) +// Get music time length (in seconds) float GetMusicTimeLength(int index) { float totalSeconds; if (currentMusic[index].chipTune) { - totalSeconds = currentMusic[index].totalLengthSeconds; + totalSeconds = (float)currentMusic[index].totalLengthSeconds; } else { @@ -959,11 +994,16 @@ float GetMusicTimePlayed(int index) float secondsPlayed = 0.0f; if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc) { - if (currentMusic[index].chipTune) + if (currentMusic[index].chipTune && currentMusic[index].xmctx) { 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 + jar_xm_get_position(currentMusic[index].xmctx, NULL, NULL, NULL, &samples); + secondsPlayed = (float)samples / (48000.f * currentMusic[index].mixc->channels); // Not sure if this is the correct value + } + else if(currentMusic[index].chipTune && currentMusic[index].modctx.mod_loaded) + { + long numsamp = jar_mod_current_samples(¤tMusic[index].modctx); + secondsPlayed = (float)numsamp / (48000.f); } else { @@ -984,7 +1024,7 @@ float GetMusicTimePlayed(int index) static bool BufferMusicStream(int index, int numBuffers) { short pcm[MUSIC_BUFFER_SIZE_SHORT]; - float pcmf[MUSIC_BUFFER_SIZE_FLOAT]; + //float pcmf[MUSIC_BUFFER_SIZE_FLOAT]; 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) @@ -998,9 +1038,13 @@ static bool BufferMusicStream(int index, int numBuffers) for(int x=0; x free.fr> +// Adapted to jar_mod by: Joshua Adam Reisenauer +// This program is free software. It comes without any warranty, to the +// extent permitted by applicable law. You can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To Public +// License, Version 2, as published by Sam Hocevar. See +// http://sam.zoy.org/wtfpl/COPYING for more details. +/////////////////////////////////////////////////////////////////////////////////// +// HxCMOD Core API: +// ------------------------------------------- +// int jar_mod_init(modcontext * modctx) +// +// - Initialize the modcontext buffer. Must be called before doing anything else. +// Return 1 if success. 0 in case of error. +// ------------------------------------------- +// mulong jar_mod_load_file(modcontext * modctx, char* filename) +// +// - "Load" a MOD from file, context must already be initialized. +// Return size of file in bytes. +// ------------------------------------------- +// void jar_mod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) +// +// - Generate and return the next samples chunk to outbuffer. +// nbsample specify the number of stereo 16bits samples you want. +// The output format is by default signed 48000Hz 16-bit Stereo PCM samples, otherwise it is changed with jar_mod_setcfg(). +// The output buffer size in bytes must be equal to ( nbsample * 2 * channels ). +// The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 is unused. +// ------------------------------------------- +// void jar_mod_unload( modcontext * modctx ) +// - "Unload" / clear the player status. +// ------------------------------------------- +/////////////////////////////////////////////////////////////////////////////////// + + +#ifndef INCLUDE_JAR_MOD_H +#define INCLUDE_JAR_MOD_H + +#include +#include +#include + + + +#ifdef __cplusplus +extern "C" { +#endif + + + +// Basic type +typedef unsigned char muchar; +typedef unsigned short muint; +typedef short mint; +typedef unsigned long mulong; + +#define NUMMAXCHANNELS 32 +#define MAXNOTES 12*12 +#define DEFAULT_SAMPLE_RATE 48000 +// +// MOD file structures +// + +#pragma pack(1) + +typedef struct { + muchar name[22]; + muint length; + muchar finetune; + muchar volume; + muint reppnt; + muint replen; +} sample; + +typedef struct { + muchar sampperiod; + muchar period; + muchar sampeffect; + muchar effect; +} note; + +typedef struct { + muchar title[20]; + sample samples[31]; + muchar length; // length of tablepos + muchar protracker; + muchar patterntable[128]; + muchar signature[4]; + muchar speed; +} module; + +#pragma pack() + +// +// HxCMod Internal structures +// +typedef struct { + char* sampdata; + muint sampnum; + muint length; + muint reppnt; + muint replen; + mulong samppos; + muint period; + muchar volume; + mulong ticks; + muchar effect; + muchar parameffect; + muint effect_code; + mint decalperiod; + mint portaspeed; + mint portaperiod; + mint vibraperiod; + mint Arpperiods[3]; + muchar ArpIndex; + mint oldk; + muchar volumeslide; + muchar vibraparam; + muchar vibrapointeur; + muchar finetune; + muchar cut_param; + muint patternloopcnt; + muint patternloopstartpoint; +} channel; + +typedef struct { + module song; + char* sampledata[31]; + note* patterndata[128]; + + mulong playrate; + muint tablepos; + muint patternpos; + muint patterndelay; + muint jump_loop_effect; + muchar bpm; + mulong patternticks; + mulong patterntickse; + mulong patternticksaim; + mulong sampleticksconst; + mulong samplenb; + channel channels[NUMMAXCHANNELS]; + muint number_of_channels; + muint fullperiod[MAXNOTES * 8]; + muint mod_loaded; + mint last_r_sample; + mint last_l_sample; + mint stereo; + mint stereo_separation; + mint bits; + mint filter; + + muchar *modfile; // the raw mod file + mulong modfilesize; + muint loopcount; +} modcontext; + +// +// Player states structures +// +typedef struct track_state_ +{ + unsigned char instrument_number; + unsigned short cur_period; + unsigned char cur_volume; + unsigned short cur_effect; + unsigned short cur_parameffect; +}track_state; + +typedef struct tracker_state_ +{ + int number_of_tracks; + int bpm; + int speed; + int cur_pattern; + int cur_pattern_pos; + int cur_pattern_table_pos; + unsigned int buf_index; + track_state tracks[32]; +}tracker_state; + +typedef struct tracker_state_instrument_ +{ + char name[22]; + int active; +}tracker_state_instrument; + +typedef struct jar_mod_tracker_buffer_state_ +{ + int nb_max_of_state; + int nb_of_state; + int cur_rd_index; + int sample_step; + char name[64]; + tracker_state_instrument instruments[31]; + tracker_state * track_state_buf; +}jar_mod_tracker_buffer_state; + + + +bool jar_mod_init(modcontext * modctx); +bool jar_mod_setcfg(modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter); +void jar_mod_fillbuffer(modcontext * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf); +void jar_mod_unload(modcontext * modctx); +mulong jar_mod_load_file(modcontext * modctx, char* filename); +mulong jar_mod_current_samples(modcontext * modctx); +mulong jar_mod_max_samples(modcontext * modctx); +void jar_mod_seek_start(modcontext * ctx); + +#ifdef __cplusplus +} +#endif +//-------------------------------------------------------------------- + + + +//------------------------------------------------------------------------------- +#ifdef JAR_MOD_IMPLEMENTATION + +// Effects list +#define EFFECT_ARPEGGIO 0x0 // Supported +#define EFFECT_PORTAMENTO_UP 0x1 // Supported +#define EFFECT_PORTAMENTO_DOWN 0x2 // Supported +#define EFFECT_TONE_PORTAMENTO 0x3 // Supported +#define EFFECT_VIBRATO 0x4 // Supported +#define EFFECT_VOLSLIDE_TONEPORTA 0x5 // Supported +#define EFFECT_VOLSLIDE_VIBRATO 0x6 // Supported +#define EFFECT_VOLSLIDE_TREMOLO 0x7 // - TO BE DONE - +#define EFFECT_SET_PANNING 0x8 // - TO BE DONE - +#define EFFECT_SET_OFFSET 0x9 // Supported +#define EFFECT_VOLUME_SLIDE 0xA // Supported +#define EFFECT_JUMP_POSITION 0xB // Supported +#define EFFECT_SET_VOLUME 0xC // Supported +#define EFFECT_PATTERN_BREAK 0xD // Supported + +#define EFFECT_EXTENDED 0xE +#define EFFECT_E_FINE_PORTA_UP 0x1 // Supported +#define EFFECT_E_FINE_PORTA_DOWN 0x2 // Supported +#define EFFECT_E_GLISSANDO_CTRL 0x3 // - TO BE DONE - +#define EFFECT_E_VIBRATO_WAVEFORM 0x4 // - TO BE DONE - +#define EFFECT_E_SET_FINETUNE 0x5 // - TO BE DONE - +#define EFFECT_E_PATTERN_LOOP 0x6 // Supported +#define EFFECT_E_TREMOLO_WAVEFORM 0x7 // - TO BE DONE - +#define EFFECT_E_SET_PANNING_2 0x8 // - TO BE DONE - +#define EFFECT_E_RETRIGGER_NOTE 0x9 // - TO BE DONE - +#define EFFECT_E_FINE_VOLSLIDE_UP 0xA // Supported +#define EFFECT_E_FINE_VOLSLIDE_DOWN 0xB // Supported +#define EFFECT_E_NOTE_CUT 0xC // Supported +#define EFFECT_E_NOTE_DELAY 0xD // - TO BE DONE - +#define EFFECT_E_PATTERN_DELAY 0xE // Supported +#define EFFECT_E_INVERT_LOOP 0xF // - TO BE DONE - +#define EFFECT_SET_SPEED 0xF0 // Supported +#define EFFECT_SET_TEMPO 0xF2 // Supported + +#define PERIOD_TABLE_LENGTH MAXNOTES +#define FULL_PERIOD_TABLE_LENGTH ( PERIOD_TABLE_LENGTH * 8 ) + +static const short periodtable[]= +{ + 27392, 25856, 24384, 23040, 21696, 20480, 19328, 18240, 17216, 16256, 15360, 14496, + 13696, 12928, 12192, 11520, 10848, 10240, 9664, 9120, 8606, 8128, 7680, 7248, + 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624, + 3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812, + 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960, 906, + 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453, + 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226, + 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113, + 107, 101, 95, 90, 85, 80, 75, 71, 67, 63, 60, 56, + 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28, + 27, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14, + 13, 13, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7 +}; + +static const short sintable[]={ + 0, 24, 49, 74, 97, 120, 141,161, + 180, 197, 212, 224, 235, 244, 250,253, + 255, 253, 250, 244, 235, 224, 212,197, + 180, 161, 141, 120, 97, 74, 49, 24 +}; + +typedef struct modtype_ +{ + unsigned char signature[5]; + int numberofchannels; +}modtype; + +modtype modlist[]= +{ + { "M!K!",4}, + { "M.K.",4}, + { "FLT4",4}, + { "FLT8",8}, + { "4CHN",4}, + { "6CHN",6}, + { "8CHN",8}, + { "10CH",10}, + { "12CH",12}, + { "14CH",14}, + { "16CH",16}, + { "18CH",18}, + { "20CH",20}, + { "22CH",22}, + { "24CH",24}, + { "26CH",26}, + { "28CH",28}, + { "30CH",30}, + { "32CH",32}, + { "",0} +}; + +/////////////////////////////////////////////////////////////////////////////////// + +static void memcopy( void * dest, void *source, unsigned long size ) +{ + unsigned long i; + unsigned char * d,*s; + + d=(unsigned char*)dest; + s=(unsigned char*)source; + for(i=0;i= mod->fullperiod[i]) + { + return i; + } + } + + return MAXNOTES; +} + +static void worknote( note * nptr, channel * cptr, char t, modcontext * mod ) +{ + muint sample, period, effect, operiod; + muint curnote, arpnote; + + sample = (nptr->sampperiod & 0xF0) | (nptr->sampeffect >> 4); + period = ((nptr->sampperiod & 0xF) << 8) | nptr->period; + effect = ((nptr->sampeffect & 0xF) << 8) | nptr->effect; + + operiod = cptr->period; + + if ( period || sample ) + { + if( sample && sample < 32 ) + { + cptr->sampnum = sample - 1; + } + + if( period || sample ) + { + cptr->sampdata = (char *) mod->sampledata[cptr->sampnum]; + cptr->length = mod->song.samples[cptr->sampnum].length; + cptr->reppnt = mod->song.samples[cptr->sampnum].reppnt; + cptr->replen = mod->song.samples[cptr->sampnum].replen; + + cptr->finetune = (mod->song.samples[cptr->sampnum].finetune)&0xF; + + if(effect>>8!=4 && effect>>8!=6) + { + cptr->vibraperiod=0; + cptr->vibrapointeur=0; + } + } + + if( (sample != 0) && ( (effect>>8) != EFFECT_VOLSLIDE_TONEPORTA ) ) + { + cptr->volume = mod->song.samples[cptr->sampnum].volume; + cptr->volumeslide = 0; + } + + if( ( (effect>>8) != EFFECT_TONE_PORTAMENTO && (effect>>8)!=EFFECT_VOLSLIDE_TONEPORTA) ) + { + if (period!=0) + cptr->samppos = 0; + } + + cptr->decalperiod = 0; + if( period ) + { + if(cptr->finetune) + { + if( cptr->finetune <= 7 ) + { + period = mod->fullperiod[getnote(mod,period,0) + cptr->finetune]; + } + else + { + period = mod->fullperiod[getnote(mod,period,0) - (16 - (cptr->finetune)) ]; + } + } + + cptr->period = period; + } + + } + + cptr->effect = 0; + cptr->parameffect = 0; + cptr->effect_code = effect; + + switch (effect >> 8) + { + case EFFECT_ARPEGGIO: + /* + [0]: Arpeggio + Where [0][x][y] means "play note, note+x semitones, note+y + semitones, then return to original note". The fluctuations are + carried out evenly spaced in one pattern division. They are usually + used to simulate chords, but this doesn't work too well. They are + also used to produce heavy vibrato. A major chord is when x=4, y=7. + A minor chord is when x=3, y=7. + */ + + if(effect&0xff) + { + cptr->effect = EFFECT_ARPEGGIO; + cptr->parameffect = effect&0xff; + + cptr->ArpIndex = 0; + + curnote = getnote(mod,cptr->period,cptr->finetune); + + cptr->Arpperiods[0] = cptr->period; + + arpnote = curnote + (((cptr->parameffect>>4)&0xF)*8); + if( arpnote >= FULL_PERIOD_TABLE_LENGTH ) + arpnote = FULL_PERIOD_TABLE_LENGTH - 1; + + cptr->Arpperiods[1] = mod->fullperiod[arpnote]; + + arpnote = curnote + (((cptr->parameffect)&0xF)*8); + if( arpnote >= FULL_PERIOD_TABLE_LENGTH ) + arpnote = FULL_PERIOD_TABLE_LENGTH - 1; + + cptr->Arpperiods[2] = mod->fullperiod[arpnote]; + } + break; + + case EFFECT_PORTAMENTO_UP: + /* + [1]: Slide up + Where [1][x][y] means "smoothly decrease the period of current + sample by x*16+y after each tick in the division". The + ticks/division are set with the 'set speed' effect (see below). If + the period of the note being played is z, then the final period + will be z - (x*16 + y)*(ticks - 1). As the slide rate depends on + the speed, changing the speed will change the slide. You cannot + slide beyond the note B3 (period 113). + */ + + cptr->effect = EFFECT_PORTAMENTO_UP; + cptr->parameffect = effect&0xff; + break; + + case EFFECT_PORTAMENTO_DOWN: + /* + [2]: Slide down + Where [2][x][y] means "smoothly increase the period of current + sample by x*16+y after each tick in the division". Similar to [1], + but lowers the pitch. You cannot slide beyond the note C1 (period + 856). + */ + + cptr->effect = EFFECT_PORTAMENTO_DOWN; + cptr->parameffect = effect&0xff; + break; + + case EFFECT_TONE_PORTAMENTO: + /* + [3]: Slide to note + Where [3][x][y] means "smoothly change the period of current sample + by x*16+y after each tick in the division, never sliding beyond + current period". The period-length in this channel's division is a + parameter to this effect, and hence is not played. Sliding to a + note is similar to effects [1] and [2], but the slide will not go + beyond the given period, and the direction is implied by that + period. If x and y are both 0, then the old slide will continue. + */ + + cptr->effect = EFFECT_TONE_PORTAMENTO; + if( (effect&0xff) != 0 ) + { + cptr->portaspeed = (short)(effect&0xff); + } + + if(period!=0) + { + cptr->portaperiod = period; + cptr->period = operiod; + } + break; + + case EFFECT_VIBRATO: + /* + [4]: Vibrato + Where [4][x][y] means "oscillate the sample pitch using a + particular waveform with amplitude y/16 semitones, such that (x * + ticks)/64 cycles occur in the division". The waveform is set using + effect [14][4]. By placing vibrato effects on consecutive + divisions, the vibrato effect can be maintained. If either x or y + are 0, then the old vibrato values will be used. + */ + + cptr->effect = EFFECT_VIBRATO; + if( ( effect & 0x0F ) != 0 ) // Depth continue or change ? + cptr->vibraparam = (cptr->vibraparam & 0xF0) | ( effect & 0x0F ); + if( ( effect & 0xF0 ) != 0 ) // Speed continue or change ? + cptr->vibraparam = (cptr->vibraparam & 0x0F) | ( effect & 0xF0 ); + + break; + + case EFFECT_VOLSLIDE_TONEPORTA: + /* + [5]: Continue 'Slide to note', but also do Volume slide + Where [5][x][y] means "either slide the volume up x*(ticks - 1) or + slide the volume down y*(ticks - 1), at the same time as continuing + the last 'Slide to note'". It is illegal for both x and y to be + non-zero. You cannot slide outside the volume range 0..64. The + period-length in this channel's division is a parameter to this + effect, and hence is not played. + */ + + if( period != 0 ) + { + cptr->portaperiod = period; + cptr->period = operiod; + } + + cptr->effect = EFFECT_VOLSLIDE_TONEPORTA; + if( ( effect & 0xFF ) != 0 ) + cptr->volumeslide = ( effect & 0xFF ); + + break; + + case EFFECT_VOLSLIDE_VIBRATO: + /* + [6]: Continue 'Vibrato', but also do Volume slide + Where [6][x][y] means "either slide the volume up x*(ticks - 1) or + slide the volume down y*(ticks - 1), at the same time as continuing + the last 'Vibrato'". It is illegal for both x and y to be non-zero. + You cannot slide outside the volume range 0..64. + */ + + cptr->effect = EFFECT_VOLSLIDE_VIBRATO; + if( (effect & 0xFF) != 0 ) + cptr->volumeslide = (effect & 0xFF); + break; + + case EFFECT_SET_OFFSET: + /* + [9]: Set sample offset + Where [9][x][y] means "play the sample from offset x*4096 + y*256". + The offset is measured in words. If no sample is given, yet one is + still playing on this channel, it should be retriggered to the new + offset using the current volume. + */ + + cptr->samppos = ((effect>>4) * 4096) + ((effect&0xF)*256); + + break; + + case EFFECT_VOLUME_SLIDE: + /* + [10]: Volume slide + Where [10][x][y] means "either slide the volume up x*(ticks - 1) or + slide the volume down y*(ticks - 1)". If both x and y are non-zero, + then the y value is ignored (assumed to be 0). You cannot slide + outside the volume range 0..64. + */ + + cptr->effect = EFFECT_VOLUME_SLIDE; + cptr->volumeslide = (effect & 0xFF); + break; + + case EFFECT_JUMP_POSITION: + /* + [11]: Position Jump + Where [11][x][y] means "stop the pattern after this division, and + continue the song at song-position x*16+y". This shifts the + 'pattern-cursor' in the pattern table (see above). Legal values for + x*16+y are from 0 to 127. + */ + + mod->tablepos = (effect & 0xFF); + if(mod->tablepos >= mod->song.length) + { + mod->tablepos = 0; + } + mod->patternpos = 0; + mod->jump_loop_effect = 1; + + break; + + case EFFECT_SET_VOLUME: + /* + [12]: Set volume + Where [12][x][y] means "set current sample's volume to x*16+y". + Legal volumes are 0..64. + */ + + cptr->volume = (effect & 0xFF); + break; + + case EFFECT_PATTERN_BREAK: + /* + [13]: Pattern Break + Where [13][x][y] means "stop the pattern after this division, and + continue the song at the next pattern at division x*10+y" (the 10 + is not a typo). Legal divisions are from 0 to 63 (note Protracker + exception above). + */ + + mod->patternpos = ( ((effect>>4)&0xF)*10 + (effect&0xF) ) * mod->number_of_channels; + mod->jump_loop_effect = 1; + mod->tablepos++; + if(mod->tablepos >= mod->song.length) + { + mod->tablepos = 0; + } + + break; + + case EFFECT_EXTENDED: + switch( (effect>>4) & 0xF ) + { + case EFFECT_E_FINE_PORTA_UP: + /* + [14][1]: Fineslide up + Where [14][1][x] means "decrement the period of the current sample + by x". The incrementing takes place at the beginning of the + division, and hence there is no actual sliding. You cannot slide + beyond the note B3 (period 113). + */ + + cptr->period -= (effect & 0xF); + if( cptr->period < 113 ) + cptr->period = 113; + break; + + case EFFECT_E_FINE_PORTA_DOWN: + /* + [14][2]: Fineslide down + Where [14][2][x] means "increment the period of the current sample + by x". Similar to [14][1] but shifts the pitch down. You cannot + slide beyond the note C1 (period 856). + */ + + cptr->period += (effect & 0xF); + if( cptr->period > 856 ) + cptr->period = 856; + break; + + case EFFECT_E_FINE_VOLSLIDE_UP: + /* + [14][10]: Fine volume slide up + Where [14][10][x] means "increment the volume of the current sample + by x". The incrementing takes place at the beginning of the + division, and hence there is no sliding. You cannot slide beyond + volume 64. + */ + + cptr->volume += (effect & 0xF); + if( cptr->volume>64 ) + cptr->volume = 64; + break; + + case EFFECT_E_FINE_VOLSLIDE_DOWN: + /* + [14][11]: Fine volume slide down + Where [14][11][x] means "decrement the volume of the current sample + by x". Similar to [14][10] but lowers volume. You cannot slide + beyond volume 0. + */ + + cptr->volume -= (effect & 0xF); + if( cptr->volume > 200 ) + cptr->volume = 0; + break; + + case EFFECT_E_PATTERN_LOOP: + /* + [14][6]: Loop pattern + Where [14][6][x] means "set the start of a loop to this division if + x is 0, otherwise after this division, jump back to the start of a + loop and play it another x times before continuing". If the start + of the loop was not set, it will default to the start of the + current pattern. Hence 'loop pattern' cannot be performed across + multiple patterns. Note that loops do not support nesting, and you + may generate an infinite loop if you try to nest 'loop pattern's. + */ + + if( effect & 0xF ) + { + if( cptr->patternloopcnt ) + { + cptr->patternloopcnt--; + if( cptr->patternloopcnt ) + { + mod->patternpos = cptr->patternloopstartpoint; + mod->jump_loop_effect = 1; + } + else + { + cptr->patternloopstartpoint = mod->patternpos ; + } + } + else + { + cptr->patternloopcnt = (effect & 0xF); + mod->patternpos = cptr->patternloopstartpoint; + mod->jump_loop_effect = 1; + } + } + else // Start point + { + cptr->patternloopstartpoint = mod->patternpos; + } + + break; + + case EFFECT_E_PATTERN_DELAY: + /* + [14][14]: Delay pattern + Where [14][14][x] means "after this division there will be a delay + equivalent to the time taken to play x divisions after which the + pattern will be resumed". The delay only relates to the + interpreting of new divisions, and all effects and previous notes + continue during delay. + */ + + mod->patterndelay = (effect & 0xF); + break; + + case EFFECT_E_NOTE_CUT: + /* + [14][12]: Cut sample + Where [14][12][x] means "after the current sample has been played + for x ticks in this division, its volume will be set to 0". This + implies that if x is 0, then you will not hear any of the sample. + If you wish to insert "silence" in a pattern, it is better to use a + "silence"-sample (see above) due to the lack of proper support for + this effect. + */ + cptr->effect = EFFECT_E_NOTE_CUT; + cptr->cut_param = (effect & 0xF); + if(!cptr->cut_param) + cptr->volume = 0; + break; + + default: + + break; + } + break; + + case 0xF: + /* + [15]: Set speed + Where [15][x][y] means "set speed to x*16+y". Though it is nowhere + near that simple. Let z = x*16+y. Depending on what values z takes, + different units of speed are set, there being two: ticks/division + and beats/minute (though this one is only a label and not strictly + true). If z=0, then what should technically happen is that the + module stops, but in practice it is treated as if z=1, because + there is already a method for stopping the module (running out of + patterns). If z<=32, then it means "set ticks/division to z" + otherwise it means "set beats/minute to z" (convention says that + this should read "If z<32.." but there are some composers out there + that defy conventions). Default values are 6 ticks/division, and + 125 beats/minute (4 divisions = 1 beat). The beats/minute tag is + only meaningful for 6 ticks/division. To get a more accurate view + of how things work, use the following formula: + 24 * beats/minute + divisions/minute = ----------------- + ticks/division + Hence divisions/minute range from 24.75 to 6120, eg. to get a value + of 2000 divisions/minute use 3 ticks/division and 250 beats/minute. + If multiple "set speed" effects are performed in a single division, + the ones on higher-numbered channels take precedence over the ones + on lower-numbered channels. This effect has a large number of + different implementations, but the one described here has the + widest usage. + */ + + if( (effect&0xFF) < 0x21 ) + { + if( effect&0xFF ) + { + mod->song.speed = effect&0xFF; + mod->patternticksaim = (long)mod->song.speed * ((mod->playrate * 5 ) / (((long)2 * (long)mod->bpm))); + } + } + + if( (effect&0xFF) >= 0x21 ) + { + /// HZ = 2 * BPM / 5 + mod->bpm = effect&0xFF; + mod->patternticksaim = (long)mod->song.speed * ((mod->playrate * 5 ) / (((long)2 * (long)mod->bpm))); + } + + break; + + default: + // Unsupported effect + break; + + } + +} + +static void workeffect( note * nptr, channel * cptr ) +{ + switch(cptr->effect) + { + case EFFECT_ARPEGGIO: + + if( cptr->parameffect ) + { + cptr->decalperiod = cptr->period - cptr->Arpperiods[cptr->ArpIndex]; + + cptr->ArpIndex++; + if( cptr->ArpIndex>2 ) + cptr->ArpIndex = 0; + } + break; + + case EFFECT_PORTAMENTO_UP: + + if(cptr->period) + { + cptr->period -= cptr->parameffect; + + if( cptr->period < 113 || cptr->period > 20000 ) + cptr->period = 113; + } + + break; + + case EFFECT_PORTAMENTO_DOWN: + + if(cptr->period) + { + cptr->period += cptr->parameffect; + + if( cptr->period > 20000 ) + cptr->period = 20000; + } + + break; + + case EFFECT_VOLSLIDE_TONEPORTA: + case EFFECT_TONE_PORTAMENTO: + + if( cptr->period && ( cptr->period != cptr->portaperiod ) && cptr->portaperiod ) + { + if( cptr->period > cptr->portaperiod ) + { + if( cptr->period - cptr->portaperiod >= cptr->portaspeed ) + { + cptr->period -= cptr->portaspeed; + } + else + { + cptr->period = cptr->portaperiod; + } + } + else + { + if( cptr->portaperiod - cptr->period >= cptr->portaspeed ) + { + cptr->period += cptr->portaspeed; + } + else + { + cptr->period = cptr->portaperiod; + } + } + + if( cptr->period == cptr->portaperiod ) + { + // If the slide is over, don't let it to be retriggered. + cptr->portaperiod = 0; + } + } + + if( cptr->effect == EFFECT_VOLSLIDE_TONEPORTA ) + { + if( cptr->volumeslide > 0x0F ) + { + cptr->volume = cptr->volume + (cptr->volumeslide>>4); + + if(cptr->volume>63) + cptr->volume = 63; + } + else + { + cptr->volume = cptr->volume - (cptr->volumeslide); + + if(cptr->volume>63) + cptr->volume=0; + } + } + break; + + case EFFECT_VOLSLIDE_VIBRATO: + case EFFECT_VIBRATO: + + cptr->vibraperiod = ( (cptr->vibraparam&0xF) * sintable[cptr->vibrapointeur&0x1F] )>>7; + + if( cptr->vibrapointeur > 31 ) + cptr->vibraperiod = -cptr->vibraperiod; + + cptr->vibrapointeur = (cptr->vibrapointeur+(((cptr->vibraparam>>4))&0xf)) & 0x3F; + + if( cptr->effect == EFFECT_VOLSLIDE_VIBRATO ) + { + if( cptr->volumeslide > 0xF ) + { + cptr->volume = cptr->volume+(cptr->volumeslide>>4); + + if( cptr->volume > 64 ) + cptr->volume = 64; + } + else + { + cptr->volume = cptr->volume - cptr->volumeslide; + + if( cptr->volume > 64 ) + cptr->volume = 0; + } + } + + break; + + case EFFECT_VOLUME_SLIDE: + + if( cptr->volumeslide > 0xF ) + { + cptr->volume += (cptr->volumeslide>>4); + + if( cptr->volume > 64 ) + cptr->volume = 64; + } + else + { + cptr->volume -= (cptr->volumeslide&0xf); + + if( cptr->volume > 64 ) + cptr->volume = 0; + } + break; + + case EFFECT_E_NOTE_CUT: + if(cptr->cut_param) + cptr->cut_param--; + + if(!cptr->cut_param) + cptr->volume = 0; + break; + + default: + break; + + } + +} + +/////////////////////////////////////////////////////////////////////////////////// +bool jar_mod_init(modcontext * modctx) +{ + muint i,j; + + if( modctx ) + { + memclear(modctx,0,sizeof(modcontext)); + modctx->playrate = DEFAULT_SAMPLE_RATE; + modctx->stereo = 1; + modctx->stereo_separation = 1; + modctx->bits = 16; + modctx->filter = 1; + modctx->loopcount = 0; + + for(i=0;ifullperiod[(i*8) + j] = periodtable[i] - ((( periodtable[i] - periodtable[i+1] ) / 8) * j); + } + } + + return 1; + } + + return 0; +} + +bool jar_mod_setcfg(modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter) +{ + if( modctx ) + { + modctx->playrate = samplerate; + + if( stereo ) + modctx->stereo = 1; + else + modctx->stereo = 0; + + if(stereo_separation < 4) + { + modctx->stereo_separation = stereo_separation; + } + + if( bits == 8 || bits == 16 ) + modctx->bits = bits; + else + modctx->bits = 16; + + if( filter ) + modctx->filter = 1; + else + modctx->filter = 0; + + return 1; + } + + return 0; +} + +// make certain that mod_data stays in memory while playing +static bool jar_mod_load( modcontext * modctx, void * mod_data, int mod_data_size ) +{ + muint i, max; + unsigned short t; + sample *sptr; + unsigned char * modmemory,* endmodmemory; + + modmemory = (unsigned char *)mod_data; + endmodmemory = modmemory + mod_data_size; + + + + if(modmemory) + { + if( modctx ) + { + memcopy(&(modctx->song.title),modmemory,1084); + + i = 0; + modctx->number_of_channels = 0; + while(modlist[i].numberofchannels) + { + if(memcompare(modctx->song.signature,modlist[i].signature,4)) + { + modctx->number_of_channels = modlist[i].numberofchannels; + } + + i++; + } + + if( !modctx->number_of_channels ) + { + // 15 Samples modules support + // Shift the whole datas to make it look likes a standard 4 channels mod. + memcopy(&(modctx->song.signature), "M.K.", 4); + memcopy(&(modctx->song.length), &(modctx->song.samples[15]), 130); + memclear(&(modctx->song.samples[15]), 0, 480); + modmemory += 600; + modctx->number_of_channels = 4; + } + else + { + modmemory += 1084; + } + + if( modmemory >= endmodmemory ) + return 0; // End passed ? - Probably a bad file ! + + // Patterns loading + for (i = max = 0; i < 128; i++) + { + while (max <= modctx->song.patterntable[i]) + { + modctx->patterndata[max] = (note*)modmemory; + modmemory += (256*modctx->number_of_channels); + max++; + + if( modmemory >= endmodmemory ) + return 0; // End passed ? - Probably a bad file ! + } + } + + for (i = 0; i < 31; i++) + modctx->sampledata[i]=0; + + // Samples loading + for (i = 0, sptr = modctx->song.samples; i <31; i++, sptr++) + { + t= (sptr->length &0xFF00)>>8 | (sptr->length &0xFF)<<8; + sptr->length = t*2; + + t= (sptr->reppnt &0xFF00)>>8 | (sptr->reppnt &0xFF)<<8; + sptr->reppnt = t*2; + + t= (sptr->replen &0xFF00)>>8 | (sptr->replen &0xFF)<<8; + sptr->replen = t*2; + + + if (sptr->length == 0) continue; + + modctx->sampledata[i] = (char*)modmemory; + modmemory += sptr->length; + + if (sptr->replen + sptr->reppnt > sptr->length) + sptr->replen = sptr->length - sptr->reppnt; + + if( modmemory > endmodmemory ) + return 0; // End passed ? - Probably a bad file ! + } + + // States init + + modctx->tablepos = 0; + modctx->patternpos = 0; + modctx->song.speed = 6; + modctx->bpm = 125; + modctx->samplenb = 0; + + modctx->patternticks = (((long)modctx->song.speed * modctx->playrate * 5)/ (2 * modctx->bpm)) + 1; + modctx->patternticksaim = ((long)modctx->song.speed * modctx->playrate * 5) / (2 * modctx->bpm); + + modctx->sampleticksconst = 3546894UL / modctx->playrate; //8448*428/playrate; + + for(i=0; i < modctx->number_of_channels; i++) + { + modctx->channels[i].volume = 0; + modctx->channels[i].period = 0; + } + + modctx->mod_loaded = 1; + + return 1; + } + } + + return 0; +} + +void jar_mod_fillbuffer( modcontext * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) +{ + unsigned long i, j; + unsigned long k; + unsigned char c; + unsigned int state_remaining_steps; + int l,r; + int ll,lr; + int tl,tr; + short finalperiod; + note *nptr; + channel *cptr; + + if( modctx && outbuffer ) + { + if(modctx->mod_loaded) + { + state_remaining_steps = 0; + + if( trkbuf ) + { + trkbuf->cur_rd_index = 0; + + memcopy(trkbuf->name,modctx->song.title,sizeof(modctx->song.title)); + + for(i=0;i<31;i++) + { + memcopy(trkbuf->instruments[i].name,modctx->song.samples[i].name,sizeof(trkbuf->instruments[i].name)); + } + } + + ll = modctx->last_l_sample; + lr = modctx->last_r_sample; + + for (i = 0; i < nbsample; i++) + { + //--------------------------------------- + if( modctx->patternticks++ > modctx->patternticksaim ) + { + if( !modctx->patterndelay ) + { + nptr = modctx->patterndata[modctx->song.patterntable[modctx->tablepos]]; + nptr = nptr + modctx->patternpos; + cptr = modctx->channels; + + modctx->patternticks = 0; + modctx->patterntickse = 0; + + for(c=0;cnumber_of_channels;c++) + { + worknote((note*)(nptr+c), (channel*)(cptr+c),(char)(c+1),modctx); + } + + if( !modctx->jump_loop_effect ) + modctx->patternpos += modctx->number_of_channels; + else + modctx->jump_loop_effect = 0; + + if( modctx->patternpos == 64*modctx->number_of_channels ) + { + modctx->tablepos++; + modctx->patternpos = 0; + if(modctx->tablepos >= modctx->song.length) + { + modctx->tablepos = 0; + modctx->loopcount++; // count next loop + } + } + } + else + { + modctx->patterndelay--; + modctx->patternticks = 0; + modctx->patterntickse = 0; + } + + } + + if( modctx->patterntickse++ > (modctx->patternticksaim/modctx->song.speed) ) + { + nptr = modctx->patterndata[modctx->song.patterntable[modctx->tablepos]]; + nptr = nptr + modctx->patternpos; + cptr = modctx->channels; + + for(c=0;cnumber_of_channels;c++) + { + workeffect(nptr+c, cptr+c); + } + + modctx->patterntickse = 0; + } + + //--------------------------------------- + + if( trkbuf && !state_remaining_steps ) + { + if( trkbuf->nb_of_state < trkbuf->nb_max_of_state ) + { + memclear(&trkbuf->track_state_buf[trkbuf->nb_of_state], 0, sizeof(tracker_state)); + } + } + + l=0; + r=0; + + for(j =0, cptr = modctx->channels; j < modctx->number_of_channels ; j++, cptr++) + { + if( cptr->period != 0 ) + { + finalperiod = cptr->period - cptr->decalperiod - cptr->vibraperiod; + if( finalperiod ) + { + cptr->samppos += ( (modctx->sampleticksconst<<10) / finalperiod ); + } + + cptr->ticks++; + + if( cptr->replen<=2 ) + { + if( (cptr->samppos>>10) >= (cptr->length) ) + { + cptr->length = 0; + cptr->reppnt = 0; + + if( cptr->length ) + cptr->samppos = cptr->samppos % (((unsigned long)cptr->length)<<10); + else + cptr->samppos = 0; + } + } + else + { + if( (cptr->samppos>>10) >= (unsigned long)(cptr->replen+cptr->reppnt) ) + { + cptr->samppos = ((unsigned long)(cptr->reppnt)<<10) + (cptr->samppos % ((unsigned long)(cptr->replen+cptr->reppnt)<<10)); + } + } + + k = cptr->samppos >> 10; + + if( cptr->sampdata!=0 && ( ((j&3)==1) || ((j&3)==2) ) ) + { + r += ( cptr->sampdata[k] * cptr->volume ); + } + + if( cptr->sampdata!=0 && ( ((j&3)==0) || ((j&3)==3) ) ) + { + l += ( cptr->sampdata[k] * cptr->volume ); + } + + if( trkbuf && !state_remaining_steps ) + { + if( trkbuf->nb_of_state < trkbuf->nb_max_of_state ) + { + trkbuf->track_state_buf[trkbuf->nb_of_state].number_of_tracks = modctx->number_of_channels; + trkbuf->track_state_buf[trkbuf->nb_of_state].buf_index = i; + trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern = modctx->song.patterntable[modctx->tablepos]; + trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern_pos = modctx->patternpos / modctx->number_of_channels; + trkbuf->track_state_buf[trkbuf->nb_of_state].cur_pattern_table_pos = modctx->tablepos; + trkbuf->track_state_buf[trkbuf->nb_of_state].bpm = modctx->bpm; + trkbuf->track_state_buf[trkbuf->nb_of_state].speed = modctx->song.speed; + trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_effect = cptr->effect_code; + trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_parameffect = cptr->parameffect; + trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_period = finalperiod; + trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].cur_volume = cptr->volume; + trkbuf->track_state_buf[trkbuf->nb_of_state].tracks[j].instrument_number = (unsigned char)cptr->sampnum; + } + } + } + } + + if( trkbuf && !state_remaining_steps ) + { + state_remaining_steps = trkbuf->sample_step; + + if(trkbuf->nb_of_state < trkbuf->nb_max_of_state) + trkbuf->nb_of_state++; + } + else + { + state_remaining_steps--; + } + + tl = (short)l; + tr = (short)r; + + if ( modctx->filter ) + { + // Filter + l = (l+ll)>>1; + r = (r+lr)>>1; + } + + if ( modctx->stereo_separation == 1 ) + { + // Left & Right Stereo panning + l = (l+(r>>1)); + r = (r+(l>>1)); + } + + // Level limitation + if( l > 32767 ) l = 32767; + if( l < -32768 ) l = -32768; + if( r > 32767 ) r = 32767; + if( r < -32768 ) r = -32768; + + // Store the final sample. + outbuffer[(i*2)] = l; + outbuffer[(i*2)+1] = r; + + ll = tl; + lr = tr; + + } + + modctx->last_l_sample = ll; + modctx->last_r_sample = lr; + + modctx->samplenb = modctx->samplenb+nbsample; + } + else + { + for (i = 0; i < nbsample; i++) + { + // Mod not loaded. Return blank buffer. + outbuffer[(i*2)] = 0; + outbuffer[(i*2)+1] = 0; + } + + if(trkbuf) + { + trkbuf->nb_of_state = 0; + trkbuf->cur_rd_index = 0; + trkbuf->name[0] = 0; + memclear(trkbuf->track_state_buf, 0, sizeof(tracker_state) * trkbuf->nb_max_of_state); + memclear(trkbuf->instruments, 0, sizeof(trkbuf->instruments)); + } + } + } +} + +void jar_mod_unload( modcontext * modctx) +{ + if(modctx) + { + if(modctx->modfile) + { + free(modctx->modfile); + modctx->modfile = 0; + } + memclear(&modctx->song, 0, sizeof(modctx->song)); + memclear(&modctx->sampledata, 0, sizeof(modctx->sampledata)); + memclear(&modctx->patterndata, 0, sizeof(modctx->patterndata)); + modctx->tablepos = 0; + modctx->patternpos = 0; + modctx->patterndelay = 0; + modctx->jump_loop_effect = 0; + modctx->bpm = 0; + modctx->patternticks = 0; + modctx->patterntickse = 0; + modctx->patternticksaim = 0; + modctx->sampleticksconst = 0; + modctx->loopcount = 0; + + modctx->samplenb = 0; + + memclear(modctx->channels, 0, sizeof(modctx->channels)); + + modctx->number_of_channels = 0; + + modctx->mod_loaded = 0; + + modctx->last_r_sample = 0; + modctx->last_l_sample = 0; + } +} + +mulong jar_mod_load_file(modcontext * modctx, char* filename) +{ + mulong fsize = 0; + if(modctx->modfile) + { + free(modctx->modfile); + modctx->modfile = 0; + } + + FILE *f = fopen(filename, "rb"); + if(f) + { + fseek(f,0,SEEK_END); + fsize = ftell(f); + fseek(f,0,SEEK_SET); + + if(fsize && fsize < 32*1024*1024) + { + modctx->modfile = malloc(fsize); + modctx->modfilesize = fsize; + memset(modctx->modfile, 0, fsize); + fread(modctx->modfile, fsize, 1, f); + fclose(f); + + if(!jar_mod_load(modctx, (void*)modctx->modfile, fsize)) fsize = 0; + } else fsize = 0; + } + return fsize; +} + +mulong jar_mod_current_samples(modcontext * modctx) +{ + if(modctx) + return modctx->samplenb; + + return 0; +} + +// Works, however it is very slow, this data should be cached to ensure it is run only once per file +mulong jar_mod_max_samples(modcontext * ctx) +{ + modcontext tmpctx; + jar_mod_init(&tmpctx); + if(!jar_mod_load(&tmpctx, (void*)ctx->modfile, ctx->modfilesize)) return 0; + + muint buff[2]; + mulong lastcount = tmpctx.loopcount; + + while(1){ + jar_mod_fillbuffer( &tmpctx, buff, 1, 0 ); + if(tmpctx.loopcount > lastcount) break; + } + return tmpctx.samplenb; +} + +// move seek_val to sample index, 0 -> jar_mod_max_samples is the range +void jar_mod_seek_start(modcontext * ctx) +{ + if(ctx) + { + char* tmpmodfile = ctx->modfile; + long size = ctx->modfilesize; + jar_mod_init(ctx); + jar_mod_load(ctx, tmpmodfile, size); + ctx->modfilesize = size; + ctx->modfile = tmpmodfile; + } +} + +#endif // end of JAR_MOD_IMPLEMENTATION +//------------------------------------------------------------------------------- + + +#endif //end of header file \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index 456f427d..59266a0c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -261,8 +261,9 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type - #ifndef true + #if !defined(_STDBOOL_H) typedef enum { false, true } bool; + #define _STDBOOL_H #endif #endif -- cgit v1.2.3 From af1eb5453acc2772afbc316375c403b31a742626 Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Thu, 2 Jun 2016 02:02:23 -0700 Subject: I added audio errors The only thing I did not change was the _g for globals. Is there any other way we can mark globals? --- src/audio.c | 254 ++++++++++++++++++++++++++++++---------------------------- src/audio.h | 20 +++++ src/jar_mod.h | 58 +++++++------- src/raylib.h | 21 +++++ 4 files changed, 200 insertions(+), 153 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index d9a527ee..452459ef 100644 --- a/src/audio.c +++ b/src/audio.c @@ -99,7 +99,7 @@ typedef struct MixChannel_t { typedef struct Music { stb_vorbis *stream; jar_xm_context_t *xmctx; // Stores jar_xm mixc, XM chiptune context - modcontext modctx; // Stores mod chiptune context + jar_mod_context_t modctx; // Stores mod chiptune context MixChannel_t *mixc; // mix channel unsigned int totalSamplesLeft; @@ -115,9 +115,9 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static MixChannel_t* mixChannelsActive_g[MAX_MIX_CHANNELS]; // What mix channels are currently active +static MixChannel_t* mixChannels_g[MAX_MIX_CHANNELS]; // What mix channels are currently active static bool musicEnabled_g = false; -static Music currentMusic_g[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time +static Music musicChannels_g[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -179,7 +179,7 @@ void CloseAudioDevice(void) { for(int index=0; index= MAX_MIX_CHANNELS) return NULL; if(!IsAudioDeviceReady()) InitAudioDevice(); - if(!mixChannelsActive_g[mixChannel]){ + if(!mixChannels_g[mixChannel]){ 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; + mixChannels_g[mixChannel] = mixc; // setup openAL format if(channels == 1) @@ -287,7 +287,7 @@ static void CloseMixChannel(MixChannel_t* mixc) //delete source and buffers alDeleteSources(1, &mixc->alSource); alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); - mixChannelsActive_g[mixc->mixChannel] = NULL; + mixChannels_g[mixc->mixChannel] = NULL; free(mixc); mixc = NULL; } @@ -298,7 +298,7 @@ static void CloseMixChannel(MixChannel_t* mixc) // @Returns number of samples that where processed. static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements) { - if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples + if(!mixc || mixChannels_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 @@ -387,20 +387,20 @@ RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingP 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(mixChannels_g[mixIndex] == NULL) break; + else if(mixIndex == MAX_MIX_CHANNELS - 1) return ERROR_OUT_OF_MIX_CHANNELS; // error } if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint)) return mixIndex; else - return -2; // error + return ERROR_RAW_CONTEXT_CREATION; // error } void CloseRawAudioContext(RawAudioContext ctx) { - if(mixChannelsActive_g[ctx]) - CloseMixChannel(mixChannelsActive_g[ctx]); + if(mixChannels_g[ctx]) + CloseMixChannel(mixChannels_g[ctx]); } // if 0 is returned, the buffers are still full and you need to keep trying with the same data until a + number is returned. @@ -411,7 +411,7 @@ int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short number int numBuffered = 0; if(ctx >= 0) { - MixChannel_t* mixc = mixChannelsActive_g[ctx]; + MixChannel_t* mixc = mixChannels_g[ctx]; numBuffered = BufferMixChannel(mixc, data, numberElements); } return numBuffered; @@ -438,7 +438,10 @@ Sound LoadSound(char *fileName) if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); - else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); + else{ + TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); + sound.error = ERROR_EXTENSION_NOT_RECOGNIZED; //error + } if (wave.data != NULL) { @@ -565,6 +568,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) if (rresFile == NULL) { TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); + sound.error = ERROR_UNABLE_TO_OPEN_RRES_FILE; //error } else { @@ -579,6 +583,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) { TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); + sound.error = ERROR_INVALID_RRES_FILE; } else { @@ -669,6 +674,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) else { TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName); + sound.error = ERROR_INVALID_RRES_RESOURCE; } } else @@ -774,134 +780,134 @@ int PlayMusicStream(int musicIndex, char *fileName) { int mixIndex; - if(currentMusic_g[musicIndex].stream || currentMusic_g[musicIndex].xmctx) return 1; // error + if(musicChannels_g[musicIndex].stream || musicChannels_g[musicIndex].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // 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(mixChannels_g[mixIndex] == NULL) break; + else if(mixIndex == MAX_MIX_CHANNELS - 1) return ERROR_OUT_OF_MIX_CHANNELS; // error } if (strcmp(GetExtension(fileName),"ogg") == 0) { // Open audio stream - currentMusic_g[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL); + musicChannels_g[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL); - if (currentMusic_g[musicIndex].stream == NULL) + if (musicChannels_g[musicIndex].stream == NULL) { TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); - return 3; // error + return ERROR_LOADING_OGG; // error } else { // Get file info - stb_vorbis_info info = stb_vorbis_get_info(currentMusic_g[musicIndex].stream); + stb_vorbis_info info = stb_vorbis_get_info(musicChannels_g[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); - currentMusic_g[musicIndex].loop = true; // We loop by default + musicChannels_g[musicIndex].loop = true; // We loop by default musicEnabled_g = true; - currentMusic_g[musicIndex].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(currentMusic_g[musicIndex].stream) * info.channels; - currentMusic_g[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic_g[musicIndex].stream); + musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicChannels_g[musicIndex].stream) * info.channels; + musicChannels_g[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[musicIndex].stream); if (info.channels == 2){ - currentMusic_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); - currentMusic_g[musicIndex].mixc->playing = true; + musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); + musicChannels_g[musicIndex].mixc->playing = true; } else{ - currentMusic_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); - currentMusic_g[musicIndex].mixc->playing = true; + musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); + musicChannels_g[musicIndex].mixc->playing = true; } - if(!currentMusic_g[musicIndex].mixc) return 4; // error + if(!musicChannels_g[musicIndex].mixc) return ERROR_LOADING_OGG; // error } } else if (strcmp(GetExtension(fileName),"xm") == 0) { // only stereo is supported for xm - if(!jar_xm_create_context_from_file(¤tMusic_g[musicIndex].xmctx, 48000, fileName)) + if(!jar_xm_create_context_from_file(&musicChannels_g[musicIndex].xmctx, 48000, fileName)) { - currentMusic_g[musicIndex].chipTune = true; - currentMusic_g[musicIndex].loop = true; - jar_xm_set_max_loop_count(currentMusic_g[musicIndex].xmctx, 0); // infinite number of loops - currentMusic_g[musicIndex].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(currentMusic_g[musicIndex].xmctx); - currentMusic_g[musicIndex].totalLengthSeconds = ((float)currentMusic_g[musicIndex].totalSamplesLeft) / 48000.f; + musicChannels_g[musicIndex].chipTune = true; + musicChannels_g[musicIndex].loop = true; + jar_xm_set_max_loop_count(musicChannels_g[musicIndex].xmctx, 0); // infinite number of loops + musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicChannels_g[musicIndex].xmctx); + musicChannels_g[musicIndex].totalLengthSeconds = ((float)musicChannels_g[musicIndex].totalSamplesLeft) / 48000.f; musicEnabled_g = true; - TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic_g[musicIndex].totalSamplesLeft); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic_g[musicIndex].totalLengthSeconds); + TraceLog(INFO, "[%s] XM number of samples: %i", fileName, musicChannels_g[musicIndex].totalSamplesLeft); + TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); - currentMusic_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, true); - if(!currentMusic_g[musicIndex].mixc) return 5; // error - currentMusic_g[musicIndex].mixc->playing = true; + musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, true); + if(!musicChannels_g[musicIndex].mixc) return ERROR_XM_CONTEXT_CREATION; // error + musicChannels_g[musicIndex].mixc->playing = true; } else { TraceLog(WARNING, "[%s] XM file could not be opened", fileName); - return 6; // error + return ERROR_LOADING_XM; // error } } else if (strcmp(GetExtension(fileName),"mod") == 0) { - jar_mod_init(¤tMusic_g[musicIndex].modctx); - if(jar_mod_load_file(¤tMusic_g[musicIndex].modctx, fileName)) + jar_mod_init(&musicChannels_g[musicIndex].modctx); + if(jar_mod_load_file(&musicChannels_g[musicIndex].modctx, fileName)) { - currentMusic_g[musicIndex].chipTune = true; - currentMusic_g[musicIndex].loop = true; - currentMusic_g[musicIndex].totalSamplesLeft = (unsigned int)jar_mod_max_samples(¤tMusic_g[musicIndex].modctx); - currentMusic_g[musicIndex].totalLengthSeconds = ((float)currentMusic_g[musicIndex].totalSamplesLeft) / 48000.f; + musicChannels_g[musicIndex].chipTune = true; + musicChannels_g[musicIndex].loop = true; + musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicChannels_g[musicIndex].modctx); + musicChannels_g[musicIndex].totalLengthSeconds = ((float)musicChannels_g[musicIndex].totalSamplesLeft) / 48000.f; musicEnabled_g = true; - TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, currentMusic_g[musicIndex].totalSamplesLeft); - TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, currentMusic_g[musicIndex].totalLengthSeconds); + TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, musicChannels_g[musicIndex].totalSamplesLeft); + TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); - currentMusic_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); - if(!currentMusic_g[musicIndex].mixc) return 7; // error - currentMusic_g[musicIndex].mixc->playing = true; + musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); + if(!musicChannels_g[musicIndex].mixc) return ERROR_MOD_CONTEXT_CREATION; // error + musicChannels_g[musicIndex].mixc->playing = true; } else { TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); - return 8; // error + return ERROR_LOADING_MOD; // error } } else { TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); - return 9; // error + return ERROR_EXTENSION_NOT_RECOGNIZED; // error } return 0; // normal return } -// Stop music playing for individual music index of currentMusic_g array (close stream) +// Stop music playing for individual music index of musicChannels_g array (close stream) void StopMusicStream(int index) { - if (index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc) + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) { - CloseMixChannel(currentMusic_g[index].mixc); + CloseMixChannel(musicChannels_g[index].mixc); - if (currentMusic_g[index].chipTune && currentMusic_g[index].xmctx) + if (musicChannels_g[index].chipTune && musicChannels_g[index].xmctx) { - jar_xm_free_context(currentMusic_g[index].xmctx); - currentMusic_g[index].xmctx = 0; + jar_xm_free_context(musicChannels_g[index].xmctx); + musicChannels_g[index].xmctx = 0; } - else if(currentMusic_g[index].chipTune && currentMusic_g[index].modctx.mod_loaded) + else if(musicChannels_g[index].chipTune && musicChannels_g[index].modctx.mod_loaded) { - jar_mod_unload(¤tMusic_g[index].modctx); + jar_mod_unload(&musicChannels_g[index].modctx); } else { - stb_vorbis_close(currentMusic_g[index].stream); + stb_vorbis_close(musicChannels_g[index].stream); } if(!getMusicStreamCount()) musicEnabled_g = false; - if(currentMusic_g[index].stream || currentMusic_g[index].xmctx) + if(musicChannels_g[index].stream || musicChannels_g[index].xmctx) { - currentMusic_g[index].stream = NULL; - currentMusic_g[index].xmctx = NULL; + musicChannels_g[index].stream = NULL; + musicChannels_g[index].xmctx = NULL; } } } @@ -911,7 +917,7 @@ int getMusicStreamCount(void) { int musicCount = 0; for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot - if(currentMusic_g[musicIndex].stream != NULL || currentMusic_g[musicIndex].chipTune) musicCount++; + if(musicChannels_g[musicIndex].stream != NULL || musicChannels_g[musicIndex].chipTune) musicCount++; return musicCount; } @@ -920,11 +926,11 @@ int getMusicStreamCount(void) void PauseMusicStream(int index) { // Pause music stream if music available! - if (index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc && musicEnabled_g) + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc && musicEnabled_g) { TraceLog(INFO, "Pausing music stream"); - alSourcePause(currentMusic_g[index].mixc->alSource); - currentMusic_g[index].mixc->playing = false; + alSourcePause(musicChannels_g[index].mixc->alSource); + musicChannels_g[index].mixc->playing = false; } } @@ -933,13 +939,13 @@ void ResumeMusicStream(int index) { // Resume music playing... if music available! ALenum state; - if(index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc){ - alGetSourcei(currentMusic_g[index].mixc->alSource, AL_SOURCE_STATE, &state); + if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + alGetSourcei(musicChannels_g[index].mixc->alSource, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) { TraceLog(INFO, "Resuming music stream"); - alSourcePlay(currentMusic_g[index].mixc->alSource); - currentMusic_g[index].mixc->playing = true; + alSourcePlay(musicChannels_g[index].mixc->alSource); + musicChannels_g[index].mixc->playing = true; } } } @@ -950,8 +956,8 @@ bool IsMusicPlaying(int index) bool playing = false; ALint state; - if(index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc){ - alGetSourcei(currentMusic_g[index].mixc->alSource, AL_SOURCE_STATE, &state); + if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + alGetSourcei(musicChannels_g[index].mixc->alSource, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) playing = true; } @@ -961,15 +967,15 @@ bool IsMusicPlaying(int index) // Set volume for music void SetMusicVolume(int index, float volume) { - if(index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc){ - alSourcef(currentMusic_g[index].mixc->alSource, AL_GAIN, volume); + if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + alSourcef(musicChannels_g[index].mixc->alSource, AL_GAIN, volume); } } void SetMusicPitch(int index, float pitch) { - if(index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc){ - alSourcef(currentMusic_g[index].mixc->alSource, AL_PITCH, pitch); + if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + alSourcef(musicChannels_g[index].mixc->alSource, AL_PITCH, pitch); } } @@ -977,13 +983,13 @@ void SetMusicPitch(int index, float pitch) float GetMusicTimeLength(int index) { float totalSeconds; - if (currentMusic_g[index].chipTune) + if (musicChannels_g[index].chipTune) { - totalSeconds = (float)currentMusic_g[index].totalLengthSeconds; + totalSeconds = (float)musicChannels_g[index].totalLengthSeconds; } else { - totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic_g[index].stream); + totalSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[index].stream); } return totalSeconds; @@ -993,24 +999,24 @@ float GetMusicTimeLength(int index) float GetMusicTimePlayed(int index) { float secondsPlayed = 0.0f; - if(index < MAX_MUSIC_STREAMS && currentMusic_g[index].mixc) + if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) { - if (currentMusic_g[index].chipTune && currentMusic_g[index].xmctx) + if (musicChannels_g[index].chipTune && musicChannels_g[index].xmctx) { uint64_t samples; - jar_xm_get_position(currentMusic_g[index].xmctx, NULL, NULL, NULL, &samples); - secondsPlayed = (float)samples / (48000.f * currentMusic_g[index].mixc->channels); // Not sure if this is the correct value + jar_xm_get_position(musicChannels_g[index].xmctx, NULL, NULL, NULL, &samples); + secondsPlayed = (float)samples / (48000.f * musicChannels_g[index].mixc->channels); // Not sure if this is the correct value } - else if(currentMusic_g[index].chipTune && currentMusic_g[index].modctx.mod_loaded) + else if(musicChannels_g[index].chipTune && musicChannels_g[index].modctx.mod_loaded) { - long numsamp = jar_mod_current_samples(¤tMusic_g[index].modctx); + long numsamp = jar_mod_current_samples(&musicChannels_g[index].modctx); secondsPlayed = (float)numsamp / (48000.f); } else { - int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic_g[index].stream) * currentMusic_g[index].mixc->channels; - int samplesPlayed = totalSamples - currentMusic_g[index].totalSamplesLeft; - secondsPlayed = (float)samplesPlayed / (currentMusic_g[index].mixc->sampleRate * currentMusic_g[index].mixc->channels); + int totalSamples = stb_vorbis_stream_length_in_samples(musicChannels_g[index].stream) * musicChannels_g[index].mixc->channels; + int samplesPlayed = totalSamples - musicChannels_g[index].totalSamplesLeft; + secondsPlayed = (float)samplesPlayed / (musicChannels_g[index].mixc->sampleRate * musicChannels_g[index].mixc->channels); } } @@ -1030,30 +1036,30 @@ static bool BufferMusicStream(int index, int numBuffers) 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 (currentMusic_g[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. + if (musicChannels_g[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. { for(int x=0; x= MUSIC_BUFFER_SIZE_SHORT) + if(musicChannels_g[index].modctx.mod_loaded){ + if(musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT / 2; else - size = currentMusic_g[index].totalSamplesLeft / 2; - jar_mod_fillbuffer(¤tMusic_g[index].modctx, pcm, size, 0 ); - BufferMixChannel(currentMusic_g[index].mixc, pcm, size * 2); + size = musicChannels_g[index].totalSamplesLeft / 2; + jar_mod_fillbuffer(&musicChannels_g[index].modctx, pcm, size, 0 ); + BufferMixChannel(musicChannels_g[index].mixc, pcm, size * 2); } - else if(currentMusic_g[index].xmctx){ - if(currentMusic_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) + else if(musicChannels_g[index].xmctx){ + if(musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) size = MUSIC_BUFFER_SIZE_FLOAT / 2; else - size = currentMusic_g[index].totalSamplesLeft / 2; - jar_xm_generate_samples(currentMusic_g[index].xmctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location - BufferMixChannel(currentMusic_g[index].mixc, pcmf, size * 2); + size = musicChannels_g[index].totalSamplesLeft / 2; + jar_xm_generate_samples(musicChannels_g[index].xmctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location + BufferMixChannel(musicChannels_g[index].mixc, pcmf, size * 2); } - currentMusic_g[index].totalSamplesLeft -= size; - if(currentMusic_g[index].totalSamplesLeft <= 0) + musicChannels_g[index].totalSamplesLeft -= size; + if(musicChannels_g[index].totalSamplesLeft <= 0) { active = false; break; @@ -1062,17 +1068,17 @@ static bool BufferMusicStream(int index, int numBuffers) } else { - if(currentMusic_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) + if(musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT; else - size = currentMusic_g[index].totalSamplesLeft; + size = musicChannels_g[index].totalSamplesLeft; for(int x=0; xchannels, pcm, size); - BufferMixChannel(currentMusic_g[index].mixc, pcm, streamedBytes * currentMusic_g[index].mixc->channels); - currentMusic_g[index].totalSamplesLeft -= streamedBytes * currentMusic_g[index].mixc->channels; - if(currentMusic_g[index].totalSamplesLeft <= 0) + int streamedBytes = stb_vorbis_get_samples_short_interleaved(musicChannels_g[index].stream, musicChannels_g[index].mixc->channels, pcm, size); + BufferMixChannel(musicChannels_g[index].mixc, pcm, streamedBytes * musicChannels_g[index].mixc->channels); + musicChannels_g[index].totalSamplesLeft -= streamedBytes * musicChannels_g[index].mixc->channels; + if(musicChannels_g[index].totalSamplesLeft <= 0) { active = false; break; @@ -1089,11 +1095,11 @@ static void EmptyMusicStream(int index) ALuint buffer = 0; int queued = 0; - alGetSourcei(currentMusic_g[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(musicChannels_g[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued); while (queued > 0) { - alSourceUnqueueBuffers(currentMusic_g[index].mixc->alSource, 1, &buffer); + alSourceUnqueueBuffers(musicChannels_g[index].mixc->alSource, 1, &buffer); queued--; } @@ -1103,7 +1109,7 @@ static void EmptyMusicStream(int index) static int IsMusicStreamReadyForBuffering(int index) { ALint processed = 0; - alGetSourcei(currentMusic_g[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(musicChannels_g[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); return processed; } @@ -1114,21 +1120,21 @@ void UpdateMusicStream(int index) bool active = true; int numBuffers = IsMusicStreamReadyForBuffering(index); - if (currentMusic_g[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic_g[index].mixc && numBuffers) + if (musicChannels_g[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && musicChannels_g[index].mixc && numBuffers) { active = BufferMusicStream(index, numBuffers); - if (!active && currentMusic_g[index].loop) + if (!active && musicChannels_g[index].loop) { - if (currentMusic_g[index].chipTune) + if (musicChannels_g[index].chipTune) { - if(currentMusic_g[index].modctx.mod_loaded) jar_mod_seek_start(¤tMusic_g[index].modctx); - currentMusic_g[index].totalSamplesLeft = currentMusic_g[index].totalLengthSeconds * 48000; + if(musicChannels_g[index].modctx.mod_loaded) jar_mod_seek_start(&musicChannels_g[index].modctx); + musicChannels_g[index].totalSamplesLeft = musicChannels_g[index].totalLengthSeconds * 48000; } else { - stb_vorbis_seek_start(currentMusic_g[index].stream); - currentMusic_g[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic_g[index].stream) * currentMusic_g[index].mixc->channels; + stb_vorbis_seek_start(musicChannels_g[index].stream); + musicChannels_g[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicChannels_g[index].stream) * musicChannels_g[index].mixc->channels; } active = true; } @@ -1136,9 +1142,9 @@ void UpdateMusicStream(int index) if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); - alGetSourcei(currentMusic_g[index].mixc->alSource, AL_SOURCE_STATE, &state); + alGetSourcei(musicChannels_g[index].mixc->alSource, AL_SOURCE_STATE, &state); - if (state != AL_PLAYING && active) alSourcePlay(currentMusic_g[index].mixc->alSource); + if (state != AL_PLAYING && active) alSourcePlay(musicChannels_g[index].mixc->alSource); if (!active) StopMusicStream(index); diff --git a/src/audio.h b/src/audio.h index ca56032e..4baa30df 100644 --- a/src/audio.h +++ b/src/audio.h @@ -47,10 +47,29 @@ #endif #endif +typedef enum { + ERROR_RAW_CONTEXT_CREATION = -20, + ERROR_XM_CONTEXT_CREATION, + ERROR_MOD_CONTEXT_CREATION, + ERROR_MIX_CHANNEL_CREATION, + ERROR_MUSIC_CHANNEL_CREATION, + ERROR_LOADING_XM, + ERROR_LOADING_MOD, + ERROR_LOADING_WAV, + ERROR_LOADING_OGG, + ERROR_OUT_OF_MIX_CHANNELS, + ERROR_EXTENSION_NOT_RECOGNIZED, + ERROR_UNABLE_TO_OPEN_RRES_FILE, + ERROR_INVALID_RRES_FILE, + ERROR_INVALID_RRES_RESOURCE, + ERROR_UNINITIALIZED_CHANNELS +} AudioError; + // Sound source type typedef struct Sound { unsigned int source; unsigned int buffer; + AudioError error; // if there was any error during the creation or use of this Sound } Sound; // Wave type, defines audio wave data @@ -64,6 +83,7 @@ typedef struct Wave { typedef int RawAudioContext; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif diff --git a/src/jar_mod.h b/src/jar_mod.h index 2066ef07..2ddc61d1 100644 --- a/src/jar_mod.h +++ b/src/jar_mod.h @@ -15,7 +15,7 @@ // Other source files should just include jar_mod.h // // SAMPLE CODE: -// modcontext modctx; +// jar_mod_context_t modctx; // short samplebuff[4096]; // bool bufferFull = false; // int intro_load(void) @@ -54,17 +54,17 @@ /////////////////////////////////////////////////////////////////////////////////// // HxCMOD Core API: // ------------------------------------------- -// int jar_mod_init(modcontext * modctx) +// int jar_mod_init(jar_mod_context_t * modctx) // -// - Initialize the modcontext buffer. Must be called before doing anything else. +// - Initialize the jar_mod_context_t buffer. Must be called before doing anything else. // Return 1 if success. 0 in case of error. // ------------------------------------------- -// mulong jar_mod_load_file(modcontext * modctx, char* filename) +// mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename) // // - "Load" a MOD from file, context must already be initialized. // Return size of file in bytes. // ------------------------------------------- -// void jar_mod_fillbuffer( modcontext * modctx, unsigned short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) +// void jar_mod_fillbuffer( jar_mod_context_t * modctx, unsigned short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) // // - Generate and return the next samples chunk to outbuffer. // nbsample specify the number of stereo 16bits samples you want. @@ -72,7 +72,7 @@ // The output buffer size in bytes must be equal to ( nbsample * 2 * channels ). // The optional trkbuf parameter can be used to get detailed status of the player. Put NULL/0 is unused. // ------------------------------------------- -// void jar_mod_unload( modcontext * modctx ) +// void jar_mod_unload( jar_mod_context_t * modctx ) // - "Unload" / clear the player status. // ------------------------------------------- /////////////////////////////////////////////////////////////////////////////////// @@ -198,7 +198,7 @@ typedef struct { muchar *modfile; // the raw mod file mulong modfilesize; muint loopcount; -} modcontext; +} jar_mod_context_t; // // Player states structures @@ -243,14 +243,14 @@ typedef struct jar_mod_tracker_buffer_state_ -bool jar_mod_init(modcontext * modctx); -bool jar_mod_setcfg(modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter); -void jar_mod_fillbuffer(modcontext * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf); -void jar_mod_unload(modcontext * modctx); -mulong jar_mod_load_file(modcontext * modctx, char* filename); -mulong jar_mod_current_samples(modcontext * modctx); -mulong jar_mod_max_samples(modcontext * modctx); -void jar_mod_seek_start(modcontext * ctx); +bool jar_mod_init(jar_mod_context_t * modctx); +bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter); +void jar_mod_fillbuffer(jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf); +void jar_mod_unload(jar_mod_context_t * modctx); +mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename); +mulong jar_mod_current_samples(jar_mod_context_t * modctx); +mulong jar_mod_max_samples(jar_mod_context_t * modctx); +void jar_mod_seek_start(jar_mod_context_t * ctx); #ifdef __cplusplus } @@ -398,7 +398,7 @@ static int memcompare( unsigned char * buf1, unsigned char * buf2, unsigned int return 1; } -static int getnote( modcontext * mod, unsigned short period, int finetune ) +static int getnote( jar_mod_context_t * mod, unsigned short period, int finetune ) { int i; @@ -413,7 +413,7 @@ static int getnote( modcontext * mod, unsigned short period, int finetune ) return MAXNOTES; } -static void worknote( note * nptr, channel * cptr, char t, modcontext * mod ) +static void worknote( note * nptr, channel * cptr, char t, jar_mod_context_t * mod ) { muint sample, period, effect, operiod; muint curnote, arpnote; @@ -1051,13 +1051,13 @@ static void workeffect( note * nptr, channel * cptr ) } /////////////////////////////////////////////////////////////////////////////////// -bool jar_mod_init(modcontext * modctx) +bool jar_mod_init(jar_mod_context_t * modctx) { muint i,j; if( modctx ) { - memclear(modctx, 0, sizeof(modcontext)); + memclear(modctx, 0, sizeof(jar_mod_context_t)); modctx->playrate = DEFAULT_SAMPLE_RATE; modctx->stereo = 1; modctx->stereo_separation = 1; @@ -1079,7 +1079,7 @@ bool jar_mod_init(modcontext * modctx) return 0; } -bool jar_mod_setcfg(modcontext * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter) +bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter) { if( modctx ) { @@ -1112,7 +1112,7 @@ bool jar_mod_setcfg(modcontext * modctx, int samplerate, int bits, int stereo, i } // make certain that mod_data stays in memory while playing -static bool jar_mod_load( modcontext * modctx, void * mod_data, int mod_data_size ) +static bool jar_mod_load( jar_mod_context_t * modctx, void * mod_data, int mod_data_size ) { muint i, max; unsigned short t; @@ -1230,7 +1230,7 @@ static bool jar_mod_load( modcontext * modctx, void * mod_data, int mod_data_siz return 0; } -void jar_mod_fillbuffer( modcontext * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) +void jar_mod_fillbuffer( jar_mod_context_t * modctx, short * outbuffer, unsigned long nbsample, jar_mod_tracker_buffer_state * trkbuf ) { unsigned long i, j; unsigned long k; @@ -1472,7 +1472,7 @@ void jar_mod_fillbuffer( modcontext * modctx, short * outbuffer, unsigned long n } //resets internals for mod context -static void jar_mod_reset( modcontext * modctx) +static void jar_mod_reset( jar_mod_context_t * modctx) { if(modctx) { @@ -1500,7 +1500,7 @@ static void jar_mod_reset( modcontext * modctx) } } -void jar_mod_unload( modcontext * modctx) +void jar_mod_unload( jar_mod_context_t * modctx) { if(modctx) { @@ -1515,7 +1515,7 @@ void jar_mod_unload( modcontext * modctx) -mulong jar_mod_load_file(modcontext * modctx, char* filename) +mulong jar_mod_load_file(jar_mod_context_t * modctx, char* filename) { mulong fsize = 0; if(modctx->modfile) @@ -1545,7 +1545,7 @@ mulong jar_mod_load_file(modcontext * modctx, char* filename) return fsize; } -mulong jar_mod_current_samples(modcontext * modctx) +mulong jar_mod_current_samples(jar_mod_context_t * modctx) { if(modctx) return modctx->samplenb; @@ -1554,9 +1554,9 @@ mulong jar_mod_current_samples(modcontext * modctx) } // Works, however it is very slow, this data should be cached to ensure it is run only once per file -mulong jar_mod_max_samples(modcontext * ctx) +mulong jar_mod_max_samples(jar_mod_context_t * ctx) { - modcontext tmpctx; + jar_mod_context_t tmpctx; jar_mod_init(&tmpctx); if(!jar_mod_load(&tmpctx, (void*)ctx->modfile, ctx->modfilesize)) return 0; @@ -1571,7 +1571,7 @@ mulong jar_mod_max_samples(modcontext * ctx) } // move seek_val to sample index, 0 -> jar_mod_max_samples is the range -void jar_mod_seek_start(modcontext * ctx) +void jar_mod_seek_start(jar_mod_context_t * ctx) { if(ctx) { diff --git a/src/raylib.h b/src/raylib.h index 47dd5d5b..a280b09e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -452,10 +452,29 @@ typedef struct Ray { Vector3 direction; } Ray; +typedef enum { + ERROR_RAW_CONTEXT_CREATION = -20, + ERROR_XM_CONTEXT_CREATION, + ERROR_MOD_CONTEXT_CREATION, + ERROR_MIX_CHANNEL_CREATION, + ERROR_MUSIC_CHANNEL_CREATION, + ERROR_LOADING_XM, + ERROR_LOADING_MOD, + ERROR_LOADING_WAV, + ERROR_LOADING_OGG, + ERROR_OUT_OF_MIX_CHANNELS, + ERROR_EXTENSION_NOT_RECOGNIZED, + ERROR_UNABLE_TO_OPEN_RRES_FILE, + ERROR_INVALID_RRES_FILE, + ERROR_INVALID_RRES_RESOURCE, + ERROR_UNINITIALIZED_CHANNELS +} AudioError; + // Sound source type typedef struct Sound { unsigned int source; unsigned int buffer; + AudioError error; // if there was any error during the creation or use of this Sound } Sound; // Wave type, defines audio wave data @@ -469,6 +488,8 @@ typedef struct Wave { typedef int RawAudioContext; + + // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { -- cgit v1.2.3 From cf2975d062a991d69fde60c3cdc043a8a39a09dc Mon Sep 17 00:00:00 2001 From: Joshua Reisenauer Date: Thu, 2 Jun 2016 02:31:25 -0700 Subject: convenient way to combine errors --- src/audio.h | 30 +++++++++++++++--------------- src/raylib.h | 32 ++++++++++++++++---------------- 2 files changed, 31 insertions(+), 31 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.h b/src/audio.h index 4baa30df..a7475566 100644 --- a/src/audio.h +++ b/src/audio.h @@ -48,21 +48,21 @@ #endif typedef enum { - ERROR_RAW_CONTEXT_CREATION = -20, - ERROR_XM_CONTEXT_CREATION, - ERROR_MOD_CONTEXT_CREATION, - ERROR_MIX_CHANNEL_CREATION, - ERROR_MUSIC_CHANNEL_CREATION, - ERROR_LOADING_XM, - ERROR_LOADING_MOD, - ERROR_LOADING_WAV, - ERROR_LOADING_OGG, - ERROR_OUT_OF_MIX_CHANNELS, - ERROR_EXTENSION_NOT_RECOGNIZED, - ERROR_UNABLE_TO_OPEN_RRES_FILE, - ERROR_INVALID_RRES_FILE, - ERROR_INVALID_RRES_RESOURCE, - ERROR_UNINITIALIZED_CHANNELS + ERROR_RAW_CONTEXT_CREATION = 1, + ERROR_XM_CONTEXT_CREATION = 2, + ERROR_MOD_CONTEXT_CREATION = 4, + ERROR_MIX_CHANNEL_CREATION = 8, + ERROR_MUSIC_CHANNEL_CREATION = 16, + ERROR_LOADING_XM = 32, + ERROR_LOADING_MOD = 64, + ERROR_LOADING_WAV = 128, + ERROR_LOADING_OGG = 256, + ERROR_OUT_OF_MIX_CHANNELS = 512, + ERROR_EXTENSION_NOT_RECOGNIZED = 1024, + ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, + ERROR_INVALID_RRES_FILE = 4096, + ERROR_INVALID_RRES_RESOURCE = 8192, + ERROR_UNINITIALIZED_CHANNELS = 16384 } AudioError; // Sound source type diff --git a/src/raylib.h b/src/raylib.h index a280b09e..21892d68 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -452,22 +452,22 @@ typedef struct Ray { Vector3 direction; } Ray; -typedef enum { - ERROR_RAW_CONTEXT_CREATION = -20, - ERROR_XM_CONTEXT_CREATION, - ERROR_MOD_CONTEXT_CREATION, - ERROR_MIX_CHANNEL_CREATION, - ERROR_MUSIC_CHANNEL_CREATION, - ERROR_LOADING_XM, - ERROR_LOADING_MOD, - ERROR_LOADING_WAV, - ERROR_LOADING_OGG, - ERROR_OUT_OF_MIX_CHANNELS, - ERROR_EXTENSION_NOT_RECOGNIZED, - ERROR_UNABLE_TO_OPEN_RRES_FILE, - ERROR_INVALID_RRES_FILE, - ERROR_INVALID_RRES_RESOURCE, - ERROR_UNINITIALIZED_CHANNELS +typedef enum { // allows errors to be & together + ERROR_RAW_CONTEXT_CREATION = 1, + ERROR_XM_CONTEXT_CREATION = 2, + ERROR_MOD_CONTEXT_CREATION = 4, + ERROR_MIX_CHANNEL_CREATION = 8, + ERROR_MUSIC_CHANNEL_CREATION = 16, + ERROR_LOADING_XM = 32, + ERROR_LOADING_MOD = 64, + ERROR_LOADING_WAV = 128, + ERROR_LOADING_OGG = 256, + ERROR_OUT_OF_MIX_CHANNELS = 512, + ERROR_EXTENSION_NOT_RECOGNIZED = 1024, + ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, + ERROR_INVALID_RRES_FILE = 4096, + ERROR_INVALID_RRES_RESOURCE = 8192, + ERROR_UNINITIALIZED_CHANNELS = 16384 } AudioError; // Sound source type -- cgit v1.2.3 From cf6d2e39852b4e73479369a383ab3666189ee23f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 2 Jun 2016 17:12:31 +0200 Subject: Review coding style to match raylib style Moved AudioError enum inside audio.c --- src/audio.c | 363 ++++++++++++++++++++++++++++++++--------------------------- src/audio.h | 20 +--- src/raylib.h | 23 +--- 3 files changed, 199 insertions(+), 207 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 452459ef..361b8b55 100644 --- a/src/audio.c +++ b/src/audio.c @@ -35,29 +35,29 @@ #include "raylib.h" #endif -#include "AL/al.h" // OpenAL basic header -#include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) -#include "AL/alext.h" // OpenAL extensions for other format types +#include "AL/al.h" // OpenAL basic header +#include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) +#include "AL/alext.h" // OpenAL extensions for other format types -#include // Required for: malloc(), free() -#include // Required for: strcmp(), strncmp() -#include // Required for: FILE, fopen(), fclose(), fread() +#include // Required for: malloc(), free() +#include // Required for: strcmp(), strncmp() +#include // Required for: FILE, fopen(), fclose(), fread() #if defined(AUDIO_STANDALONE) - #include // Required for: va_list, va_start(), vfprintf(), va_end() + #include // Required for: va_list, va_start(), vfprintf(), va_end() #else - #include "utils.h" // Required for: DecompressData() - // NOTE: Includes Android fopen() function map + #include "utils.h" // Required for: DecompressData() + // NOTE: Includes Android fopen() function map #endif //#define STB_VORBIS_HEADER_ONLY -#include "stb_vorbis.h" // OGG loading functions +#include "stb_vorbis.h" // OGG loading functions #define JAR_XM_IMPLEMENTATION -#include "jar_xm.h" // XM loading functions +#include "jar_xm.h" // XM loading functions #define JAR_MOD_IMPLEMENTATION -#include "jar_mod.h" // For playing .mod files +#include "jar_mod.h" // MOD loading functions //---------------------------------------------------------------------------------- // Defines and Macros @@ -89,25 +89,45 @@ typedef struct MixChannel_t { 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; // false if paused - ALenum alFormat; // openAL format specifier - ALuint alSource; // openAL source - ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer + + ALenum alFormat; // OpenAL format specifier + ALuint alSource; // OpenAL source + ALuint alBuffer[MAX_STREAM_BUFFERS]; // OpenAL sample buffer } 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 *xmctx; // Stores jar_xm mixc, XM chiptune context - jar_mod_context_t modctx; // Stores mod chiptune context + jar_xm_context_t *xmctx; // XM chiptune context + jar_mod_context_t modctx; // MOD chiptune context MixChannel_t *mixc; // mix channel unsigned int totalSamplesLeft; float totalLengthSeconds; bool loop; - bool chipTune; // True if chiptune is loaded + bool chipTune; // chiptune is loaded? } Music; +// Audio errors registered +typedef enum { + ERROR_RAW_CONTEXT_CREATION = 1, + ERROR_XM_CONTEXT_CREATION = 2, + ERROR_MOD_CONTEXT_CREATION = 4, + ERROR_MIX_CHANNEL_CREATION = 8, + ERROR_MUSIC_CHANNEL_CREATION = 16, + ERROR_LOADING_XM = 32, + ERROR_LOADING_MOD = 64, + ERROR_LOADING_WAV = 128, + ERROR_LOADING_OGG = 256, + ERROR_OUT_OF_MIX_CHANNELS = 512, + ERROR_EXTENSION_NOT_RECOGNIZED = 1024, + ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, + ERROR_INVALID_RRES_FILE = 4096, + ERROR_INVALID_RRES_RESOURCE = 8192, + ERROR_UNINITIALIZED_CHANNELS = 16384 +} AudioError; + #if defined(AUDIO_STANDALONE) typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; #endif @@ -119,6 +139,8 @@ static MixChannel_t* mixChannels_g[MAX_MIX_CHANNELS]; // What mix channel static bool musicEnabled_g = false; static Music musicChannels_g[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time +static lastAudioError = 0; // Registers last audio error + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -129,10 +151,9 @@ static void UnloadWave(Wave wave); // Unload wave data static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data static void EmptyMusicStream(int index); // Empty music buffers - -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 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 @@ -153,13 +174,13 @@ void InitAudioDevice(void) // Open and initialize a device with default settings ALCdevice *device = alcOpenDevice(NULL); - if(!device) TraceLog(ERROR, "Audio device could not be opened"); + if (!device) TraceLog(ERROR, "Audio device could not be opened"); ALCcontext *context = alcCreateContext(device, NULL); - if(context == NULL || alcMakeContextCurrent(context) == ALC_FALSE) + if ((context == NULL) || (alcMakeContextCurrent(context) == ALC_FALSE)) { - if(context != NULL) alcDestroyContext(context); + if (context != NULL) alcDestroyContext(context); alcCloseDevice(device); @@ -177,11 +198,10 @@ void InitAudioDevice(void) // Close the audio device for all contexts void CloseAudioDevice(void) { - for(int index=0; index= MAX_MIX_CHANNELS) return NULL; - if(!IsAudioDeviceReady()) InitAudioDevice(); + if (mixChannel >= MAX_MIX_CHANNELS) return NULL; + if (!IsAudioDeviceReady()) InitAudioDevice(); - if(!mixChannels_g[mixChannel]){ - MixChannel_t *mixc = (MixChannel_t*)malloc(sizeof(MixChannel_t)); + if (!mixChannels_g[mixChannel]) + { + MixChannel_t *mixc = (MixChannel_t *)malloc(sizeof(MixChannel_t)); mixc->sampleRate = sampleRate; mixc->channels = channels; mixc->mixChannel = mixChannel; mixc->floatingPoint = floatingPoint; mixChannels_g[mixChannel] = mixc; - // setup openAL format - if(channels == 1) + // Setup OpenAL format + if (channels == 1) { - if(floatingPoint) - mixc->alFormat = AL_FORMAT_MONO_FLOAT32; - else - mixc->alFormat = AL_FORMAT_MONO16; + if (floatingPoint) mixc->alFormat = AL_FORMAT_MONO_FLOAT32; + else mixc->alFormat = AL_FORMAT_MONO16; } - else if(channels == 2) + else if (channels == 2) { - if(floatingPoint) - mixc->alFormat = AL_FORMAT_STEREO_FLOAT32; - else - mixc->alFormat = AL_FORMAT_STEREO16; + if (floatingPoint) mixc->alFormat = AL_FORMAT_STEREO_FLOAT32; + else mixc->alFormat = AL_FORMAT_STEREO16; } // Create an audio source @@ -253,10 +273,8 @@ static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mix // Create Buffer alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); - //fill buffers - int x; - for(x=0;xalBuffer[x]); + // Fill buffers + for (int i = 0; i < MAX_STREAM_BUFFERS; i++) FillAlBufferWithSilence(mixc, mixc->alBuffer[i]); alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer); mixc->playing = true; @@ -264,27 +282,30 @@ static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mix return mixc; } + return NULL; } // Frees buffer in mix channel -static void CloseMixChannel(MixChannel_t* mixc) +static void CloseMixChannel(MixChannel_t *mixc) { - if(mixc){ + if (mixc) + { alSourceStop(mixc->alSource); mixc->playing = false; - //flush out all queued buffers + // Flush out all queued buffers ALuint buffer = 0; int queued = 0; alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued); + while (queued > 0) { alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); queued--; } - //delete source and buffers + // Delete source and buffers alDeleteSources(1, &mixc->alSource); alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); mixChannels_g[mixc->mixChannel] = NULL; @@ -296,39 +317,46 @@ static void CloseMixChannel(MixChannel_t* mixc) // 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. -static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements) +static int BufferMixChannel(MixChannel_t *mixc, void *data, int numberElements) { - if(!mixc || mixChannels_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples + if (!mixc || (mixChannels_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 - if(mixc->playing){ + if (!data || !numberElements) + { + // Pauses audio until data is given + if (mixc->playing) + { alSourcePause(mixc->alSource); mixc->playing = false; } + return 0; } - else if(!mixc->playing) - { // restart audio otherwise + else if (!mixc->playing) + { + // Restart audio otherwise alSourcePlay(mixc->alSource); mixc->playing = true; } - - + ALuint buffer = 0; alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); - if(!buffer) return 0; - if(mixc->floatingPoint) // process float buffers + if (!buffer) return 0; + + if (mixc->floatingPoint) { - float *ptr = (float*)data; + // Process float buffers + float *ptr = (float *)data; alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate); } - else // process short buffers + else { - short *ptr = (short*)data; + // Process short buffers + short *ptr = (short *)data; alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate); } + alSourceQueueBuffers(mixc->alSource, 1, &buffer); return numberElements; @@ -337,15 +365,18 @@ static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements) // fill buffer with zeros, returns number processed static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer) { - if(mixc->floatingPoint){ - float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f}; + if (mixc->floatingPoint) + { + float pcm[MUSIC_BUFFER_SIZE_FLOAT] = { 0.0f }; 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}; + short pcm[MUSIC_BUFFER_SIZE_SHORT] = { 0 }; alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate); + return MUSIC_BUFFER_SIZE_SHORT; } } @@ -355,13 +386,10 @@ static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer) // ResampleShortToFloat(sh,fl,3); static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len) { - int x; - for(x=0;x= 0) + + if (ctx >= 0) { MixChannel_t* mixc = mixChannels_g[ctx]; numBuffered = BufferMixChannel(mixc, data, numberElements); } + return numBuffered; } - - - - //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- @@ -438,9 +458,12 @@ Sound LoadSound(char *fileName) if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); - else{ + else + { TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); - sound.error = ERROR_EXTENSION_NOT_RECOGNIZED; //error + + // TODO: Find a better way to register errors (similar to glGetError()) + lastAudioError = ERROR_EXTENSION_NOT_RECOGNIZED; } if (wave.data != NULL) @@ -568,7 +591,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) if (rresFile == NULL) { TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); - sound.error = ERROR_UNABLE_TO_OPEN_RRES_FILE; //error + lastAudioError = ERROR_UNABLE_TO_OPEN_RRES_FILE; } else { @@ -583,7 +606,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) { TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); - sound.error = ERROR_INVALID_RRES_FILE; + lastAudioError = ERROR_INVALID_RRES_FILE; } else { @@ -674,7 +697,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) else { TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName); - sound.error = ERROR_INVALID_RRES_RESOURCE; + lastAudioError = ERROR_INVALID_RRES_RESOURCE; } } else @@ -780,12 +803,12 @@ int PlayMusicStream(int musicIndex, char *fileName) { int mixIndex; - if(musicChannels_g[musicIndex].stream || musicChannels_g[musicIndex].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // error + if (musicChannels_g[musicIndex].stream || musicChannels_g[musicIndex].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // error - for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot + for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { - if(mixChannels_g[mixIndex] == NULL) break; - else if(mixIndex == MAX_MIX_CHANNELS - 1) return ERROR_OUT_OF_MIX_CHANNELS; // error + if (mixChannels_g[mixIndex] == NULL) break; + else if (mixIndex == (MAX_MIX_CHANNELS - 1)) return ERROR_OUT_OF_MIX_CHANNELS; // error } if (strcmp(GetExtension(fileName),"ogg") == 0) @@ -814,21 +837,24 @@ int PlayMusicStream(int musicIndex, char *fileName) musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicChannels_g[musicIndex].stream) * info.channels; musicChannels_g[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[musicIndex].stream); - if (info.channels == 2){ + if (info.channels == 2) + { musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); musicChannels_g[musicIndex].mixc->playing = true; } - else{ + else + { musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); musicChannels_g[musicIndex].mixc->playing = true; } - if(!musicChannels_g[musicIndex].mixc) return ERROR_LOADING_OGG; // error + + if (!musicChannels_g[musicIndex].mixc) return ERROR_LOADING_OGG; // error } } else if (strcmp(GetExtension(fileName),"xm") == 0) { // only stereo is supported for xm - if(!jar_xm_create_context_from_file(&musicChannels_g[musicIndex].xmctx, 48000, fileName)) + if (!jar_xm_create_context_from_file(&musicChannels_g[musicIndex].xmctx, 48000, fileName)) { musicChannels_g[musicIndex].chipTune = true; musicChannels_g[musicIndex].loop = true; @@ -841,7 +867,9 @@ int PlayMusicStream(int musicIndex, char *fileName) TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, true); - if(!musicChannels_g[musicIndex].mixc) return ERROR_XM_CONTEXT_CREATION; // error + + if (!musicChannels_g[musicIndex].mixc) return ERROR_XM_CONTEXT_CREATION; // error + musicChannels_g[musicIndex].mixc->playing = true; } else @@ -853,7 +881,8 @@ int PlayMusicStream(int musicIndex, char *fileName) else if (strcmp(GetExtension(fileName),"mod") == 0) { jar_mod_init(&musicChannels_g[musicIndex].modctx); - if(jar_mod_load_file(&musicChannels_g[musicIndex].modctx, fileName)) + + if (jar_mod_load_file(&musicChannels_g[musicIndex].modctx, fileName)) { musicChannels_g[musicIndex].chipTune = true; musicChannels_g[musicIndex].loop = true; @@ -865,7 +894,9 @@ int PlayMusicStream(int musicIndex, char *fileName) TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); - if(!musicChannels_g[musicIndex].mixc) return ERROR_MOD_CONTEXT_CREATION; // error + + if (!musicChannels_g[musicIndex].mixc) return ERROR_MOD_CONTEXT_CREATION; // error + musicChannels_g[musicIndex].mixc->playing = true; } else @@ -879,6 +910,7 @@ int PlayMusicStream(int musicIndex, char *fileName) TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); return ERROR_EXTENSION_NOT_RECOGNIZED; // error } + return 0; // normal return } @@ -894,17 +926,12 @@ void StopMusicStream(int index) jar_xm_free_context(musicChannels_g[index].xmctx); musicChannels_g[index].xmctx = 0; } - else if(musicChannels_g[index].chipTune && musicChannels_g[index].modctx.mod_loaded) - { - jar_mod_unload(&musicChannels_g[index].modctx); - } - else - { - stb_vorbis_close(musicChannels_g[index].stream); - } + else if (musicChannels_g[index].chipTune && musicChannels_g[index].modctx.mod_loaded) jar_mod_unload(&musicChannels_g[index].modctx); + else stb_vorbis_close(musicChannels_g[index].stream); - if(!getMusicStreamCount()) musicEnabled_g = false; - if(musicChannels_g[index].stream || musicChannels_g[index].xmctx) + if (!GetMusicStreamCount()) musicEnabled_g = false; + + if (musicChannels_g[index].stream || musicChannels_g[index].xmctx) { musicChannels_g[index].stream = NULL; musicChannels_g[index].xmctx = NULL; @@ -913,11 +940,15 @@ void StopMusicStream(int index) } //get number of music channels active at this time, this does not mean they are playing -int getMusicStreamCount(void) +int GetMusicStreamCount(void) { int musicCount = 0; - for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot + + // Find empty music slot + for (int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) + { if(musicChannels_g[musicIndex].stream != NULL || musicChannels_g[musicIndex].chipTune) musicCount++; + } return musicCount; } @@ -939,8 +970,11 @@ void ResumeMusicStream(int index) { // Resume music playing... if music available! ALenum state; - if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) + { alGetSourcei(musicChannels_g[index].mixc->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PAUSED) { TraceLog(INFO, "Resuming music stream"); @@ -956,8 +990,10 @@ bool IsMusicPlaying(int index) bool playing = false; ALint state; - if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) + { alGetSourcei(musicChannels_g[index].mixc->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) playing = true; } @@ -967,14 +1003,17 @@ bool IsMusicPlaying(int index) // Set volume for music void SetMusicVolume(int index, float volume) { - if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) + { alSourcef(musicChannels_g[index].mixc->alSource, AL_GAIN, volume); } } +// Set pitch for music void SetMusicPitch(int index, float pitch) { - if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc){ + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) + { alSourcef(musicChannels_g[index].mixc->alSource, AL_PITCH, pitch); } } @@ -983,14 +1022,9 @@ void SetMusicPitch(int index, float pitch) float GetMusicTimeLength(int index) { float totalSeconds; - if (musicChannels_g[index].chipTune) - { - totalSeconds = (float)musicChannels_g[index].totalLengthSeconds; - } - else - { - totalSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[index].stream); - } + + if (musicChannels_g[index].chipTune) totalSeconds = (float)musicChannels_g[index].totalLengthSeconds; + else totalSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[index].stream); return totalSeconds; } @@ -999,7 +1033,8 @@ float GetMusicTimeLength(int index) float GetMusicTimePlayed(int index) { float secondsPlayed = 0.0f; - if(index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) + + if (index < MAX_MUSIC_STREAMS && musicChannels_g[index].mixc) { if (musicChannels_g[index].chipTune && musicChannels_g[index].xmctx) { @@ -1033,33 +1068,33 @@ 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 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) + 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 (musicChannels_g[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. { - for(int x=0; x= MUSIC_BUFFER_SIZE_SHORT) - size = MUSIC_BUFFER_SIZE_SHORT / 2; - else - size = musicChannels_g[index].totalSamplesLeft / 2; + if (musicChannels_g[index].modctx.mod_loaded) + { + if (musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT/2; + else size = musicChannels_g[index].totalSamplesLeft/2; + jar_mod_fillbuffer(&musicChannels_g[index].modctx, pcm, size, 0 ); - BufferMixChannel(musicChannels_g[index].mixc, pcm, size * 2); + BufferMixChannel(musicChannels_g[index].mixc, pcm, size*2); } - else if(musicChannels_g[index].xmctx){ - if(musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) - size = MUSIC_BUFFER_SIZE_FLOAT / 2; - else - size = musicChannels_g[index].totalSamplesLeft / 2; + else if (musicChannels_g[index].xmctx) + { + if (musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) size = MUSIC_BUFFER_SIZE_FLOAT/2; + else size = musicChannels_g[index].totalSamplesLeft/2; + jar_xm_generate_samples(musicChannels_g[index].xmctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location - BufferMixChannel(musicChannels_g[index].mixc, pcmf, size * 2); + BufferMixChannel(musicChannels_g[index].mixc, pcmf, size*2); } - musicChannels_g[index].totalSamplesLeft -= size; - if(musicChannels_g[index].totalSamplesLeft <= 0) + + if (musicChannels_g[index].totalSamplesLeft <= 0) { active = false; break; @@ -1068,17 +1103,16 @@ static bool BufferMusicStream(int index, int numBuffers) } else { - if(musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) - size = MUSIC_BUFFER_SIZE_SHORT; - else - size = musicChannels_g[index].totalSamplesLeft; + if (musicChannels_g[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT; + else size = musicChannels_g[index].totalSamplesLeft; - for(int x=0; xchannels, pcm, size); BufferMixChannel(musicChannels_g[index].mixc, pcm, streamedBytes * musicChannels_g[index].mixc->channels); musicChannels_g[index].totalSamplesLeft -= streamedBytes * musicChannels_g[index].mixc->channels; - if(musicChannels_g[index].totalSamplesLeft <= 0) + + if (musicChannels_g[index].totalSamplesLeft <= 0) { active = false; break; @@ -1105,7 +1139,7 @@ static void EmptyMusicStream(int index) } } -//determine if a music stream is ready to be written to +// Determine if a music stream is ready to be written static int IsMusicStreamReadyForBuffering(int index) { ALint processed = 0; @@ -1120,7 +1154,7 @@ void UpdateMusicStream(int index) bool active = true; int numBuffers = IsMusicStreamReadyForBuffering(index); - if (musicChannels_g[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && musicChannels_g[index].mixc && numBuffers) + if (musicChannels_g[index].mixc->playing && (index < MAX_MUSIC_STREAMS) && musicEnabled_g && musicChannels_g[index].mixc && numBuffers) { active = BufferMusicStream(index, numBuffers); @@ -1136,9 +1170,9 @@ void UpdateMusicStream(int index) stb_vorbis_seek_start(musicChannels_g[index].stream); musicChannels_g[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicChannels_g[index].stream) * musicChannels_g[index].mixc->channels; } + active = true; } - if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); @@ -1149,9 +1183,6 @@ void UpdateMusicStream(int index) if (!active) StopMusicStream(index); } - else - return; - } // Load WAV file into Wave structure diff --git a/src/audio.h b/src/audio.h index a7475566..e30087ba 100644 --- a/src/audio.h +++ b/src/audio.h @@ -47,24 +47,6 @@ #endif #endif -typedef enum { - ERROR_RAW_CONTEXT_CREATION = 1, - ERROR_XM_CONTEXT_CREATION = 2, - ERROR_MOD_CONTEXT_CREATION = 4, - ERROR_MIX_CHANNEL_CREATION = 8, - ERROR_MUSIC_CHANNEL_CREATION = 16, - ERROR_LOADING_XM = 32, - ERROR_LOADING_MOD = 64, - ERROR_LOADING_WAV = 128, - ERROR_LOADING_OGG = 256, - ERROR_OUT_OF_MIX_CHANNELS = 512, - ERROR_EXTENSION_NOT_RECOGNIZED = 1024, - ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, - ERROR_INVALID_RRES_FILE = 4096, - ERROR_INVALID_RRES_RESOURCE = 8192, - ERROR_UNINITIALIZED_CHANNELS = 16384 -} AudioError; - // Sound source type typedef struct Sound { unsigned int source; @@ -120,7 +102,7 @@ bool IsMusicPlaying(int index); // Check if musi 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); +int GetMusicStreamCount(void); void SetMusicPitch(int index, float pitch); // used to output raw audio streams, returns negative numbers on error diff --git a/src/raylib.h b/src/raylib.h index 21892d68..97f4a2e6 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -452,29 +452,10 @@ typedef struct Ray { Vector3 direction; } Ray; -typedef enum { // allows errors to be & together - ERROR_RAW_CONTEXT_CREATION = 1, - ERROR_XM_CONTEXT_CREATION = 2, - ERROR_MOD_CONTEXT_CREATION = 4, - ERROR_MIX_CHANNEL_CREATION = 8, - ERROR_MUSIC_CHANNEL_CREATION = 16, - ERROR_LOADING_XM = 32, - ERROR_LOADING_MOD = 64, - ERROR_LOADING_WAV = 128, - ERROR_LOADING_OGG = 256, - ERROR_OUT_OF_MIX_CHANNELS = 512, - ERROR_EXTENSION_NOT_RECOGNIZED = 1024, - ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, - ERROR_INVALID_RRES_FILE = 4096, - ERROR_INVALID_RRES_RESOURCE = 8192, - ERROR_UNINITIALIZED_CHANNELS = 16384 -} AudioError; - // Sound source type typedef struct Sound { unsigned int source; unsigned int buffer; - AudioError error; // if there was any error during the creation or use of this Sound } Sound; // Wave type, defines audio wave data @@ -488,8 +469,6 @@ typedef struct Wave { typedef int RawAudioContext; - - // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -940,7 +919,7 @@ bool IsMusicPlaying(int index); // Check if musi 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); +int GetMusicStreamCount(void); void SetMusicPitch(int index, float pitch); // used to output raw audio streams, returns negative numbers on error -- cgit v1.2.3 From cafc66a3c18ae4b8adf2673dfecda1ad3604aaee Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 2 Jun 2016 19:09:56 +0200 Subject: Rename for consistency with other functions --- src/audio.c | 70 ++++++++++++++++++++++++++++++------------------------------ src/audio.h | 2 +- src/raylib.h | 2 +- 3 files changed, 37 insertions(+), 37 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 31ecd879..b5514b12 100644 --- a/src/audio.c +++ b/src/audio.c @@ -799,11 +799,11 @@ void SetSoundPitch(Sound sound, float pitch) // Start music playing (open stream) // returns 0 on success -int PlayMusicStream(int musicIndex, char *fileName) +int PlayMusicStream(int index, char *fileName) { int mixIndex; - if (musicChannels_g[musicIndex].stream || musicChannels_g[musicIndex].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // error + if (musicChannels_g[index].stream || musicChannels_g[index].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // error for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { @@ -814,9 +814,9 @@ int PlayMusicStream(int musicIndex, char *fileName) if (strcmp(GetExtension(fileName),"ogg") == 0) { // Open audio stream - musicChannels_g[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL); + musicChannels_g[index].stream = stb_vorbis_open_filename(fileName, NULL, NULL); - if (musicChannels_g[musicIndex].stream == NULL) + if (musicChannels_g[index].stream == NULL) { TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); return ERROR_LOADING_OGG; // error @@ -824,53 +824,53 @@ int PlayMusicStream(int musicIndex, char *fileName) else { // Get file info - stb_vorbis_info info = stb_vorbis_get_info(musicChannels_g[musicIndex].stream); + stb_vorbis_info info = stb_vorbis_get_info(musicChannels_g[index].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); - musicChannels_g[musicIndex].loop = true; // We loop by default + musicChannels_g[index].loop = true; // We loop by default musicEnabled_g = true; - musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicChannels_g[musicIndex].stream) * info.channels; - musicChannels_g[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[musicIndex].stream); + musicChannels_g[index].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicChannels_g[index].stream) * info.channels; + musicChannels_g[index].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicChannels_g[index].stream); if (info.channels == 2) { - musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); - musicChannels_g[musicIndex].mixc->playing = true; + musicChannels_g[index].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); + musicChannels_g[index].mixc->playing = true; } else { - musicChannels_g[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); - musicChannels_g[musicIndex].mixc->playing = true; + musicChannels_g[index].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); + musicChannels_g[index].mixc->playing = true; } - if (!musicChannels_g[musicIndex].mixc) return ERROR_LOADING_OGG; // error + if (!musicChannels_g[index].mixc) return ERROR_LOADING_OGG; // error } } else if (strcmp(GetExtension(fileName),"xm") == 0) { // only stereo is supported for xm - if (!jar_xm_create_context_from_file(&musicChannels_g[musicIndex].xmctx, 48000, fileName)) + if (!jar_xm_create_context_from_file(&musicChannels_g[index].xmctx, 48000, fileName)) { - musicChannels_g[musicIndex].chipTune = true; - musicChannels_g[musicIndex].loop = true; - jar_xm_set_max_loop_count(musicChannels_g[musicIndex].xmctx, 0); // infinite number of loops - musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicChannels_g[musicIndex].xmctx); - musicChannels_g[musicIndex].totalLengthSeconds = ((float)musicChannels_g[musicIndex].totalSamplesLeft) / 48000.f; + musicChannels_g[index].chipTune = true; + musicChannels_g[index].loop = true; + jar_xm_set_max_loop_count(musicChannels_g[index].xmctx, 0); // infinite number of loops + musicChannels_g[index].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicChannels_g[index].xmctx); + musicChannels_g[index].totalLengthSeconds = ((float)musicChannels_g[index].totalSamplesLeft) / 48000.f; musicEnabled_g = true; - TraceLog(INFO, "[%s] XM number of samples: %i", fileName, musicChannels_g[musicIndex].totalSamplesLeft); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); + TraceLog(INFO, "[%s] XM number of samples: %i", fileName, musicChannels_g[index].totalSamplesLeft); + TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, musicChannels_g[index].totalLengthSeconds); - musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, true); + musicChannels_g[index].mixc = InitMixChannel(48000, mixIndex, 2, true); - if (!musicChannels_g[musicIndex].mixc) return ERROR_XM_CONTEXT_CREATION; // error + if (!musicChannels_g[index].mixc) return ERROR_XM_CONTEXT_CREATION; // error - musicChannels_g[musicIndex].mixc->playing = true; + musicChannels_g[index].mixc->playing = true; } else { @@ -880,24 +880,24 @@ int PlayMusicStream(int musicIndex, char *fileName) } else if (strcmp(GetExtension(fileName),"mod") == 0) { - jar_mod_init(&musicChannels_g[musicIndex].modctx); + jar_mod_init(&musicChannels_g[index].modctx); - if (jar_mod_load_file(&musicChannels_g[musicIndex].modctx, fileName)) + if (jar_mod_load_file(&musicChannels_g[index].modctx, fileName)) { - musicChannels_g[musicIndex].chipTune = true; - musicChannels_g[musicIndex].loop = true; - musicChannels_g[musicIndex].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicChannels_g[musicIndex].modctx); - musicChannels_g[musicIndex].totalLengthSeconds = ((float)musicChannels_g[musicIndex].totalSamplesLeft) / 48000.f; + musicChannels_g[index].chipTune = true; + musicChannels_g[index].loop = true; + musicChannels_g[index].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicChannels_g[index].modctx); + musicChannels_g[index].totalLengthSeconds = ((float)musicChannels_g[index].totalSamplesLeft) / 48000.f; musicEnabled_g = true; - TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, musicChannels_g[musicIndex].totalSamplesLeft); - TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, musicChannels_g[musicIndex].totalLengthSeconds); + TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, musicChannels_g[index].totalSamplesLeft); + TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, musicChannels_g[index].totalLengthSeconds); - musicChannels_g[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false); + musicChannels_g[index].mixc = InitMixChannel(48000, mixIndex, 2, false); - if (!musicChannels_g[musicIndex].mixc) return ERROR_MOD_CONTEXT_CREATION; // error + if (!musicChannels_g[index].mixc) return ERROR_MOD_CONTEXT_CREATION; // error - musicChannels_g[musicIndex].mixc->playing = true; + musicChannels_g[index].mixc->playing = true; } else { diff --git a/src/audio.h b/src/audio.h index e30087ba..fe72d866 100644 --- a/src/audio.h +++ b/src/audio.h @@ -93,7 +93,7 @@ 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) -int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) +int PlayMusicStream(int index, 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 diff --git a/src/raylib.h b/src/raylib.h index 97f4a2e6..bc2f658f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -910,7 +910,7 @@ 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) -int PlayMusicStream(int musicIndex, char *fileName); // Start music playing (open stream) +int PlayMusicStream(int index, 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 -- cgit v1.2.3 From 2168d8aa1af1e60467983099c5f72b7ac5ab5144 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 2 Jun 2016 19:16:11 +0200 Subject: Removed DrawPhysicObjectInfo() function To avoid additional dependencies --- src/physac.c | 16 ---------------- src/physac.h | 1 - src/raylib.h | 1 - 3 files changed, 18 deletions(-) (limited to 'src/raylib.h') diff --git a/src/physac.c b/src/physac.c index eed2f26e..1d577d3d 100644 --- a/src/physac.c +++ b/src/physac.c @@ -570,22 +570,6 @@ Rectangle TransformToRectangle(Transform transform) return (Rectangle){transform.position.x, transform.position.y, transform.scale.x, transform.scale.y}; } -// Draw physic object information at screen position -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); - - // Draw physic object transform values - DrawText(FormatText("\nTRANSFORM\nPosition: %f, %f\nRotation: %f\nScale: %f, %f", pObj->transform.position.x, pObj->transform.position.y, pObj->transform.rotation, pObj->transform.scale.x, pObj->transform.scale.y), position.x, position.y, fontSize, BLACK); - - // Draw physic object rigidbody values - DrawText(FormatText("\n\n\n\n\n\nRIGIDBODY\nEnabled: %i\nMass: %f\nAcceleration: %f, %f\nVelocity: %f, %f\nApplyGravity: %i\nIsGrounded: %i\nFriction: %f\nBounciness: %f", pObj->rigidbody.enabled, pObj->rigidbody.mass, pObj->rigidbody.acceleration.x, pObj->rigidbody.acceleration.y, - pObj->rigidbody.velocity.x, pObj->rigidbody.velocity.y, pObj->rigidbody.applyGravity, pObj->rigidbody.isGrounded, pObj->rigidbody.friction, pObj->rigidbody.bounciness), position.x, position.y, fontSize, BLACK); - - DrawText(FormatText("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nCOLLIDER\nEnabled: %i\nBounds: %i, %i, %i, %i\nRadius: %i", pObj->collider.enabled, pObj->collider.bounds.x, pObj->collider.bounds.y, pObj->collider.bounds.width, pObj->collider.bounds.height, pObj->collider.radius), position.x, position.y, fontSize, BLACK); -} - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/physac.h b/src/physac.h index 6cef480a..b2ae2766 100644 --- a/src/physac.h +++ b/src/physac.h @@ -92,7 +92,6 @@ void ApplyForce(PhysicObject pObj, Vector2 force); 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 #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index bc2f658f..a00c0ff9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -890,7 +890,6 @@ void ApplyForce(PhysicObject pObj, Vector2 force); 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 //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) -- cgit v1.2.3 From 0bc71d84f8ca2b8cbe48eae8769fb16958b98531 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 2 Jun 2016 20:23:09 +0200 Subject: Added functions to customize internal matrix Internal modelview and projection matrices can be replaced before drawing. --- src/raylib.h | 3 +++ src/raymath.h | 5 ++--- src/rlgl.c | 25 ++++++++++++++++++------- src/rlgl.h | 3 +++ 4 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index a00c0ff9..efd96a67 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -868,6 +868,9 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // S void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) +void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) + void BeginShaderMode(Shader shader); // Begin custom shader drawing void EndShaderMode(void); // End custom shader drawing (use default shader) void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) diff --git a/src/raymath.h b/src/raymath.h index 188bd610..4075a1a9 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -339,15 +339,14 @@ RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal) return result; } -// Transforms a Vector3 with a given Matrix +// Transforms a Vector3 by a given Matrix +// TODO: Review math (matrix transpose required?) RMDEF void VectorTransform(Vector3 *v, Matrix mat) { float x = v->x; float y = v->y; float z = v->z; - //MatrixTranspose(&mat); - v->x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; v->y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; v->z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; diff --git a/src/rlgl.c b/src/rlgl.c index cfa6e2e6..6beececb 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -28,7 +28,7 @@ #include "rlgl.h" -#include // Standard input / output lib +#include // Required for: fopen(), fclose(), fread()... [Used only on ReadTextFile()] #include // Required for: malloc(), free(), rand() #include // Required for: strcmp(), strlen(), strtok() @@ -59,8 +59,8 @@ #endif #if defined(RLGL_STANDALONE) - #include // Required for: va_list, va_start(), vfprintf(), va_end() -#endif // NOTE: Used on TraceLog() + #include // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()] +#endif //---------------------------------------------------------------------------------- // Defines and Macros @@ -355,7 +355,6 @@ void rlRotatef(float angleDeg, float x, float y, float z) Vector3 axis = (Vector3){ x, y, z }; VectorNormalize(&axis); matRotation = MatrixRotate(axis, angleDeg*DEG2RAD); - MatrixTranspose(&matRotation); *currentMatrix = MatrixMultiply(*currentMatrix, matRotation); @@ -2153,7 +2152,7 @@ void UnloadShader(Shader shader) } } -// Set custom shader to be used on batch draw +// Begin custom shader mode void BeginShaderMode(Shader shader) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -2165,7 +2164,7 @@ void BeginShaderMode(Shader shader) #endif } -// Set default shader to be used in batch draw +// End custom shader mode (returns to default shader) void EndShaderMode(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) @@ -2251,6 +2250,18 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) #endif } +// Set a custom projection matrix (replaces internal projection matrix) +void SetMatrixProjection(Matrix proj) +{ + projection = proj; +} + +// Set a custom modelview matrix (replaces internal modelview matrix) +void SetMatrixModelview(Matrix view) +{ + modelview = view; +} + // Begin blending mode (alpha, additive, multiplied) // NOTE: Only 3 blending modes supported, default blend mode is alpha void BeginBlendMode(int mode) @@ -3068,7 +3079,7 @@ static void UnloadDefaultBuffers(void) free(quads.indices); } -// Sets shader uniform values for lights array +// Setup 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) { diff --git a/src/rlgl.h b/src/rlgl.h index 00482d2e..2a578a1f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -329,6 +329,9 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // S void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) +void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) + void BeginShaderMode(Shader shader); // Begin custom shader drawing void EndShaderMode(void); // End custom shader drawing (use default shader) void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) -- cgit v1.2.3 From 13bef7aa0215c135074947a28dce92695d456565 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 3 Jun 2016 18:26:59 +0200 Subject: Work on Oculus functionality Trying to find the best way to integrate Oculus support into raylib, making it easy for the user... --- src/core.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/raylib.h | 6 ++++++ 2 files changed, 63 insertions(+), 5 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index d4db5017..7316c79c 100644 --- a/src/core.c +++ b/src/core.c @@ -483,11 +483,6 @@ void CloseWindow(void) { UnloadDefaultFont(); -#if defined(PLATFORM_OCULUS) - UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer - UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers -#endif - rlglClose(); // De-init rlgl #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) @@ -526,6 +521,63 @@ void CloseWindow(void) TraceLog(INFO, "Window closed successfully"); } +#if defined(PLATFORM_OCULUS) +// Init Oculus Rift device +// NOTE: Device initialization should be done before window creation? +void InitOculusDevice(void) +{ + ovrResult result = ovr_Initialize(NULL); + if (OVR_FAILURE(result)) TraceLog(ERROR, "OVR: Could not initialize Oculus device"); + + result = ovr_Create(&session, &luid); + if (OVR_FAILURE(result)) + { + TraceLog(WARNING, "OVR: Could not create Oculus session"); + ovr_Shutdown(); + } + + hmdDesc = ovr_GetHmdDesc(session); + + TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); + TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); + TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); + TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); + TraceLog(INFO, "OVR: Serian Number: %s", hmdDesc.SerialNumber); + TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); + + screenWidth = hmdDesc.Resolution.w/2; + screenHeight = hmdDesc.Resolution.h/2; + + // Initialize Oculus Buffers + layer = InitOculusLayer(session); + buffer = LoadOculusBuffer(session, layer.width, layer.height); + mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); + layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); +} + +// Close Oculus Rift device +void CloseOculusDevice(void) +{ + UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer + UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers + + ovr_Destroy(session); // Must be called after glfwTerminate() --> REALLY??? + ovr_Shutdown(); +} + +// Update Oculus Rift tracking (position and orientation) +void UpdateOculusTracking(void) +{ + frameIndex++; + + ovrPosef eyePoses[2]; + ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); + + layer.eyeLayer.RenderPose[0] = eyePoses[0]; + layer.eyeLayer.RenderPose[1] = eyePoses[1]; +} +#endif + // Detect if KEY_ESCAPE pressed or Close icon pressed bool WindowShouldClose(void) { diff --git a/src/raylib.h b/src/raylib.h index efd96a67..bdaaeb08 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -578,6 +578,12 @@ void InitWindow(int width, int height, struct android_app *state); // Init Andr void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif +#if defined(PLATFORM_OCULUS) +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +#endif + void CloseWindow(void); // Close Window and Terminate Context bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) -- cgit v1.2.3 From 60232810d83c7ea3a52491f0b20444003be53358 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 3 Jun 2016 19:00:58 +0200 Subject: Added some comments --- src/raygui.c | 3 +-- src/raylib.h | 11 ++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raygui.c b/src/raygui.c index eaf15224..5064f123 100644 --- a/src/raygui.c +++ b/src/raygui.c @@ -177,7 +177,7 @@ static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if p static const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' // NOTE: raygui depend on some raylib input and drawing functions -// TODO: Set your own functions +// TODO: Replace by your own functions static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } static int IsMouseButtonDown(int button) { return 0; } static int IsMouseButtonPressed(int button) { return 0; } @@ -191,7 +191,6 @@ static int MeasureText(const char *text, int fontSize) { return 0; } static void DrawText(const char *text, int posX, int posY, int fontSize, Color color) { } static void DrawRectangleRec(Rectangle rec, Color color) { } static void DrawRectangle(int posX, int posY, int width, int height, Color color) { DrawRectangleRec((Rectangle){ posX, posY, width, height }, color); } - #endif //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index bdaaeb08..706c4f4a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -64,6 +64,7 @@ //#define PLATFORM_ANDROID // Android device //#define PLATFORM_RPI // Raspberry Pi //#define PLATFORM_WEB // HTML5 (emscripten, asm.js) +//#define PLATFORM_OCULUS // Oculus Rift CV1 // Security check in case no PLATFORM_* defined #if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB) @@ -71,7 +72,7 @@ #endif #if defined(PLATFORM_ANDROID) - typedef struct android_app; // Define android_app struct (android_native_app_glue.h) + typedef struct android_app; // Define android_app struct (android_native_app_glue.h) #endif //---------------------------------------------------------------------------------- @@ -448,14 +449,14 @@ typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; // Ray type (useful for raycast) typedef struct Ray { - Vector3 position; - Vector3 direction; + Vector3 position; // Ray position (origin) + Vector3 direction; // Ray direction } Ray; // Sound source type typedef struct Sound { - unsigned int source; - unsigned int buffer; + unsigned int source; // Sound audio source id + unsigned int buffer; // Sound audio buffer id } Sound; // Wave type, defines audio wave data -- cgit v1.2.3 From 5f4449f0a199ae2f1750eb60f2fcc4dd8c41ab79 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 9 Jun 2016 20:02:15 +0200 Subject: Removed physac functions from raylib header --- src/raylib.h | 49 ------------------------------------------------- 1 file changed, 49 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 706c4f4a..bfcb9bf5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -527,40 +527,6 @@ typedef struct GestureEvent { // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; -typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType; - -typedef struct Transform { - Vector2 position; - float rotation; // Radians (not used) - Vector2 scale; // Just for rectangle physic objects, for circle physic objects use collider radius and keep scale as { 0, 0 } -} Transform; - -typedef struct Rigidbody { - bool enabled; // Acts as kinematic state (collisions are calculated anyway) - float mass; - Vector2 acceleration; - Vector2 velocity; - bool applyGravity; - bool isGrounded; - float friction; // Normalized value - float bounciness; -} Rigidbody; - -typedef struct Collider { - bool enabled; - ColliderType type; - Rectangle bounds; // Used for COLLIDER_RECTANGLE - int radius; // Used for COLLIDER_CIRCLE -} Collider; - -typedef struct PhysicObjectData { - unsigned int id; - Transform transform; - Rigidbody rigidbody; - Collider collider; - bool enabled; -} PhysicObjectData, *PhysicObject; - #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -886,21 +852,6 @@ void EndBlendMode(void); // End blend 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 -//---------------------------------------------------------------------------------- -// Physics System Functions (Module: physac) -//---------------------------------------------------------------------------------- -void InitPhysics(Vector2 gravity); // Initializes pointers array (just pointers, fixed size) -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 - -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) - //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ -- cgit v1.2.3 From 47afda2549cdab0429047fcc64540a4ed5d0ede7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 11:55:32 +0200 Subject: Removed useless function: GetGestureDetected() Use instead: IsGestureDetected() --- src/gestures.c | 7 ------- src/gestures.h | 7 +++---- src/raylib.h | 7 +++---- 3 files changed, 6 insertions(+), 15 deletions(-) (limited to 'src/raylib.h') diff --git a/src/gestures.c b/src/gestures.c index 90371620..8e6005b3 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -298,13 +298,6 @@ bool IsGestureDetected(int gesture) else return false; } -// Check gesture type -int GetGestureDetected(void) -{ - // Get current gesture only if enabled - return (enabledGestures & currentGesture); -} - // Get number of touch points int GetTouchPointsCount(void) { diff --git a/src/gestures.h b/src/gestures.h index f2bdaba4..ab5287cc 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -90,13 +90,12 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +bool IsGestureDetected(int gesture); // Check if a gesture have been detected void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -int GetTouchPointsCount(void); // Get touch points count +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/raylib.h b/src/raylib.h index bfcb9bf5..343e86f1 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -644,13 +644,12 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +bool IsGestureDetected(int gesture); // Check if a gesture have been detected void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -int GetTouchPointsCount(void); // Get touch points count +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle -- cgit v1.2.3 From 3d6be7fd8000bf7bd9da0b9ad8764021f86c0d01 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 12:01:57 +0200 Subject: Added GetGestureDetected() again... Required by gestures example.... --- src/gestures.c | 27 +++++++++++++++++---------- src/gestures.h | 1 + src/raylib.h | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/gestures.c b/src/gestures.c index 8e6005b3..57b96bd2 100644 --- a/src/gestures.c +++ b/src/gestures.c @@ -111,6 +111,19 @@ static double GetCurrentTime(void); // Module Functions Definition //---------------------------------------------------------------------------------- +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) +{ + enabledGestures = gestureFlags; +} + +// Check if a gesture have been detected +bool IsGestureDetected(int gesture) +{ + if ((enabledGestures & currentGesture) == gesture) return true; + else return false; +} + // Process gesture event and translate it into gestures void ProcessGestureEvent(GestureEvent event) { @@ -291,13 +304,6 @@ void UpdateGestures(void) } } -// Check if a gesture have been detected -bool IsGestureDetected(int gesture) -{ - if ((enabledGestures & currentGesture) == gesture) return true; - else return false; -} - // Get number of touch points int GetTouchPointsCount(void) { @@ -306,10 +312,11 @@ int GetTouchPointsCount(void) return pointCount; } -// Enable only desired getures to be detected -void SetGesturesEnabled(unsigned int gestureFlags) +// Get latest detected gesture +int GetGestureDetected(void) { - enabledGestures = gestureFlags; + // Get current gesture only if enabled + return (enabledGestures & currentGesture); } // Hold time measured in ms diff --git a/src/gestures.h b/src/gestures.h index ab5287cc..912d0b92 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -96,6 +96,7 @@ void ProcessGestureEvent(GestureEvent event); // Process gesture event void UpdateGestures(void); // Update gestures detected (must be called every frame) int GetTouchPointsCount(void); // Get touch points count +int GetGestureDetected(void); // Get latest detected gesture float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/raylib.h b/src/raylib.h index 343e86f1..9120ddc4 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -650,6 +650,7 @@ void ProcessGestureEvent(GestureEvent event); // Process gesture event void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) int GetTouchPointsCount(void); // Get touch points count +int GetGestureDetected(void); // Get latest detected gesture float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle -- cgit v1.2.3 From 3ce02282063b47bd3e0beb0453d33ef316a371fa Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 14 Jun 2016 17:16:20 +0200 Subject: Move Oculus Rift support to rlgl module --- src/core.c | 386 +--------------------------------------------------------- src/raylib.h | 19 +-- src/rlgl.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/rlgl.h | 9 ++ 4 files changed, 399 insertions(+), 405 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index bd49b549..fb71af21 100644 --- a/src/core.c +++ b/src/core.c @@ -9,7 +9,7 @@ * PLATFORM_ANDROID - Only OpenGL ES 2.0 devices * PLATFORM_RPI - Rapsberry Pi (tested on Raspbian) * PLATFORM_WEB - Emscripten, HTML5 -* PLATFORM_OCULUS - Oculus Rift CV1 (with desktop mirror) +* Oculus Rift CV1 (with desktop mirror) - View [rlgl] module to enable it * * On PLATFORM_DESKTOP, the external lib GLFW3 (www.glfw.com) is used to manage graphic * device, OpenGL context and input on multiple operating systems (Windows, Linux, OSX). @@ -54,14 +54,6 @@ #include // String function definitions, memset() #include // Macros for reporting and retrieving error conditions through error codes -#if defined(PLATFORM_OCULUS) - #define PLATFORM_DESKTOP // Enable PLATFORM_DESKTOP code-base -#endif - -#if defined(PLATFORM_OCULUS) - #include "../examples/oculus_glfw_sample/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL -#endif - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 #include // GLFW3 library: Windows, OpenGL context and Input management @@ -134,31 +126,7 @@ //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- -#if defined(PLATFORM_OCULUS) -typedef struct OculusBuffer { - ovrTextureSwapChain textureChain; - GLuint depthId; - GLuint fboId; - int width; - int height; -} OculusBuffer; - -typedef struct OculusMirror { - ovrMirrorTexture texture; - GLuint fboId; - int width; - int height; -} OculusMirror; - -typedef struct OculusLayer { - ovrViewScaleDesc viewScaleDesc; - ovrLayerEyeFov eyeLayer; // layer 0 - //ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI - Matrix eyeProjections[2]; - int width; - int height; -} OculusLayer; -#endif +// ... //---------------------------------------------------------------------------------- // Global Variables Definition @@ -213,17 +181,6 @@ static uint64_t baseTime; // Base time measure for hi-res timer static bool windowShouldClose = false; // Flag to set window for closing #endif -#if defined(PLATFORM_OCULUS) -// OVR device variables -static ovrSession session; // Oculus session (pointer to ovrHmdStruct) -static ovrHmdDesc hmdDesc; // Oculus device descriptor parameters -static ovrGraphicsLuid luid; // Oculus locally unique identifier for the program (64 bit) -static OculusLayer layer; // Oculus drawing layer (similar to photoshop) -static OculusBuffer buffer; // Oculus internal buffers (texture chain and fbo) -static OculusMirror mirror; // Oculus mirror texture and fbo -static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain -#endif - static unsigned int displayWidth, displayHeight; // Display width and height (monitor, device-screen, LCD, ...) static int screenWidth, screenHeight; // Screen width and height (used render area) static int renderWidth, renderHeight; // Framebuffer width and height (render area) @@ -233,7 +190,6 @@ static int renderOffsetX = 0; // Offset X from render area (must b static int renderOffsetY = 0; // Offset Y from render area (must be divided by 2) static bool fullscreen = false; // Fullscreen mode (useful only for PLATFORM_DESKTOP) static Matrix downscaleView; // Matrix to downscale view (in case screen size bigger than display size) -static Matrix cameraView; // Store camera view matrix (required for Oculus Rift) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) static const char *windowTitle; // Window text title... @@ -332,19 +288,6 @@ static void InitGamepad(void); // Init raw gamepad inpu static void *GamepadThread(void *arg); // Mouse reading thread #endif -#if defined(PLATFORM_OCULUS) -// Oculus Rift functions -static Matrix FromOvrMatrix(ovrMatrix4f ovrM); -static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); -static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer); -static void SetOculusBuffer(ovrSession session, OculusBuffer buffer); -static void UnsetOculusBuffer(OculusBuffer buffer); -static OculusMirror LoadOculusMirror(ovrSession session, int width, int height); // Load Oculus mirror buffers -static void UnloadOculusMirror(ovrSession session, OculusMirror mirror); // Unload Oculus mirror buffers -static void BlitOculusMirror(ovrSession session, OculusMirror mirror); -static OculusLayer InitOculusLayer(ovrSession session); -#endif - //---------------------------------------------------------------------------------- // Module Functions Definition - Window and OpenGL Context Functions //---------------------------------------------------------------------------------- @@ -393,11 +336,6 @@ void InitWindow(int width, int height, const char *title) //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback); #endif -#if defined(PLATFORM_OCULUS) - // Recenter OVR tracking origin - ovr_RecenterTrackingOrigin(session); -#endif - mousePosition.x = (float)screenWidth/2.0f; mousePosition.y = (float)screenHeight/2.0f; @@ -512,64 +450,6 @@ void CloseWindow(void) TraceLog(INFO, "Window closed successfully"); } -#if defined(PLATFORM_OCULUS) -// Init Oculus Rift device -// NOTE: Device initialization should be done before window creation? -void InitOculusDevice(void) -{ - // Initialize Oculus device - ovrResult result = ovr_Initialize(NULL); - if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); - - result = ovr_Create(&session, &luid); - if (OVR_FAILURE(result)) - { - TraceLog(WARNING, "OVR: Could not create Oculus session"); - ovr_Shutdown(); - } - - hmdDesc = ovr_GetHmdDesc(session); - - TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); - TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); - TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); - TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); - //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); - TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); - - // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... - // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) - - // Initialize Oculus Buffers - layer = InitOculusLayer(session); - buffer = LoadOculusBuffer(session, layer.width, layer.height); - mirror = LoadOculusMirror(session, screenWidth, screenHeight); - layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); -} - -// Close Oculus Rift device -void CloseOculusDevice(void) -{ - UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer - UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers - - ovr_Destroy(session); // Free Oculus session data - ovr_Shutdown(); // Close Oculus device connection -} - -// Update Oculus Rift tracking (position and orientation) -void UpdateOculusTracking(void) -{ - frameIndex++; - - ovrPosef eyePoses[2]; - ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); - - layer.eyeLayer.RenderPose[0] = eyePoses[0]; - layer.eyeLayer.RenderPose[1] = eyePoses[1]; -} -#endif - // Detect if KEY_ESCAPE pressed or Close icon pressed bool WindowShouldClose(void) { @@ -638,10 +518,6 @@ void BeginDrawing(void) currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called updateTime = currentTime - previousTime; previousTime = currentTime; - -#if defined(PLATFORM_OCULUS) - SetOculusBuffer(session, buffer); -#endif rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -654,49 +530,7 @@ void BeginDrawing(void) // End canvas drawing and Swap Buffers (Double Buffering) void EndDrawing(void) { -#if defined(PLATFORM_OCULUS) - for (int eye = 0; eye < 2; eye++) - { - rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); - - Quaternion eyeRPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, - layer.eyeLayer.RenderPose[eye].Orientation.y, - layer.eyeLayer.RenderPose[eye].Orientation.z, - layer.eyeLayer.RenderPose[eye].Orientation.w }; - QuaternionInvert(&eyeRPose); - Matrix eyeOrientation = QuaternionToMatrix(eyeRPose); - Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, - -layer.eyeLayer.RenderPose[eye].Position.y, - -layer.eyeLayer.RenderPose[eye].Position.z); - - Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); - Matrix modelEyeView = MatrixMultiply(cameraView, eyeView); // Using internal camera modelview matrix - - SetMatrixModelview(modelEyeView); - SetMatrixProjection(layer.eyeProjections[eye]); -#endif - - rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - -#if defined(PLATFORM_OCULUS) - } - - UnsetOculusBuffer(buffer); - - ovr_CommitTextureSwapChain(session, buffer.textureChain); - - ovrLayerHeader *layers = &layer.eyeLayer.Header; - ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); - - // Blit mirror texture to back buffer - BlitOculusMirror(session, mirror); - - // Get session status information - ovrSessionStatus sessionStatus; - ovr_GetSessionStatus(session, &sessionStatus); - if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); - if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); -#endif + rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -768,7 +602,7 @@ void Begin3dMode(Camera camera) rlLoadIdentity(); // Reset current matrix (MODELVIEW) // Setup Camera view - cameraView = MatrixLookAt(camera.position, camera.target, camera.up); + Matrix cameraView = MatrixLookAt(camera.position, camera.target, camera.up); rlMultMatrixf(MatrixToFloat(cameraView)); // Multiply MODELVIEW matrix by view matrix (camera) rlEnableDepthTest(); // Enable DEPTH_TEST for 3D @@ -1738,9 +1572,7 @@ static void InitDisplay(int width, int height) #endif glfwMakeContextCurrent(window); -#if defined(PLATFORM_OCULUS) - glfwSwapInterval(0); -#endif + glfwSwapInterval(0); // Disable VSync by default #if defined(PLATFORM_DESKTOP) // Load OpenGL 3.3 extensions @@ -2940,214 +2772,6 @@ static void *GamepadThread(void *arg) } #endif - -#if defined(PLATFORM_OCULUS) -// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct -static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) -{ - Matrix rmat; - - rmat.m0 = ovrmat.M[0][0]; - rmat.m1 = ovrmat.M[1][0]; - rmat.m2 = ovrmat.M[2][0]; - rmat.m3 = ovrmat.M[3][0]; - rmat.m4 = ovrmat.M[0][1]; - rmat.m5 = ovrmat.M[1][1]; - rmat.m6 = ovrmat.M[2][1]; - rmat.m7 = ovrmat.M[3][1]; - rmat.m8 = ovrmat.M[0][2]; - rmat.m9 = ovrmat.M[1][2]; - rmat.m10 = ovrmat.M[2][2]; - rmat.m11 = ovrmat.M[3][2]; - rmat.m12 = ovrmat.M[0][3]; - rmat.m13 = ovrmat.M[1][3]; - rmat.m14 = ovrmat.M[2][3]; - rmat.m15 = ovrmat.M[3][3]; - - MatrixTranspose(&rmat); - - return rmat; -} - -// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth -static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) -{ - OculusBuffer buffer; - buffer.width = width; - buffer.height = height; - - // Create OVR texture chain - ovrTextureSwapChainDesc desc = {}; - desc.Type = ovrTexture_2D; - desc.ArraySize = 1; - desc.Width = width; - desc.Height = height; - desc.MipLevels = 1; - desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Requires glEnable(GL_FRAMEBUFFER_SRGB); - desc.SampleCount = 1; - desc.StaticImage = ovrFalse; - - ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); - - if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); - - int textureCount = 0; - ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); - - if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); - - for (int i = 0; i < textureCount; ++i) - { - GLuint chainTexId; - ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId); - glBindTexture(GL_TEXTURE_2D, chainTexId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - glBindTexture(GL_TEXTURE_2D, 0); - - /* - // Setup framebuffer object (using depth texture) - glGenFramebuffers(1, &buffer.fboId); - glGenTextures(1, &buffer.depthId); - glBindTexture(GL_TEXTURE_2D, buffer.depthId); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - */ - - // Setup framebuffer object (using depth renderbuffer) - glGenFramebuffers(1, &buffer.fboId); - glGenRenderbuffers(1, &buffer.depthId); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); - glBindRenderbuffer(GL_RENDERBUFFER, buffer.depthId); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buffer.width, buffer.height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer.depthId); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - - return buffer; -} - -// Unload texture required buffers -static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer) -{ - if (buffer.textureChain) - { - ovr_DestroyTextureSwapChain(session, buffer.textureChain); - buffer.textureChain = NULL; - } - - if (buffer.depthId != 0) glDeleteTextures(1, &buffer.depthId); - if (buffer.fboId != 0) glDeleteFramebuffers(1, &buffer.fboId); -} - -// Set current Oculus buffer -static void SetOculusBuffer(ovrSession session, OculusBuffer buffer) -{ - GLuint currentTexId; - int currentIndex; - - ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); - ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0); - //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded - - //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Required if OculusBuffer format is OVR_FORMAT_R8G8B8A8_UNORM_SRGB - glEnable(GL_FRAMEBUFFER_SRGB); -} - -// Unset Oculus buffer -static void UnsetOculusBuffer(OculusBuffer buffer) -{ - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -} - -// Load Oculus mirror buffers -static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) -{ - OculusMirror mirror; - mirror.width = width; - mirror.height = height; - - ovrMirrorTextureDesc mirrorDesc; - memset(&mirrorDesc, 0, sizeof(mirrorDesc)); - mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; - mirrorDesc.Width = mirror.width; - mirrorDesc.Height = mirror.height; - - if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); - - glGenFramebuffers(1, &mirror.fboId); - - return mirror; -} - -// Unload Oculus mirror buffers -static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) -{ - if (mirror.fboId != 0) glDeleteFramebuffers(1, &mirror.fboId); - if (mirror.texture) ovr_DestroyMirrorTexture(session, mirror.texture); -} - -static void BlitOculusMirror(ovrSession session, OculusMirror mirror) -{ - GLuint mirrorTextureId; - - ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); - glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); -} - -// Requires: session, hmdDesc -static OculusLayer InitOculusLayer(ovrSession session) -{ - OculusLayer layer = { 0 }; - - layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; - - memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); - layer.eyeLayer.Header.Type = ovrLayerType_EyeFov; - layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; - - ovrEyeRenderDesc eyeRenderDescs[2]; - - for (int eye = 0; eye < 2; eye++) - { - eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); - ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 10000.0f, ovrProjection_None); //ovrProjection_ClipRangeOpenGL); - layer.eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection); // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix - - layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; - layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; - - ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); - layer.eyeLayer.Viewport[eye].Size = eyeSize; - layer.eyeLayer.Viewport[eye].Pos.x = layer.width; - layer.eyeLayer.Viewport[eye].Pos.y = 0; - - layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); - layer.width += eyeSize.w; - } - - return layer; -} -#endif - // Plays raylib logo appearing animation static void LogoAnimation(void) { diff --git a/src/raylib.h b/src/raylib.h index 9120ddc4..0c9f0280 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -64,7 +64,7 @@ //#define PLATFORM_ANDROID // Android device //#define PLATFORM_RPI // Raspberry Pi //#define PLATFORM_WEB // HTML5 (emscripten, asm.js) -//#define PLATFORM_OCULUS // Oculus Rift CV1 +//#define RLGL_OCULUS_SUPPORT // Oculus Rift CV1 (complementary to PLATFORM_DESKTOP) // Security check in case no PLATFORM_* defined #if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB) @@ -545,12 +545,6 @@ void InitWindow(int width, int height, struct android_app *state); // Init Andr void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif -#if defined(PLATFORM_OCULUS) -void InitOculusDevice(void); // Init Oculus Rift device -void CloseOculusDevice(void); // Close Oculus Rift device -void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -#endif - void CloseWindow(void); // Close Window and Terminate Context bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) @@ -852,6 +846,17 @@ void EndBlendMode(void); // End blend 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 +//------------------------------------------------------------------------------------ +// Oculus Rift CV1 Functions (Module: rlgl) +// NOTE: This functions are useless when using OpenGL 1.1 +//------------------------------------------------------------------------------------ +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void BeginOculusDrawing(void); // Begin Oculus drawing configuration +void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) + //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ diff --git a/src/rlgl.c b/src/rlgl.c index 26961ca9..1e392889 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -72,6 +72,10 @@ #include "standard_shader.h" // Standard shader to embed #endif +#if defined(RLGL_OCULUS_SUPPORT) + #include "external/OculusSDK/LibOVR/Include/OVR_CAPI_GL.h" // Oculus SDK for OpenGL +#endif + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -172,6 +176,32 @@ typedef struct { //Guint fboId; } DrawCall; +#if defined(RLGL_OCULUS_SUPPORT) +typedef struct OculusBuffer { + ovrTextureSwapChain textureChain; + GLuint depthId; + GLuint fboId; + int width; + int height; +} OculusBuffer; + +typedef struct OculusMirror { + ovrMirrorTexture texture; + GLuint fboId; + int width; + int height; +} OculusMirror; + +typedef struct OculusLayer { + ovrViewScaleDesc viewScaleDesc; + ovrLayerEyeFov eyeLayer; // layer 0 + //ovrLayerQuad quadLayer; // TODO: layer 1: '2D' quad for GUI + Matrix eyeProjections[2]; + int width; + int height; +} OculusLayer; +#endif + //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -221,6 +251,17 @@ static Light lights[MAX_LIGHTS]; // Lights pool static int lightsCount; // Counts current enabled physic objects #endif +#if defined(RLGL_OCULUS_SUPPORT) +// OVR device variables +static ovrSession session; // Oculus session (pointer to ovrHmdStruct) +static ovrHmdDesc hmdDesc; // Oculus device descriptor parameters +static ovrGraphicsLuid luid; // Oculus locally unique identifier for the program (64 bit) +static OculusLayer layer; // Oculus drawing layer (similar to photoshop) +static OculusBuffer buffer; // Oculus internal buffers (texture chain and fbo) +static OculusMirror mirror; // Oculus mirror texture and fbo +static unsigned int frameIndex = 0; // Oculus frames counter, used to discard frames from chain +#endif + // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support static bool npotSupported = false; // NPOT textures full support @@ -261,6 +302,16 @@ static void SetShaderLights(Shader shader); // Sets shader uniform values for li static char *ReadTextFile(const char *fileName); #endif +#if defined(RLGL_OCULUS_SUPPORT) // Oculus Rift functions +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height); // Load Oculus required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer); // Unload texture required buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height); // Load Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror); // Unload Oculus mirror buffers +static void BlitOculusMirror(ovrSession session, OculusMirror mirror); // Copy Oculus screen buffer to mirror texture +static OculusLayer InitOculusLayer(ovrSession session); // Init Oculus layer (similar to photoshop) +static Matrix FromOvrMatrix(ovrMatrix4f ovrM); // Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +#endif + #if defined(GRAPHICS_API_OPENGL_11) static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight); static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight); @@ -872,23 +923,6 @@ int rlGetVersion(void) #endif } -// Load OpenGL extensions -// NOTE: External loader function could be passed as a pointer -void rlglLoadExtensions(void *loader) -{ -#if defined(GRAPHICS_API_OPENGL_33) - // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions - if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); - else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); - - if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); - else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); - - // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans - //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object -#endif -} - //---------------------------------------------------------------------------------- // Module Functions Definition - rlgl Functions //---------------------------------------------------------------------------------- @@ -1170,6 +1204,23 @@ void rlglInitGraphics(int offsetX, int offsetY, int width, int height) TraceLog(INFO, "OpenGL graphic device initialized successfully"); } +// Load OpenGL extensions +// NOTE: External loader function could be passed as a pointer +void rlglLoadExtensions(void *loader) +{ +#if defined(GRAPHICS_API_OPENGL_33) + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions + if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); + else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + + if (GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + + // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans + //if (GLAD_GL_ARB_vertex_array_object) // Use GL_ARB_vertex_array_object +#endif +} + // Get world coordinates from screen coordinates Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { @@ -2410,6 +2461,130 @@ void DestroyLight(Light light) #endif } +#if defined(RLGL_OCULUS_SUPPORT) +// Init Oculus Rift device +// NOTE: Device initialization should be done before window creation? +void InitOculusDevice(void) +{ + // Initialize Oculus device + ovrResult result = ovr_Initialize(NULL); + if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); + + result = ovr_Create(&session, &luid); + if (OVR_FAILURE(result)) + { + TraceLog(WARNING, "OVR: Could not create Oculus session"); + ovr_Shutdown(); + } + + hmdDesc = ovr_GetHmdDesc(session); + + TraceLog(INFO, "OVR: Product Name: %s", hmdDesc.ProductName); + TraceLog(INFO, "OVR: Manufacturer: %s", hmdDesc.Manufacturer); + TraceLog(INFO, "OVR: Product ID: %i", hmdDesc.ProductId); + TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); + //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); + TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); + + // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... + // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) + + // Initialize Oculus Buffers + layer = InitOculusLayer(session); + buffer = LoadOculusBuffer(session, layer.width, layer.height); + mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); // NOTE: hardcoded... + layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); + + // Recenter OVR tracking origin + ovr_RecenterTrackingOrigin(session); +} + +// Close Oculus Rift device +void CloseOculusDevice(void) +{ + UnloadOculusMirror(session, mirror); // Unload Oculus mirror buffer + UnloadOculusBuffer(session, buffer); // Unload Oculus texture buffers + + ovr_Destroy(session); // Free Oculus session data + ovr_Shutdown(); // Close Oculus device connection +} + +// Update Oculus Rift tracking (position and orientation) +void UpdateOculusTracking(void) +{ + frameIndex++; + + ovrPosef eyePoses[2]; + ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); + + layer.eyeLayer.RenderPose[0] = eyePoses[0]; + layer.eyeLayer.RenderPose[1] = eyePoses[1]; +} + +void SetOculusMatrix(int eye) +{ + rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); + + Quaternion eyeRPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, + layer.eyeLayer.RenderPose[eye].Orientation.y, + layer.eyeLayer.RenderPose[eye].Orientation.z, + layer.eyeLayer.RenderPose[eye].Orientation.w }; + QuaternionInvert(&eyeRPose); + Matrix eyeOrientation = QuaternionToMatrix(eyeRPose); + Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, + -layer.eyeLayer.RenderPose[eye].Position.y, + -layer.eyeLayer.RenderPose[eye].Position.z); + + Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); + Matrix modelEyeView = MatrixMultiply(modelview, eyeView); // Using internal camera modelview matrix + + SetMatrixModelview(modelEyeView); + SetMatrixProjection(layer.eyeProjections[eye]); +} + +void BeginOculusDrawing(void) +{ + GLuint currentTexId; + int currentIndex; + + ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, currentTexId, 0); + //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, buffer.depthId, 0); // Already binded + + //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Same as rlClearScreenBuffers() + + // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) + // and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then: + // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB + // - Do NOT enable GL_FRAMEBUFFER_SRGB + //glEnable(GL_FRAMEBUFFER_SRGB); +} + +void EndOculusDrawing(void) +{ + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + ovr_CommitTextureSwapChain(session, buffer.textureChain); + + ovrLayerHeader *layers = &layer.eyeLayer.Header; + ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); + + // Blit mirror texture to back buffer + BlitOculusMirror(session, mirror); + + // Get session status information + ovrSessionStatus sessionStatus; + ovr_GetSessionStatus(session, &sessionStatus); + if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); + if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); +} +#endif + //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -3390,6 +3565,187 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) } #endif +#if defined(RLGL_OCULUS_SUPPORT) +// Load Oculus required buffers: texture-swap-chain, fbo, texture-depth +static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) +{ + OculusBuffer buffer; + buffer.width = width; + buffer.height = height; + + // Create OVR texture chain + ovrTextureSwapChainDesc desc = {}; + desc.Type = ovrTexture_2D; + desc.ArraySize = 1; + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; // Requires glEnable(GL_FRAMEBUFFER_SRGB); + desc.SampleCount = 1; + desc.StaticImage = ovrFalse; + + ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); + + if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); + + int textureCount = 0; + ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); + + if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); + + for (int i = 0; i < textureCount; ++i) + { + GLuint chainTexId; + ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, i, &chainTexId); + glBindTexture(GL_TEXTURE_2D, chainTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + /* + // Setup framebuffer object (using depth texture) + glGenFramebuffers(1, &buffer.fboId); + glGenTextures(1, &buffer.depthId); + glBindTexture(GL_TEXTURE_2D, buffer.depthId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + */ + + // Setup framebuffer object (using depth renderbuffer) + glGenFramebuffers(1, &buffer.fboId); + glGenRenderbuffers(1, &buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, buffer.fboId); + glBindRenderbuffer(GL_RENDERBUFFER, buffer.depthId); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buffer.width, buffer.height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, buffer.depthId); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + return buffer; +} + +// Unload texture required buffers +static void UnloadOculusBuffer(ovrSession session, OculusBuffer buffer) +{ + if (buffer.textureChain) + { + ovr_DestroyTextureSwapChain(session, buffer.textureChain); + buffer.textureChain = NULL; + } + + if (buffer.depthId != 0) glDeleteTextures(1, &buffer.depthId); + if (buffer.fboId != 0) glDeleteFramebuffers(1, &buffer.fboId); +} + +// Load Oculus mirror buffers +static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) +{ + OculusMirror mirror; + mirror.width = width; + mirror.height = height; + + ovrMirrorTextureDesc mirrorDesc; + memset(&mirrorDesc, 0, sizeof(mirrorDesc)); + mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; + mirrorDesc.Width = mirror.width; + mirrorDesc.Height = mirror.height; + + if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); + + glGenFramebuffers(1, &mirror.fboId); + + return mirror; +} + +// Unload Oculus mirror buffers +static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) +{ + if (mirror.fboId != 0) glDeleteFramebuffers(1, &mirror.fboId); + if (mirror.texture) ovr_DestroyMirrorTexture(session, mirror.texture); +} + +// Copy Oculus screen buffer to mirror texture +static void BlitOculusMirror(ovrSession session, OculusMirror mirror) +{ + GLuint mirrorTextureId; + + ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); + glBlitFramebuffer(0, 0, mirror.width, mirror.height, 0, mirror.height, mirror.width, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +} + +// Init Oculus layer (similar to photoshop) +static OculusLayer InitOculusLayer(ovrSession session) +{ + OculusLayer layer = { 0 }; + + layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; + + memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); + layer.eyeLayer.Header.Type = ovrLayerType_EyeFov; + layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; + + ovrEyeRenderDesc eyeRenderDescs[2]; + + for (int eye = 0; eye < 2; eye++) + { + eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); + ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(eyeRenderDescs[eye].Fov, 0.01f, 10000.0f, ovrProjection_None); //ovrProjection_ClipRangeOpenGL); + layer.eyeProjections[eye] = FromOvrMatrix(ovrPerspectiveProjection); // NOTE: struct ovrMatrix4f { float M[4][4] } --> struct Matrix + + layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; + layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; + + ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); + layer.eyeLayer.Viewport[eye].Size = eyeSize; + layer.eyeLayer.Viewport[eye].Pos.x = layer.width; + layer.eyeLayer.Viewport[eye].Pos.y = 0; + + layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); + layer.width += eyeSize.w; + } + + return layer; +} + +// Convert from Oculus ovrMatrix4f struct to raymath Matrix struct +static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) +{ + Matrix rmat; + + rmat.m0 = ovrmat.M[0][0]; + rmat.m1 = ovrmat.M[1][0]; + rmat.m2 = ovrmat.M[2][0]; + rmat.m3 = ovrmat.M[3][0]; + rmat.m4 = ovrmat.M[0][1]; + rmat.m5 = ovrmat.M[1][1]; + rmat.m6 = ovrmat.M[2][1]; + rmat.m7 = ovrmat.M[3][1]; + rmat.m8 = ovrmat.M[0][2]; + rmat.m9 = ovrmat.M[1][2]; + rmat.m10 = ovrmat.M[2][2]; + rmat.m11 = ovrmat.M[3][2]; + rmat.m12 = ovrmat.M[0][3]; + rmat.m13 = ovrmat.M[1][3]; + rmat.m14 = ovrmat.M[2][3]; + rmat.m15 = ovrmat.M[3][3]; + + MatrixTranspose(&rmat); + + return rmat; +} +#endif + #if defined(RLGL_STANDALONE) // Output a trace log message // NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning diff --git a/src/rlgl.h b/src/rlgl.h index 28c50b8f..1e77b771 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -347,6 +347,15 @@ void DestroyLight(Light light); // Destroy a void TraceLog(int msgType, const char *text, ...); #endif +#if defined(RLGL_OCULUS_SUPPORT) +void InitOculusDevice(void); // Init Oculus Rift device +void CloseOculusDevice(void); // Close Oculus Rift device +void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) +void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void BeginOculusDrawing(void); // Begin Oculus drawing configuration +void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 24c9b1f717bd9a6510667907614928188a6b6a6f Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 17 Jun 2016 13:54:45 +0200 Subject: Improving Oculus Rift example... Under design... looking for the easiest and most comprehensive way for the user to use VR... --- examples/core_oculus_rift.c | 40 ++++++++++++++++++++++------------------ src/core.c | 10 ++++++++++ src/raylib.h | 3 ++- src/rlgl.c | 10 +++++----- src/rlgl.h | 2 +- 5 files changed, 40 insertions(+), 25 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index 3c9d7840..32e6b1c6 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -51,27 +51,31 @@ int main() ClearBackground(RAYWHITE); - BeginOculusDrawing(); + Begin3dMode(camera); + //BeginOculusDrawing(camera); // Add it to Begin3dMode() ? - for (int eye = 0; eye < 2; eye++) - { - // TODO: Probably projection and view matrices could be created here... - // ...without the need to create it internally through Begin3dMode() - Begin3dMode(camera); + for (int eye = 0; eye < 2; eye++) + { + // TODO: Probably projection and view matrices could be created here... + // ...without the need to create it internally through Begin3dMode() + //Begin3dMode(camera); + + SetOculusView(eye); + + DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); + DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); + + DrawGrid(10, 1.0f); + + // TODO: Call internal buffers drawing directly (rlglDraw()) and... + // ...reset internal matrices, instead of letting End3dMode() do that + //End3dMode(); - SetOculusMatrix(eye); - - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); - DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - - DrawGrid(10, 1.0f); - - // TODO: Call internal buffers drawing directly (rlglDraw()) and... - // ...reset internal matrices, instead of letting End3dMode() do that - End3dMode(); - } + DrawDefaultBuffers(); // Process internal dynamic buffers + } - EndOculusDrawing(); + End3dMode(); + //EndOculusDrawing(); // Add it to End3dMode() ? EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/src/core.c b/src/core.c index 7c2dbcb9..eef81bad 100644 --- a/src/core.c +++ b/src/core.c @@ -606,6 +606,8 @@ void Begin3dMode(Camera camera) rlMultMatrixf(MatrixToFloat(cameraView)); // Multiply MODELVIEW matrix by view matrix (camera) rlEnableDepthTest(); // Enable DEPTH_TEST for 3D + + //if (vrEnabled) BeginVrMode(); } // Ends 3D mode and returns to default 2D orthographic mode @@ -1015,6 +1017,14 @@ Matrix GetCameraMatrix(Camera camera) return MatrixLookAt(camera.position, camera.target, camera.up); } +// Update and draw default buffers vertex data +// NOTE: This data has been stored dynamically during frame on each Draw*() call +void DrawDefaultBuffers(void) +{ + rlglUpdateDefaultBuffers(); // Upload frame vertex data to GPU + rlglDrawDefaultBuffers(); // Draw vertex data into framebuffer +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index 0c9f0280..ed787892 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -572,6 +572,7 @@ void EndTextureMode(void); // Ends drawing to r Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) +void DrawDefaultBuffers(void); // Update and draw default buffers vertex data (stored dynamically in frame) void SetTargetFPS(int fps); // Set target FPS (maximum) float GetFPS(void); // Returns current FPS @@ -853,7 +854,7 @@ void DestroyLight(Light light); // Destroy a void InitOculusDevice(void); // Init Oculus Rift device void CloseOculusDevice(void); // Close Oculus Rift device void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void SetOculusView(int eye); // Set internal projection and modelview matrix depending on eyes tracking data void BeginOculusDrawing(void); // Begin Oculus drawing configuration void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) diff --git a/src/rlgl.c b/src/rlgl.c index 6d003869..d68b9109 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -297,8 +297,8 @@ 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 +void rlglUpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data +void rlglDrawDefaultBuffers(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 @@ -2542,7 +2542,7 @@ void UpdateOculusTracking(void) //if (sessionStatus.IsVisible) // the game or experience has VR focus and is visible in the HMD. } -void SetOculusMatrix(int eye) +void SetOculusView(int eye) { rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); @@ -3089,7 +3089,7 @@ static void LoadDefaultBuffers(void) // Update default internal buffers (VAOs/VBOs) with vertex array data // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) -static void UpdateDefaultBuffers(void) +void rlglUpdateDefaultBuffers(void) { // Update lines vertex buffers if (lines.vCounter > 0) @@ -3159,7 +3159,7 @@ static void UpdateDefaultBuffers(void) // Draw default internal buffers vertex data // NOTE: We draw in this order: lines, triangles, quads -static void DrawDefaultBuffers(void) +void rlglDrawDefaultBuffers(void) { // Set current shader and upload current MVP matrix if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) diff --git a/src/rlgl.h b/src/rlgl.h index 3322d80c..8904b9ac 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -357,7 +357,7 @@ void TraceLog(int msgType, const char *text, ...); void InitOculusDevice(void); // Init Oculus Rift device void CloseOculusDevice(void); // Close Oculus Rift device void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void SetOculusMatrix(int eye); // Set internal projection and modelview matrix depending on eyes tracking data +void SetOculusView(int eye); // Set internal projection and modelview matrix depending on eyes tracking data void BeginOculusDrawing(void); // Begin Oculus drawing configuration void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) #endif -- cgit v1.2.3 From 5f7ac64c44543383b10ec6a56e5ec1db5706276e Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 24 Jun 2016 19:49:36 +0200 Subject: Removed function SetModelTexture() It's more educational to go through new material system, so, I decide to remove this function to avoid students confusion... --- CHANGELOG | 7 ++++--- examples/models_cubicmap.c | 2 +- examples/models_heightmap.c | 2 +- examples/models_obj_loading.c | 2 +- examples/shaders_custom_uniform.c | 2 +- examples/shaders_postprocessing.c | 2 +- games/raylib_demo/raylib_demo.c | 4 ++-- src/models.c | 7 ------- src/raylib.h | 1 - 9 files changed, 11 insertions(+), 18 deletions(-) (limited to 'src/raylib.h') diff --git a/CHANGELOG b/CHANGELOG index 5024dc6e..300c9089 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,20 +1,20 @@ changelog --------- -Current Release: raylib 1.5.0 (23 June 2016) +Current Release: raylib 1.5.0 (xx June 2016) NOTE: Only versions marked as 'Release' are available in installer, updates are only available as source. NOTE: Current Release includes all previous updates. ----------------------------------------------- -Release: raylib 1.5.0 (23 June 2016) +Release: raylib 1.5.0 (xx June 2016) ----------------------------------------------- NOTE: Probably this new version is the biggest boost of the library ever, lots of parts of the library have been redesigned, lots of bugs have been solved and some **AMAZING** new features have been added. HUGE changes: -[core] OCULUS RIFT CV1: Added support for VR witha bunch of Oculus-specific functions to init/close device and Oculus rendering. +[rlgl] OCULUS RIFT CV1: Added support for VR witha bunch of Oculus-specific functions to init/close device and Oculus rendering. [rlgl] MATERIALS SYSTEM: Added support for Materials (.mtl) and multiple material properties: diffuse, specular, normal. [rlgl] LIGHTING SYSTEM: Added support for up to 8 lights of 3 different types: Omni, Directional and Spot [physac] REDESIGNED: Improved performance and simplified usage, physic objects are managed internally @@ -65,6 +65,7 @@ other changes: [models] Updated BoundingBox collision detections [models] Added color parameter to DrawBoundigBox() [models] Removed function: DrawQuad() +[models] Removed function: SetModelTexture() [models] Redesigned DrawPlane() to use RL_TRIANGLES [models] Redesigned DrawRectangleV() to use RL_TRIANGLES [models] Redesign to accomodate new materials system: LoadMaterial() diff --git a/examples/models_cubicmap.c b/examples/models_cubicmap.c index 1ca27dfd..89bc75cf 100644 --- a/examples/models_cubicmap.c +++ b/examples/models_cubicmap.c @@ -29,7 +29,7 @@ int main() // NOTE: By default each cube is mapped to one part of texture atlas Texture2D texture = LoadTexture("resources/cubicmap_atlas.png"); // Load map texture - SetModelTexture(&map, texture); // Bind texture to map model + map.material.texDiffuse = texture; // Set map diffuse texture Vector3 mapPosition = { -16.0f, 0.0f, -8.0f }; // Set model position diff --git a/examples/models_heightmap.c b/examples/models_heightmap.c index c8e5ff35..90e5f5bb 100644 --- a/examples/models_heightmap.c +++ b/examples/models_heightmap.c @@ -26,7 +26,7 @@ int main() Image image = LoadImage("resources/heightmap.png"); // Load heightmap image (RAM) Texture2D texture = LoadTextureFromImage(image); // Convert image to texture (VRAM) Model map = LoadHeightmap(image, (Vector3){ 16, 8, 16 }); // Load heightmap model with defined size - SetModelTexture(&map, texture); // Bind texture to model + map.material.texDiffuse = texture; // Set map diffuse texture Vector3 mapPosition = { -8.0f, 0.0f, -8.0f }; // Set model position (depends on model scaling!) UnloadImage(image); // Unload heightmap image from RAM, already uploaded to VRAM diff --git a/examples/models_obj_loading.c b/examples/models_obj_loading.c index e8dd0adc..a6969f70 100644 --- a/examples/models_obj_loading.c +++ b/examples/models_obj_loading.c @@ -25,7 +25,7 @@ int main() Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture - SetModelTexture(&dwarf, texture); // Bind texture to model + dwarf.material.texDiffuse = texture; // Set dwarf model diffuse texture Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position SetTargetFPS(60); // Set our game to run at 60 frames-per-second diff --git a/examples/shaders_custom_uniform.c b/examples/shaders_custom_uniform.c index 516d5087..c4f87259 100644 --- a/examples/shaders_custom_uniform.c +++ b/examples/shaders_custom_uniform.c @@ -34,7 +34,7 @@ int main() Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture (diffuse map) - SetModelTexture(&dwarf, texture); // Bind texture to model + dwarf.material.texDiffuse = texture; // Set dwarf model diffuse texture Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position diff --git a/examples/shaders_postprocessing.c b/examples/shaders_postprocessing.c index 5e8b5a80..43d21e08 100644 --- a/examples/shaders_postprocessing.c +++ b/examples/shaders_postprocessing.c @@ -34,7 +34,7 @@ int main() Model dwarf = LoadModel("resources/model/dwarf.obj"); // Load OBJ model Texture2D texture = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model texture (diffuse map) - SetModelTexture(&dwarf, texture); // Bind texture to model + dwarf.material.texDiffuse = texture; // Set dwarf model diffuse texture Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position diff --git a/games/raylib_demo/raylib_demo.c b/games/raylib_demo/raylib_demo.c index 7f6f291a..22213b46 100644 --- a/games/raylib_demo/raylib_demo.c +++ b/games/raylib_demo/raylib_demo.c @@ -202,8 +202,8 @@ int main() camera = (Camera){{ 0.0, 12.0, 15.0 }, { 0.0, 3.0, 0.0 }, { 0.0, 1.0, 0.0 }}; catTexture = LoadTexture("resources/catsham.png"); // Load model texture - cat = LoadModel("resources/cat.obj"); // Load OBJ model - SetModelTexture(&cat, catTexture); + cat = LoadModel("resources/cat.obj"); // Load OBJ model + cat.material.texDiffuse = texture; // Set cat model diffuse texture fxWav = LoadSound("resources/audio/weird.wav"); // Load WAV audio file fxOgg = LoadSound("resources/audio/tanatana.ogg"); // Load OGG audio file diff --git a/src/models.c b/src/models.c index 8deabcb0..a4bcde8f 100644 --- a/src/models.c +++ b/src/models.c @@ -808,13 +808,6 @@ void UnloadMaterial(Material material) rlDeleteTextures(material.texSpecular.id); } -// Link a texture to a model -void SetModelTexture(Model *model, Texture2D texture) -{ - if (texture.id <= 0) model->material.texDiffuse = GetDefaultTexture(); // Use default white texture - else model->material.texDiffuse = texture; -} - // Generate a mesh from heightmap static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) { diff --git a/src/raylib.h b/src/raylib.h index ed787892..641f4c09 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -795,7 +795,6 @@ Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d mod 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) void UnloadModel(Model model); // Unload 3d model from memory -void SetModelTexture(Model *model, Texture2D texture); // Link a texture to a model Material LoadMaterial(const char *fileName); // Load material data (from file) Material LoadDefaultMaterial(void); // Load default material (uses default models shader) -- cgit v1.2.3 From 572936ec65c127c7fecc69f025b819ffec20cdc0 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 27 Jun 2016 18:30:58 +0200 Subject: Added Oculus functions to raylib header --- src/raylib.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 641f4c09..6bacfc67 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -856,6 +856,8 @@ void UpdateOculusTracking(void); // Update Oculus Rift tracking (posi void SetOculusView(int eye); // Set internal projection and modelview matrix depending on eyes tracking data void BeginOculusDrawing(void); // Begin Oculus drawing configuration void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) +bool IsOculusReady(void); // Detect if oculus device (or simulator) is ready +void ToggleVR(void); // Enable/Disable VR experience (Oculus device or simulator) //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) -- cgit v1.2.3 From ee72654b557202a673f042484c83d3020ae618b8 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 4 Jul 2016 01:29:23 +0200 Subject: Redesigned stereo rendering mechanism Now it's easier for the user! Just init Oculus device and get stereo rendering! --- examples/core_oculus_rift.c | 11 +- examples/resources/shaders/glsl330/distortion.fs | 9 +- src/core.c | 18 +- src/raylib.h | 2 - src/rlgl.c | 443 ++++++++++++----------- src/rlgl.h | 4 - 6 files changed, 251 insertions(+), 236 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index c073d3d6..131a21c2 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -50,22 +50,15 @@ int main() // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - + ClearBackground(RAYWHITE); - + Begin3dMode(camera); - for (int eye = 0; eye < 2; eye++) - { - SetOculusView(eye); - DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); DrawGrid(10, 1.0f); - - DrawDefaultBuffers(); // Process internal dynamic buffers - } End3dMode(); diff --git a/examples/resources/shaders/glsl330/distortion.fs b/examples/resources/shaders/glsl330/distortion.fs index 4cd9937f..62856341 100644 --- a/examples/resources/shaders/glsl330/distortion.fs +++ b/examples/resources/shaders/glsl330/distortion.fs @@ -10,12 +10,13 @@ uniform sampler2D texture0; out vec4 finalColor; // NOTE: Add here your custom variables -const vec2 LeftLensCenter = vec2(0.2863248, 0.5); -const vec2 RightLensCenter = vec2(0.7136753, 0.5); +const vec2 LeftLensCenter = vec2(0.288, 0.5); +const vec2 RightLensCenter = vec2(0.712, 0.5); const vec2 LeftScreenCenter = vec2(0.25, 0.5); const vec2 RightScreenCenter = vec2(0.75, 0.5); -const vec2 Scale = vec2(0.25, 0.45); //vec2(0.1469278, 0.2350845); -const vec2 ScaleIn = vec2(4, 2.2222); +uniform vec2 Scale = vec2(0.25, 0.45); //vec2(0.1469278, 0.2350845); +uniform vec2 ScaleIn = vec2(4, 2.2222); + const vec4 HmdWarpParam = vec4(1, 0.22, 0.24, 0); const vec4 ChromaAbParam = vec4(0.996, -0.004, 1.014, 0.0); diff --git a/src/core.c b/src/core.c index 47ce5cea..a8557831 100644 --- a/src/core.c +++ b/src/core.c @@ -520,6 +520,8 @@ void BeginDrawing(void) currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called updateTime = currentTime - previousTime; previousTime = currentTime; + + if (IsOculusReady()) BeginOculusDrawing(); rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -533,6 +535,8 @@ void BeginDrawing(void) void EndDrawing(void) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + if (IsOculusReady()) EndOculusDrawing(); SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -608,15 +612,11 @@ void Begin3dMode(Camera camera) rlMultMatrixf(MatrixToFloat(cameraView)); // Multiply MODELVIEW matrix by view matrix (camera) rlEnableDepthTest(); // Enable DEPTH_TEST for 3D - - if (IsOculusReady()) BeginOculusDrawing(); } // Ends 3D mode and returns to default 2D orthographic mode void End3dMode(void) -{ - if (IsOculusReady()) EndOculusDrawing(); - +{ rlglDraw(); // Process internal buffers (update + draw) rlMatrixMode(RL_PROJECTION); // Switch to projection matrix @@ -1021,14 +1021,6 @@ Matrix GetCameraMatrix(Camera camera) return MatrixLookAt(camera.position, camera.target, camera.up); } -// Update and draw default buffers vertex data -// NOTE: This data has been stored dynamically during frame on each Draw*() call -void DrawDefaultBuffers(void) -{ - rlglUpdateDefaultBuffers(); // Upload frame vertex data to GPU - rlglDrawDefaultBuffers(); // Draw vertex data into framebuffer -} - //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index 6bacfc67..89fc457f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -572,7 +572,6 @@ void EndTextureMode(void); // Ends drawing to r Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) -void DrawDefaultBuffers(void); // Update and draw default buffers vertex data (stored dynamically in frame) void SetTargetFPS(int fps); // Set target FPS (maximum) float GetFPS(void); // Returns current FPS @@ -853,7 +852,6 @@ void DestroyLight(Light light); // Destroy a void InitOculusDevice(void); // Init Oculus Rift device void CloseOculusDevice(void); // Close Oculus Rift device void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void SetOculusView(int eye); // Set internal projection and modelview matrix depending on eyes tracking data void BeginOculusDrawing(void); // Begin Oculus drawing configuration void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) bool IsOculusReady(void); // Detect if oculus device (or simulator) is ready diff --git a/src/rlgl.c b/src/rlgl.c index d3ffdd8b..57e6b894 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -276,9 +276,10 @@ static unsigned int frameIndex = 0; // Oculus frames counter, used to discar static bool oculusReady = false; // Oculus device ready flag static bool oculusSimulator = false; // Oculus device simulator static bool vrEnabled = false; // VR experience enabled (Oculus device or simulator) +static bool vrControl = true; // VR controlled by user code, instead of internally static RenderTexture2D stereoFbo; -static Shader distortion; +static Shader distortionShader; // Compressed textures support flags static bool texCompDXTSupported = false; // DDS texture compression support @@ -315,10 +316,13 @@ 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) -void rlglUpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data -void rlglDrawDefaultBuffers(void); // Draw default internal buffers vertex data +static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data +static void DrawDefaultBuffers(int eyesCount); // Draw default internal buffers vertex data static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU +// Set internal projection and modelview matrix depending on eyes tracking data +static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView); + static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array static char *ReadTextFile(const char *fileName); @@ -1205,15 +1209,14 @@ 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 - rlglUpdateDefaultBuffers(); - rlglDrawDefaultBuffers(); + // NOTE: In a future version, models could be stored in a stack... + //for (int i = 0; i < modelsCount; i++) rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform); + + // NOTE: Default buffers upload and draw + UpdateDefaultBuffers(); + + if (vrEnabled && vrControl) DrawDefaultBuffers(2); + else DrawDefaultBuffers(1); #endif } @@ -1865,26 +1868,23 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int eyesCount = 1; + if (vrEnabled) eyesCount = 2; + glUseProgram(material.shader.id); + // 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); + // 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) @@ -1989,9 +1989,20 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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); + for (int eye = 0; eye < eyesCount; eye++) + { + if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); + + // Calculate model-view-projection matrix (MVP) + Matrix matMVP = MatrixMultiply(modelview, projection); // Transform to screen-space coordinates + + // Send combined model-view-projection matrix to shader + glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + + // 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) { @@ -2016,6 +2027,10 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) } glUseProgram(0); // Unbind shader program + + // Restore projection/modelview matrices + projection = matProjection; + modelview = matView; #endif } @@ -2538,7 +2553,7 @@ void InitOculusDevice(void) // Load oculus-distortion shader (oculus parameters setup internally) // TODO: Embed coulus distortion shader (in this function like default shader?) - distortion = LoadShader("resources/shaders/glsl330/base.vs", "resources/shaders/glsl330/distortion.fs"); + distortionShader = LoadShader("resources/shaders/glsl330/base.vs", "resources/shaders/glsl330/distortion.fs"); oculusSimulator = true; vrEnabled = true; @@ -2564,7 +2579,7 @@ void CloseOculusDevice(void) rlDeleteRenderTextures(stereoFbo); // Unload oculus-distortion shader - UnloadShader(distortion); + UnloadShader(distortionShader); } oculusReady = false; @@ -2615,13 +2630,13 @@ void UpdateOculusTracking(void) } // Set internal projection and modelview matrix depending on eyes tracking data -void SetOculusView(int eye) -{ - Matrix eyeProjection; - Matrix eyeModelView; - +static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView) +{ if (vrEnabled) { + Matrix eyeProjection = matProjection; + Matrix eyeModelView = matModelView; + #if defined(RLGL_OCULUS_SUPPORT) if (oculusReady) { @@ -2639,10 +2654,8 @@ void SetOculusView(int eye) -layer.eyeLayer.RenderPose[eye].Position.z); Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); // Matrix containing eye-head movement - eyeModelView = MatrixMultiply(modelview, eyeView); // Combine internal camera matrix (modelview) wih eye-head movement + eyeModelView = MatrixMultiply(matModelView, eyeView); // Combine internal camera matrix (modelview) wih eye-head movement - // TODO: Find a better way to get camera view matrix (instead of using internal modelview) - eyeProjection = layer.eyeProjections[eye]; } else @@ -2651,28 +2664,43 @@ void SetOculusView(int eye) // Setup viewport and projection/modelview matrices using tracking data rlViewport(eye*screenWidth/2, 0, screenWidth/2, screenHeight); - float hmdIPD = 0.064f; - float hmdHScreenSize = 0.14976f; - float hmdVScreenSize = 0.0936f; - //float hmdVScreenCenter = 0.04675f; - float hmdEyeToScreenDistance = 0.041f; - float hmdLensSeparationDistance = 0.064f; + static float IPD = 0.064f; // InterpupillaryDistance + float HScreenSize = 0.14976f; + float VScreenSize = 0.0936f; // HScreenSize/(1280.0f/800.0f) + float VScreenCenter = 0.04675f; + float EyeToScreenDistance = 0.041f; + float LensSeparationDistance = 0.064f; //0.0635f (DK1) - //NOTE: fovy value hardcoded to 60 degrees (Oculus Rift CV1 vertical FOV is 100 degrees) - //float halfScreenDistance = hmdVScreenSize/2.0f; - //float yfov = 2.0f*atan(halfScreenDistance/hmdEyeToScreenDistance); - - float viewCenter = (float)hmdHScreenSize*0.25f; - float eyeProjectionShift = viewCenter - hmdLensSeparationDistance*0.5f; - float projectionCenterOffset = 4.0f*eyeProjectionShift/(float)hmdHScreenSize; - + // NOTE: fovy value obtained from device parameters (Oculus Rift CV1) + float halfScreenDistance = VScreenSize/2.0f; + float fovy = 2.0f*atan(halfScreenDistance/EyeToScreenDistance)*RAD2DEG; + + float viewCenter = (float)HScreenSize*0.25f; + float eyeProjectionShift = viewCenter - LensSeparationDistance*0.5f; + float projectionCenterOffset = 4.0f*eyeProjectionShift/(float)HScreenSize; +/* + static float scale[2] = { 0.25, 0.45 }; + + if (IsKeyDown(KEY_RIGHT)) scale[0] += 0.01; + else if (IsKeyDown(KEY_LEFT)) scale[0] -= 0.01; + else if (IsKeyDown(KEY_UP)) scale[1] += 0.01; + else if (IsKeyDown(KEY_DOWN)) scale[1] -= 0.01; + SetShaderValue(distortionShader, GetShaderLocation(distortionShader, "Scale"), scale, 2); + + if (IsKeyDown(KEY_N)) IPD += 0.02; + else if (IsKeyDown(KEY_M)) IPD -= 0.02; +*/ // The matrixes for offsetting the projection and view for each eye, to achieve stereo effect Vector3 projectionOffset = { -projectionCenterOffset, 0.0f, 0.0f }; - Vector3 viewOffset = { -hmdIPD/2.0f, 0.0f, 0.0f }; + + // Camera movement might seem more natural if we model the head. + // Our axis of rotation is the base of our head, so we might want to add + // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions. + Vector3 viewOffset = { -IPD/2.0f, 0.075f, 0.045f }; // Negate the left eye versions - if (eye == 1) + if (eye == 0) { projectionOffset.x *= -1.0f; viewOffset.x *= -1.0f; @@ -2680,29 +2708,18 @@ void SetOculusView(int eye) // Adjust the view and projection matrixes // View matrix is translated based on the eye offset - Matrix projCenter = MatrixPerspective(60.0, (double)((float)screenWidth*0.5f)/(double)screenHeight, 0.01, 1000.0); + Matrix projCenter = MatrixPerspective(fovy, (double)((float)screenWidth*0.5f)/(double)screenHeight, 0.01, 1000.0); Matrix projTranslation = MatrixTranslate(projectionOffset.x, projectionOffset.y, projectionOffset.z); Matrix viewTranslation = MatrixTranslate(viewOffset.x, viewOffset.y, viewOffset.z); eyeProjection = MatrixMultiply(projCenter, projTranslation); // projection - eyeModelView = MatrixMultiply(modelview, viewTranslation); // modelview + eyeModelView = MatrixMultiply(matModelView, viewTranslation); // modelview MatrixTranspose(&eyeProjection); - - /* - // NOTE: fovy value hardcoded to 60 degrees (Oculus Rift CV1 vertical FOV is 100 degrees) - eyeProjection = MatrixPerspective(60.0, (double)(screenWidth/2)/(double)screenHeight, 0.01, 1000.0); - MatrixTranspose(&eyeProjection); - - // TODO: Compute eyes IPD and apply to current modelview matrix (camera) - Matrix eyeView = MatrixIdentity(); - - eyeModelView = MatrixMultiply(modelview, eyeView); - */ } - SetMatrixModelview(eyeModelView); + SetMatrixModelview(eyeModelView); // ERROR! We are modifying modelview for next eye!!! SetMatrixProjection(eyeProjection); } } @@ -2738,6 +2755,8 @@ void BeginOculusDrawing(void) //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) rlClearScreenBuffers(); // Clear current framebuffer(s) + + vrControl = true; } // End Oculus drawing process (and desktop mirror) @@ -2777,40 +2796,44 @@ void EndOculusDrawing(void) rlLoadIdentity(); // Reset internal modelview matrix // Draw RenderTexture (stereoFbo) using distortion shader - BeginShaderMode(distortion); + currentShader = distortionShader; - rlEnableTexture(stereoFbo.texture.id); + rlEnableTexture(stereoFbo.texture.id); - rlPushMatrix(); - rlBegin(RL_QUADS); - rlColor4ub(255, 255, 255, 255); - rlNormal3f(0.0f, 0.0f, 1.0f); + rlPushMatrix(); + rlBegin(RL_QUADS); + rlColor4ub(255, 255, 255, 255); + rlNormal3f(0.0f, 0.0f, 1.0f); - // Bottom-left corner for texture and quad - rlTexCoord2f(0.0f, 1.0f); - rlVertex2f(0.0f, 0.0f); + // Bottom-left corner for texture and quad + rlTexCoord2f(0.0f, 1.0f); + rlVertex2f(0.0f, 0.0f); - // Bottom-right corner for texture and quad - rlTexCoord2f(0.0f, 0.0f); - rlVertex2f(0.0f, stereoFbo.texture.height); + // Bottom-right corner for texture and quad + rlTexCoord2f(0.0f, 0.0f); + rlVertex2f(0.0f, stereoFbo.texture.height); - // Top-right corner for texture and quad - rlTexCoord2f(1.0f, 0.0f); - rlVertex2f(stereoFbo.texture.width, stereoFbo.texture.height); + // Top-right corner for texture and quad + rlTexCoord2f(1.0f, 0.0f); + rlVertex2f(stereoFbo.texture.width, stereoFbo.texture.height); - // Top-left corner for texture and quad - rlTexCoord2f(1.0f, 1.0f); - rlVertex2f(stereoFbo.texture.width, 0.0f); - rlEnd(); - rlPopMatrix(); + // Top-left corner for texture and quad + rlTexCoord2f(1.0f, 1.0f); + rlVertex2f(stereoFbo.texture.width, 0.0f); + rlEnd(); + rlPopMatrix(); - rlDisableTexture(); - - //rlglDraw(); - EndShaderMode(); + rlDisableTexture(); + + UpdateDefaultBuffers(); + DrawDefaultBuffers(1); + + currentShader = defaultShader; } rlDisableDepthTest(); + + vrControl = false; } //---------------------------------------------------------------------------------- @@ -3303,7 +3326,7 @@ static void LoadDefaultBuffers(void) // Update default internal buffers (VAOs/VBOs) with vertex array data // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) -void rlglUpdateDefaultBuffers(void) +static void UpdateDefaultBuffers(void) { // Update lines vertex buffers if (lines.vCounter > 0) @@ -3373,146 +3396,154 @@ void rlglUpdateDefaultBuffers(void) // Draw default internal buffers vertex data // NOTE: We draw in this order: lines, triangles, quads -void rlglDrawDefaultBuffers(void) +static void DrawDefaultBuffers(int eyesCount) { - // Set current shader and upload current MVP matrix - if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) - { - glUseProgram(currentShader.id); - - // Create modelview-projection matrix - Matrix matMVP = MatrixMultiply(modelview, projection); - - glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); - glUniform1i(currentShader.mapTexture0Loc, 0); - - // NOTE: Additional map textures not considered for default buffers drawing - } - - // Draw lines buffers - if (lines.vCounter > 0) + Matrix matProjection = projection; + Matrix matModelView = modelview; + + for (int eye = 0; eye < eyesCount; eye++) { - glBindTexture(GL_TEXTURE_2D, whiteTexture); + if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); - if (vaoSupported) + // Set current shader and upload current MVP matrix + if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) { - glBindVertexArray(lines.vaoId); + glUseProgram(currentShader.id); + + // Create modelview-projection matrix + Matrix matMVP = MatrixMultiply(modelview, projection); + + glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); + glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1i(currentShader.mapTexture0Loc, 0); + + // NOTE: Additional map textures not considered for default buffers drawing } - else + + // Draw lines buffers + if (lines.vCounter > 0) { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - } + glBindTexture(GL_TEXTURE_2D, whiteTexture); - glDrawArrays(GL_LINES, 0, lines.vCounter); - - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } + if (vaoSupported) + { + glBindVertexArray(lines.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } - // Draw triangles buffers - if (triangles.vCounter > 0) - { - glBindTexture(GL_TEXTURE_2D, whiteTexture); + glDrawArrays(GL_LINES, 0, lines.vCounter); - if (vaoSupported) - { - glBindVertexArray(triangles.vaoId); - } - else - { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); } - glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); + // Draw triangles buffers + if (triangles.vCounter > 0) + { + glBindTexture(GL_TEXTURE_2D, whiteTexture); - if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - } + if (vaoSupported) + { + glBindVertexArray(triangles.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[1]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + } - // Draw quads buffers - if (quads.vCounter > 0) - { - int quadsCount = 0; - int numIndicesToProcess = 0; - int indicesOffset = 0; + glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter); - if (vaoSupported) - { - glBindVertexArray(quads.vaoId); + if (!vaoSupported) glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); } - else + + // Draw quads buffers + if (quads.vCounter > 0) { - // Bind vertex attrib: position (shader-location = 0) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); - glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.vertexLoc); - - // Bind vertex attrib: texcoord (shader-location = 1) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); - glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); - glEnableVertexAttribArray(currentShader.texcoordLoc); - - // Bind vertex attrib: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); - glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); - glEnableVertexAttribArray(currentShader.colorLoc); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); - } + int quadsCount = 0; + int numIndicesToProcess = 0; + int indicesOffset = 0; - //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); + if (vaoSupported) + { + glBindVertexArray(quads.vaoId); + } + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); + glVertexAttribPointer(currentShader.vertexLoc, 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.vertexLoc); + + // Bind vertex attrib: texcoord (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[1]); + glVertexAttribPointer(currentShader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(currentShader.texcoordLoc); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); + glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(currentShader.colorLoc); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); + } - for (int i = 0; i < drawsCounter; i++) - { - quadsCount = draws[i].vertexCount/4; - numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad + //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter); - //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); + for (int i = 0; i < drawsCounter; i++) + { + quadsCount = draws[i].vertexCount/4; + numIndicesToProcess = quadsCount*6; // Get number of Quads * 6 index by Quad - glBindTexture(GL_TEXTURE_2D, draws[i].textureId); + //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount); - // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process -#if defined(GRAPHICS_API_OPENGL_33) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); -#elif defined(GRAPHICS_API_OPENGL_ES2) - glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); -#endif - //GLenum err; - //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! + glBindTexture(GL_TEXTURE_2D, draws[i].textureId); - indicesOffset += draws[i].vertexCount/4*6; - } + // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process + #if defined(GRAPHICS_API_OPENGL_33) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*indicesOffset)); + #elif defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_SHORT, (GLvoid *)(sizeof(GLushort)*indicesOffset)); + #endif + //GLenum err; + //if ((err = glGetError()) != GL_NO_ERROR) TraceLog(INFO, "OpenGL error: %i", (int)err); //GL_INVALID_ENUM! - if (!vaoSupported) - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + indicesOffset += draws[i].vertexCount/4*6; + } - glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures - } + if (!vaoSupported) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } - if (vaoSupported) glBindVertexArray(0); // Unbind VAO + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } - glUseProgram(0); // Unbind shader program + if (vaoSupported) glBindVertexArray(0); // Unbind VAO + glUseProgram(0); // Unbind shader program + } + // Reset draws counter drawsCounter = 1; draws[0].textureId = whiteTexture; @@ -3529,6 +3560,10 @@ void rlglDrawDefaultBuffers(void) // Reset depth for next draw currentDepth = -1.0f; + + // Restore projection/modelview matrices + projection = matProjection; + modelview = matModelView; } // Unload default internal buffers vertex data from CPU and GPU diff --git a/src/rlgl.h b/src/rlgl.h index 675bb74f..f52af6f9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -303,9 +303,6 @@ void rlglClose(void); // De-init rlgl void rlglDraw(void); // Draw VAO/VBO void rlglLoadExtensions(void *loader); // Load OpenGL extensions -void rlglUpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data -void rlglDrawDefaultBuffers(void); // Draw default internal buffers vertex data - unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU 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 @@ -358,7 +355,6 @@ void TraceLog(int msgType, const char *text, ...); void InitOculusDevice(void); // Init Oculus Rift device void CloseOculusDevice(void); // Close Oculus Rift device void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void SetOculusView(int eye); // Set internal projection and modelview matrix depending on eyes tracking data void BeginOculusDrawing(void); // Begin Oculus drawing configuration void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) bool IsOculusReady(void); // Detect if oculus device (or simulator) is ready -- cgit v1.2.3 From bc80174357392c0a16b74cd4a9e497a1de367760 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 6 Jul 2016 00:54:38 +0200 Subject: VR Functions renaming (for generic HMD device) Stereo rendering has been moved again to Begin3dMode() and End3dMode(), it has some limitations but makes more sense... --- examples/core_oculus_rift.c | 19 ++++++++----------- src/core.c | 8 ++++---- src/raylib.h | 29 +++++++++++++++++++++-------- src/rlgl.c | 45 +++++++++++++++++++++++---------------------- src/rlgl.h | 16 ++++++++-------- 5 files changed, 64 insertions(+), 53 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index 734ba8fd..fa70c487 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -23,7 +23,8 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - oculus rift"); - InitOculusDevice(); + // NOTE: If device is not available, it fallbacks to default device (simulator) + InitVrDevice(HMD_OCULUS_RIFT_CV1); // Init VR device (Oculus Rift CV1) // Define the camera to look into our 3d world Camera camera; @@ -42,9 +43,9 @@ int main() { // Update //---------------------------------------------------------------------------------- - UpdateOculusTracking(); + UpdateVrTracking(); - if (IsKeyPressed(KEY_SPACE)) ToggleVR(); + if (IsKeyPressed(KEY_SPACE)) ToggleVrMode(); //---------------------------------------------------------------------------------- // Draw @@ -52,20 +53,16 @@ int main() BeginDrawing(); ClearBackground(RAYWHITE); - - if (IsOculusReady()) BeginOculusDrawing(); Begin3dMode(camera); DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - + DrawGrid(10, 1.0f); - + End3dMode(); - - if (IsOculusReady()) EndOculusDrawing(); - + DrawFPS(10, 10); EndDrawing(); @@ -74,7 +71,7 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - CloseOculusDevice(); // Close Oculus Rift device + CloseVrDevice(); // Close VR device CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- diff --git a/src/core.c b/src/core.c index f8a83e25..107fc0a0 100644 --- a/src/core.c +++ b/src/core.c @@ -521,8 +521,6 @@ void BeginDrawing(void) updateTime = currentTime - previousTime; previousTime = currentTime; - //if (IsOculusReady()) BeginOculusDrawing(); - rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here @@ -535,8 +533,6 @@ void BeginDrawing(void) void EndDrawing(void) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - - //if (IsOculusReady()) EndOculusDrawing(); SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events @@ -590,6 +586,8 @@ void End2dMode(void) void Begin3dMode(Camera camera) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) + + if (IsVrDeviceReady()) BeginVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix @@ -618,6 +616,8 @@ void Begin3dMode(Camera camera) void End3dMode(void) { rlglDraw(); // Process internal buffers (update + draw) + + if (IsVrDeviceReady()) EndVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack diff --git a/src/raylib.h b/src/raylib.h index 89fc457f..227f83f2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -527,6 +527,19 @@ typedef struct GestureEvent { // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; +// Head Mounted Display devices +typedef enum { + HMD_DEFAULT_DEVICE = 0, + HMD_OCULUS_RIFT_DK2, + HMD_OCULUS_RIFT_CV1, + HMD_VALVE_HTC_VIVE, + HMD_SAMSUNG_GEAR_VR, + HMD_GOOGLE_CARDBOARD, + HMD_SONY_PLAYSTATION_VR, + HMD_RAZER_OSVR, + HMD_FOVE_VR, +} HmdDevice; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -846,16 +859,16 @@ Light CreateLight(int type, Vector3 position, Color diffuse); // Create a void DestroyLight(Light light); // Destroy a light and take it out of the list //------------------------------------------------------------------------------------ -// Oculus Rift CV1 Functions (Module: rlgl) +// VR experience Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ -void InitOculusDevice(void); // Init Oculus Rift device -void CloseOculusDevice(void); // Close Oculus Rift device -void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void BeginOculusDrawing(void); // Begin Oculus drawing configuration -void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) -bool IsOculusReady(void); // Detect if oculus device (or simulator) is ready -void ToggleVR(void); // Enable/Disable VR experience (Oculus device or simulator) +void InitVrDevice(int hmdDevice); // Init VR device +void CloseVrDevice(void); // Close VR device +void UpdateVrTracking(void); // Update VR tracking (position and orientation) +void BeginVrDrawing(void); // Begin VR drawing configuration +void EndVrDrawing(void); // End VR drawing process (and desktop mirror) +bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) diff --git a/src/rlgl.c b/src/rlgl.c index af2d57cb..a71142b0 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -322,7 +322,7 @@ static void DrawDefaultBuffers(int eyesCount); // Draw default internal buffers static void UnloadDefaultBuffers(void); // Unload default internal buffers vertex data from CPU and GPU // Set internal projection and modelview matrix depending on eyes tracking data -static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView); +static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array @@ -2001,7 +2001,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) for (int eye = 0; eye < eyesCount; eye++) { - if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); + if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); else modelview = matModelView; // Calculate model-view-projection matrix (MVP) @@ -2504,8 +2504,9 @@ void DestroyLight(Light light) #endif } -// Init Oculus Rift device (or Oculus device simulator) -void InitOculusDevice(void) +// Init VR device (or simulator) +// NOTE: If device is not available, it fallbacks to default device (simulator) +void InitVrDevice(int hmdDevice) { #if defined(RLGL_OCULUS_SUPPORT) // Initialize Oculus device @@ -2557,7 +2558,7 @@ void InitOculusDevice(void) if (!oculusReady) { - TraceLog(WARNING, "VR: Initializing Oculus simulator"); + TraceLog(WARNING, "HMD Device not found: Initializing VR simulator"); // Initialize framebuffer and textures for stereo rendering stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight); @@ -2571,8 +2572,8 @@ void InitOculusDevice(void) } } -// Close Oculus Rift device (or Oculus device simulator) -void CloseOculusDevice(void) +// Close VR device (or simulator) +void CloseVrDevice(void) { #if defined(RLGL_OCULUS_SUPPORT) if (oculusReady) @@ -2596,20 +2597,20 @@ void CloseOculusDevice(void) oculusReady = false; } -// Detect if oculus device is available -bool IsOculusReady(void) +// Detect if VR device is available +bool IsVrDeviceReady(void) { return (oculusReady || oculusSimulator) && vrEnabled; } -// Enable/Disable VR experience (Oculus device or simulator) -void ToggleVR(void) +// Enable/Disable VR experience (device or simulator) +void ToggleVrMode(void) { vrEnabled = !vrEnabled; } -// Update Oculus Rift tracking (position and orientation) -void UpdateOculusTracking(void) +// Update VR tracking (position and orientation) +void UpdateVrTracking(void) { #if defined(RLGL_OCULUS_SUPPORT) if (oculusReady) @@ -2641,7 +2642,7 @@ void UpdateOculusTracking(void) } // Set internal projection and modelview matrix depending on eyes tracking data -static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView) +static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) { if (vrEnabled) { @@ -2675,12 +2676,12 @@ static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView) // Setup viewport and projection/modelview matrices using tracking data rlViewport(eye*screenWidth/2, 0, screenWidth/2, screenHeight); - static float IPD = 0.064f; // InterpupillaryDistance + static float IPD = 0.064f; // InterpupillaryDistance float HScreenSize = 0.14976f; - float VScreenSize = 0.0936f; // HScreenSize/(1280.0f/800.0f) - float VScreenCenter = 0.04675f; + float VScreenSize = 0.0936f; // HScreenSize/(1280.0f/800.0f) (DK2) + float VScreenCenter = 0.04675f; // VScreenSize/2 float EyeToScreenDistance = 0.041f; - float LensSeparationDistance = 0.064f; //0.0635f (DK1) + float LensSeparationDistance = 0.064f; //0.0635f (DK1) // NOTE: fovy value obtained from device parameters (Oculus Rift CV1) float halfScreenDistance = VScreenSize/2.0f; @@ -2730,13 +2731,13 @@ static void SetOculusView(int eye, Matrix matProjection, Matrix matModelView) MatrixTranspose(&eyeProjection); } - SetMatrixModelview(eyeModelView); // ERROR! We are modifying modelview for next eye!!! + SetMatrixModelview(eyeModelView); SetMatrixProjection(eyeProjection); } } // Begin Oculus drawing configuration -void BeginOculusDrawing(void) +void BeginVrDrawing(void) { #if defined(RLGL_OCULUS_SUPPORT) if (oculusReady) @@ -2771,7 +2772,7 @@ void BeginOculusDrawing(void) } // End Oculus drawing process (and desktop mirror) -void EndOculusDrawing(void) +void EndVrDrawing(void) { #if defined(RLGL_OCULUS_SUPPORT) if (oculusReady) @@ -3414,7 +3415,7 @@ static void DrawDefaultBuffers(int eyesCount) for (int eye = 0; eye < eyesCount; eye++) { - if (eyesCount == 2) SetOculusView(eye, matProjection, matModelView); + if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); // Set current shader and upload current MVP matrix if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) diff --git a/src/rlgl.h b/src/rlgl.h index f52af6f9..f984c0c6 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -350,15 +350,15 @@ Light CreateLight(int type, Vector3 position, Color diffuse); // Create a void DestroyLight(Light light); // Destroy a light and take it out of the list void TraceLog(int msgType, const char *text, ...); -#endif -void InitOculusDevice(void); // Init Oculus Rift device -void CloseOculusDevice(void); // Close Oculus Rift device -void UpdateOculusTracking(void); // Update Oculus Rift tracking (position and orientation) -void BeginOculusDrawing(void); // Begin Oculus drawing configuration -void EndOculusDrawing(void); // End Oculus drawing process (and desktop mirror) -bool IsOculusReady(void); // Detect if oculus device (or simulator) is ready -void ToggleVR(void); // Enable/Disable VR experience (Oculus device or simulator) +void InitVrDevice(int hmdDevice); // Init VR device +void CloseVrDevice(void); // Close VR device +void UpdateVrTracking(void); // Update VR tracking (position and orientation) +void BeginVrDrawing(void); // Begin VR drawing configuration +void EndVrDrawing(void); // End VR drawing process (and desktop mirror) +bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) +#endif #ifdef __cplusplus } -- cgit v1.2.3 From 7cefbd8a947551f6c63dba88117099d6c0f4998b Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 6 Jul 2016 20:33:46 +0200 Subject: Updated lighting system... ...to avoid dynamic conditions on for loop (lightsCount) on standard shader, it seems GLSL 100 doesn't support that feature... on some GPUs like RaspberryPi... --- src/raylib.h | 2 +- src/rlgl.c | 196 +++++++++++++++++++++++++++----------------------- src/rlgl.h | 4 +- src/standard_shader.h | 3 +- 4 files changed, 109 insertions(+), 96 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 227f83f2..1d160492 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -431,8 +431,8 @@ typedef struct Model { // Light type typedef struct LightData { unsigned int id; // Light unique id - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; // Light enabled + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT Vector3 position; // Light position Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) diff --git a/src/rlgl.c b/src/rlgl.c index 089e2809..aa729824 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -260,7 +260,7 @@ static bool texCompASTCSupported = false; // ASTC texture compression support // Lighting data static Light lights[MAX_LIGHTS]; // Lights pool -static int lightsCount; // Enabled lights counter +static int lightsCount = 0; // Enabled lights counter #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -2454,24 +2454,28 @@ Light CreateLight(int type, Vector3 position, Color diffuse) Light light = NULL; #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Allocate dynamic memory - 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++; + if (lightsCount < MAX_LIGHTS) + { + // Allocate dynamic memory + 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++; + } + else TraceLog(WARNING, "Too many lights, only supported up to %i lights", MAX_LIGHTS); #else // TODO: Support OpenGL 1.1 lighting system TraceLog(WARNING, "Lighting currently not supported on OpenGL 1.1"); @@ -2484,23 +2488,26 @@ Light CreateLight(int type, Vector3 position, Color diffuse) void DestroyLight(Light light) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // Free dynamic memory allocation - free(lights[light->id]); - - // Remove *obj from the pointers array - for (int i = light->id; i < lightsCount; i++) + if (light != NULL) { - // Resort all the following pointers of the array - if ((i + 1) < lightsCount) + // Free dynamic memory allocation + free(lights[light->id]); + + // Remove *obj from the pointers array + for (int i = light->id; i < lightsCount; i++) { - lights[i] = lights[i + 1]; - lights[i]->id = lights[i + 1]->id; + // 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]); } - else free(lights[i]); + + // Decrease enabled physic objects count + lightsCount--; } - - // Decrease enabled physic objects count - lightsCount--; #endif } @@ -3625,72 +3632,79 @@ static void UnloadDefaultBuffers(void) // 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); - + int locPoint = -1; char locName[32] = "lights[x].position\0"; - for (int i = 0; i < lightsCount; i++) + for (int i = 0; i < MAX_LIGHTS; 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) + + if (lights[i] != NULL) // Only upload registered lights data { - 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], "radius\0", strlen("radius\0") + 2); - locPoint = GetShaderLocation(shader, locName); - glUniform1f(locPoint, lights[i]->radius); - } 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], "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) { - 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; + 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], "radius\0", strlen("radius\0") + 2); + locPoint = GetShaderLocation(shader, locName); + glUniform1f(locPoint, lights[i]->radius); + } 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 + } + else // Not enabled lights + { + memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); + locPoint = GetShaderLocation(shader, locName); + glUniform1i(locPoint, 0); } - - // TODO: Pass to the shader any other required data from LightData struct } } diff --git a/src/rlgl.h b/src/rlgl.h index f984c0c6..9afafc52 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -218,9 +218,9 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Light type typedef struct LightData { unsigned int id; // Light unique id - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT bool enabled; // Light enabled - + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + Vector3 position; // Light position Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) float radius; // Light attenuation radius light intensity reduced with distance (world distance) diff --git a/src/standard_shader.h b/src/standard_shader.h index e1668ae7..deae7fe1 100644 --- a/src/standard_shader.h +++ b/src/standard_shader.h @@ -78,7 +78,6 @@ static const char fStandardShaderStr[] = " float radius; \n" " float coneAngle; }; \n" "const int maxLights = 8; \n" -"uniform int lightsCount; \n" "uniform Light lights[maxLights]; \n" "\n" "vec3 CalcPointLight(Light l, vec3 n, vec3 v, float s) \n" @@ -157,7 +156,7 @@ static const char fStandardShaderStr[] = #elif defined(GRAPHICS_API_OPENGL_33) " if (useSpecular == 1) spec *= normalize(texture(texture2, fragTexCoord).r);\n" #endif -" for (int i = 0; i < lightsCount; i++)\n" +" for (int i = 0; i < maxLights; i++)\n" " {\n" " if (lights[i].enabled == 1)\n" " {\n" -- cgit v1.2.3 From 17331258738229ca087437c31bbfc3c9495fe42e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 8 Jul 2016 23:17:18 +0200 Subject: Do not expose raw audio context to final user... ...at least, directly, available if using directly audio module... --- src/audio.h | 4 ++-- src/raylib.h | 11 ++--------- 2 files changed, 4 insertions(+), 11 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.h b/src/audio.h index fe72d866..3ffe575c 100644 --- a/src/audio.h +++ b/src/audio.h @@ -100,10 +100,10 @@ void PauseMusicStream(int index); // Pause music p 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) +void SetMusicPitch(int index, float pitch); // Set pitch for a music (1.0 is base 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); +int GetMusicStreamCount(void); // Get number of streams loaded // 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 diff --git a/src/raylib.h b/src/raylib.h index 1d160492..9225c5ee 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -895,17 +895,10 @@ void PauseMusicStream(int index); // Pause music p 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) +void SetMusicPitch(int index, float pitch); // Set pitch for a music (1.0 is base 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, unsigned short numberElements); // returns number of elements buffered +int GetMusicStreamCount(void); // Get number of streams loaded #ifdef __cplusplus } -- cgit v1.2.3 From 7959ccd84dd9eedd7aad10fe8b6bea988f828f40 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Fri, 15 Jul 2016 18:16:34 +0200 Subject: Review some functions, formatting and comments --- src/audio.c | 240 ++++++++++++++++++++++++++++++++--------------------------- src/audio.h | 31 +++++--- src/raylib.h | 2 - 3 files changed, 148 insertions(+), 125 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 2941b9fb..38fefd12 100644 --- a/src/audio.c +++ b/src/audio.c @@ -2,13 +2,26 @@ * * raylib.audio * -* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles +* Basic functions to manage Audio: +* Manage audio device (init/close) +* Load and Unload audio files +* Play/Stop/Pause/Resume loaded audio +* Manage mixing channels +* Manage raw audio context * * Uses external lib: * OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) * stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) +* jar_xm - XM module file loading +* jar_mod - MOD audio file loading * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: +* XM audio module support (jar_xm) +* MOD audio module support (jar_mod) +* Mixing channels support +* Raw audio context support +* +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -68,9 +81,9 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_STREAM_BUFFERS 2 // Number of buffers for each alSource -#define MAX_MIX_CHANNELS 4 // Number of OpenAL sources +#define MAX_STREAM_BUFFERS 2 // Number of buffers for each source #define MAX_MUSIC_STREAMS 2 // Number of simultanious music sources +#define MAX_MIX_CHANNELS 4 // Number of mix channels (OpenAL sources) #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) // NOTE: On RPI and Android should be lower to avoid frame-stalls @@ -143,7 +156,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; // Global Variables Definition //---------------------------------------------------------------------------------- static Music musicStreams[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time -static MixChannel *mixChannels[MAX_MIX_CHANNELS]; // What mix channels are currently active +static MixChannel *mixChannels[MAX_MIX_CHANNELS]; // Mix channels currently active (from music streams) static int lastAudioError = 0; // Registers last audio error @@ -157,13 +170,11 @@ static void UnloadWave(Wave wave); // Unload wave data static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data static void EmptyMusicStream(int index); // Empty music buffers -static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels. +static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); static void CloseMixChannel(MixChannel *mixc); // Frees mix channel -static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses -static int FillAlBufferWithSilence(MixChannel *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 +static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements); // Pushes more audio data into mix channel +//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 #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename @@ -204,7 +215,7 @@ void InitAudioDevice(void) // Close the audio device for all contexts void CloseAudioDevice(void) { - for (int index=0; index= MAX_MIX_CHANNELS) return NULL; @@ -280,7 +291,20 @@ static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixCh alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); // Fill buffers - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) FillAlBufferWithSilence(mixc, mixc->alBuffer[i]); + for (int i = 0; i < MAX_STREAM_BUFFERS; i++) + { + // Initialize buffer with zeros by default + if (mixc->floatingPoint) + { + float pcm[MUSIC_BUFFER_SIZE_FLOAT] = { 0.0f }; + alBufferData(mixc->alBuffer[i], mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), mixc->sampleRate); + } + else + { + short pcm[MUSIC_BUFFER_SIZE_SHORT] = { 0 }; + alBufferData(mixc->alBuffer[i], mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate); + } + } alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer); mixc->playing = true; @@ -320,9 +344,9 @@ static void CloseMixChannel(MixChannel *mixc) } } -// Pushes more audio data into mixc mix channel, only one buffer per call +// Pushes more audio data into 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. +// Returns number of samples that where processed. static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements) { if (!mixc || (mixChannels[mixc->mixChannel] != mixc)) return 0; // When there is two channels there must be an even number of samples @@ -368,28 +392,11 @@ static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements) return numberElements; } -// fill buffer with zeros, returns number processed -static int FillAlBufferWithSilence(MixChannel *mixc, ALuint buffer) -{ - if (mixc->floatingPoint) - { - float pcm[MUSIC_BUFFER_SIZE_FLOAT] = { 0.0f }; - 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, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate); - - return MUSIC_BUFFER_SIZE_SHORT; - } -} - +/* +// Convert data from short to float // example usage: -// short sh[3] = {1,2,3};float fl[3]; -// ResampleShortToFloat(sh,fl,3); +// short sh[3] = {1,2,3};float fl[3]; +// ResampleShortToFloat(sh,fl,3); static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len) { for (int i = 0; i < len; i++) @@ -399,9 +406,10 @@ static void ResampleShortToFloat(short *shorts, float *floats, unsigned short le } } +// Convert data from float to short // example usage: -// char ch[3] = {1,2,3};float fl[3]; -// ResampleByteToFloat(ch,fl,3); +// char ch[3] = {1,2,3};float fl[3]; +// ResampleByteToFloat(ch,fl,3); static void ResampleByteToFloat(char *chars, float *floats, unsigned short len) { for (int i = 0; i < len; i++) @@ -410,43 +418,55 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len) else floats[i] = (float)chars[i]/128.0f; } } +*/ -// used to output raw audio streams, returns negative numbers on error, + number represents the mix channel index -// if floating point is false the data size is 16bit short, otherwise it is float 32bit -RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint) +// Initialize raw audio mix channel for audio buffering +// NOTE: Returns mix channel index or -1 if it fails (errors are registered on lastAudioError) +int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint) { int mixIndex; + for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { if (mixChannels[mixIndex] == NULL) break; - else if (mixIndex == (MAX_MIX_CHANNELS - 1)) return ERROR_OUT_OF_MIX_CHANNELS; // error + else if (mixIndex == (MAX_MIX_CHANNELS - 1)) + { + lastAudioError = ERROR_OUT_OF_MIX_CHANNELS; + return -1; + } } if (InitMixChannel(sampleRate, mixIndex, channels, floatingPoint)) return mixIndex; - else return ERROR_RAW_CONTEXT_CREATION; // error -} - -void CloseRawAudioContext(RawAudioContext ctx) -{ - if (mixChannels[ctx]) CloseMixChannel(mixChannels[ctx]); + else + { + lastAudioError = ERROR_RAW_CONTEXT_CREATION; + return -1; + } } -// if 0 is returned, the buffers are still full and you need to keep trying with the same data until a + number is returned. -// any + number returned is the number of samples that was processed and passed into buffer. -// data either needs to be array of floats or shorts. -int BufferRawAudioContext(RawAudioContext ctx, void *data, unsigned short numberElements) +// Buffers data directly to raw mix channel +// if 0 is returned, buffers are still full and you need to keep trying with the same data +// otherwise it will return number of samples buffered. +// NOTE: Data could be either be an array of floats or shorts, depending on the created context +int BufferRawAudioContext(int ctx, void *data, unsigned short numberElements) { int numBuffered = 0; if (ctx >= 0) { - MixChannel* mixc = mixChannels[ctx]; + MixChannel *mixc = mixChannels[ctx]; numBuffered = BufferMixChannel(mixc, data, numberElements); } return numBuffered; } +// Closes and frees raw mix channel +void CloseRawAudioContext(int ctx) +{ + if (mixChannels[ctx]) CloseMixChannel(mixChannels[ctx]); +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- @@ -804,7 +824,7 @@ void SetSoundPitch(Sound sound, float pitch) //---------------------------------------------------------------------------------- // Start music playing (open stream) -// returns 0 on success +// returns 0 on success or error code int PlayMusicStream(int index, char *fileName) { int mixIndex; @@ -866,7 +886,7 @@ int PlayMusicStream(int index, char *fileName) musicStreams[index].loop = true; jar_xm_set_max_loop_count(musicStreams[index].xmctx, 0); // infinite number of loops musicStreams[index].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicStreams[index].xmctx); - musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft) / 48000.f; + musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft)/48000.0f; musicStreams[index].enabled = true; TraceLog(INFO, "[%s] XM number of samples: %i", fileName, musicStreams[index].totalSamplesLeft); @@ -893,7 +913,7 @@ int PlayMusicStream(int index, char *fileName) musicStreams[index].chipTune = true; musicStreams[index].loop = true; musicStreams[index].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicStreams[index].modctx); - musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft) / 48000.f; + musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft)/48000.0f; musicStreams[index].enabled = true; TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, musicStreams[index].totalSamplesLeft); @@ -944,6 +964,51 @@ void StopMusicStream(int index) } } +// Update (re-fill) music buffers if data already processed +void UpdateMusicStream(int index) +{ + ALenum state; + bool active = true; + ALint processed = 0; + + // Determine if music stream is ready to be written + alGetSourcei(musicStreams[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + + if (musicStreams[index].mixc->playing && (index < MAX_MUSIC_STREAMS) && musicStreams[index].enabled && musicStreams[index].mixc && (processed > 0)) + { + active = BufferMusicStream(index, processed); + + if (!active && musicStreams[index].loop) + { + if (musicStreams[index].chipTune) + { + if(musicStreams[index].modctx.mod_loaded) jar_mod_seek_start(&musicStreams[index].modctx); + + musicStreams[index].totalSamplesLeft = musicStreams[index].totalLengthSeconds*48000.0f; + } + else + { + stb_vorbis_seek_start(musicStreams[index].stream); + musicStreams[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicStreams[index].stream)*musicStreams[index].mixc->channels; + } + + // Determine if music stream is ready to be written + alGetSourcei(musicStreams[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + + active = BufferMusicStream(index, processed); + } + + if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); + + alGetSourcei(musicStreams[index].mixc->alSource, AL_SOURCE_STATE, &state); + + if (state != AL_PLAYING && active) alSourcePlay(musicStreams[index].mixc->alSource); + + if (!active) StopMusicStream(index); + + } +} + //get number of music channels active at this time, this does not mean they are playing int GetMusicStreamCount(void) { @@ -1045,18 +1110,18 @@ float GetMusicTimePlayed(int index) { uint64_t samples; jar_xm_get_position(musicStreams[index].xmctx, NULL, NULL, NULL, &samples); - secondsPlayed = (float)samples / (48000.f * musicStreams[index].mixc->channels); // Not sure if this is the correct value + secondsPlayed = (float)samples/(48000.0f*musicStreams[index].mixc->channels); // Not sure if this is the correct value } else if(musicStreams[index].chipTune && musicStreams[index].modctx.mod_loaded) { long numsamp = jar_mod_current_samples(&musicStreams[index].modctx); - secondsPlayed = (float)numsamp / (48000.f); + secondsPlayed = (float)numsamp/(48000.0f); } else { - int totalSamples = stb_vorbis_stream_length_in_samples(musicStreams[index].stream) * musicStreams[index].mixc->channels; + int totalSamples = stb_vorbis_stream_length_in_samples(musicStreams[index].stream)*musicStreams[index].mixc->channels; int samplesPlayed = totalSamples - musicStreams[index].totalSamplesLeft; - secondsPlayed = (float)samplesPlayed / (musicStreams[index].mixc->sampleRate * musicStreams[index].mixc->channels); + secondsPlayed = (float)samplesPlayed/(musicStreams[index].mixc->sampleRate*musicStreams[index].mixc->channels); } } @@ -1144,53 +1209,6 @@ static void EmptyMusicStream(int index) } } -// Determine if a music stream is ready to be written -static int IsMusicStreamReadyForBuffering(int index) -{ - ALint processed = 0; - alGetSourcei(musicStreams[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; - int numBuffers = IsMusicStreamReadyForBuffering(index); - - if (musicStreams[index].mixc->playing && (index < MAX_MUSIC_STREAMS) && musicStreams[index].enabled && musicStreams[index].mixc && numBuffers) - { - active = BufferMusicStream(index, numBuffers); - - if (!active && musicStreams[index].loop) - { - if (musicStreams[index].chipTune) - { - if(musicStreams[index].modctx.mod_loaded) jar_mod_seek_start(&musicStreams[index].modctx); - - musicStreams[index].totalSamplesLeft = musicStreams[index].totalLengthSeconds * 48000.f; - } - else - { - stb_vorbis_seek_start(musicStreams[index].stream); - musicStreams[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicStreams[index].stream) * musicStreams[index].mixc->channels; - } - - active = BufferMusicStream(index, IsMusicStreamReadyForBuffering(index)); - } - - if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); - - alGetSourcei(musicStreams[index].mixc->alSource, AL_SOURCE_STATE, &state); - - if (state != AL_PLAYING && active) alSourcePlay(musicStreams[index].mixc->alSource); - - if (!active) StopMusicStream(index); - - } -} - // Load WAV file into Wave structure static Wave LoadWAV(const char *fileName) { diff --git a/src/audio.h b/src/audio.h index 3ffe575c..f4a82a55 100644 --- a/src/audio.h +++ b/src/audio.h @@ -2,13 +2,26 @@ * * raylib.audio * -* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles +* Basic functions to manage Audio: +* Manage audio device (init/close) +* Load and Unload audio files +* Play/Stop/Pause/Resume loaded audio +* Manage mixing channels +* Manage raw audio context * * Uses external lib: * OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) * stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) +* jar_xm - XM module file loading +* jar_mod - MOD audio file loading * -* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: +* XM audio module support (jar_xm) +* MOD audio module support (jar_mod) +* Mixing channels support +* Raw audio context support +* +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -63,9 +76,6 @@ typedef struct Wave { short channels; } Wave; -typedef int RawAudioContext; - - #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -80,7 +90,7 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool IsAudioDeviceReady(void); // Check if device has been initialized successfully Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -105,12 +115,9 @@ float GetMusicTimeLength(int index); // Get music tim float GetMusicTimePlayed(int index); // Get current music time played (in seconds) int GetMusicStreamCount(void); // Get number of streams loaded -// 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, unsigned short numberElements); // returns number of elements buffered +int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint); // Initialize raw audio mix channel for audio buffering +int BufferRawMixChannel(int mixc, void *data, unsigned short numberElements); // Buffers data directly to raw mix channel +void CloseRawMixChannel(int mixc); // Closes and frees raw mix channel #ifdef __cplusplus } diff --git a/src/raylib.h b/src/raylib.h index 9225c5ee..e3a17ebb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -468,8 +468,6 @@ typedef struct Wave { short channels; } Wave; -typedef int RawAudioContext; - // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { -- cgit v1.2.3 From 5ff9811ea8ece7adb8e999a0beb063a678b502d0 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 18 Jul 2016 17:06:33 +0200 Subject: Some code tweaks --- src/raylib.h | 32 +++++++++++++++++++------------- src/rlgl.c | 11 ++++++----- src/rlgl.h | 9 +++++---- src/utils.c | 7 ++++++- 4 files changed, 36 insertions(+), 23 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index e3a17ebb..19c67712 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -7,14 +7,18 @@ * Features: * Library written in plain C code (C99) * Uses C# PascalCase/camelCase notation -* Hardware accelerated with OpenGL (1.1, 3.3 or ES2) -* Unique OpenGL abstraction layer [rlgl] -* Powerful fonts module with SpriteFonts support (including AngelCode fonts and TTF) +* Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) +* Unique OpenGL abstraction layer (usable as standalone module): [rlgl] +* Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) * Multiple textures support, including compressed formats and mipmaps generation -* Basic 3d support for Shapes, Models, Heightmaps and Billboards -* Powerful math module for Vector and Matrix operations [raymath] -* Audio loading and playing with streaming support (WAV and OGG) -* Multiplatform support, including Android devices, Raspberry Pi and HTML5 +* Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps +* Materials (diffuse, normal, specular) and Lighting (point, directional, spot) support +* Powerful math module for Vector, Matrix and Quaternion operations [raymath] +* Audio loading and playing with streaming support and mixing channels (WAV, OGG, XM, MOD) +* VR stereo rendering support with configurable HMD device parameters +* Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1 +* Custom color palette for fancy visuals on raywhite background +* Minimal external dependencies (GLFW3, OpenGL, OpenAL) * * Used external libs: * GLFW3 (www.glfw.org) for window/context management and input @@ -23,6 +27,8 @@ * stb_image_write (Sean Barret) for image writting (PNG) * stb_vorbis (Sean Barret) for ogg audio loading * stb_truetype (Sean Barret) for ttf fonts loading +* jar_xm (Joshua Reisenauer) for XM audio module loading +* jar_mod (Joshua Reisenauer) for MOD audio module loading * OpenAL Soft for audio device/context management * tinfl for data decompression (DEFLATE algorithm) * @@ -37,7 +43,7 @@ * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: * -* Copyright (c) 2013 Ramon Santamaria (@raysan5) +* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -536,7 +542,7 @@ typedef enum { HMD_SONY_PLAYSTATION_VR, HMD_RAZER_OSVR, HMD_FOVE_VR, -} HmdDevice; +} VrDevice; #ifdef __cplusplus extern "C" { // Prevents name mangling of functions @@ -778,8 +784,6 @@ 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 Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle 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 @@ -794,6 +798,8 @@ void DrawRay(Ray ray, Color color); void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) void DrawGizmo(Vector3 position); // Draw simple gizmo void DrawLight(Light light); // Draw light in 3D world +void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space +void Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle in 3D world space //DrawTorus(), DrawTeapot() are useless... //------------------------------------------------------------------------------------ @@ -837,7 +843,7 @@ Shader LoadShader(char *vsFileName, char *fsFileName); // Load a cu void UnloadShader(Shader shader); // Unload a custom shader from memory Shader GetDefaultShader(void); // Get default shader -Shader GetStandardShader(void); // Get default shader +Shader GetStandardShader(void); // Get standard shader Texture2D GetDefaultTexture(void); // Get default texture int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location @@ -860,7 +866,7 @@ void DestroyLight(Light light); // Destroy a // VR experience Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ -void InitVrDevice(int hmdDevice); // Init VR device +void InitVrDevice(int vdDevice); // Init VR device void CloseVrDevice(void); // Close VR device void UpdateVrTracking(void); // Update VR tracking (position and orientation) void BeginVrDrawing(void); // Begin VR drawing configuration diff --git a/src/rlgl.c b/src/rlgl.c index defbe04f..6477efaa 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -4,10 +4,11 @@ * * raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version: * OpenGL 1.1 - Direct map rl* -> gl* +* OpenGL 2.1 - Vertex data is stored in VBOs, call rlglDraw() to render * OpenGL 3.3 - Vertex data is stored in VAOs, call rlglDraw() to render * OpenGL ES 2 - Vertex data is stored in VBOs or VAOs (when available), call rlglDraw() to render * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -2566,10 +2567,10 @@ void DestroyLight(Light light) // Init VR device (or simulator) // NOTE: If device is not available, it fallbacks to default device (simulator) // NOTE: It modifies the global variable: VrDeviceInfo hmd -void InitVrDevice(int hmdDevice) +void InitVrDevice(int vrDevice) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - switch (hmdDevice) + switch (vrDevice) { case HMD_DEFAULT_DEVICE: TraceLog(INFO, "Initializing default VR Device (Oculus Rift CV1)"); case HMD_OCULUS_RIFT_DK2: @@ -2594,7 +2595,7 @@ void InitVrDevice(int hmdDevice) { TraceLog(WARNING, "VR Device not found: Initializing VR Simulator (Oculus Rift CV1)"); - if (hmdDevice == HMD_OCULUS_RIFT_DK2) + if (vrDevice == HMD_OCULUS_RIFT_DK2) { // Oculus Rift DK2 parameters hmd.hResolution = 1280; // HMD horizontal resolution in pixels @@ -2614,7 +2615,7 @@ void InitVrDevice(int hmdDevice) hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 } - else if ((hmdDevice == HMD_DEFAULT_DEVICE) || (hmdDevice == HMD_OCULUS_RIFT_CV1)) + else if ((vrDevice == HMD_DEFAULT_DEVICE) || (vrDevice == HMD_OCULUS_RIFT_CV1)) { // Oculus Rift CV1 parameters // NOTE: CV1 represents a complete HMD redesign compared to previous versions, diff --git a/src/rlgl.h b/src/rlgl.h index 306e5361..425871a9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -4,10 +4,11 @@ * * raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version: * OpenGL 1.1 - Direct map rl* -> gl* +* OpenGL 2.1 - Vertex data is stored in VBOs, call rlglDraw() to render * OpenGL 3.3 - Vertex data is stored in VAOs, call rlglDraw() to render * OpenGL ES 2 - Vertex data is stored in VBOs or VAOs (when available), call rlglDraw() to render * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -240,7 +241,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // TraceLog message types typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; - // Head Mounted Display devices + // VR Head Mounted Display devices typedef enum { HMD_DEFAULT_DEVICE = 0, HMD_OCULUS_RIFT_DK2, @@ -251,7 +252,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; HMD_SONY_PLAYSTATION_VR, HMD_RAZER_OSVR, HMD_FOVE_VR, - } HmdDevice; + } VrDevice; #endif #ifdef __cplusplus @@ -365,7 +366,7 @@ void DestroyLight(Light light); // Destroy a void TraceLog(int msgType, const char *text, ...); float *MatrixToFloat(Matrix mat); -void InitVrDevice(int hmdDevice); // Init VR device +void InitVrDevice(int vrDevice); // Init VR device void CloseVrDevice(void); // Close VR device void UpdateVrTracking(void); // Update VR tracking (position and orientation) void BeginVrDrawing(void); // Begin VR drawing configuration diff --git a/src/utils.c b/src/utils.c index 5340b3e5..36b06f0f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -205,6 +205,11 @@ void TraceLog(int msgType, const char *text, ...) void TraceLog(int msgType, const char *text, ...) { static char buffer[100]; + int traceDebugMsgs = 1; + +#ifdef DO_NOT_TRACE_DEBUG_MSGS + traceDebugMsgs = 0; +#endif switch(msgType) { @@ -226,7 +231,7 @@ void TraceLog(int msgType, const char *text, ...) case INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break; case ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break; case WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break; - case DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; + case DEBUG: if (traceDebugMsgs) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break; default: break; } -- cgit v1.2.3 From 32a671b9da172a5e8405bf6da916c53fc748c126 Mon Sep 17 00:00:00 2001 From: sol-prog Date: Fri, 22 Jul 2016 11:55:04 -0400 Subject: OS X comaptiblity changes and compiled library --- release/osx/helpme! | 0 release/osx/libraylib.a | Bin 0 -> 559760 bytes src/Makefile | 12 ++++++------ src/raylib.h | 10 +++++++--- src/rlgl.c | 16 +++++++++++----- 5 files changed, 24 insertions(+), 14 deletions(-) delete mode 100644 release/osx/helpme! create mode 100644 release/osx/libraylib.a (limited to 'src/raylib.h') diff --git a/release/osx/helpme! b/release/osx/helpme! deleted file mode 100644 index e69de29b..00000000 diff --git a/release/osx/libraylib.a b/release/osx/libraylib.a new file mode 100644 index 00000000..32ca7a24 Binary files /dev/null and b/release/osx/libraylib.a differ diff --git a/src/Makefile b/src/Makefile index 3c66e4f4..c41fe2f5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -169,15 +169,15 @@ endif # compile core module core.o : core.c raylib.h rlgl.h utils.h raymath.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) # compile rlgl module rlgl.o : rlgl.c rlgl.h raymath.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) -D$(GRAPHICS) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(GRAPHICS) # compile shapes module shapes.o : shapes.c raylib.h rlgl.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) + $(CC) -c $< $(CFLAGS) $(INCLUDES) # compile textures module textures.o : textures.c rlgl.h utils.h @@ -185,11 +185,11 @@ textures.o : textures.c rlgl.h utils.h # compile text module text.o : text.c raylib.h utils.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) + $(CC) -c $< $(CFLAGS) $(INCLUDES) # compile models module models.o : models.c raylib.h rlgl.h raymath.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) # compile audio module audio.o : audio.c raylib.h @@ -209,7 +209,7 @@ camera.o : camera.c raylib.h #compile gestures module gestures.o : gestures.c raylib.h - $(CC) -c $< $(CFLAGS) $(INCLUDE) + $(CC) -c $< $(CFLAGS) $(INCLUDES) # It installs generated and needed files to compile projects using raylib. # The installation works manually. diff --git a/src/raylib.h b/src/raylib.h index 19c67712..fee6aa91 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -268,9 +268,13 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type - #if !defined(_STDBOOL_H) - typedef enum { false, true } bool; - #define _STDBOOL_H + #ifndef __APPLE__ + #if !defined(_STDBOOL_H) + typedef enum { false, true } bool; + #define _STDBOOL_H + #endif + #else + #include #endif #endif diff --git a/src/rlgl.c b/src/rlgl.c index 6477efaa..2b551469 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1275,14 +1275,20 @@ void rlglLoadExtensions(void *loader) { #if defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_33) // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions) - if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); - else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + #ifndef __APPLE__ + if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); + else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); + #endif #if defined(GRAPHICS_API_OPENGL_21) - if (GLAD_GL_VERSION_2_1) TraceLog(INFO, "OpenGL 2.1 profile supported"); + #ifndef __APPLE__ + if (GLAD_GL_VERSION_2_1) TraceLog(INFO, "OpenGL 2.1 profile supported"); + #endif #elif defined(GRAPHICS_API_OPENGL_33) - if(GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); - else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + #ifndef __APPLE__ + if(GLAD_GL_VERSION_3_3) TraceLog(INFO, "OpenGL 3.3 Core profile supported"); + else TraceLog(ERROR, "OpenGL 3.3 Core profile not supported"); + #endif #endif // With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans -- cgit v1.2.3 From 8f7cb6fb190834dc07f275e8a4666ec5815c89f6 Mon Sep 17 00:00:00 2001 From: Bil152 Date: Fri, 29 Jul 2016 21:35:57 +0200 Subject: Code refractoring of music model to be more friendly-user (issue #144) --- src/audio.c | 409 +++++++++++++++++++++++++++++++++-------------------------- src/audio.h | 28 ++-- src/raylib.h | 47 ++++--- 3 files changed, 271 insertions(+), 213 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 3c618dd2..19a80712 100644 --- a/src/audio.c +++ b/src/audio.c @@ -2,7 +2,7 @@ * * raylib.audio * -* Basic functions to manage Audio: +* Basic functions to manage Audio: * Manage audio device (init/close) * Load and Unload audio files * Play/Stop/Pause/Resume loaded audio @@ -99,8 +99,8 @@ // Types and Structures Definition //---------------------------------------------------------------------------------- -// 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. +// 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 { unsigned short sampleRate; // default is 48000 @@ -108,7 +108,7 @@ typedef struct MixChannel { 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; // false if paused - + ALenum alFormat; // OpenAL format specifier ALuint alSource; // OpenAL source ALuint alBuffer[MAX_STREAM_BUFFERS]; // OpenAL sample buffer @@ -121,7 +121,7 @@ typedef struct Music { jar_xm_context_t *xmctx; // XM chiptune context jar_mod_context_t modctx; // MOD chiptune context MixChannel *mixc; // Mix channel - + unsigned int totalSamplesLeft; float totalLengthSeconds; bool loop; @@ -145,7 +145,8 @@ typedef enum { ERROR_UNABLE_TO_OPEN_RRES_FILE = 2048, ERROR_INVALID_RRES_FILE = 4096, ERROR_INVALID_RRES_RESOURCE = 8192, - ERROR_UNINITIALIZED_CHANNELS = 16384 + ERROR_UNINITIALIZED_CHANNELS = 16384, + ERROR_UNINTIALIZED_MUSIC_BUFFER = 32768 } AudioError; #if defined(AUDIO_STANDALONE) @@ -217,7 +218,7 @@ void CloseAudioDevice(void) { for (int index = 0; index < MAX_MUSIC_STREAMS; index++) { - if (musicStreams[index].mixc) StopMusicStream(index); // Stop music streaming and close current stream + if (musicStreams[index].mixc) StopMusicStreamEx(index); // Stop music streaming and close current stream } ALCdevice *device; @@ -236,12 +237,12 @@ void CloseAudioDevice(void) bool IsAudioDeviceReady(void) { ALCcontext *context = alcGetCurrentContext(); - + if (context == NULL) return false; else { ALCdevice *device = alcGetContextsDevice(context); - + if (device == NULL) return false; else return true; } @@ -252,13 +253,13 @@ bool IsAudioDeviceReady(void) //---------------------------------------------------------------------------------- // Init mix channel for streaming -// The mixChannel is what audio muxing channel you want to operate on, 0-3 are the ones available. +// 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. static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint) { if (mixChannel >= MAX_MIX_CHANNELS) return NULL; if (!IsAudioDeviceReady()) InitAudioDevice(); - + if (!mixChannels[mixChannel]) { MixChannel *mixc = (MixChannel *)malloc(sizeof(MixChannel)); @@ -267,7 +268,7 @@ static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixCh mixc->mixChannel = mixChannel; mixc->floatingPoint = floatingPoint; mixChannels[mixChannel] = mixc; - + // Setup OpenAL format if (channels == 1) { @@ -279,17 +280,17 @@ static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixCh if (floatingPoint) mixc->alFormat = AL_FORMAT_STEREO_FLOAT32; else mixc->alFormat = AL_FORMAT_STEREO16; } - + // Create an audio source 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, mixc->alBuffer); - + // Fill buffers for (int i = 0; i < MAX_STREAM_BUFFERS; i++) { @@ -305,14 +306,14 @@ static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixCh alBufferData(mixc->alBuffer[i], mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate); } } - + alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer); mixc->playing = true; alSourcePlay(mixc->alSource); - + return mixc; } - + return NULL; } @@ -323,18 +324,18 @@ static void CloseMixChannel(MixChannel *mixc) { alSourceStop(mixc->alSource); mixc->playing = false; - + // Flush out all queued buffers ALuint buffer = 0; int queued = 0; alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued); - + while (queued > 0) { alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); queued--; } - + // Delete source and buffers alDeleteSources(1, &mixc->alSource); alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); @@ -350,30 +351,30 @@ static void CloseMixChannel(MixChannel *mixc) static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements) { if (!mixc || (mixChannels[mixc->mixChannel] != mixc)) return 0; // When there is two channels there must be an even number of samples - - if (!data || !numberElements) - { + + if (!data || !numberElements) + { // Pauses audio until data is given if (mixc->playing) { alSourcePause(mixc->alSource); mixc->playing = false; } - + return 0; } else if (!mixc->playing) - { + { // Restart audio otherwise alSourcePlay(mixc->alSource); mixc->playing = true; } ALuint buffer = 0; - + alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); if (!buffer) return 0; - + if (mixc->floatingPoint) { // Process float buffers @@ -386,9 +387,9 @@ static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements) short *ptr = (short *)data; alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate); } - + alSourceQueueBuffers(mixc->alSource, 1, &buffer); - + return numberElements; } @@ -435,7 +436,7 @@ int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint) return -1; } } - + if (InitMixChannel(sampleRate, mixIndex, channels, floatingPoint)) return mixIndex; else { @@ -451,13 +452,13 @@ int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint) int BufferRawAudioContext(int ctx, void *data, unsigned short numberElements) { int numBuffered = 0; - + if (ctx >= 0) { MixChannel *mixc = mixChannels[ctx]; numBuffered = BufferMixChannel(mixc, data, numberElements); } - + return numBuffered; } @@ -482,12 +483,12 @@ Sound LoadSound(char *fileName) // Audio file loading // NOTE: Buffer space is allocated inside function, Wave must be freed - if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName); - else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName); + if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); + else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); else { TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); - + // TODO: Find a better way to register errors (similar to glGetError()) lastAudioError = ERROR_EXTENSION_NOT_RECOGNIZED; } @@ -528,7 +529,7 @@ Sound LoadSound(char *fileName) // Attach sound buffer to source alSourcei(source, AL_BUFFER, buffer); - TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(INFO, "[%s] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); // Unallocate WAV data UnloadWave(wave); @@ -602,9 +603,9 @@ Sound LoadSoundFromRES(const char *rresName, int resId) #if defined(AUDIO_STANDALONE) TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode"); #else - + bool found = false; - + char id[4]; // rRES file identifier unsigned char version; // rRES file version and subversion char useless; // rRES header reserved data @@ -758,8 +759,8 @@ void UnloadSound(Sound sound) { alDeleteSources(1, &sound.source); alDeleteBuffers(1, &sound.buffer); - - TraceLog(INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); + + TraceLog(INFO, "Unloaded sound data"); } // Play a sound @@ -823,138 +824,182 @@ void SetSoundPitch(Sound sound, float pitch) // Module Functions Definition - Music loading and stream playing (.OGG) //---------------------------------------------------------------------------------- +MusicBuffer LoadMusicBufferStream(char *fileName, int index) +{ + MusicBuffer buffer = { 0 }; + + if(index > MAX_MUSIC_STREAMS) + { + TraceLog("[%s] index is greater than MAX_MUSIC_STREAMS", ERROR); + return; // error + } + + buffer.fileName = fileName; + buffer.index = index; + + + if (musicStreams[buffer.index].stream || musicStreams[buffer.index].xmctx) return; // error + + return buffer; +} + // Start music playing (open stream) // returns 0 on success or error code -int PlayMusicStream(int index, char *fileName) +int PlayMusicStream(MusicBuffer musicBuffer) { + if(musicBuffer.fileName == 0) + { + return ERROR_UNINTIALIZED_MUSIC_BUFFER; + } int mixIndex; - - if (musicStreams[index].stream || musicStreams[index].xmctx) return ERROR_UNINITIALIZED_CHANNELS; // error - for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot { if (mixChannels[mixIndex] == NULL) break; else if (mixIndex == (MAX_MIX_CHANNELS - 1)) return ERROR_OUT_OF_MIX_CHANNELS; // error } - - if (strcmp(GetExtension(fileName), "ogg") == 0) + + if (strcmp(GetExtension(musicBuffer.fileName),"ogg") == 0) { // Open audio stream - musicStreams[index].stream = stb_vorbis_open_filename(fileName, NULL, NULL); + musicStreams[musicBuffer.index].stream = stb_vorbis_open_filename(musicBuffer.fileName, NULL, NULL); - if (musicStreams[index].stream == NULL) + if (musicStreams[musicBuffer.index].stream == NULL) { - TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); + TraceLog(WARNING, "[%s] OGG audio file could not be opened", musicBuffer.fileName); return ERROR_LOADING_OGG; // error } else { // Get file info - stb_vorbis_info info = stb_vorbis_get_info(musicStreams[index].stream); - - TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); - TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); - TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); - - musicStreams[index].loop = true; // We loop by default - musicStreams[index].enabled = true; - - musicStreams[index].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicStreams[index].stream) * info.channels; - musicStreams[index].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[index].stream); - + stb_vorbis_info info = stb_vorbis_get_info(musicStreams[musicBuffer.index].stream); + + TraceLog(INFO, "[%s] Ogg sample rate: %i", musicBuffer.fileName, info.sample_rate); + TraceLog(INFO, "[%s] Ogg channels: %i", musicBuffer.fileName, info.channels); + TraceLog(DEBUG, "[%s] Temp memory required: %i", musicBuffer.fileName, info.temp_memory_required); + + musicStreams[musicBuffer.index].loop = true; // We loop by default + musicStreams[musicBuffer.index].enabled = true; + + + musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream) * info.channels; + musicStreams[musicBuffer.index].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[musicBuffer.index].stream); + if (info.channels == 2) { - musicStreams[index].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); - musicStreams[index].mixc->playing = true; + musicStreams[musicBuffer.index].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); + musicStreams[musicBuffer.index].mixc->playing = true; } else { - musicStreams[index].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); - musicStreams[index].mixc->playing = true; + musicStreams[musicBuffer.index].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); + musicStreams[musicBuffer.index].mixc->playing = true; } - - if (!musicStreams[index].mixc) return ERROR_LOADING_OGG; // error + + if (!musicStreams[musicBuffer.index].mixc) return ERROR_LOADING_OGG; // error } } - else if (strcmp(GetExtension(fileName), "xm") == 0) + else if (strcmp(GetExtension(musicBuffer.fileName),"xm") == 0) { // only stereo is supported for xm - if (!jar_xm_create_context_from_file(&musicStreams[index].xmctx, 48000, fileName)) + if (!jar_xm_create_context_from_file(&musicStreams[musicBuffer.index].xmctx, 48000, musicBuffer.fileName)) { - musicStreams[index].chipTune = true; - musicStreams[index].loop = true; - jar_xm_set_max_loop_count(musicStreams[index].xmctx, 0); // infinite number of loops - musicStreams[index].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicStreams[index].xmctx); - musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft)/48000.0f; - musicStreams[index].enabled = true; - - TraceLog(INFO, "[%s] XM number of samples: %i", fileName, musicStreams[index].totalSamplesLeft); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, musicStreams[index].totalLengthSeconds); - - musicStreams[index].mixc = InitMixChannel(48000, mixIndex, 2, true); - - if (!musicStreams[index].mixc) return ERROR_XM_CONTEXT_CREATION; // error - - musicStreams[index].mixc->playing = true; + musicStreams[musicBuffer.index].chipTune = true; + musicStreams[musicBuffer.index].loop = true; + jar_xm_set_max_loop_count(musicStreams[musicBuffer.index].xmctx, 0); // infinite number of loops + musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicStreams[musicBuffer.index].xmctx); + musicStreams[musicBuffer.index].totalLengthSeconds = ((float)musicStreams[musicBuffer.index].totalSamplesLeft)/48000.0f; + musicStreams[musicBuffer.index].enabled = true; + + TraceLog(INFO, "[%s] XM number of samples: %i", musicBuffer.fileName, musicStreams[musicBuffer.index].totalSamplesLeft); + TraceLog(INFO, "[%s] XM track length: %11.6f sec", musicBuffer.fileName, musicStreams[musicBuffer.index].totalLengthSeconds); + + musicStreams[musicBuffer.index].mixc = InitMixChannel(48000, mixIndex, 2, true); + + if (!musicStreams[musicBuffer.index].mixc) return ERROR_XM_CONTEXT_CREATION; // error + + musicStreams[musicBuffer.index].mixc->playing = true; } else { - TraceLog(WARNING, "[%s] XM file could not be opened", fileName); + TraceLog(WARNING, "[%s] XM file could not be opened", musicBuffer.fileName); return ERROR_LOADING_XM; // error } } - else if (strcmp(GetExtension(fileName), "mod") == 0) + else if (strcmp(GetExtension(musicBuffer.fileName),"mod") == 0) { - jar_mod_init(&musicStreams[index].modctx); - - if (jar_mod_load_file(&musicStreams[index].modctx, fileName)) + jar_mod_init(&musicStreams[musicBuffer.index].modctx); + + if (jar_mod_load_file(&musicStreams[musicBuffer.index].modctx, musicBuffer.fileName)) { - musicStreams[index].chipTune = true; - musicStreams[index].loop = true; - musicStreams[index].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicStreams[index].modctx); - musicStreams[index].totalLengthSeconds = ((float)musicStreams[index].totalSamplesLeft)/48000.0f; - musicStreams[index].enabled = true; - - TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, musicStreams[index].totalSamplesLeft); - TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, musicStreams[index].totalLengthSeconds); - - musicStreams[index].mixc = InitMixChannel(48000, mixIndex, 2, false); - - if (!musicStreams[index].mixc) return ERROR_MOD_CONTEXT_CREATION; // error - - musicStreams[index].mixc->playing = true; + musicStreams[musicBuffer.index].chipTune = true; + musicStreams[musicBuffer.index].loop = true; + musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicStreams[musicBuffer.index].modctx); + musicStreams[musicBuffer.index].totalLengthSeconds = ((float)musicStreams[musicBuffer.index].totalSamplesLeft)/48000.0f; + musicStreams[musicBuffer.index].enabled = true; + + TraceLog(INFO, "[%s] MOD number of samples: %i", musicBuffer.fileName, musicStreams[musicBuffer.index].totalSamplesLeft); + TraceLog(INFO, "[%s] MOD track length: %11.6f sec", musicBuffer.fileName, musicStreams[musicBuffer.index].totalLengthSeconds); + + musicStreams[musicBuffer.index].mixc = InitMixChannel(48000, mixIndex, 2, false); + + if (!musicStreams[musicBuffer.index].mixc) return ERROR_MOD_CONTEXT_CREATION; // error + + musicStreams[musicBuffer.index].mixc->playing = true; } else { - TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); + TraceLog(WARNING, "[%s] MOD file could not be opened", musicBuffer.fileName); return ERROR_LOADING_MOD; // error } } else { - TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); + TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", musicBuffer.fileName); return ERROR_EXTENSION_NOT_RECOGNIZED; // error } - + return 0; // normal return } // Stop music playing for individual music index of musicStreams array (close stream) -void StopMusicStream(int index) +void StopMusicStream(MusicBuffer musicBuffer) +{ + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) + { + CloseMixChannel(musicStreams[musicBuffer.index].mixc); + + if (musicStreams[musicBuffer.index].xmctx) + jar_xm_free_context(musicStreams[musicBuffer.index].xmctx); + else if (musicStreams[musicBuffer.index].modctx.mod_loaded) + jar_mod_unload(&musicStreams[musicBuffer.index].modctx); + else + stb_vorbis_close(musicStreams[musicBuffer.index].stream); + + musicStreams[musicBuffer.index].enabled = false; + + if (musicStreams[musicBuffer.index].stream || musicStreams[musicBuffer.index].xmctx) + { + musicStreams[musicBuffer.index].stream = NULL; + musicStreams[musicBuffer.index].xmctx = NULL; + } + } +} + +void StopMusicStreamEx(int index) { if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) { CloseMixChannel(musicStreams[index].mixc); - + if (musicStreams[index].xmctx) jar_xm_free_context(musicStreams[index].xmctx); else if (musicStreams[index].modctx.mod_loaded) jar_mod_unload(&musicStreams[index].modctx); else stb_vorbis_close(musicStreams[index].stream); - + musicStreams[index].enabled = false; - + if (musicStreams[index].stream || musicStreams[index].xmctx) { musicStreams[index].stream = NULL; @@ -964,47 +1009,47 @@ void StopMusicStream(int index) } // Update (re-fill) music buffers if data already processed -void UpdateMusicStream(int index) +void UpdateMusicStream(MusicBuffer musicBuffer) { ALenum state; bool active = true; ALint processed = 0; - + // Determine if music stream is ready to be written - alGetSourcei(musicStreams[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); - - if (musicStreams[index].mixc->playing && (index < MAX_MUSIC_STREAMS) && musicStreams[index].enabled && musicStreams[index].mixc && (processed > 0)) + alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + + if (musicStreams[musicBuffer.index].mixc->playing && (musicBuffer.index < MAX_MUSIC_STREAMS) && musicStreams[musicBuffer.index].enabled && musicStreams[musicBuffer.index].mixc && (processed > 0)) { - active = BufferMusicStream(index, processed); - - if (!active && musicStreams[index].loop) + active = BufferMusicStream(musicBuffer.index, processed); + + if (!active && musicStreams[musicBuffer.index].loop) { - if (musicStreams[index].chipTune) + if (musicStreams[musicBuffer.index].chipTune) { - if(musicStreams[index].modctx.mod_loaded) jar_mod_seek_start(&musicStreams[index].modctx); - - musicStreams[index].totalSamplesLeft = musicStreams[index].totalLengthSeconds*48000.0f; + if(musicStreams[musicBuffer.index].modctx.mod_loaded) jar_mod_seek_start(&musicStreams[musicBuffer.index].modctx); + + musicStreams[musicBuffer.index].totalSamplesLeft = musicStreams[musicBuffer.index].totalLengthSeconds*48000.0f; } else { - stb_vorbis_seek_start(musicStreams[index].stream); - musicStreams[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicStreams[index].stream)*musicStreams[index].mixc->channels; + stb_vorbis_seek_start(musicStreams[musicBuffer.index].stream); + musicStreams[musicBuffer.index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream)*musicStreams[musicBuffer.index].mixc->channels; } - + // Determine if music stream is ready to be written - alGetSourcei(musicStreams[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); - - active = BufferMusicStream(index, processed); + alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + + active = BufferMusicStream(musicBuffer.index, processed); } if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); - - alGetSourcei(musicStreams[index].mixc->alSource, AL_SOURCE_STATE, &state); - if (state != AL_PLAYING && active) alSourcePlay(musicStreams[index].mixc->alSource); + alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); + + if (state != AL_PLAYING && active) alSourcePlay(musicStreams[musicBuffer.index].mixc->alSource); + + if (!active) StopMusicStream(musicBuffer); - if (!active) StopMusicStream(index); - } } @@ -1012,57 +1057,57 @@ void UpdateMusicStream(int index) int GetMusicStreamCount(void) { int musicCount = 0; - + // Find empty music slot for (int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) { if(musicStreams[musicIndex].stream != NULL || musicStreams[musicIndex].chipTune) musicCount++; } - + return musicCount; } // Pause music playing -void PauseMusicStream(int index) +void PauseMusicStream(MusicBuffer musicBuffer) { // Pause music stream if music available! - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc && musicStreams[index].enabled) + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc && musicStreams[musicBuffer.index].enabled) { TraceLog(INFO, "Pausing music stream"); - alSourcePause(musicStreams[index].mixc->alSource); - musicStreams[index].mixc->playing = false; + alSourcePause(musicStreams[musicBuffer.index].mixc->alSource); + musicStreams[musicBuffer.index].mixc->playing = false; } } // Resume music playing -void ResumeMusicStream(int index) +void ResumeMusicStream(MusicBuffer musicBuffer) { // Resume music playing... if music available! ALenum state; - - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) + + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) { - alGetSourcei(musicStreams[index].mixc->alSource, AL_SOURCE_STATE, &state); - + alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PAUSED) { TraceLog(INFO, "Resuming music stream"); - alSourcePlay(musicStreams[index].mixc->alSource); - musicStreams[index].mixc->playing = true; + alSourcePlay(musicStreams[musicBuffer.index].mixc->alSource); + musicStreams[musicBuffer.index].mixc->playing = true; } } } // Check if any music is playing -bool IsMusicPlaying(int index) +bool IsMusicPlaying(MusicBuffer musicBuffer) { bool playing = false; ALint state; - - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) + + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) { - alGetSourcei(musicStreams[index].mixc->alSource, AL_SOURCE_STATE, &state); - + alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) playing = true; } @@ -1070,57 +1115,57 @@ bool IsMusicPlaying(int index) } // Set volume for music -void SetMusicVolume(int index, float volume) +void SetMusicVolume(MusicBuffer musicBuffer, float volume) { - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) { - alSourcef(musicStreams[index].mixc->alSource, AL_GAIN, volume); + alSourcef(musicStreams[musicBuffer.index].mixc->alSource, AL_GAIN, volume); } } // Set pitch for music -void SetMusicPitch(int index, float pitch) +void SetMusicPitch(MusicBuffer musicBuffer, float pitch) { - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) { - alSourcef(musicStreams[index].mixc->alSource, AL_PITCH, pitch); + alSourcef(musicStreams[musicBuffer.index].mixc->alSource, AL_PITCH, pitch); } } // Get music time length (in seconds) -float GetMusicTimeLength(int index) +float GetMusicTimeLength(MusicBuffer musicBuffer) { float totalSeconds; - - if (musicStreams[index].chipTune) totalSeconds = (float)musicStreams[index].totalLengthSeconds; - else totalSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[index].stream); + + if (musicStreams[musicBuffer.index].chipTune) totalSeconds = (float)musicStreams[musicBuffer.index].totalLengthSeconds; + else totalSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[musicBuffer.index].stream); return totalSeconds; } // Get current music time played (in seconds) -float GetMusicTimePlayed(int index) +float GetMusicTimePlayed(MusicBuffer musicBuffer) { float secondsPlayed = 0.0f; - - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) + + if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) { - if (musicStreams[index].chipTune && musicStreams[index].xmctx) + if (musicStreams[musicBuffer.index].chipTune && musicStreams[musicBuffer.index].xmctx) { uint64_t samples; - jar_xm_get_position(musicStreams[index].xmctx, NULL, NULL, NULL, &samples); - secondsPlayed = (float)samples/(48000.0f*musicStreams[index].mixc->channels); // Not sure if this is the correct value + jar_xm_get_position(musicStreams[musicBuffer.index].xmctx, NULL, NULL, NULL, &samples); + secondsPlayed = (float)samples/(48000.0f*musicStreams[musicBuffer.index].mixc->channels); // Not sure if this is the correct value } - else if(musicStreams[index].chipTune && musicStreams[index].modctx.mod_loaded) + else if(musicStreams[musicBuffer.index].chipTune && musicStreams[musicBuffer.index].modctx.mod_loaded) { - long numsamp = jar_mod_current_samples(&musicStreams[index].modctx); + long numsamp = jar_mod_current_samples(&musicStreams[musicBuffer.index].modctx); secondsPlayed = (float)numsamp/(48000.0f); } else { - int totalSamples = stb_vorbis_stream_length_in_samples(musicStreams[index].stream)*musicStreams[index].mixc->channels; - int samplesPlayed = totalSamples - musicStreams[index].totalSamplesLeft; - secondsPlayed = (float)samplesPlayed/(musicStreams[index].mixc->sampleRate*musicStreams[index].mixc->channels); + int totalSamples = stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream)*musicStreams[musicBuffer.index].mixc->channels; + int samplesPlayed = totalSamples - musicStreams[musicBuffer.index].totalSamplesLeft; + secondsPlayed = (float)samplesPlayed/(musicStreams[musicBuffer.index].mixc->sampleRate*musicStreams[musicBuffer.index].mixc->channels); } } @@ -1136,10 +1181,10 @@ 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 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 (musicStreams[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. { for (int i = 0; i < numBuffers; i++) @@ -1148,7 +1193,7 @@ static bool BufferMusicStream(int index, int numBuffers) { if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT/2; else size = musicStreams[index].totalSamplesLeft/2; - + jar_mod_fillbuffer(&musicStreams[index].modctx, pcm, size, 0 ); BufferMixChannel(musicStreams[index].mixc, pcm, size*2); } @@ -1156,13 +1201,13 @@ static bool BufferMusicStream(int index, int numBuffers) { if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) size = MUSIC_BUFFER_SIZE_FLOAT/2; else size = musicStreams[index].totalSamplesLeft/2; - + jar_xm_generate_samples(musicStreams[index].xmctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location BufferMixChannel(musicStreams[index].mixc, pcmf, size*2); } musicStreams[index].totalSamplesLeft -= size; - + if (musicStreams[index].totalSamplesLeft <= 0) { active = false; @@ -1174,13 +1219,13 @@ static bool BufferMusicStream(int index, int numBuffers) { if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT; else size = musicStreams[index].totalSamplesLeft; - + for (int i = 0; i < numBuffers; i++) { int streamedBytes = stb_vorbis_get_samples_short_interleaved(musicStreams[index].stream, musicStreams[index].mixc->channels, pcm, size); BufferMixChannel(musicStreams[index].mixc, pcm, streamedBytes * musicStreams[index].mixc->channels); musicStreams[index].totalSamplesLeft -= streamedBytes * musicStreams[index].mixc->channels; - + if (musicStreams[index].totalSamplesLeft <= 0) { active = false; @@ -1367,8 +1412,8 @@ static Wave LoadOGG(char *fileName) static void UnloadWave(Wave wave) { free(wave.data); - - TraceLog(INFO, "Unloaded wave data from RAM"); + + TraceLog(INFO, "Unloaded wave data"); } // Some required functions for audio standalone module version diff --git a/src/audio.h b/src/audio.h index b6850911..d39162b5 100644 --- a/src/audio.h +++ b/src/audio.h @@ -2,7 +2,7 @@ * * raylib.audio * -* Basic functions to manage Audio: +* Basic functions to manage Audio: * Manage audio device (init/close) * Load and Unload audio files * Play/Stop/Pause/Resume loaded audio @@ -75,6 +75,11 @@ typedef struct Wave { short channels; } Wave; +typedef struct MusicBuffer { + char *fileName; + int index; // index in musicStreams +} MusicBuffer; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -102,16 +107,17 @@ 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) -int PlayMusicStream(int index, 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) -void SetMusicPitch(int index, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(int index); // Get music time length (in seconds) -float GetMusicTimePlayed(int index); // Get current music time played (in seconds) +MusicBuffer LoadMusicBufferStream(char *fileName, int index); +int PlayMusicStream(MusicBuffer buffer); // Start music playing (open stream) +void UpdateMusicStream(MusicBuffer buffer); // Updates buffers for music streaming +void StopMusicStream(MusicBuffer buffer); // Stop music playing (close stream) +void PauseMusicStream(MusicBuffer buffer); // Pause music playing +void ResumeMusicStream(MusicBuffer buffer); // Resume playing paused music +bool IsMusicPlaying(MusicBuffer buffer); // Check if music is playing +void SetMusicVolume(MusicBuffer buffer float volume); // Set volume for music (1.0 is max level) +void SetMusicPitch(MusicBuffer buffer, float pitch); // Set pitch for a music (1.0 is base level) +float GetMusicTimeLength(MusicBuffer buffer); // Get music time length (in seconds) +float GetMusicTimePlayed(MusicBuffer buffer); // Get current music time played (in seconds) int GetMusicStreamCount(void); // Get number of streams loaded int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint); // Initialize raw audio mix channel for audio buffering diff --git a/src/raylib.h b/src/raylib.h index fee6aa91..1966f75e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -397,7 +397,7 @@ typedef struct Mesh { // Shader type (generic shader) typedef struct Shader { unsigned int id; // Shader program id - + // Vertex attributes locations (default locations) int vertexLoc; // Vertex attribute location point (default-location = 0) int texcoordLoc; // Texcoord attribute location point (default-location = 1) @@ -409,7 +409,7 @@ typedef struct Shader { // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int tintColorLoc; // Diffuse color uniform location point (fragment shader) - + // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) @@ -423,11 +423,11 @@ typedef struct Material { Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc) Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc) Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc) - + Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color - + float glossiness; // Glossiness level (Ranges from 0 to 1000) } Material; @@ -443,14 +443,14 @@ typedef struct LightData { unsigned int id; // Light unique id bool enabled; // Light enabled int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - + Vector3 position; // Light position Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) float radius; // Light attenuation radius light intensity reduced with distance (world distance) - + Color diffuse; // Light diffuse color float intensity; // Light intensity level - + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; @@ -478,6 +478,11 @@ typedef struct Wave { short channels; } Wave; +typedef struct MusicBuffer { + char *fileName; + int index; // index in musicStreams +} MusicBuffer; + // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -647,7 +652,7 @@ void SetMousePosition(Vector2 position); // Set mouse position XY int GetMouseWheelMove(void); // Returns mouse wheel movement Y int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) -int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) #if defined(PLATFORM_ANDROID) @@ -687,8 +692,8 @@ void SetCameraPanControl(int panKey); // Set camera pan ke void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int frontKey, int backKey, - int leftKey, int rightKey, +void SetCameraMoveControls(int frontKey, int backKey, + int leftKey, int rightKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) @@ -815,6 +820,7 @@ Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d mod 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) void UnloadModel(Model model); // Unload 3d model from memory +Mesh GenMeshCube(float width, float height, float depth); Material LoadMaterial(const char *fileName); // Load material data (from file) Material LoadDefaultMaterial(void); // Load default material (uses default models shader) @@ -896,16 +902,17 @@ 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) -int PlayMusicStream(int index, 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) -void SetMusicPitch(int index, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(int index); // Get current music time length (in seconds) -float GetMusicTimePlayed(int index); // Get current music time played (in seconds) +MusicBuffer LoadMusicBufferStream(char *fileName, int index); +int PlayMusicStream(MusicBuffer buffer); // Start music playing (open stream) +void UpdateMusicStream(MusicBuffer buffer); // Updates buffers for music streaming +void StopMusicStream(MusicBuffer buffer); // Stop music playing (close stream) +void PauseMusicStream(MusicBuffer buffer); // Pause music playing +void ResumeMusicStream(MusicBuffer buffer); // Resume playing paused music +bool IsMusicPlaying(MusicBuffer buffer); // Check if music is playing +void SetMusicVolume(MusicBuffer buffer, float volume); // Set volume for music (1.0 is max level) +void SetMusicPitch(MusicBuffer buffer, float pitch); // Set pitch for a music (1.0 is base level) +float GetMusicTimeLength(MusicBuffer buffer); // Get music time length (in seconds) +float GetMusicTimePlayed(MusicBuffer buffer); // Get current music time played (in seconds) int GetMusicStreamCount(void); // Get number of streams loaded #ifdef __cplusplus -- cgit v1.2.3 From 02c456432d7f284c41519f6d540ad6c4dfb4a065 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 1 Aug 2016 12:49:17 +0200 Subject: Complete review of audio system Still some work left... --- examples/audio_module_playing.c | 10 +- examples/audio_music_stream.c | 20 +- src/audio.c | 1091 ++++++++++++++------------------------- src/audio.h | 36 +- src/external/jar_xm.h | 60 ++- src/raylib.h | 32 +- 6 files changed, 464 insertions(+), 785 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/audio_module_playing.c b/examples/audio_module_playing.c index 6189b866..07165c76 100644 --- a/examples/audio_module_playing.c +++ b/examples/audio_module_playing.c @@ -57,7 +57,9 @@ int main() // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - PlayMusicStream(0, "resources/audio/2t2m_spa.xm"); // Play module stream + Music xm = LoadMusicStream("resources/audio/2t2m_spa.xm"); + + PlayMusicStream(xm); float timePlayed = 0.0f; @@ -88,9 +90,9 @@ int main() } // Get timePlayed scaled to bar dimensions - timePlayed = (GetMusicTimePlayed(0)/GetMusicTimeLength(0)*(screenWidth - 40))*2; + timePlayed = (GetMusicTimePlayed(xm)/GetMusicTimeLength(xm)*(screenWidth - 40))*2; - UpdateMusicStream(0); // Update music buffer with new stream data + UpdateMusicStream(xm); // Update music buffer with new stream data //---------------------------------------------------------------------------------- // Draw @@ -129,6 +131,8 @@ int main() UnloadShader(shader); // Unload shader UnloadRenderTexture(target); // Unload render texture + UnloadMusicStream(xm); // Unload music stream buffers from RAM + CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) CloseWindow(); // Close window and OpenGL context diff --git a/examples/audio_music_stream.c b/examples/audio_music_stream.c index e135a6e4..b96b85f7 100644 --- a/examples/audio_music_stream.c +++ b/examples/audio_music_stream.c @@ -24,7 +24,9 @@ int main() InitAudioDevice(); // Initialize audio device - PlayMusicStream(0, "resources/audio/guitar_noodling.ogg"); // Play music stream + Music music = LoadMusicStream("resources/audio/guitar_noodling.ogg"); + + PlayMusicStream(music); int framesCounter = 0; float timePlayed = 0.0f; @@ -58,12 +60,12 @@ int main() SetMusicVolume(volume); } */ - if (IsWindowMinimized()) PauseMusicStream(0); - else ResumeMusicStream(0); + if (IsWindowMinimized()) PauseMusicStream(music); + else ResumeMusicStream(music); - timePlayed = GetMusicTimePlayed(0)/GetMusicTimeLength(0)*100*4; // We scale by 4 to fit 400 pixels - - UpdateMusicStream(0); // Update music buffer with new stream data + timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*100*4; // We scale by 4 to fit 400 pixels + + UpdateMusicStream(music); // Update music buffer with new stream data //---------------------------------------------------------------------------------- // Draw @@ -83,9 +85,11 @@ int main() // De-Initialization //-------------------------------------------------------------------------------------- - CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) + UnloadMusicStream(music); // Unload music stream buffers from RAM + + CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) - CloseWindow(); // Close window and OpenGL context + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; diff --git a/src/audio.c b/src/audio.c index 93987c6e..94bbb376 100644 --- a/src/audio.c +++ b/src/audio.c @@ -55,6 +55,7 @@ #include // Required for: strcmp(), strncmp() #include // Required for: FILE, fopen(), fclose(), fread() +// Tokens defined by OpenAL extension: AL_EXT_float32 #ifndef AL_FORMAT_MONO_FLOAT32 #define AL_FORMAT_MONO_FLOAT32 0x10010 #endif @@ -85,55 +86,47 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define MAX_STREAM_BUFFERS 2 // Number of buffers for each source -#define MAX_MUSIC_STREAMS 2 // Number of simultanious music sources -#define MAX_MIX_CHANNELS 4 // Number of mix channels (OpenAL sources) - -#if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID) - // NOTE: On RPI and Android should be lower to avoid frame-stalls - #define MUSIC_BUFFER_SIZE_SHORT 4096*2 // PCM data buffer (short) - 16Kb (RPI) - #define MUSIC_BUFFER_SIZE_FLOAT 4096 // PCM data buffer (float) - 16Kb (RPI) -#else - // NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care... - #define MUSIC_BUFFER_SIZE_SHORT 4096*8 // PCM data buffer (short) - 64Kb - #define MUSIC_BUFFER_SIZE_FLOAT 4096*4 // PCM data buffer (float) - 64Kb -#endif +#define MAX_STREAM_BUFFERS 2 // Number of buffers for each audio stream + +// NOTE: Music buffer size is defined by number of samples, independent of sample size +// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds +// and double-buffering system, I concluded that a 4096 samples buffer should be enough +// In case of music-stalls, just inclease this number +#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. short: 32Kb) //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- +typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_MODULE_XM, MUSIC_MODULE_MOD } MusicContextType; + // 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 { - 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; // false if paused - - ALenum alFormat; // OpenAL format specifier - ALuint alSource; // OpenAL source - ALuint alBuffer[MAX_STREAM_BUFFERS]; // OpenAL sample buffer -} MixChannel; +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second): default is 48000 + unsigned int sampleSize; // BitDepth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels + + ALenum format; // OpenAL format specifier + ALuint source; // OpenAL source + ALuint buffers[MAX_STREAM_BUFFERS]; // OpenAL buffers (double buffering) +} AudioStream; // 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 *xmctx; // XM chiptune context - jar_mod_context_t modctx; // MOD chiptune context - MixChannel *mixc; // Mix channel - - unsigned int totalSamplesLeft; - float totalLengthSeconds; - bool loop; - bool chipTune; // chiptune is loaded? - bool enabled; -} Music; - -// Audio errors registered + MusicContextType ctxType; // Type of music context (OGG, XM, MOD) + stb_vorbis *ctxOgg; // OGG audio context + jar_xm_context_t *ctxXm; // XM chiptune context + jar_mod_context_t ctxMod; // MOD chiptune context + + AudioStream stream; // Audio stream + + bool loop; // Repeat music after finish (loop) + unsigned int totalSamples; // Total number of samples + unsigned int samplesLeft; // Number of samples left to end +} MusicData, *Music; + +// Audio errors to register +/* typedef enum { ERROR_RAW_CONTEXT_CREATION = 1, ERROR_XM_CONTEXT_CREATION = 2, @@ -152,6 +145,7 @@ typedef enum { ERROR_UNINITIALIZED_CHANNELS = 16384, ERROR_UNINTIALIZED_MUSIC_BUFFER = 32768 } AudioError; +*/ #if defined(AUDIO_STANDALONE) typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; @@ -160,10 +154,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Music musicStreams[MAX_MUSIC_STREAMS]; // Current music loaded, up to two can play at the same time -static MixChannel *mixChannels[MAX_MIX_CHANNELS]; // Mix channels currently active (from music streams) - -static int lastAudioError = 0; // Registers last audio error +static int lastAudioError = 0; // Registers last audio error //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -172,14 +163,11 @@ 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(int index, int numBuffers); // Fill music buffers with data -static void EmptyMusicStream(int index); // Empty music buffers +static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); +static void CloseAudioStream(AudioStream stream); // Frees mix channel +static int BufferAudioStream(AudioStream stream, void *data, int numberElements); // Pushes more audio data into mix channel -static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); -static void CloseMixChannel(MixChannel *mixc); // Frees mix channel -static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements); // Pushes more audio data into mix channel -//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 bool BufferMusicStream(Music music, int numBuffersToProcess); // Fill music buffers with data #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename @@ -190,45 +178,44 @@ void TraceLog(int msgType, const char *text, ...); // Outputs a trace log messa // Module Functions Definition - Audio Device initialization and Closing //---------------------------------------------------------------------------------- -// Initialize audio device and mixc +// Initialize audio device void InitAudioDevice(void) { // Open and initialize a device with default settings ALCdevice *device = alcOpenDevice(NULL); if (!device) TraceLog(ERROR, "Audio device could not be opened"); - - ALCcontext *context = alcCreateContext(device, NULL); - - if ((context == NULL) || (alcMakeContextCurrent(context) == ALC_FALSE)) + else { - if (context != NULL) alcDestroyContext(context); + ALCcontext *context = alcCreateContext(device, NULL); - alcCloseDevice(device); + if ((context == NULL) || (alcMakeContextCurrent(context) == ALC_FALSE)) + { + if (context != NULL) alcDestroyContext(context); - TraceLog(ERROR, "Could not setup mix channel"); - } + alcCloseDevice(device); - TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); + TraceLog(ERROR, "Could not initialize audio context"); + } + else + { + TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); - // Listener definition (just for 2D) - alListener3f(AL_POSITION, 0, 0, 0); - alListener3f(AL_VELOCITY, 0, 0, 0); - alListener3f(AL_ORIENTATION, 0, 0, -1); + // Listener definition (just for 2D) + alListener3f(AL_POSITION, 0, 0, 0); + alListener3f(AL_VELOCITY, 0, 0, 0); + alListener3f(AL_ORIENTATION, 0, 0, -1); + } + } } // Close the audio device for all contexts void CloseAudioDevice(void) { - for (int index = 0; index < MAX_MUSIC_STREAMS; index++) - { - if (musicStreams[index].mixc) StopMusicStreamEx(index); // Stop music streaming and close current stream - } - ALCdevice *device; ALCcontext *context = alcGetCurrentContext(); - if (context == NULL) TraceLog(WARNING, "Could not get current mix channel for closing"); + if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing"); device = alcGetContextsDevice(context); @@ -252,300 +239,30 @@ bool IsAudioDeviceReady(void) } } -//---------------------------------------------------------------------------------- -// Module Functions Definition - Custom audio output -//---------------------------------------------------------------------------------- - -// Init mix channel for streaming -// 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. -static MixChannel *InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint) -{ - if (mixChannel >= MAX_MIX_CHANNELS) return NULL; - if (!IsAudioDeviceReady()) InitAudioDevice(); - - if (!mixChannels[mixChannel]) - { - MixChannel *mixc = (MixChannel *)malloc(sizeof(MixChannel)); - mixc->sampleRate = sampleRate; - mixc->channels = channels; - mixc->mixChannel = mixChannel; - mixc->floatingPoint = floatingPoint; - mixChannels[mixChannel] = mixc; - - // Setup OpenAL format - if (channels == 1) - { - if (floatingPoint) mixc->alFormat = AL_FORMAT_MONO_FLOAT32; - else mixc->alFormat = AL_FORMAT_MONO16; - } - else if (channels == 2) - { - if (floatingPoint) mixc->alFormat = AL_FORMAT_STEREO_FLOAT32; - else mixc->alFormat = AL_FORMAT_STEREO16; - } - - // Create an audio source - 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, mixc->alBuffer); - - // Fill buffers - for (int i = 0; i < MAX_STREAM_BUFFERS; i++) - { - // Initialize buffer with zeros by default - if (mixc->floatingPoint) - { - float pcm[MUSIC_BUFFER_SIZE_FLOAT] = { 0.0f }; - alBufferData(mixc->alBuffer[i], mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), mixc->sampleRate); - } - else - { - short pcm[MUSIC_BUFFER_SIZE_SHORT] = { 0 }; - alBufferData(mixc->alBuffer[i], mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate); - } - } - - alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer); - mixc->playing = true; - alSourcePlay(mixc->alSource); - - return mixc; - } - - return NULL; -} - -// Frees buffer in mix channel -static void CloseMixChannel(MixChannel *mixc) -{ - if (mixc) - { - alSourceStop(mixc->alSource); - mixc->playing = false; - - // Flush out all queued buffers - ALuint buffer = 0; - int queued = 0; - alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued); - - while (queued > 0) - { - alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); - queued--; - } - - // Delete source and buffers - alDeleteSources(1, &mixc->alSource); - alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer); - mixChannels[mixc->mixChannel] = NULL; - free(mixc); - mixc = NULL; - } -} - -// Pushes more audio data into 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. -static int BufferMixChannel(MixChannel *mixc, void *data, int numberElements) -{ - if (!mixc || (mixChannels[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 - if (mixc->playing) - { - alSourcePause(mixc->alSource); - mixc->playing = false; - } - - return 0; - } - else if (!mixc->playing) - { - // Restart audio otherwise - alSourcePlay(mixc->alSource); - mixc->playing = true; - } - - ALuint buffer = 0; - - alSourceUnqueueBuffers(mixc->alSource, 1, &buffer); - if (!buffer) return 0; - - if (mixc->floatingPoint) - { - // Process float buffers - float *ptr = (float *)data; - alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate); - } - 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; -} - -/* -// Convert data from short to float -// example usage: -// short sh[3] = {1,2,3};float fl[3]; -// ResampleShortToFloat(sh,fl,3); -static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len) -{ - for (int i = 0; i < len; i++) - { - if (shorts[i] < 0) floats[i] = (float)shorts[i]/32766.0f; - else floats[i] = (float)shorts[i]/32767.0f; - } -} - -// Convert data from float to short -// example usage: -// char ch[3] = {1,2,3};float fl[3]; -// ResampleByteToFloat(ch,fl,3); -static void ResampleByteToFloat(char *chars, float *floats, unsigned short len) -{ - for (int i = 0; i < len; i++) - { - if (chars[i] < 0) floats[i] = (float)chars[i]/127.0f; - else floats[i] = (float)chars[i]/128.0f; - } -} -*/ - -// Initialize raw audio mix channel for audio buffering -// NOTE: Returns mix channel index or -1 if it fails (errors are registered on lastAudioError) -int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint) -{ - int mixIndex; - - for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot - { - if (mixChannels[mixIndex] == NULL) break; - else if (mixIndex == (MAX_MIX_CHANNELS - 1)) - { - lastAudioError = ERROR_OUT_OF_MIX_CHANNELS; - return -1; - } - } - - if (InitMixChannel(sampleRate, mixIndex, channels, floatingPoint)) return mixIndex; - else - { - lastAudioError = ERROR_RAW_CONTEXT_CREATION; - return -1; - } -} - -// Buffers data directly to raw mix channel -// if 0 is returned, buffers are still full and you need to keep trying with the same data -// otherwise it will return number of samples buffered. -// NOTE: Data could be either be an array of floats or shorts, depending on the created context -int BufferRawAudioContext(int ctx, void *data, unsigned short numberElements) -{ - int numBuffered = 0; - - if (ctx >= 0) - { - MixChannel *mixc = mixChannels[ctx]; - numBuffered = BufferMixChannel(mixc, data, numberElements); - } - - return numBuffered; -} - -// Closes and frees raw mix channel -void CloseRawAudioContext(int ctx) -{ - if (mixChannels[ctx]) CloseMixChannel(mixChannels[ctx]); -} - //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- // Load sound to memory +// NOTE: The entire file is loaded to memory to be played (no-streaming) Sound LoadSound(char *fileName) { - Sound sound = { 0 }; Wave wave = { 0 }; - // NOTE: The entire file is loaded to memory to play it all at once (no-streaming) - - // Audio file loading - // NOTE: Buffer space is allocated inside function, Wave must be freed - - if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); - else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); - else - { - TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); - - // TODO: Find a better way to register errors (similar to glGetError()) - lastAudioError = ERROR_EXTENSION_NOT_RECOGNIZED; - } - - if (wave.data != NULL) - { - ALenum format = 0; - // The OpenAL format is worked out by looking at the number of channels and the bits per sample - if (wave.channels == 1) - { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; - } - else if (wave.channels == 2) - { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; - } - - // Create an audio source - ALuint source; - alGenSources(1, &source); // Generate pointer to audio source + if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName); + else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName); + else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); - alSourcef(source, AL_PITCH, 1); - alSourcef(source, AL_GAIN, 1); - alSource3f(source, AL_POSITION, 0, 0, 0); - alSource3f(source, AL_VELOCITY, 0, 0, 0); - alSourcei(source, AL_LOOPING, AL_FALSE); - - // Convert loaded data to OpenAL buffer - //---------------------------------------- - ALuint buffer; - alGenBuffers(1, &buffer); // Generate pointer to buffer - - // Upload sound data to buffer - alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate); - - // Attach sound buffer to source - alSourcei(source, AL_BUFFER, buffer); - - TraceLog(INFO, "[%s] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); - - // Unallocate WAV data - UnloadWave(wave); - - sound.source = source; - sound.buffer = buffer; - } + Sound sound = LoadSoundFromWave(wave); + + // Sound is loaded, we can unload wave + UnloadWave(wave); return sound; } // Load sound from wave data +// NOTE: Wave data must be unallocated manually Sound LoadSoundFromWave(Wave wave) { Sound sound = { 0 }; @@ -586,10 +303,7 @@ Sound LoadSoundFromWave(Wave wave) // Attach sound buffer to source alSourcei(source, AL_BUFFER, buffer); - // Unallocate WAV data - UnloadWave(wave); - - TraceLog(INFO, "[Wave] Sound file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.bitsPerSample, wave.channels); sound.source = source; sound.buffer = buffer; @@ -619,11 +333,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) FILE *rresFile = fopen(rresName, "rb"); - if (rresFile == NULL) - { - TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); - lastAudioError = ERROR_UNABLE_TO_OPEN_RRES_FILE; - } + if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); else { // Read rres file (basic file check - id) @@ -637,7 +347,6 @@ Sound LoadSoundFromRES(const char *rresName, int resId) if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) { TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); - lastAudioError = ERROR_INVALID_RRES_FILE; } else { @@ -681,55 +390,12 @@ Sound LoadSoundFromRES(const char *rresName, int resId) free(data); - // Convert wave to Sound (OpenAL) - ALenum format = 0; - - // The OpenAL format is worked out by looking at the number of channels and the bits per sample - if (wave.channels == 1) - { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; - } - else if (wave.channels == 2) - { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; - } - - // Create an audio source - ALuint source; - alGenSources(1, &source); // Generate pointer to audio source - - alSourcef(source, AL_PITCH, 1); - alSourcef(source, AL_GAIN, 1); - alSource3f(source, AL_POSITION, 0, 0, 0); - alSource3f(source, AL_VELOCITY, 0, 0, 0); - alSourcei(source, AL_LOOPING, AL_FALSE); - - // Convert loaded data to OpenAL buffer - //---------------------------------------- - ALuint buffer; - alGenBuffers(1, &buffer); // Generate pointer to buffer - - // Upload sound data to buffer - alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate); - - // Attach sound buffer to source - alSourcei(source, AL_BUFFER, buffer); - - TraceLog(INFO, "[%s] Sound loaded successfully from resource (SampleRate: %i, BitRate: %i, Channels: %i)", rresName, wave.sampleRate, wave.bitsPerSample, wave.channels); - - // Unallocate WAV data + sound = LoadSoundFromWave(wave); + + // Sound is loaded, we can unload wave data UnloadWave(wave); - - sound.source = source; - sound.buffer = buffer; - } - else - { - TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName); - lastAudioError = ERROR_INVALID_RRES_RESOURCE; } + else TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName); } else { @@ -764,7 +430,7 @@ void UnloadSound(Sound sound) alDeleteSources(1, &sound.source); alDeleteBuffers(1, &sound.buffer); - TraceLog(INFO, "Unloaded sound data"); + TraceLog(INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); } // Play a sound @@ -794,6 +460,16 @@ void PauseSound(Sound sound) alSourcePause(sound.source); } +// Resume a paused sound +void ResumeSound(Sound sound) +{ + ALenum state; + + alGetSourcei(sound.source, AL_SOURCE_STATE, &state); + + if (state == AL_PAUSED) alSourcePlay(sound.source); +} + // Stop reproducing a sound void StopSound(Sound sound) { @@ -828,409 +504,426 @@ void SetSoundPitch(Sound sound, float pitch) // Module Functions Definition - Music loading and stream playing (.OGG) //---------------------------------------------------------------------------------- -MusicBuffer LoadMusicBufferStream(char *fileName, int index) +// Load music stream from file +Music LoadMusicStream(char *fileName) { - MusicBuffer buffer = { 0 }; + Music music = (MusicData *)malloc(sizeof(MusicData)); - if(index > MAX_MUSIC_STREAMS) + if (strcmp(GetExtension(fileName), "ogg") == 0) { - TraceLog("[%s] index is greater than MAX_MUSIC_STREAMS", ERROR); - return; // error - } - - buffer.fileName = fileName; - buffer.index = index; - - - if (musicStreams[buffer.index].stream || musicStreams[buffer.index].xmctx) return; // error + // Open ogg audio stream + music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL); - return buffer; -} - -// Start music playing (open stream) -// returns 0 on success or error code -int PlayMusicStream(MusicBuffer musicBuffer) -{ - if(musicBuffer.fileName == 0) - { - return ERROR_UNINTIALIZED_MUSIC_BUFFER; - } - int mixIndex; - for (mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot - { - if (mixChannels[mixIndex] == NULL) break; - else if (mixIndex == (MAX_MIX_CHANNELS - 1)) return ERROR_OUT_OF_MIX_CHANNELS; // error - } - - if (strcmp(GetExtension(musicBuffer.fileName),"ogg") == 0) - { - // Open audio stream - musicStreams[musicBuffer.index].stream = stb_vorbis_open_filename(musicBuffer.fileName, NULL, NULL); - - if (musicStreams[musicBuffer.index].stream == NULL) + if (music->ctxOgg == NULL) { - TraceLog(WARNING, "[%s] OGG audio file could not be opened", musicBuffer.fileName); - return ERROR_LOADING_OGG; // error + TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName); } else { - // Get file info - stb_vorbis_info info = stb_vorbis_get_info(musicStreams[musicBuffer.index].stream); - - TraceLog(INFO, "[%s] Ogg sample rate: %i", musicBuffer.fileName, info.sample_rate); - TraceLog(INFO, "[%s] Ogg channels: %i", musicBuffer.fileName, info.channels); - TraceLog(DEBUG, "[%s] Temp memory required: %i", musicBuffer.fileName, info.temp_memory_required); + stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // Get Ogg file info - musicStreams[musicBuffer.index].loop = true; // We loop by default - musicStreams[musicBuffer.index].enabled = true; + TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); + TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); + TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); + // TODO: Support 32-bit sampleSize OGGs + music->stream = InitAudioStream(info.sample_rate, 16, info.channels); + + music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg)*info.channels; + music->samplesLeft = music->totalSamples; + //float totalLengthSeconds = stb_vorbis_stream_length_in_seconds(music->ctxOgg); - musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream) * info.channels; - musicStreams[musicBuffer.index].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[musicBuffer.index].stream); - - if (info.channels == 2) - { - musicStreams[musicBuffer.index].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false); - musicStreams[musicBuffer.index].mixc->playing = true; - } - else - { - musicStreams[musicBuffer.index].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false); - musicStreams[musicBuffer.index].mixc->playing = true; - } - - if (!musicStreams[musicBuffer.index].mixc) return ERROR_LOADING_OGG; // error + music->ctxType = MUSIC_AUDIO_OGG; + music->loop = true; // We loop by default } } - else if (strcmp(GetExtension(musicBuffer.fileName),"xm") == 0) + else if (strcmp(GetExtension(fileName), "xm") == 0) { - // only stereo is supported for xm - if (!jar_xm_create_context_from_file(&musicStreams[musicBuffer.index].xmctx, 48000, musicBuffer.fileName)) + int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName); + + if (!result) // XM context created successfully { - musicStreams[musicBuffer.index].chipTune = true; - musicStreams[musicBuffer.index].loop = true; - jar_xm_set_max_loop_count(musicStreams[musicBuffer.index].xmctx, 0); // infinite number of loops - musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)jar_xm_get_remaining_samples(musicStreams[musicBuffer.index].xmctx); - musicStreams[musicBuffer.index].totalLengthSeconds = ((float)musicStreams[musicBuffer.index].totalSamplesLeft)/48000.0f; - musicStreams[musicBuffer.index].enabled = true; - - TraceLog(INFO, "[%s] XM number of samples: %i", musicBuffer.fileName, musicStreams[musicBuffer.index].totalSamplesLeft); - TraceLog(INFO, "[%s] XM track length: %11.6f sec", musicBuffer.fileName, musicStreams[musicBuffer.index].totalLengthSeconds); - - musicStreams[musicBuffer.index].mixc = InitMixChannel(48000, mixIndex, 2, true); - - if (!musicStreams[musicBuffer.index].mixc) return ERROR_XM_CONTEXT_CREATION; // error - - musicStreams[musicBuffer.index].mixc->playing = true; - } - else - { - TraceLog(WARNING, "[%s] XM file could not be opened", musicBuffer.fileName); - return ERROR_LOADING_XM; // error + jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops + + music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); + music->samplesLeft = music->totalSamples; + + TraceLog(INFO, "[%s] XM number of samples: %i", fileName, music->totalSamples); + TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); + + // NOTE: Only stereo is supported for XM + music->stream = InitAudioStream(48000, 32, 2); + + music->ctxType = MUSIC_MODULE_XM; + music->loop = true; } + else TraceLog(WARNING, "[%s] XM file could not be opened", fileName); } - else if (strcmp(GetExtension(musicBuffer.fileName),"mod") == 0) + else if (strcmp(GetExtension(fileName), "mod") == 0) { - jar_mod_init(&musicStreams[musicBuffer.index].modctx); + jar_mod_init(&music->ctxMod); - if (jar_mod_load_file(&musicStreams[musicBuffer.index].modctx, musicBuffer.fileName)) + if (jar_mod_load_file(&music->ctxMod, fileName)) { - musicStreams[musicBuffer.index].chipTune = true; - musicStreams[musicBuffer.index].loop = true; - musicStreams[musicBuffer.index].totalSamplesLeft = (unsigned int)jar_mod_max_samples(&musicStreams[musicBuffer.index].modctx); - musicStreams[musicBuffer.index].totalLengthSeconds = ((float)musicStreams[musicBuffer.index].totalSamplesLeft)/48000.0f; - musicStreams[musicBuffer.index].enabled = true; + music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod); + music->samplesLeft = music->totalSamples; - TraceLog(INFO, "[%s] MOD number of samples: %i", musicBuffer.fileName, musicStreams[musicBuffer.index].totalSamplesLeft); - TraceLog(INFO, "[%s] MOD track length: %11.6f sec", musicBuffer.fileName, musicStreams[musicBuffer.index].totalLengthSeconds); + TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, music->samplesLeft); + TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); - musicStreams[musicBuffer.index].mixc = InitMixChannel(48000, mixIndex, 2, false); + music->stream = InitAudioStream(48000, 16, 2); - if (!musicStreams[musicBuffer.index].mixc) return ERROR_MOD_CONTEXT_CREATION; // error - - musicStreams[musicBuffer.index].mixc->playing = true; - } - else - { - TraceLog(WARNING, "[%s] MOD file could not be opened", musicBuffer.fileName); - return ERROR_LOADING_MOD; // error + music->ctxType = MUSIC_MODULE_MOD; + music->loop = true; } + else TraceLog(WARNING, "[%s] MOD file could not be opened", fileName); } - else - { - TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", musicBuffer.fileName); - return ERROR_EXTENSION_NOT_RECOGNIZED; // error - } + else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName); - return 0; // normal return + return music; } -// Stop music playing for individual music index of musicStreams array (close stream) -void StopMusicStream(MusicBuffer musicBuffer) +// Unload music stream +void UnloadMusicStream(Music music) { - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) - { - CloseMixChannel(musicStreams[musicBuffer.index].mixc); - - if (musicStreams[musicBuffer.index].xmctx) - jar_xm_free_context(musicStreams[musicBuffer.index].xmctx); - else if (musicStreams[musicBuffer.index].modctx.mod_loaded) - jar_mod_unload(&musicStreams[musicBuffer.index].modctx); - else - stb_vorbis_close(musicStreams[musicBuffer.index].stream); - - musicStreams[musicBuffer.index].enabled = false; + CloseAudioStream(music->stream); + + if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); + else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm); + else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); + + free(music); +} - if (musicStreams[musicBuffer.index].stream || musicStreams[musicBuffer.index].xmctx) - { - musicStreams[musicBuffer.index].stream = NULL; - musicStreams[musicBuffer.index].xmctx = NULL; - } - } +// Start music playing (open stream) +void PlayMusicStream(Music music) +{ + alSourcePlay(music->stream.source); } -void StopMusicStreamEx(int index) +// Pause music playing +void PauseMusicStream(Music music) { - if (index < MAX_MUSIC_STREAMS && musicStreams[index].mixc) - { - CloseMixChannel(musicStreams[index].mixc); + alSourcePause(music->stream.source); +} - if (musicStreams[index].xmctx) - jar_xm_free_context(musicStreams[index].xmctx); - else if (musicStreams[index].modctx.mod_loaded) - jar_mod_unload(&musicStreams[index].modctx); - else - stb_vorbis_close(musicStreams[index].stream); +// Resume music playing +void ResumeMusicStream(Music music) +{ + ALenum state; + alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - musicStreams[index].enabled = false; + if (state == AL_PAUSED) alSourcePlay(music->stream.source); +} - if (musicStreams[index].stream || musicStreams[index].xmctx) - { - musicStreams[index].stream = NULL; - musicStreams[index].xmctx = NULL; - } - } +// Stop music playing (close stream) +void StopMusicStream(Music music) +{ + alSourceStop(music->stream.source); } // Update (re-fill) music buffers if data already processed -void UpdateMusicStream(MusicBuffer musicBuffer) +void UpdateMusicStream(Music music) { ALenum state; bool active = true; ALint processed = 0; // Determine if music stream is ready to be written - alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - if (musicStreams[musicBuffer.index].mixc->playing && (musicBuffer.index < MAX_MUSIC_STREAMS) && musicStreams[musicBuffer.index].enabled && musicStreams[musicBuffer.index].mixc && (processed > 0)) + if (processed > 0) { - active = BufferMusicStream(musicBuffer.index, processed); + active = BufferMusicStream(music, processed); - if (!active && musicStreams[musicBuffer.index].loop) + if (!active && music->loop) { - if (musicStreams[musicBuffer.index].chipTune) - { - if(musicStreams[musicBuffer.index].modctx.mod_loaded) jar_mod_seek_start(&musicStreams[musicBuffer.index].modctx); - - musicStreams[musicBuffer.index].totalSamplesLeft = musicStreams[musicBuffer.index].totalLengthSeconds*48000.0f; - } - else - { - stb_vorbis_seek_start(musicStreams[musicBuffer.index].stream); - musicStreams[musicBuffer.index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream)*musicStreams[musicBuffer.index].mixc->channels; - } + // Restart music context (if required) + if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_seek_start(&music->ctxMod); + else if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_seek_start(music->ctxOgg); + + music->samplesLeft = music->totalSamples; // Determine if music stream is ready to be written - alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - active = BufferMusicStream(musicBuffer.index, processed); + active = BufferMusicStream(music, processed); } if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); - alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); - - if (state != AL_PLAYING && active) alSourcePlay(musicStreams[musicBuffer.index].mixc->alSource); + alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - if (!active) StopMusicStream(musicBuffer); + if (state != AL_PLAYING && active) alSourcePlay(music->stream.source); - } -} - -//get number of music channels active at this time, this does not mean they are playing -int GetMusicStreamCount(void) -{ - int musicCount = 0; - - // Find empty music slot - for (int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) - { - if(musicStreams[musicIndex].stream != NULL || musicStreams[musicIndex].chipTune) musicCount++; - } - - return musicCount; -} - -// Pause music playing -void PauseMusicStream(MusicBuffer musicBuffer) -{ - // Pause music stream if music available! - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc && musicStreams[musicBuffer.index].enabled) - { - TraceLog(INFO, "Pausing music stream"); - alSourcePause(musicStreams[musicBuffer.index].mixc->alSource); - musicStreams[musicBuffer.index].mixc->playing = false; - } -} - -// Resume music playing -void ResumeMusicStream(MusicBuffer musicBuffer) -{ - // Resume music playing... if music available! - ALenum state; - - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) - { - alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); - - if (state == AL_PAUSED) - { - TraceLog(INFO, "Resuming music stream"); - alSourcePlay(musicStreams[musicBuffer.index].mixc->alSource); - musicStreams[musicBuffer.index].mixc->playing = true; - } + if (!active) StopMusicStream(music); } } // Check if any music is playing -bool IsMusicPlaying(MusicBuffer musicBuffer) +bool IsMusicPlaying(Music music) { bool playing = false; ALint state; - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) - { - alGetSourcei(musicStreams[musicBuffer.index].mixc->alSource, AL_SOURCE_STATE, &state); + alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); - if (state == AL_PLAYING) playing = true; - } + if (state == AL_PLAYING) playing = true; return playing; } // Set volume for music -void SetMusicVolume(MusicBuffer musicBuffer, float volume) +void SetMusicVolume(Music music, float volume) { - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) - { - alSourcef(musicStreams[musicBuffer.index].mixc->alSource, AL_GAIN, volume); - } + alSourcef(music->stream.source, AL_GAIN, volume); } // Set pitch for music -void SetMusicPitch(MusicBuffer musicBuffer, float pitch) +void SetMusicPitch(Music music, float pitch) { - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) - { - alSourcef(musicStreams[musicBuffer.index].mixc->alSource, AL_PITCH, pitch); - } + alSourcef(music->stream.source, AL_PITCH, pitch); } // Get music time length (in seconds) -float GetMusicTimeLength(MusicBuffer musicBuffer) +float GetMusicTimeLength(Music music) { - float totalSeconds; - - if (musicStreams[musicBuffer.index].chipTune) totalSeconds = (float)musicStreams[musicBuffer.index].totalLengthSeconds; - else totalSeconds = stb_vorbis_stream_length_in_seconds(musicStreams[musicBuffer.index].stream); - + float totalSeconds = (float)music->totalSamples/music->stream.sampleRate; + return totalSeconds; } // Get current music time played (in seconds) -float GetMusicTimePlayed(MusicBuffer musicBuffer) +float GetMusicTimePlayed(Music music) { float secondsPlayed = 0.0f; - if (musicBuffer.index < MAX_MUSIC_STREAMS && musicStreams[musicBuffer.index].mixc) + if (music->ctxType == MUSIC_MODULE_XM) { - if (musicStreams[musicBuffer.index].chipTune && musicStreams[musicBuffer.index].xmctx) + uint64_t samplesPlayed; + jar_xm_get_position(music->ctxXm, NULL, NULL, NULL, &samplesPlayed); + + // TODO: Not sure if this is the correct value + secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); + } + else if (music->ctxType == MUSIC_MODULE_MOD) + { + long samplesPlayed = jar_mod_current_samples(&music->ctxMod); + + secondsPlayed = (float)samplesPlayed/music->stream.sampleRate; + } + else if (music->ctxType == MUSIC_AUDIO_OGG) + { + unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; + + secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); + } + + return secondsPlayed; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Init audio stream (to stream audio pcm data) +static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) +{ + AudioStream stream = { 0 }; + + stream.sampleRate = sampleRate; + stream.sampleSize = sampleSize; + stream.channels = channels; + + // Setup OpenAL format + if (channels == 1) + { + switch (sampleSize) { - uint64_t samples; - jar_xm_get_position(musicStreams[musicBuffer.index].xmctx, NULL, NULL, NULL, &samples); - secondsPlayed = (float)samples/(48000.0f*musicStreams[musicBuffer.index].mixc->channels); // Not sure if this is the correct value + case 8: stream.format = AL_FORMAT_MONO8; break; + case 16: stream.format = AL_FORMAT_MONO16; break; + case 32: stream.format = AL_FORMAT_MONO_FLOAT32; break; + default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; } - else if(musicStreams[musicBuffer.index].chipTune && musicStreams[musicBuffer.index].modctx.mod_loaded) + } + else if (channels == 2) + { + switch (sampleSize) { - long numsamp = jar_mod_current_samples(&musicStreams[musicBuffer.index].modctx); - secondsPlayed = (float)numsamp/(48000.0f); + case 8: stream.format = AL_FORMAT_STEREO8; break; + case 16: stream.format = AL_FORMAT_STEREO16; break; + case 32: stream.format = AL_FORMAT_STEREO_FLOAT32; break; + default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break; } - else + } + else TraceLog(WARNING, "Init audio stream: Number of channels not supported: %i", channels); + + // Create an audio source + alGenSources(1, &stream.source); + alSourcef(stream.source, AL_PITCH, 1); + alSourcef(stream.source, AL_GAIN, 1); + alSource3f(stream.source, AL_POSITION, 0, 0, 0); + alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); + + // Create Buffers + alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); + + // Initialize buffer with zeros by default + for (int i = 0; i < MAX_STREAM_BUFFERS; i++) + { + if (stream.sampleSize == 8) { - int totalSamples = stb_vorbis_stream_length_in_samples(musicStreams[musicBuffer.index].stream)*musicStreams[musicBuffer.index].mixc->channels; - int samplesPlayed = totalSamples - musicStreams[musicBuffer.index].totalSamplesLeft; - secondsPlayed = (float)samplesPlayed/(musicStreams[musicBuffer.index].mixc->sampleRate*musicStreams[musicBuffer.index].mixc->channels); + unsigned char pcm[AUDIO_BUFFER_SIZE] = { 0 }; + alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(unsigned char), stream.sampleRate); + } + else if (stream.sampleSize == 16) + { + short pcm[AUDIO_BUFFER_SIZE] = { 0 }; + alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(short), stream.sampleRate); + } + else if (stream.sampleSize == 32) + { + float pcm[AUDIO_BUFFER_SIZE] = { 0.0f }; + alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(float), stream.sampleRate); } } - return secondsPlayed; + alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); + + TraceLog(INFO, "[AUD ID %i] Audio stream loaded successfully", stream.source); + + return stream; } -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- +// Close audio stream and free memory +static void CloseAudioStream(AudioStream stream) +{ + // Stop playing channel + alSourceStop(stream.source); + + // Flush out all queued buffers + int queued = 0; + alGetSourcei(stream.source, AL_BUFFERS_QUEUED, &queued); + + ALuint buffer = 0; + + while (queued > 0) + { + alSourceUnqueueBuffers(stream.source, 1, &buffer); + queued--; + } + + // Delete source and buffers + alDeleteSources(1, &stream.source); + alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers); + + TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); +} + +// Push more audio data into audio stream, only one buffer per call +// NOTE: Returns number of samples that were processed +static int BufferAudioStream(AudioStream stream, void *data, int numberElements) +{ + if (!data || !numberElements) + { + // Pauses audio until data is given + alSourcePause(stream.source); + return 0; + } + + ALuint buffer = 0; + alSourceUnqueueBuffers(stream.source, 1, &buffer); + + if (!buffer) return 0; + + // Reference + //void alBufferData(ALuint bufferName, ALenum format, const ALvoid *data, ALsizei size, ALsizei frequency); + + // ALuint bufferName: buffer id + // ALenum format: Valid formats are + // AL_FORMAT_MONO8, // unsigned char + // AL_FORMAT_MONO16, // short + // AL_FORMAT_STEREO8, + // AL_FORMAT_STEREO16 // stereo data is interleaved: left+right channels sample + // AL_FORMAT_MONO_FLOAT32 (extension) + // AL_FORMAT_STEREO_FLOAT32 (extension) + // ALsizei size: Number of bytes, must be coherent with format + // ALsizei frequency: sample rate + + if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numberElements*sizeof(unsigned char), stream.sampleRate); + else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numberElements*sizeof(short), stream.sampleRate); + else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numberElements*sizeof(float), stream.sampleRate); + + alSourceQueueBuffers(stream.source, 1, &buffer); + + return numberElements; +} // Fill music buffers with new data from music stream -static bool BufferMusicStream(int index, int numBuffers) +static bool BufferMusicStream(Music music, int numBuffersToProcess) { - short pcm[MUSIC_BUFFER_SIZE_SHORT]; - float pcmf[MUSIC_BUFFER_SIZE_FLOAT]; + short pcm[AUDIO_BUFFER_SIZE]; + float pcmf[AUDIO_BUFFER_SIZE]; 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 (musicStreams[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. + if (music->ctxType == MUSIC_MODULE_XM) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes. { - for (int i = 0; i < numBuffers; i++) + for (int i = 0; i < numBuffersToProcess; i++) { - if (musicStreams[index].modctx.mod_loaded) - { - if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT/2; - else size = musicStreams[index].totalSamplesLeft/2; + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE/2; + else size = music->samplesLeft/2; - jar_mod_fillbuffer(&musicStreams[index].modctx, pcm, size, 0 ); - BufferMixChannel(musicStreams[index].mixc, pcm, size*2); - } - else if (musicStreams[index].xmctx) - { - if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT) size = MUSIC_BUFFER_SIZE_FLOAT/2; - else size = musicStreams[index].totalSamplesLeft/2; + // Read 2*shorts and moves them to buffer+size memory location + jar_xm_generate_samples(music->ctxXm, pcmf, size); + + BufferAudioStream(music->stream, pcmf, size*2); + + music->samplesLeft -= size; - jar_xm_generate_samples(musicStreams[index].xmctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location - BufferMixChannel(musicStreams[index].mixc, pcmf, size*2); + if (music->samplesLeft <= 0) + { + active = false; + break; } + } + } + else if (music->ctxType == MUSIC_MODULE_MOD) + { + for (int i = 0; i < numBuffersToProcess; i++) + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE/2; + else size = music->samplesLeft/2; + + jar_mod_fillbuffer(&music->ctxMod, pcm, size, 0); + + BufferAudioStream(music->stream, pcm, size*2); - musicStreams[index].totalSamplesLeft -= size; + music->samplesLeft -= size; - if (musicStreams[index].totalSamplesLeft <= 0) + if (music->samplesLeft <= 0) { active = false; break; } } } - else + else if (music->ctxType == MUSIC_AUDIO_OGG) { - if (musicStreams[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT) size = MUSIC_BUFFER_SIZE_SHORT; - else size = musicStreams[index].totalSamplesLeft; + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE; + else size = music->samplesLeft; - for (int i = 0; i < numBuffers; i++) + for (int i = 0; i < numBuffersToProcess; i++) { - int streamedBytes = stb_vorbis_get_samples_short_interleaved(musicStreams[index].stream, musicStreams[index].mixc->channels, pcm, size); - BufferMixChannel(musicStreams[index].mixc, pcm, streamedBytes * musicStreams[index].mixc->channels); - musicStreams[index].totalSamplesLeft -= streamedBytes * musicStreams[index].mixc->channels; - - if (musicStreams[index].totalSamplesLeft <= 0) + // NOTE: Returns the number of samples stored per channel + int numSamples = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, size); + + BufferAudioStream(music->stream, pcm, numSamples*music->stream.channels); + + music->samplesLeft -= (numSamples*music->stream.channels); + + if (music->samplesLeft <= 0) { active = false; break; @@ -1241,22 +934,6 @@ static bool BufferMusicStream(int index, int numBuffers) return active; } -// Empty music buffers -static void EmptyMusicStream(int index) -{ - ALuint buffer = 0; - int queued = 0; - - alGetSourcei(musicStreams[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued); - - while (queued > 0) - { - alSourceUnqueueBuffers(musicStreams[index].mixc->alSource, 1, &buffer); - - queued--; - } -} - // Load WAV file into Wave structure static Wave LoadWAV(const char *fileName) { @@ -1382,7 +1059,7 @@ static Wave LoadOGG(char *fileName) TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); - int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels); + int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile)*info.channels); wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes @@ -1417,7 +1094,7 @@ static void UnloadWave(Wave wave) { free(wave.data); - TraceLog(INFO, "Unloaded wave data"); + TraceLog(INFO, "Unloaded wave data from RAM"); } // Some required functions for audio standalone module version diff --git a/src/audio.h b/src/audio.h index d39162b5..c9171339 100644 --- a/src/audio.h +++ b/src/audio.h @@ -75,10 +75,9 @@ typedef struct Wave { short channels; } Wave; -typedef struct MusicBuffer { - char *fileName; - int index; // index in musicStreams -} MusicBuffer; +// Music type (file streaming from memory) +// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel... +typedef struct Music *Music; #ifdef __cplusplus extern "C" { // Prevents name mangling of functions @@ -102,27 +101,24 @@ Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound void PauseSound(Sound sound); // Pause a sound +void ResumeSound(Sound sound); // Resume a paused sound void StopSound(Sound sound); // Stop playing a sound bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing 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) -MusicBuffer LoadMusicBufferStream(char *fileName, int index); -int PlayMusicStream(MusicBuffer buffer); // Start music playing (open stream) -void UpdateMusicStream(MusicBuffer buffer); // Updates buffers for music streaming -void StopMusicStream(MusicBuffer buffer); // Stop music playing (close stream) -void PauseMusicStream(MusicBuffer buffer); // Pause music playing -void ResumeMusicStream(MusicBuffer buffer); // Resume playing paused music -bool IsMusicPlaying(MusicBuffer buffer); // Check if music is playing -void SetMusicVolume(MusicBuffer buffer float volume); // Set volume for music (1.0 is max level) -void SetMusicPitch(MusicBuffer buffer, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(MusicBuffer buffer); // Get music time length (in seconds) -float GetMusicTimePlayed(MusicBuffer buffer); // Get current music time played (in seconds) -int GetMusicStreamCount(void); // Get number of streams loaded - -int InitRawMixChannel(int sampleRate, int channels, bool floatingPoint); // Initialize raw audio mix channel for audio buffering -int BufferRawMixChannel(int mixc, void *data, unsigned short numberElements); // Buffers data directly to raw mix channel -void CloseRawMixChannel(int mixc); // Closes and frees raw mix channel +Music LoadMusicStream(char *fileName); // Load music stream from file +void UnloadMusicStream(Music music); // Unload music stream +void PlayMusicStream(Music music); // Start music playing (open stream) +void UpdateMusicStream(Music music); // Updates buffers for music streaming +void StopMusicStream(Music music); // Stop music playing (close stream) +void PauseMusicStream(Music music); // Pause music playing +void ResumeMusicStream(Music music); // Resume playing paused music +bool IsMusicPlaying(Music music); // Check if music is playing +void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +float GetMusicTimeLength(Music music); // Get music time length (in seconds) +float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) #ifdef __cplusplus } diff --git a/src/external/jar_xm.h b/src/external/jar_xm.h index 02463e08..7f0517df 100644 --- a/src/external/jar_xm.h +++ b/src/external/jar_xm.h @@ -102,7 +102,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const * @deprecated This function is unsafe! * @see jar_xm_create_context_safe() */ -int jar_xm_create_context(jar_xm_context_t**, const char* moddata, uint32_t rate); +int jar_xm_create_context(jar_xm_context_t** ctx, const char* moddata, uint32_t rate); /** Create a XM context. * @@ -114,17 +114,17 @@ int jar_xm_create_context(jar_xm_context_t**, const char* moddata, uint32_t rate * @returns 1 if module data is not sane * @returns 2 if memory allocation failed */ -int jar_xm_create_context_safe(jar_xm_context_t**, const char* moddata, size_t moddata_length, uint32_t rate); +int jar_xm_create_context_safe(jar_xm_context_t** ctx, const char* moddata, size_t moddata_length, uint32_t rate); /** Free a XM context created by jar_xm_create_context(). */ -void jar_xm_free_context(jar_xm_context_t*); +void jar_xm_free_context(jar_xm_context_t* ctx); /** Play the module and put the sound samples in an output buffer. * * @param output buffer of 2*numsamples elements (A left and right value for each sample) * @param numsamples number of samples to generate */ -void jar_xm_generate_samples(jar_xm_context_t*, float* output, size_t numsamples); +void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsamples); /** Play the module, resample from 32 bit to 16 bit, and put the sound samples in an output buffer. * @@ -173,12 +173,12 @@ void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t nu * * @param loopcnt maximum number of loops. Use 0 to loop * indefinitely. */ -void jar_xm_set_max_loop_count(jar_xm_context_t*, uint8_t loopcnt); +void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt); /** Get the loop count of the currently playing module. This value is * 0 when the module is still playing, 1 when the module has looped * once, etc. */ -uint8_t jar_xm_get_loop_count(jar_xm_context_t*); +uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx); @@ -188,7 +188,7 @@ uint8_t jar_xm_get_loop_count(jar_xm_context_t*); * * @return whether the channel was muted. */ -bool jar_xm_mute_channel(jar_xm_context_t*, uint16_t, bool); +bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t, bool); /** Mute or unmute an instrument. * @@ -197,43 +197,43 @@ bool jar_xm_mute_channel(jar_xm_context_t*, uint16_t, bool); * * @return whether the instrument was muted. */ -bool jar_xm_mute_instrument(jar_xm_context_t*, uint16_t, bool); +bool jar_xm_mute_instrument(jar_xm_context_t* ctx, uint16_t, bool); /** Get the module name as a NUL-terminated string. */ -const char* jar_xm_get_module_name(jar_xm_context_t*); +const char* jar_xm_get_module_name(jar_xm_context_t* ctx); /** Get the tracker name as a NUL-terminated string. */ -const char* jar_xm_get_tracker_name(jar_xm_context_t*); +const char* jar_xm_get_tracker_name(jar_xm_context_t* ctx); /** Get the number of channels. */ -uint16_t jar_xm_get_number_of_channels(jar_xm_context_t*); +uint16_t jar_xm_get_number_of_channels(jar_xm_context_t* ctx); /** Get the module length (in patterns). */ uint16_t jar_xm_get_module_length(jar_xm_context_t*); /** Get the number of patterns. */ -uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t*); +uint16_t jar_xm_get_number_of_patterns(jar_xm_context_t* ctx); /** Get the number of rows of a pattern. * * @note Pattern numbers go from 0 to * jar_xm_get_number_of_patterns(...)-1. */ -uint16_t jar_xm_get_number_of_rows(jar_xm_context_t*, uint16_t); +uint16_t jar_xm_get_number_of_rows(jar_xm_context_t* ctx, uint16_t); /** Get the number of instruments. */ -uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t*); +uint16_t jar_xm_get_number_of_instruments(jar_xm_context_t* ctx); /** Get the number of samples of an instrument. * * @note Instrument numbers go from 1 to * jar_xm_get_number_of_instruments(...). */ -uint16_t jar_xm_get_number_of_samples(jar_xm_context_t*, uint16_t); +uint16_t jar_xm_get_number_of_samples(jar_xm_context_t* ctx, uint16_t); @@ -242,7 +242,7 @@ uint16_t jar_xm_get_number_of_samples(jar_xm_context_t*, uint16_t); * @param bpm will receive the current BPM * @param tempo will receive the current tempo (ticks per line) */ -void jar_xm_get_playing_speed(jar_xm_context_t*, uint16_t* bpm, uint16_t* tempo); +void jar_xm_get_playing_speed(jar_xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo); /** Get the current position in the module being played. * @@ -257,7 +257,7 @@ void jar_xm_get_playing_speed(jar_xm_context_t*, uint16_t* bpm, uint16_t* tempo) * generated samples (divide by sample rate to get seconds of * generated audio) */ -void jar_xm_get_position(jar_xm_context_t*, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples); +void jar_xm_get_position(jar_xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples); /** Get the latest time (in number of generated samples) when a * particular instrument was triggered in any channel. @@ -265,7 +265,7 @@ void jar_xm_get_position(jar_xm_context_t*, uint8_t* pattern_index, uint8_t* pat * @note Instrument numbers go from 1 to * jar_xm_get_number_of_instruments(...). */ -uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t*, uint16_t); +uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t* ctx, uint16_t); /** Get the latest time (in number of generated samples) when a * particular sample was triggered in any channel. @@ -276,21 +276,21 @@ uint64_t jar_xm_get_latest_trigger_of_instrument(jar_xm_context_t*, uint16_t); * @note Sample numbers go from 0 to * jar_xm_get_nubmer_of_samples(...,instr)-1. */ -uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t*, uint16_t instr, uint16_t sample); +uint64_t jar_xm_get_latest_trigger_of_sample(jar_xm_context_t* ctx, uint16_t instr, uint16_t sample); /** Get the latest time (in number of generated samples) when any * instrument was triggered in a given channel. * * @note Channel numbers go from 1 to jar_xm_get_number_of_channels(...). */ -uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t*, uint16_t); +uint64_t jar_xm_get_latest_trigger_of_channel(jar_xm_context_t* ctx, uint16_t); /** Get the number of remaining samples. Divide by 2 to get the number of individual LR data samples. * * @note This is the remaining number of samples before the loop starts module again, or halts if on last pass. * @note This function is very slow and should only be run once, if at all. */ -uint64_t jar_xm_get_remaining_samples(jar_xm_context_t*); +uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx); #ifdef __cplusplus } @@ -308,7 +308,7 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t*); #include #include -#if JAR_XM_DEBUG +#ifdef JAR_XM_DEBUG #include #define DEBUG(fmt, ...) do { \ fprintf(stderr, "%s(): " fmt "\n", __func__, __VA_ARGS__); \ @@ -638,7 +638,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz /* Initialize most of the fields to 0, 0.f, NULL or false depending on type */ memset(mempool, 0, bytes_needed); - ctx = (*ctxp = (jar_xm_context_t*)mempool); + ctx = (*ctxp = (jar_xm_context_t *)mempool); ctx->allocated_memory = mempool; /* Keep original pointer for free() */ mempool += sizeof(jar_xm_context_t); @@ -685,20 +685,18 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz return 0; } -void jar_xm_free_context(jar_xm_context_t* context) { - free(context->allocated_memory); +void jar_xm_free_context(jar_xm_context_t* ctx) { + free(ctx->allocated_memory); } -void jar_xm_set_max_loop_count(jar_xm_context_t* context, uint8_t loopcnt) { - context->max_loop_count = loopcnt; +void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) { + ctx->max_loop_count = loopcnt; } -uint8_t jar_xm_get_loop_count(jar_xm_context_t* context) { - return context->loop_count; +uint8_t jar_xm_get_loop_count(jar_xm_context_t* ctx) { + return ctx->loop_count; } - - bool jar_xm_mute_channel(jar_xm_context_t* ctx, uint16_t channel, bool mute) { bool old = ctx->channels[channel - 1].muted; ctx->channels[channel - 1].muted = mute; diff --git a/src/raylib.h b/src/raylib.h index 1966f75e..f8dd8359 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -478,10 +478,9 @@ typedef struct Wave { short channels; } Wave; -typedef struct MusicBuffer { - char *fileName; - int index; // index in musicStreams -} MusicBuffer; +// Music type (file streaming from memory) +// NOTE: Anything longer than ~10 seconds should be streamed +typedef struct Music *Music; // Texture formats // NOTE: Support depends on OpenGL version and platform @@ -897,23 +896,24 @@ Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound void PauseSound(Sound sound); // Pause a sound +void ResumeSound(Sound sound); // Resume a paused sound void StopSound(Sound sound); // Stop playing a sound bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing 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) -MusicBuffer LoadMusicBufferStream(char *fileName, int index); -int PlayMusicStream(MusicBuffer buffer); // Start music playing (open stream) -void UpdateMusicStream(MusicBuffer buffer); // Updates buffers for music streaming -void StopMusicStream(MusicBuffer buffer); // Stop music playing (close stream) -void PauseMusicStream(MusicBuffer buffer); // Pause music playing -void ResumeMusicStream(MusicBuffer buffer); // Resume playing paused music -bool IsMusicPlaying(MusicBuffer buffer); // Check if music is playing -void SetMusicVolume(MusicBuffer buffer, float volume); // Set volume for music (1.0 is max level) -void SetMusicPitch(MusicBuffer buffer, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(MusicBuffer buffer); // Get music time length (in seconds) -float GetMusicTimePlayed(MusicBuffer buffer); // Get current music time played (in seconds) -int GetMusicStreamCount(void); // Get number of streams loaded +Music LoadMusicStream(char *fileName); // Load music stream from file +void UnloadMusicStream(Music music); // Unload music stream +void PlayMusicStream(Music music); // Start music playing (open stream) +void UpdateMusicStream(Music music); // Updates buffers for music streaming +void StopMusicStream(Music music); // Stop music playing (close stream) +void PauseMusicStream(Music music); // Pause music playing +void ResumeMusicStream(Music music); // Resume playing paused music +bool IsMusicPlaying(Music music); // Check if music is playing +void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +float GetMusicTimeLength(Music music); // Get music time length (in seconds) +float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) #ifdef __cplusplus } -- cgit v1.2.3 From 36cf1f7dfd8865310c21b0f78cf1de9976d9197a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 1 Aug 2016 18:05:07 +0200 Subject: Improved support for C++ Added compound literals (C99) alternative for C++ compilers that don't support this feature --- src/raylib.h | 91 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 28 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index f8dd8359..4b9f6ca0 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -235,33 +235,64 @@ // Some Basic Colors // NOTE: Custom raylib color palette for amazing visuals on WHITE background -#define LIGHTGRAY (Color){ 200, 200, 200, 255 } // Light Gray -#define GRAY (Color){ 130, 130, 130, 255 } // Gray -#define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray -#define YELLOW (Color){ 253, 249, 0, 255 } // Yellow -#define GOLD (Color){ 255, 203, 0, 255 } // Gold -#define ORANGE (Color){ 255, 161, 0, 255 } // Orange -#define PINK (Color){ 255, 109, 194, 255 } // Pink -#define RED (Color){ 230, 41, 55, 255 } // Red -#define MAROON (Color){ 190, 33, 55, 255 } // Maroon -#define GREEN (Color){ 0, 228, 48, 255 } // Green -#define LIME (Color){ 0, 158, 47, 255 } // Lime -#define DARKGREEN (Color){ 0, 117, 44, 255 } // Dark Green -#define SKYBLUE (Color){ 102, 191, 255, 255 } // Sky Blue -#define BLUE (Color){ 0, 121, 241, 255 } // Blue -#define DARKBLUE (Color){ 0, 82, 172, 255 } // Dark Blue -#define PURPLE (Color){ 200, 122, 255, 255 } // Purple -#define VIOLET (Color){ 135, 60, 190, 255 } // Violet -#define DARKPURPLE (Color){ 112, 31, 126, 255 } // Dark Purple -#define BEIGE (Color){ 211, 176, 131, 255 } // Beige -#define BROWN (Color){ 127, 106, 79, 255 } // Brown -#define DARKBROWN (Color){ 76, 63, 47, 255 } // Dark Brown - -#define WHITE (Color){ 255, 255, 255, 255 } // White -#define BLACK (Color){ 0, 0, 0, 255 } // Black -#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) -#define MAGENTA (Color){ 255, 0, 255, 255 } // Magenta -#define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) +#ifdef __cplusplus + // NOTE: MSC C++ compiler does not support compound literals (C99 feature) + #define LIGHTGRAY Color(200, 200, 200, 255) // Light Gray + #define GRAY Color(130, 130, 130, 255) // Gray + #define DARKGRAY Color(80, 80, 80, 255) // Dark Gray + #define YELLOW Color(253, 249, 0, 255) // Yellow + #define GOLD Color(255, 203, 0, 255) // Gold + #define ORANGE Color(255, 161, 0, 255) // Orange + #define PINK Color(255, 109, 194, 255) // Pink + #define RED Color(230, 41, 55, 255) // Red + #define MAROON Color(190, 33, 55, 255) // Maroon + #define GREEN Color(0, 228, 48, 255) // Green + #define LIME Color(0, 158, 47, 255) // Lime + #define DARKGREEN Color(0, 117, 44, 255) // Dark Green + #define SKYBLUE Color(102, 191, 255, 255) // Sky Blue + #define BLUE Color(0, 121, 241, 255) // Blue + #define DARKBLUE Color(0, 82, 172, 255) // Dark Blue + #define PURPLE Color(200, 122, 255, 255) // Purple + #define VIOLET Color(135, 60, 190, 255) // Violet + #define DARKPURPLE Color(112, 31, 126, 255) // Dark Purple + #define BEIGE Color(211, 176, 131, 255) // Beige + #define BROWN Color(127, 106, 79, 255) // Brown + #define DARKBROWN Color(76, 63, 47, 255) // Dark Brown + + #define WHITE Color(255, 255, 255, 255) // White + #define BLACK Color(0, 0, 0, 255) // Black + #define BLANK Color(0, 0, 0, 0) // Blank (Transparent) + #define MAGENTA Color(255, 0, 255, 255) // Magenta + #define RAYWHITE Color(245, 245, 245, 255) // My own White (raylib logo) +#else + #define LIGHTGRAY (Color){ 200, 200, 200, 255 } // Light Gray + #define GRAY (Color){ 130, 130, 130, 255 } // Gray + #define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray + #define YELLOW (Color){ 253, 249, 0, 255 } // Yellow + #define GOLD (Color){ 255, 203, 0, 255 } // Gold + #define ORANGE (Color){ 255, 161, 0, 255 } // Orange + #define PINK (Color){ 255, 109, 194, 255 } // Pink + #define RED (Color){ 230, 41, 55, 255 } // Red + #define MAROON (Color){ 190, 33, 55, 255 } // Maroon + #define GREEN (Color){ 0, 228, 48, 255 } // Green + #define LIME (Color){ 0, 158, 47, 255 } // Lime + #define DARKGREEN (Color){ 0, 117, 44, 255 } // Dark Green + #define SKYBLUE (Color){ 102, 191, 255, 255 } // Sky Blue + #define BLUE (Color){ 0, 121, 241, 255 } // Blue + #define DARKBLUE (Color){ 0, 82, 172, 255 } // Dark Blue + #define PURPLE (Color){ 200, 122, 255, 255 } // Purple + #define VIOLET (Color){ 135, 60, 190, 255 } // Violet + #define DARKPURPLE (Color){ 112, 31, 126, 255 } // Dark Purple + #define BEIGE (Color){ 211, 176, 131, 255 } // Beige + #define BROWN (Color){ 127, 106, 79, 255 } // Brown + #define DARKBROWN (Color){ 76, 63, 47, 255 } // Dark Brown + + #define WHITE (Color){ 255, 255, 255, 255 } // White + #define BLACK (Color){ 0, 0, 0, 255 } // Black + #define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + #define MAGENTA (Color){ 255, 0, 255, 255 } // Magenta + #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -308,6 +339,9 @@ typedef struct Color { unsigned char g; unsigned char b; unsigned char a; +#ifdef __cplusplus + Color(unsigned char cr, unsigned char cg, unsigned char cb, unsigned char ca) : r(cr), g(cg), b(cb), a(ca) { } +#endif } Color; // Rectangle type @@ -819,7 +853,8 @@ Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d mod 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) void UnloadModel(Model model); // Unload 3d model from memory -Mesh GenMeshCube(float width, float height, float depth); + +Mesh GenMeshCube(float width, float height, float depth); // Generate mesh: cube Material LoadMaterial(const char *fileName); // Load material data (from file) Material LoadDefaultMaterial(void); // Load default material (uses default models shader) -- cgit v1.2.3 From 68d647c1af1b9f0479f680dbd7c4f93586cd51a2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 2 Aug 2016 17:32:24 +0200 Subject: Complete review and update Simplified module for Music and AudioStream Added support for raw audio streaming (with example) --- examples/audio_module_playing.c | 2 +- examples/audio_music_stream.c | 3 - examples/audio_raw_stream.c | 106 ++++++++++++++++ examples/audio_sound_loading.c | 1 - examples/resources/audio/2t2m_spa.xm | Bin 2287400 -> 0 bytes examples/resources/audio/chiptun1.mod | Bin 0 -> 2142 bytes examples/resources/audio/mini1111.xm | Bin 0 -> 25676 bytes src/audio.c | 230 ++++++++++++++++++---------------- src/audio.h | 27 +++- src/raylib.h | 29 ++++- 10 files changed, 277 insertions(+), 121 deletions(-) create mode 100644 examples/audio_raw_stream.c delete mode 100644 examples/resources/audio/2t2m_spa.xm create mode 100644 examples/resources/audio/chiptun1.mod create mode 100644 examples/resources/audio/mini1111.xm (limited to 'src/raylib.h') diff --git a/examples/audio_module_playing.c b/examples/audio_module_playing.c index 07165c76..fe9ea15c 100644 --- a/examples/audio_module_playing.c +++ b/examples/audio_module_playing.c @@ -57,7 +57,7 @@ int main() // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - Music xm = LoadMusicStream("resources/audio/2t2m_spa.xm"); + Music xm = LoadMusicStream("resources/audio/mini1111.xm"); PlayMusicStream(xm); diff --git a/examples/audio_music_stream.c b/examples/audio_music_stream.c index 1d86bd1a..c552d030 100644 --- a/examples/audio_music_stream.c +++ b/examples/audio_music_stream.c @@ -59,9 +59,6 @@ int main() SetMusicVolume(volume); } */ - if (IsWindowMinimized()) PauseMusicStream(music); - else ResumeMusicStream(music); - timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*100*4; // We scale by 4 to fit 400 pixels UpdateMusicStream(music); // Update music buffer with new stream data diff --git a/examples/audio_raw_stream.c b/examples/audio_raw_stream.c new file mode 100644 index 00000000..37a5b4ff --- /dev/null +++ b/examples/audio_raw_stream.c @@ -0,0 +1,106 @@ +/******************************************************************************************* +* +* raylib [audio] example - Raw audio streaming +* +* NOTE: This example requires OpenAL Soft library installed +* +* This example has been created using raylib 1.6 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: malloc(), free() +#include // Required for: sinf() + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio streaming"); + + InitAudioDevice(); // Initialize audio device + + AudioStream stream = InitAudioStream(44100, 32, 1); // Init raw audio stream + + // Fill audio stream with some samples (sine wave) + float *data = (float *)malloc(sizeof(float)*44100); + + for (int i = 0; i < 44100; i++) + { + data[i] = sinf(2*PI*(float)i*DEG2RAD); + } + + PlayAudioStream(stream); + + int totalSamples = 44100; + int samplesLeft = totalSamples; + + Vector2 position = { 0, 0 }; + + SetTargetFPS(30); // Set our game to run at 30 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Refill audio stream if required + if (IsAudioBufferProcessed(stream)) + { + int numSamples = 0; + if (samplesLeft >= 4096) numSamples = 4096; + else numSamples = samplesLeft; + + UpdateAudioStream(stream, data + (totalSamples - samplesLeft), numSamples); + + samplesLeft -= numSamples; + + // Reset samples feeding (loop audio) + if (samplesLeft <= 0) samplesLeft = totalSamples; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("SINE WAVE SHOULD BE PLAYING!", 240, 140, 20, LIGHTGRAY); + + // NOTE: Draw a part of the sine wave (only screen width) + for (int i = 0; i < GetScreenWidth(); i++) + { + position.x = i; + position.y = 250 + 50*data[i]; + + DrawPixelV(position, RED); + } + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + free(data); // Unload sine wave data + + CloseAudioStream(stream); // Close raw audio stream and delete buffers from RAM + + CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/audio_sound_loading.c b/examples/audio_sound_loading.c index 8819aad1..f081e8ed 100644 --- a/examples/audio_sound_loading.c +++ b/examples/audio_sound_loading.c @@ -36,7 +36,6 @@ int main() // Update //---------------------------------------------------------------------------------- if (IsKeyPressed(KEY_SPACE)) PlaySound(fxWav); // Play WAV sound - if (IsKeyPressed(KEY_ENTER)) PlaySound(fxOgg); // Play OGG sound //---------------------------------------------------------------------------------- diff --git a/examples/resources/audio/2t2m_spa.xm b/examples/resources/audio/2t2m_spa.xm deleted file mode 100644 index fa416ef2..00000000 Binary files a/examples/resources/audio/2t2m_spa.xm and /dev/null differ diff --git a/examples/resources/audio/chiptun1.mod b/examples/resources/audio/chiptun1.mod new file mode 100644 index 00000000..00d16885 Binary files /dev/null and b/examples/resources/audio/chiptun1.mod differ diff --git a/examples/resources/audio/mini1111.xm b/examples/resources/audio/mini1111.xm new file mode 100644 index 00000000..a185c1a2 Binary files /dev/null and b/examples/resources/audio/mini1111.xm differ diff --git a/src/audio.c b/src/audio.c index d1c425d5..befed61c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -100,17 +100,6 @@ typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_MODULE_XM, MUSIC_MODULE_MOD } MusicContextType; -// Used to create custom audio streams that are not bound to a specific file. -typedef struct AudioStream { - unsigned int sampleRate; // Frequency (samples per second): default is 48000 - unsigned int sampleSize; // BitDepth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels - - ALenum format; // OpenAL format specifier - ALuint source; // OpenAL source - ALuint buffers[MAX_STREAM_BUFFERS]; // OpenAL buffers (double buffering) -} AudioStream; - // Music type (file streaming from memory) typedef struct Music { MusicContextType ctxType; // Type of music context (OGG, XM, MOD) @@ -118,7 +107,7 @@ typedef struct Music { jar_xm_context_t *ctxXm; // XM chiptune context jar_mod_context_t ctxMod; // MOD chiptune context - AudioStream stream; // Audio stream + AudioStream stream; // Audio stream (double buffering) bool loop; // Repeat music after finish (loop) unsigned int totalSamples; // Total number of samples @@ -141,12 +130,6 @@ 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(Music music, int numBuffersToProcess); // Fill music buffers with data - -static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); -static void BufferAudioStream(AudioStream stream, void *data, int numSamples); -static void CloseAudioStream(AudioStream stream); - #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) @@ -595,33 +578,89 @@ void StopMusicStream(Music music) // Update (re-fill) music buffers if data already processed void UpdateMusicStream(Music music) { - ALenum state; - bool active = true; ALint processed = 0; // Determine if music stream is ready to be written alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - + + int numBuffersToProcess = processed; + if (processed > 0) { - active = BufferMusicStream(music, processed); + bool active = true; + short pcm[AUDIO_BUFFER_SIZE]; + float pcmf[AUDIO_BUFFER_SIZE]; + + int numSamples = 0; // Total size of data steamed in L+R samples for xm floats, + // individual L or R for ogg shorts + + for (int i = 0; i < numBuffersToProcess; i++) + { + switch (music->ctxType) + { + case MUSIC_AUDIO_OGG: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE; + else numSamples = music->samplesLeft; + + // NOTE: Returns the number of samples to process (should be the same as numSamples -> it is) + int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, numSamples); + + // TODO: Review stereo channels Ogg, not enough samples served! + UpdateAudioStream(music->stream, pcm, numSamples*music->stream.channels); + music->samplesLeft -= (numSamples*music->stream.channels); + + } break; + case MUSIC_MODULE_XM: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; + else numSamples = music->samplesLeft; + + // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) + jar_xm_generate_samples(music->ctxXm, pcmf, numSamples); + UpdateAudioStream(music->stream, pcmf, numSamples*2); // Using 32bit PCM data + music->samplesLeft -= numSamples; + + //TraceLog(INFO, "Samples left: %i", music->samplesLeft); + + } break; + case MUSIC_MODULE_MOD: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; + else numSamples = music->samplesLeft; + + // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) + jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); + UpdateAudioStream(music->stream, pcm, numSamples*2); + music->samplesLeft -= numSamples; + + } break; + default: break; + } + if (music->samplesLeft <= 0) + { + active = false; + break; + } + } + + // Reset audio stream for looping if (!active && music->loop) { // Restart music context (if required) + //if (music->ctxType == MUSIC_MODULE_XM) if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_seek_start(&music->ctxMod); else if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_seek_start(music->ctxOgg); + // Reset samples left to total samples music->samplesLeft = music->totalSamples; - - // Determine if music stream is ready to be written - alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - - active = BufferMusicStream(music, processed); } - if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); + // This error is registered when UpdateAudioStream() fails + if (alGetError() == AL_INVALID_VALUE) TraceLog(WARNING, "OpenAL: Error buffering data..."); + ALenum state; alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); if (state != AL_PLAYING && active) alSourcePlay(music->stream.source); @@ -668,36 +707,14 @@ float GetMusicTimePlayed(Music music) { float secondsPlayed = 0.0f; - if (music->ctxType == MUSIC_MODULE_XM) - { - uint64_t samplesPlayed; - jar_xm_get_position(music->ctxXm, NULL, NULL, NULL, &samplesPlayed); - - // TODO: Not sure if this is the correct value - secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); - } - else if (music->ctxType == MUSIC_MODULE_MOD) - { - long samplesPlayed = jar_mod_current_samples(&music->ctxMod); - - secondsPlayed = (float)samplesPlayed/music->stream.sampleRate; - } - else if (music->ctxType == MUSIC_AUDIO_OGG) - { - unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; - - secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); - } + unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; + secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); return secondsPlayed; } -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - // Init audio stream (to stream audio pcm data) -static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) +AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) { AudioStream stream = { 0 }; @@ -735,7 +752,7 @@ static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleS alSource3f(stream.source, AL_POSITION, 0, 0, 0); alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); - // Create Buffers + // Create Buffers (double buffering) alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); // Initialize buffer with zeros by default @@ -766,7 +783,7 @@ static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleS } // Close audio stream and free memory -static void CloseAudioStream(AudioStream stream) +void CloseAudioStream(AudioStream stream) { // Stop playing channel alSourceStop(stream.source); @@ -790,75 +807,66 @@ static void CloseAudioStream(AudioStream stream) TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } -// Push more audio data into audio stream, only one buffer per call -static void BufferAudioStream(AudioStream stream, void *data, int numSamples) -{ +// Update audio stream buffers with data +// NOTE: Only one buffer per call +void UpdateAudioStream(AudioStream stream, void *data, int numSamples) +{ ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); - //TraceLog(DEBUG, "Buffer to refill: %i", buffer); + // Check if any buffer was available for unqueue + if (alGetError() != AL_INVALID_VALUE) + { + if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); + else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); + else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); + + alSourceQueueBuffers(stream.source, 1, &buffer); + } +} + +// Check if any audio stream buffers requires refill +bool IsAudioBufferProcessed(AudioStream stream) +{ + ALint processed = 0; - if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); - else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); - else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); + // Determine if music stream is ready to be written + alGetSourcei(stream.source, AL_BUFFERS_PROCESSED, &processed); - alSourceQueueBuffers(stream.source, 1, &buffer); + return (processed > 0); } -// Fill music buffers with new data from music stream -static bool BufferMusicStream(Music music, int numBuffersToProcess) +// Play audio stream +void PlayAudioStream(AudioStream stream) { - short pcm[AUDIO_BUFFER_SIZE]; - float pcmf[AUDIO_BUFFER_SIZE]; + alSourcePlay(stream.source); +} - 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) - - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE; - else size = music->samplesLeft; +// Play audio stream +void PauseAudioStream(AudioStream stream) +{ + alSourcePause(stream.source); +} - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: - { - // NOTE: Returns the number of samples to process (should be the same as size) - int numSamples = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, size); - - BufferAudioStream(music->stream, pcm, numSamples*music->stream.channels); - music->samplesLeft -= (numSamples*music->stream.channels); - - } break; - case MUSIC_MODULE_XM: - { - // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) - jar_xm_generate_samples(music->ctxXm, pcmf, size/2); - BufferAudioStream(music->stream, pcmf, size); // Using 32bit PCM data - music->samplesLeft -= (size/2); - - } break; - case MUSIC_MODULE_MOD: - { - // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) - jar_mod_fillbuffer(&music->ctxMod, pcm, size/2, 0); - BufferAudioStream(music->stream, pcm, size); - music->samplesLeft -= (size/2); - - } break; - default: break; - } +// Resume audio stream playing +void ResumeAudioStream(AudioStream stream) +{ + ALenum state; + alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - if (music->samplesLeft <= 0) - { - active = false; - break; - } - } - - return active; + if (state == AL_PAUSED) alSourcePlay(stream.source); } +// Stop audio stream +void StopAudioStream(AudioStream stream) +{ + alSourceStop(stream.source); +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + // Load WAV file into Wave structure static Wave LoadWAV(const char *fileName) { diff --git a/src/audio.h b/src/audio.h index c9171339..dbd88939 100644 --- a/src/audio.h +++ b/src/audio.h @@ -76,9 +76,21 @@ typedef struct Wave { } Wave; // Music type (file streaming from memory) -// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel... +// NOTE: Anything longer than ~10 seconds should be streamed typedef struct Music *Music; +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + + int format; // OpenAL audio format specifier + unsigned int source; // OpenAL audio source id + unsigned int buffers[2]; // OpenAL audio buffers (double buffering) +} AudioStream; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -93,7 +105,7 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // Check if device has been initialized successfully +bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -120,6 +132,17 @@ void SetMusicPitch(Music music, float pitch); // Set pitch for float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) +AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, + unsigned int channels); // Init audio stream (to stream audio pcm data) +void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +void PlayAudioStream(AudioStream stream); // Play audio stream +void PauseAudioStream(AudioStream stream); // Pause audio stream +void ResumeAudioStream(AudioStream stream); // Resume audio stream +void StopAudioStream(AudioStream stream); // Stop audio stream + #ifdef __cplusplus } #endif diff --git a/src/raylib.h b/src/raylib.h index 4b9f6ca0..3ee7a793 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -499,8 +499,8 @@ typedef struct Ray { // Sound source type typedef struct Sound { - unsigned int source; // Sound audio source id - unsigned int buffer; // Sound audio buffer id + unsigned int source; // OpenAL audio source id + unsigned int buffer; // OpenAL audio buffer id } Sound; // Wave type, defines audio wave data @@ -516,6 +516,18 @@ typedef struct Wave { // NOTE: Anything longer than ~10 seconds should be streamed typedef struct Music *Music; +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + + int format; // OpenAL audio format specifier + unsigned int source; // OpenAL audio source id + unsigned int buffers[2]; // OpenAL audio buffers (double buffering) +} AudioStream; + // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -923,7 +935,7 @@ void ToggleVrMode(void); // Enable/Disable VR experience (dev //------------------------------------------------------------------------------------ void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -950,6 +962,17 @@ void SetMusicPitch(Music music, float pitch); // Set pitch for float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) +AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, + unsigned int channels); // Init audio stream (to stream audio pcm data) +void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +void PlayAudioStream(AudioStream stream); // Play audio stream +void PauseAudioStream(AudioStream stream); // Pause audio stream +void ResumeAudioStream(AudioStream stream); // Resume audio stream +void StopAudioStream(AudioStream stream); // Stop audio stream + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 8c0bd30fcb62550f71237cce73fc80efacbf8909 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 2 Aug 2016 19:09:07 +0200 Subject: Corrected issue with Music type --- src/audio.c | 2 +- src/raylib.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index befed61c..0896e4ca 100644 --- a/src/audio.c +++ b/src/audio.c @@ -101,7 +101,7 @@ typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_MODULE_XM, MUSIC_MODULE_MOD } MusicContextType; // Music type (file streaming from memory) -typedef struct Music { +typedef struct MusicData { MusicContextType ctxType; // Type of music context (OGG, XM, MOD) stb_vorbis *ctxOgg; // OGG audio context jar_xm_context_t *ctxXm; // XM chiptune context diff --git a/src/raylib.h b/src/raylib.h index 3ee7a793..d9a12cec 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -514,7 +514,7 @@ typedef struct Wave { // Music type (file streaming from memory) // NOTE: Anything longer than ~10 seconds should be streamed -typedef struct Music *Music; +typedef struct MusicData *Music; // Audio stream type // NOTE: Useful to create custom audio streams not bound to a specific file -- cgit v1.2.3 From d5f5f0a9302435945b730e5ec001bda39741f3c7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Aug 2016 11:33:05 +0200 Subject: Updated raylib version to 1.6 --- src/core.c | 4 ++-- src/raylib.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 0008ef2f..47463a23 100644 --- a/src/core.c +++ b/src/core.c @@ -293,7 +293,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread // Initialize Window and Graphics Context (OpenGL) void InitWindow(int width, int height, const char *title) { - TraceLog(INFO, "Initializing raylib (v1.5.0)"); + TraceLog(INFO, "Initializing raylib (v1.6.0)"); // Store window title (could be useful...) windowTitle = title; @@ -347,7 +347,7 @@ void InitWindow(int width, int height, const char *title) // Android activity initialization void InitWindow(int width, int height, struct android_app *state) { - TraceLog(INFO, "Initializing raylib (v1.5.0)"); + TraceLog(INFO, "Initializing raylib (v1.6.0)"); app_dummy(); diff --git a/src/raylib.h b/src/raylib.h index d9a12cec..104d5677 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raylib 1.5.0 (www.raylib.com) +* raylib 1.6.0 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * -- cgit v1.2.3 From 3b80e2c1e03e0f87d50ca8876b50a11c7df1f56f Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Aug 2016 16:32:46 +0200 Subject: Redesigned gestures module to header-only --- src/Makefile | 6 +- src/core.c | 16 +- src/gestures.c | 423 -------------------------------------------------- src/gestures.h | 480 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/raylib.h | 17 +- src/rlua.h | 10 +- 6 files changed, 458 insertions(+), 494 deletions(-) delete mode 100644 src/gestures.c (limited to 'src/raylib.h') diff --git a/src/Makefile b/src/Makefile index 1360a920..e82c2861 100644 --- a/src/Makefile +++ b/src/Makefile @@ -168,7 +168,7 @@ endif # compile all modules with their prerequisites # compile core module -core.o : core.c raylib.h rlgl.h utils.h raymath.h +core.o : core.c raylib.h rlgl.h utils.h raymath.h gestures.h $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) # compile rlgl module @@ -207,10 +207,6 @@ utils.o : utils.c utils.h camera.o : camera.c raylib.h $(CC) -c $< $(CFLAGS) $(INCLUDES) -#compile gestures module -gestures.o : gestures.c raylib.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) - # It installs generated and needed files to compile projects using raylib. # The installation works manually. # TODO: add other platforms. diff --git a/src/core.c b/src/core.c index 47463a23..4cb34b0a 100644 --- a/src/core.c +++ b/src/core.c @@ -39,13 +39,15 @@ #include "raylib.h" // raylib main header #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 -#include "utils.h" // TraceLog() function - // NOTE: Includes Android fopen map, InitAssetManager() - +#include "utils.h" // Includes Android fopen map, InitAssetManager(), TraceLog() + #define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation) #define RAYMATH_EXTERN_INLINE // Compile raymath functions as static inline (remember, it's a compiler hint) #include "raymath.h" // Required for Vector3 and Matrix functions +#define GESTURES_IMPLEMENTATION +#include "gestures.h" // Gestures detection functionality + #include // Standard input / output lib #include // Declares malloc() and free() for memory management, rand(), atexit() #include // Required for typedef unsigned long long int uint64_t, used by hi-res timer @@ -234,6 +236,9 @@ static bool showLogo = false; // Track if showing logo at init is extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow() extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory +extern void ProcessGestureEvent(GestureEvent event); // [Module: gestures] Process gesture event and translate it into gestures +extern void UpdateGestures(void); // [Module: gestures] Update gestures detected (called in PollInputEvents()) + //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -2052,10 +2057,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i // NOTE: Before closing window, while loop must be left! } #if defined(PLATFORM_DESKTOP) - else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) - { - TakeScreenshot(); - } + else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) TakeScreenshot(); #endif else { diff --git a/src/gestures.c b/src/gestures.c deleted file mode 100644 index 57b96bd2..00000000 --- a/src/gestures.c +++ /dev/null @@ -1,423 +0,0 @@ -/********************************************************************************************** -* -* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) -* -* Initial design by Marc Palau -* Redesigned by Albert Martos and Ian Eito -* Reviewed by Ramon Santamaria (@raysan5) -* -* This software is provided "as-is", without any express or implied warranty. In no event -* will the authors be held liable for any damages arising from the use of this software. -* -* Permission is granted to anyone to use this software for any purpose, including commercial -* applications, and to alter it and redistribute it freely, subject to the following restrictions: -* -* 1. The origin of this software must not be misrepresented; you must not claim that you -* wrote the original software. If you use this software in a product, an acknowledgment -* in the product documentation would be appreciated but is not required. -* -* 2. Altered source versions must be plainly marked as such, and must not be misrepresented -* as being the original software. -* -* 3. This notice may not be removed or altered from any source distribution. -* -**********************************************************************************************/ - -//#define GESTURES_STANDALONE // NOTE: To use the gestures module as standalone lib, just uncomment this line - -#if defined(GESTURES_STANDALONE) - #include "gestures.h" -#else - #include "raylib.h" // Required for: Vector2, Gestures -#endif - -#include // Required for: atan2(), sqrt() -#include // Required for: uint64_t - -#if defined(_WIN32) - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); -#elif defined(__linux) - #include // Required for: timespec - #include // Required for: clock_gettime() -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time -#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f) -#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f) -#define TAP_TIMEOUT 300 // Time in milliseconds -#define PINCH_TIMEOUT 300 // Time in milliseconds -#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- - -// Touch gesture variables -static Vector2 touchDownPosition = { 0.0f, 0.0f }; -static Vector2 touchDownPosition2 = { 0.0f, 0.0f }; -static Vector2 touchDownDragPosition = { 0.0f, 0.0f }; -static Vector2 touchUpPosition = { 0.0f, 0.0f }; -static Vector2 moveDownPosition = { 0.0f, 0.0f }; -static Vector2 moveDownPosition2 = { 0.0f, 0.0f }; -static int numTap = 0; - -static int pointCount = 0; -static int firstTouchId = -1; - -static double eventTime = 0.0; -static double swipeTime = 0.0; - -// Hold gesture variables -static int numHold = 0; -static float timeHold = 0.0f; - -// Drag gesture variables -static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) -static float dragAngle = 0.0f; // DRAG angle (relative to x-axis) -static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1]) -static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) -static bool startMoving = false; // SWIPE used to define when start measuring swipeTime - -// Pinch gesture variables -static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points) -static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis) -static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1]) - -// Detected gestures -static int previousGesture = GESTURE_NONE; -static int currentGesture = GESTURE_NONE; - -// Enabled gestures flags, all gestures enabled by default -static unsigned int enabledGestures = 0b0000001111111111; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); -static float Vector2Distance(Vector2 v1, Vector2 v2); -static double GetCurrentTime(void); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Enable only desired getures to be detected -void SetGesturesEnabled(unsigned int gestureFlags) -{ - enabledGestures = gestureFlags; -} - -// Check if a gesture have been detected -bool IsGestureDetected(int gesture) -{ - if ((enabledGestures & currentGesture) == gesture) return true; - else return false; -} - -// Process gesture event and translate it into gestures -void ProcessGestureEvent(GestureEvent event) -{ - // Reset required variables - previousGesture = currentGesture; - - pointCount = event.pointCount; // Required on UpdateGestures() - - if (pointCount < 2) - { - if (event.touchAction == TOUCH_DOWN) - { - numTap++; // Tap counter - - // Detect GESTURE_DOUBLE_TAP - if ((currentGesture == GESTURE_NONE) && (numTap >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) - { - currentGesture = GESTURE_DOUBLETAP; - numTap = 0; - } - else // Detect GESTURE_TAP - { - numTap = 1; - currentGesture = GESTURE_TAP; - } - - touchDownPosition = event.position[0]; - touchDownDragPosition = event.position[0]; - - touchUpPosition = touchDownPosition; - eventTime = GetCurrentTime(); - - firstTouchId = event.pointerId[0]; - - dragVector = (Vector2){ 0.0f, 0.0f }; - } - else if (event.touchAction == TOUCH_UP) - { - if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; - - // NOTE: dragIntensity dependend on the resolution of the screen - dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); - dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); - - startMoving = false; - - // Detect GESTURE_SWIPE - if ((dragIntensity > FORCE_TO_SWIPE) && firstTouchId == event.pointerId[0]) - { - // NOTE: Angle should be inverted in Y - dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition); - - if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right - else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up - else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left - else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down - else currentGesture = GESTURE_NONE; - } - else - { - dragDistance = 0.0f; - dragIntensity = 0.0f; - dragAngle = 0.0f; - - currentGesture = GESTURE_NONE; - } - - touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; - pointCount = 0; - } - else if (event.touchAction == TOUCH_MOVE) - { - if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime(); - - if (!startMoving) - { - swipeTime = GetCurrentTime(); - startMoving = true; - } - - moveDownPosition = event.position[0]; - - if (currentGesture == GESTURE_HOLD) - { - if (numHold == 1) touchDownPosition = event.position[0]; - - numHold = 2; - - // Detect GESTURE_DRAG - if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) - { - eventTime = GetCurrentTime(); - currentGesture = GESTURE_DRAG; - } - } - - dragVector.x = moveDownPosition.x - touchDownDragPosition.x; - dragVector.y = moveDownPosition.y - touchDownDragPosition.y; - } - } - else // Two touch points - { - if (event.touchAction == TOUCH_DOWN) - { - touchDownPosition = event.position[0]; - touchDownPosition2 = event.position[1]; - - //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); - - pinchVector.x = touchDownPosition2.x - touchDownPosition.x; - pinchVector.y = touchDownPosition2.y - touchDownPosition.y; - - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - else if (event.touchAction == TOUCH_MOVE) - { - pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); - - touchDownPosition = moveDownPosition; - touchDownPosition2 = moveDownPosition2; - - moveDownPosition = event.position[0]; - moveDownPosition2 = event.position[1]; - - pinchVector.x = moveDownPosition2.x - moveDownPosition.x; - pinchVector.y = moveDownPosition2.y - moveDownPosition.y; - - if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH)) - { - if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; - else currentGesture = GESTURE_PINCH_OUT; - } - else - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - - // NOTE: Angle should be inverted in Y - pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2); - } - else if (event.touchAction == TOUCH_UP) - { - pinchDistance = 0.0f; - pinchAngle = 0.0f; - pinchVector = (Vector2){ 0.0f, 0.0f }; - pointCount = 0; - - currentGesture = GESTURE_NONE; - } - } -} - -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events - - // Detect GESTURE_HOLD - if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2)) - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - } - - if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) - { - currentGesture = GESTURE_HOLD; - timeHold = GetCurrentTime(); - numHold = 1; - } - - // Detect GESTURE_NONE - if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) - { - currentGesture = GESTURE_NONE; - } -} - -// Get number of touch points -int GetTouchPointsCount(void) -{ - // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called - - return pointCount; -} - -// Get latest detected gesture -int GetGestureDetected(void) -{ - // Get current gesture only if enabled - return (enabledGestures & currentGesture); -} - -// Hold time measured in ms -float GetGestureHoldDuration(void) -{ - // NOTE: time is calculated on current gesture HOLD - - float time = 0.0f; - - if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; - - return time; -} - -// Get drag vector (between initial touch point to current) -Vector2 GetGestureDragVector(void) -{ - // NOTE: drag vector is calculated on one touch points TOUCH_MOVE - - return dragVector; -} - -// Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGestureDragAngle(void) -{ - // NOTE: drag angle is calculated on one touch points TOUCH_UP - - return dragAngle; -} - -// Get distance between two pinch points -Vector2 GetGesturePinchVector(void) -{ - // NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index) - // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE - - return pinchVector; -} - -// Get angle beween two pinch points -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGesturePinchAngle(void) -{ - // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE - - return pinchAngle; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - -// Returns angle from two-points vector with X-axis -static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) -{ - float angle; - - angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x); - angle *= RAD2DEG; - - if (angle < 0) angle += 360.0f; - - return angle; -} - -// Calculate distance between two Vector2 -static float Vector2Distance(Vector2 v1, Vector2 v2) -{ - float result; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - - result = sqrt(dx*dx + dy*dy); - - return result; -} - -// Time measure returned are milliseconds -static double GetCurrentTime(void) -{ - double time = 0; - -#if defined(_WIN32) - unsigned long long int clockFrequency, currentTime; - - QueryPerformanceFrequency(&clockFrequency); - QueryPerformanceCounter(¤tTime); - - time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds -#endif - -#if defined(__linux) - // NOTE: Only for Linux-based systems - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds - - time = ((double)nowTime/1000000.0); // Time in miliseconds -#endif - - return time; -} diff --git a/src/gestures.h b/src/gestures.h index 912d0b92..4c59ee39 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -1,8 +1,21 @@ /********************************************************************************************** * -* raylib Gestures System - Gestures Detection and Usage Functions (Android and HTML5) +* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * -* Copyright (c) 2015 Marc Palau and Ramon Santamaria +* #define GESTURES_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. +* +* #define GESTURES_STANDALONE +* If defined, the library can be used as standalone to process gesture events with +* no external dependencies. +* +* NOTE: Memory footprint of this library is aproximately 128 bytes +* +* Initial design by Marc Palau +* Redesigned by Albert Martos and Ian Eito +* Reviewed by Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -28,9 +41,6 @@ #define PI 3.14159265358979323846 #endif -#define DEG2RAD (PI / 180.0f) -#define RAD2DEG (180.0f / PI) - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -40,32 +50,34 @@ // Types and Structures Definition // NOTE: Below types are required for GESTURES_STANDALONE usage //---------------------------------------------------------------------------------- -#ifndef __cplusplus - // Boolean type - typedef enum { false, true } bool; -#endif +#if defined(GESTURES_STANDALONE) + #ifndef __cplusplus + // Boolean type + typedef enum { false, true } bool; + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; - -// Gestures type -// NOTE: It could be used as flags to enable only some gestures -typedef enum { - GESTURE_NONE = 1, - GESTURE_TAP = 2, - GESTURE_DOUBLETAP = 4, - GESTURE_HOLD = 8, - GESTURE_DRAG = 16, - GESTURE_SWIPE_RIGHT = 32, - GESTURE_SWIPE_LEFT = 64, - GESTURE_SWIPE_UP = 128, - GESTURE_SWIPE_DOWN = 256, - GESTURE_PINCH_IN = 512, - GESTURE_PINCH_OUT = 1024 -} Gestures; + // Gestures type + // NOTE: It could be used as flags to enable only some gestures + typedef enum { + GESTURE_NONE = 1, + GESTURE_TAP = 2, + GESTURE_DOUBLETAP = 4, + GESTURE_HOLD = 8, + GESTURE_DRAG = 16, + GESTURE_SWIPE_RIGHT = 32, + GESTURE_SWIPE_LEFT = 64, + GESTURE_SWIPE_UP = 128, + GESTURE_SWIPE_DOWN = 256, + GESTURE_PINCH_IN = 512, + GESTURE_PINCH_OUT = 1024 + } Gestures; +#endif typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; @@ -90,22 +102,422 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -bool IsGestureDetected(int gesture); // Check if a gesture have been detected void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures void UpdateGestures(void); // Update gestures detected (must be called every frame) -int GetTouchPointsCount(void); // Get touch points count +#if defined(GESTURES_STANDALONE) +void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +bool IsGestureDetected(int gesture); // Check if a gesture have been detected int GetGestureDetected(void); // Get latest detected gesture +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle Vector2 GetGesturePinchVector(void); // Get gesture pinch delta float GetGesturePinchAngle(void); // Get gesture pinch angle - +#endif #ifdef __cplusplus } #endif #endif // GESTURES_H + +/*********************************************************************************** +* +* GESTURES IMPLEMENTATION +* +************************************************************************************/ + +#if defined(GESTURES_IMPLEMENTATION) + +#include // Required for: atan2(), sqrt() +#include // Required for: uint64_t + +#if defined(_WIN32) + // Functions required to query time on Windows + int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); + int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); +#elif defined(__linux) + #include // Required for: timespec + #include // Required for: clock_gettime() +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time +#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f) +#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f) +#define TAP_TIMEOUT 300 // Time in milliseconds +#define PINCH_TIMEOUT 300 // Time in milliseconds +#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f) + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- + +// Touch gesture variables +static Vector2 touchDownPosition = { 0.0f, 0.0f }; +static Vector2 touchDownPosition2 = { 0.0f, 0.0f }; +static Vector2 touchDownDragPosition = { 0.0f, 0.0f }; +static Vector2 touchUpPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition = { 0.0f, 0.0f }; +static Vector2 moveDownPosition2 = { 0.0f, 0.0f }; + +static int pointCount = 0; // Touch points counter +static int firstTouchId = -1; // Touch id for first touch point +static double eventTime = 0.0; // Time stamp when an event happened + +// Tap gesture variables +static int tapCounter = 0; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions) + +// Hold gesture variables +static bool resetHold = false; // HOLD reset to get first touch point again +static float timeHold = 0.0f; // HOLD duration in milliseconds + +// Drag gesture variables +static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position) +static float dragAngle = 0.0f; // DRAG angle (relative to x-axis) +static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1]) +static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame) + +// Swipe gestures variables +static bool startMoving = false; // SWIPE used to define when start measuring swipeTime +static double swipeTime = 0.0; // SWIPE time to calculate drag intensity + +// Pinch gesture variables +static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points) +static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis) +static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1]) + +static int currentGesture = GESTURE_NONE; // Current detected gesture + +// Enabled gestures flags, all gestures enabled by default +static unsigned int enabledGestures = 0b0000001111111111; + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition); +static float Vector2Distance(Vector2 v1, Vector2 v2); +static double GetCurrentTime(void); + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Enable only desired getures to be detected +void SetGesturesEnabled(unsigned int gestureFlags) +{ + enabledGestures = gestureFlags; +} + +// Check if a gesture have been detected +bool IsGestureDetected(int gesture) +{ + if ((enabledGestures & currentGesture) == gesture) return true; + else return false; +} + +// Process gesture event and translate it into gestures +void ProcessGestureEvent(GestureEvent event) +{ + // Reset required variables + pointCount = event.pointCount; // Required on UpdateGestures() + + if (pointCount < 2) + { + if (event.touchAction == TOUCH_DOWN) + { + tapCounter++; // Tap counter + + // Detect GESTURE_DOUBLE_TAP + if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE)) + { + currentGesture = GESTURE_DOUBLETAP; + tapCounter = 0; + } + else // Detect GESTURE_TAP + { + tapCounter = 1; + currentGesture = GESTURE_TAP; + } + + touchDownPosition = event.position[0]; + touchDownDragPosition = event.position[0]; + + touchUpPosition = touchDownPosition; + eventTime = GetCurrentTime(); + + firstTouchId = event.pointerId[0]; + + dragVector = (Vector2){ 0.0f, 0.0f }; + } + else if (event.touchAction == TOUCH_UP) + { + if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0]; + + // NOTE: dragIntensity dependend on the resolution of the screen + dragDistance = Vector2Distance(touchDownPosition, touchUpPosition); + dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime)); + + startMoving = false; + + // Detect GESTURE_SWIPE + if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0])) + { + // NOTE: Angle should be inverted in Y + dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition); + + if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right + else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up + else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left + else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down + else currentGesture = GESTURE_NONE; + } + else + { + dragDistance = 0.0f; + dragIntensity = 0.0f; + dragAngle = 0.0f; + + currentGesture = GESTURE_NONE; + } + + touchDownDragPosition = (Vector2){ 0.0f, 0.0f }; + pointCount = 0; + } + else if (event.touchAction == TOUCH_MOVE) + { + if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime(); + + if (!startMoving) + { + swipeTime = GetCurrentTime(); + startMoving = true; + } + + moveDownPosition = event.position[0]; + + if (currentGesture == GESTURE_HOLD) + { + if (resetHold) touchDownPosition = event.position[0]; + + resetHold = false; + + // Detect GESTURE_DRAG + if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG) + { + eventTime = GetCurrentTime(); + currentGesture = GESTURE_DRAG; + } + } + + dragVector.x = moveDownPosition.x - touchDownDragPosition.x; + dragVector.y = moveDownPosition.y - touchDownDragPosition.y; + } + } + else // Two touch points + { + if (event.touchAction == TOUCH_DOWN) + { + touchDownPosition = event.position[0]; + touchDownPosition2 = event.position[1]; + + //pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2); + + pinchVector.x = touchDownPosition2.x - touchDownPosition.x; + pinchVector.y = touchDownPosition2.y - touchDownPosition.y; + + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + else if (event.touchAction == TOUCH_MOVE) + { + pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2); + + touchDownPosition = moveDownPosition; + touchDownPosition2 = moveDownPosition2; + + moveDownPosition = event.position[0]; + moveDownPosition2 = event.position[1]; + + pinchVector.x = moveDownPosition2.x - moveDownPosition.x; + pinchVector.y = moveDownPosition2.y - moveDownPosition.y; + + if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH)) + { + if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN; + else currentGesture = GESTURE_PINCH_OUT; + } + else + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + + // NOTE: Angle should be inverted in Y + pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2); + } + else if (event.touchAction == TOUCH_UP) + { + pinchDistance = 0.0f; + pinchAngle = 0.0f; + pinchVector = (Vector2){ 0.0f, 0.0f }; + pointCount = 0; + + currentGesture = GESTURE_NONE; + } + } +} + +// Update gestures detected (must be called every frame) +void UpdateGestures(void) +{ + // NOTE: Gestures are processed through system callbacks on touch events + + // Detect GESTURE_HOLD + if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2)) + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + } + + if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2)) + { + currentGesture = GESTURE_HOLD; + timeHold = GetCurrentTime(); + resetHold = true; + } + + // Detect GESTURE_NONE + if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN)) + { + currentGesture = GESTURE_NONE; + } +} + +// Get number of touch points +int GetTouchPointsCount(void) +{ + // NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called + + return pointCount; +} + +// Get latest detected gesture +int GetGestureDetected(void) +{ + // Get current gesture only if enabled + return (enabledGestures & currentGesture); +} + +// Hold time measured in ms +float GetGestureHoldDuration(void) +{ + // NOTE: time is calculated on current gesture HOLD + + float time = 0.0f; + + if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold; + + return time; +} + +// Get drag vector (between initial touch point to current) +Vector2 GetGestureDragVector(void) +{ + // NOTE: drag vector is calculated on one touch points TOUCH_MOVE + + return dragVector; +} + +// Get drag angle +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGestureDragAngle(void) +{ + // NOTE: drag angle is calculated on one touch points TOUCH_UP + + return dragAngle; +} + +// Get distance between two pinch points +Vector2 GetGesturePinchVector(void) +{ + // NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index) + // NOTE: pinch distance is calculated on two touch points TOUCH_MOVE + + return pinchVector; +} + +// Get angle beween two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise +float GetGesturePinchAngle(void) +{ + // NOTE: pinch angle is calculated on two touch points TOUCH_MOVE + + return pinchAngle; +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Returns angle from two-points vector with X-axis +static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition) +{ + float angle; + + angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x)*(180.0f/PI); + + if (angle < 0) angle += 360.0f; + + return angle; +} + +// Calculate distance between two Vector2 +static float Vector2Distance(Vector2 v1, Vector2 v2) +{ + float result; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + + result = sqrt(dx*dx + dy*dy); + + return result; +} + +// Time measure returned are milliseconds +static double GetCurrentTime(void) +{ + double time = 0; + +#if defined(_WIN32) + unsigned long long int clockFrequency, currentTime; + + QueryPerformanceFrequency(&clockFrequency); + QueryPerformanceCounter(¤tTime); + + time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds +#endif + +#if defined(__linux) + // NOTE: Only for Linux-based systems + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds + + time = ((double)nowTime/1000000.0); // Time in miliseconds +#endif + + return time; +} + +#endif // GESTURES_IMPLEMENTATION diff --git a/src/raylib.h b/src/raylib.h index 104d5677..1489546a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -570,18 +570,6 @@ typedef enum { GESTURE_PINCH_OUT = 512 } Gestures; -// Touch action (fingers or mouse) -typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction; - -// Gesture events -// NOTE: MAX_TOUCH_POINTS fixed to 2 -typedef struct GestureEvent { - int touchAction; - int pointCount; - int pointerId[MAX_TOUCH_POINTS]; - Vector2 position[MAX_TOUCH_POINTS]; -} GestureEvent; - // Camera system modes typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; @@ -711,11 +699,8 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags bool IsGestureDetected(int gesture); // Check if a gesture have been detected -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures -void UpdateGestures(void); // Update gestures detected (called automatically in PollInputEvents()) - -int GetTouchPointsCount(void); // Get touch points count int GetGestureDetected(void); // Get latest detected gesture +int GetTouchPointsCount(void); // Get touch points count float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds Vector2 GetGestureDragVector(void); // Get gesture drag vector float GetGestureDragAngle(void); // Get gesture drag angle diff --git a/src/rlua.h b/src/rlua.h index 675edbfc..acd0d037 100644 --- a/src/rlua.h +++ b/src/rlua.h @@ -1313,12 +1313,6 @@ int lua_IsGestureDetected(lua_State* L) return 1; } -int lua_UpdateGestures(lua_State* L) -{ - UpdateGestures(); - return 0; -} - int lua_GetTouchPointsCount(lua_State* L) { int result = GetTouchPointsCount(); @@ -3576,10 +3570,8 @@ static luaL_Reg raylib_functions[] = { REG(SetGesturesEnabled) REG(IsGestureDetected) - //REG(ProcessGestureEvent) - REG(UpdateGestures) - REG(GetTouchPointsCount) REG(GetGestureDetected) + REG(GetTouchPointsCount) REG(GetGestureHoldDuration) REG(GetGestureDragVector) REG(GetGestureDragAngle) -- cgit v1.2.3 From 16ac468bdb121cc9539959d7e921b32932f6fc75 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 6 Aug 2016 19:30:41 +0200 Subject: Remove functions from user exposure --- src/raylib.h | 4 +--- src/rlgl.h | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 1489546a..bbf83ccd 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -909,10 +909,8 @@ void DestroyLight(Light light); // Destroy a //------------------------------------------------------------------------------------ void InitVrDevice(int vdDevice); // Init VR device void CloseVrDevice(void); // Close VR device -void UpdateVrTracking(void); // Update VR tracking (position and orientation) -void BeginVrDrawing(void); // Begin VR drawing configuration -void EndVrDrawing(void); // End VR drawing process (and desktop mirror) bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +void UpdateVrTracking(void); // Update VR tracking (position and orientation) void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) //------------------------------------------------------------------------------------ diff --git a/src/rlgl.h b/src/rlgl.h index 425871a9..bcb7c24f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -332,6 +332,10 @@ Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data +// VR functions exposed to core module but not to raylib users +void BeginVrDrawing(void); // Begin VR drawing configuration +void EndVrDrawing(void); // End VR drawing process (and desktop mirror) + // NOTE: There is a set of shader related functions that are available to end user, // to avoid creating function wrappers through core module, they have been directly declared in raylib.h @@ -368,10 +372,8 @@ float *MatrixToFloat(Matrix mat); void InitVrDevice(int vrDevice); // Init VR device void CloseVrDevice(void); // Close VR device -void UpdateVrTracking(void); // Update VR tracking (position and orientation) -void BeginVrDrawing(void); // Begin VR drawing configuration -void EndVrDrawing(void); // End VR drawing process (and desktop mirror) bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +void UpdateVrTracking(void); // Update VR tracking (position and orientation) void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) // Oculus Rift API for direct access the device (no simulator) -- cgit v1.2.3 From f69f930b51d64d8f1dff5cb4d6c810b4a5e7335a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 7 Aug 2016 13:38:48 +0200 Subject: Some functions review --- src/raylib.h | 31 +++++++++++++++++-------------- src/text.c | 40 +++++++++++++++++++++++----------------- src/textures.c | 8 ++++---- 3 files changed, 44 insertions(+), 35 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index bbf83ccd..8045e436 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -185,17 +185,20 @@ #define GAMEPAD_PLAYER4 3 // Not supported // Gamepad Buttons -// NOTE: Adjusted for a PS3 USB Controller -#define GAMEPAD_BUTTON_A 2 -#define GAMEPAD_BUTTON_B 1 -#define GAMEPAD_BUTTON_X 3 -#define GAMEPAD_BUTTON_Y 4 -#define GAMEPAD_BUTTON_R1 7 -#define GAMEPAD_BUTTON_R2 5 -#define GAMEPAD_BUTTON_L1 6 -#define GAMEPAD_BUTTON_L2 8 -#define GAMEPAD_BUTTON_SELECT 9 -#define GAMEPAD_BUTTON_START 10 + +// PS3 USB Controller +#define GAMEPAD_PS3_BUTTON_A 2 +#define GAMEPAD_PS3_BUTTON_B 1 +#define GAMEPAD_PS3_BUTTON_X 3 +#define GAMEPAD_PS3_BUTTON_Y 4 +#define GAMEPAD_PS3_BUTTON_R1 7 +#define GAMEPAD_PS3_BUTTON_R2 5 +#define GAMEPAD_PS3_BUTTON_L1 6 +#define GAMEPAD_PS3_BUTTON_L2 8 +#define GAMEPAD_PS3_BUTTON_SELECT 9 +#define GAMEPAD_PS3_BUTTON_START 10 + +// TODO: Add PS3 d-pad axis // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -782,10 +785,10 @@ void ImageCrop(Image *image, Rectangle crop); void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) -Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) +Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, int fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) +void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) void ImageFlipVertical(Image *image); // Flip image vertically void ImageFlipHorizontal(Image *image); // Flip image horizontally void ImageColorTint(Image *image, Color color); // Modify image color: tint @@ -812,7 +815,7 @@ void UnloadSpriteFont(SpriteFont spriteFont); void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters - int fontSize, int spacing, Color tint); + float fontSize, int spacing, Color tint); int MeasureText(const char *text, int fontSize); // Measure string width for default font Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont diff --git a/src/text.c b/src/text.c index ec2480e3..d6a44bec 100644 --- a/src/text.c +++ b/src/text.c @@ -34,7 +34,7 @@ // Following libs are used on LoadTTF() #define STB_TRUETYPE_IMPLEMENTATION -#include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() +#include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() // Rectangle packing functions (not used at the moment) //#define STB_RECT_PACK_IMPLEMENTATION @@ -43,8 +43,7 @@ //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -#define FONT_FIRST_CHAR 32 -#define MAX_FONTCHARS 128 +#define FONT_FIRST_CHAR 32 // NOTE: Expected first char for a sprite font #define MAX_FORMATTEXT_LENGTH 64 #define MAX_SUBTEXT_LENGTH 64 @@ -72,7 +71,9 @@ static SpriteFont defaultFont; // Default font provided by raylib static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) -static SpriteFont LoadTTF(const char *fileName, int fontSize); // Generate a sprite font image from TTF data (font size required) + +// Generate a sprite font image from TTF data +static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars); extern void LoadDefaultFont(void); extern void UnloadDefaultFont(void); @@ -245,16 +246,20 @@ SpriteFont GetDefaultFont() // Load a SpriteFont image into GPU memory SpriteFont LoadSpriteFont(const char *fileName) { + // Default hardcoded values for ttf file loading + #define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) + #define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs + SpriteFont spriteFont = { 0 }; // Check file extension if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); - else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadTTF(fileName, 32); + else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadTTF(fileName, DEFAULT_TTF_FONTSIZE, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName); else { Image image = LoadImage(fileName); - if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, 32); + if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, FONT_FIRST_CHAR); UnloadImage(image); } @@ -294,12 +299,12 @@ void DrawText(const char *text, int posX, int posY, int fontSize, Color color) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize / defaultFontSize; - DrawTextEx(defaultFont, text, position, fontSize, spacing, color); + DrawTextEx(defaultFont, text, position, (float)fontSize, spacing, color); } // Draw text using SpriteFont // NOTE: chars spacing is NOT proportional to fontSize -void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int fontSize, int spacing, Color tint) +void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint) { int length = strlen(text); int textOffsetX = 0; @@ -309,7 +314,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, int f Rectangle rec; - scaleFactor = (float)fontSize/spriteFont.size; + scaleFactor = fontSize/spriteFont.size; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // written in C code files (codified by default as UTF-8) @@ -497,6 +502,9 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) int x = 0; int y = 0; + + // Default number of characters expected supported + #define MAX_FONTCHARS 128 // We allocate a temporal arrays for chars data measures, // once we get the actual number of chars, we copy data to a sized arrays @@ -634,7 +642,7 @@ static SpriteFont LoadRBMF(const char *fileName) spriteFont.numChars = (int)rbmfHeader.numChars; - int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32; + int numPixelBits = rbmfHeader.imgWidth*rbmfHeader.imgHeight/32; rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int)); @@ -843,17 +851,15 @@ static SpriteFont LoadBMFont(const char *fileName) // Generate a sprite font from TTF file data (font size required) // TODO: Review texture packing method and generation (use oversampling) -static SpriteFont LoadTTF(const char *fileName, int fontSize) +static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars) { // NOTE: Generated font uses some hardcoded values #define FONT_TEXTURE_WIDTH 512 // Font texture width #define FONT_TEXTURE_HEIGHT 512 // Font texture height - #define FONT_FIRST_CHAR 32 // Font first character (32 - space) - #define FONT_NUM_CHARS 95 // ASCII 32..126 is 95 glyphs unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); unsigned char *dataBitmap = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar charData[FONT_NUM_CHARS]; // ASCII 32..126 is 95 glyphs + stbtt_bakedchar charData[numChars]; SpriteFont font = { 0 }; @@ -868,7 +874,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize) fread(ttfBuffer, 1, 1<<25, ttfFile); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... - stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, FONT_FIRST_CHAR, FONT_NUM_CHARS, charData); + stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, firstChar, numChars, charData); free(ttfBuffer); @@ -898,7 +904,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize) UnloadImage(image); // Unloads dataGrayAlpha font.size = fontSize; - font.numChars = FONT_NUM_CHARS; + font.numChars = numChars; font.charValues = (int *)malloc(font.numChars*sizeof(int)); font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle)); font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2)); @@ -906,7 +912,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize) for (int i = 0; i < font.numChars; i++) { - font.charValues[i] = i + FONT_FIRST_CHAR; + font.charValues[i] = i + firstChar; font.charRecs[i].x = (int)charData[i].x0; font.charRecs[i].y = (int)charData[i].y0; diff --git a/src/textures.c b/src/textures.c index f5523a3e..c6b7e0bb 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1053,7 +1053,7 @@ Image ImageText(const char *text, int fontSize, Color color) } // Create an image from text (custom sprite font) -Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Color tint) +Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint) { int length = strlen(text); int posX = 0; @@ -1091,9 +1091,9 @@ Image ImageTextEx(SpriteFont font, const char *text, int fontSize, int spacing, Image imText = LoadImageEx(pixels, (int)imSize.x, (int)imSize.y); // Scale image depending on text size - if (fontSize > (int)imSize.y) + if (fontSize > imSize.y) { - float scaleFactor = (float)fontSize/imSize.y; + float scaleFactor = fontSize/imSize.y; TraceLog(INFO, "Scalefactor: %f", scaleFactor); // Using nearest-neighbor scaling algorithm for default font @@ -1114,7 +1114,7 @@ void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, } // Draw text (custom sprite font) within an image (destination) -void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, int fontSize, int spacing, Color color) +void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color) { Image imText = ImageTextEx(font, text, fontSize, spacing, color); -- cgit v1.2.3 From cc2b3228d18f3bc4cd58ee4298cde78846cfde9e Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Aug 2016 23:03:29 +0200 Subject: Updated for C++ --- src/raylib.h | 94 ++++++++++++++++++++++-------------------------------------- 1 file changed, 34 insertions(+), 60 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 8045e436..41c32476 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -236,67 +236,44 @@ #define ANDROID_VOLUME_UP 24 #define ANDROID_VOLUME_DOWN 25 -// Some Basic Colors -// NOTE: Custom raylib color palette for amazing visuals on WHITE background +// NOTE: MSC C++ compiler does not support compound literals (C99 feature) +// Plain structures in C++ (without constructors) can be initialized from { } initializers. #ifdef __cplusplus - // NOTE: MSC C++ compiler does not support compound literals (C99 feature) - #define LIGHTGRAY Color(200, 200, 200, 255) // Light Gray - #define GRAY Color(130, 130, 130, 255) // Gray - #define DARKGRAY Color(80, 80, 80, 255) // Dark Gray - #define YELLOW Color(253, 249, 0, 255) // Yellow - #define GOLD Color(255, 203, 0, 255) // Gold - #define ORANGE Color(255, 161, 0, 255) // Orange - #define PINK Color(255, 109, 194, 255) // Pink - #define RED Color(230, 41, 55, 255) // Red - #define MAROON Color(190, 33, 55, 255) // Maroon - #define GREEN Color(0, 228, 48, 255) // Green - #define LIME Color(0, 158, 47, 255) // Lime - #define DARKGREEN Color(0, 117, 44, 255) // Dark Green - #define SKYBLUE Color(102, 191, 255, 255) // Sky Blue - #define BLUE Color(0, 121, 241, 255) // Blue - #define DARKBLUE Color(0, 82, 172, 255) // Dark Blue - #define PURPLE Color(200, 122, 255, 255) // Purple - #define VIOLET Color(135, 60, 190, 255) // Violet - #define DARKPURPLE Color(112, 31, 126, 255) // Dark Purple - #define BEIGE Color(211, 176, 131, 255) // Beige - #define BROWN Color(127, 106, 79, 255) // Brown - #define DARKBROWN Color(76, 63, 47, 255) // Dark Brown - - #define WHITE Color(255, 255, 255, 255) // White - #define BLACK Color(0, 0, 0, 255) // Black - #define BLANK Color(0, 0, 0, 0) // Blank (Transparent) - #define MAGENTA Color(255, 0, 255, 255) // Magenta - #define RAYWHITE Color(245, 245, 245, 255) // My own White (raylib logo) + #define CLITERAL #else - #define LIGHTGRAY (Color){ 200, 200, 200, 255 } // Light Gray - #define GRAY (Color){ 130, 130, 130, 255 } // Gray - #define DARKGRAY (Color){ 80, 80, 80, 255 } // Dark Gray - #define YELLOW (Color){ 253, 249, 0, 255 } // Yellow - #define GOLD (Color){ 255, 203, 0, 255 } // Gold - #define ORANGE (Color){ 255, 161, 0, 255 } // Orange - #define PINK (Color){ 255, 109, 194, 255 } // Pink - #define RED (Color){ 230, 41, 55, 255 } // Red - #define MAROON (Color){ 190, 33, 55, 255 } // Maroon - #define GREEN (Color){ 0, 228, 48, 255 } // Green - #define LIME (Color){ 0, 158, 47, 255 } // Lime - #define DARKGREEN (Color){ 0, 117, 44, 255 } // Dark Green - #define SKYBLUE (Color){ 102, 191, 255, 255 } // Sky Blue - #define BLUE (Color){ 0, 121, 241, 255 } // Blue - #define DARKBLUE (Color){ 0, 82, 172, 255 } // Dark Blue - #define PURPLE (Color){ 200, 122, 255, 255 } // Purple - #define VIOLET (Color){ 135, 60, 190, 255 } // Violet - #define DARKPURPLE (Color){ 112, 31, 126, 255 } // Dark Purple - #define BEIGE (Color){ 211, 176, 131, 255 } // Beige - #define BROWN (Color){ 127, 106, 79, 255 } // Brown - #define DARKBROWN (Color){ 76, 63, 47, 255 } // Dark Brown - - #define WHITE (Color){ 255, 255, 255, 255 } // White - #define BLACK (Color){ 0, 0, 0, 255 } // Black - #define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) - #define MAGENTA (Color){ 255, 0, 255, 255 } // Magenta - #define RAYWHITE (Color){ 245, 245, 245, 255 } // My own White (raylib logo) + #define CLITERAL (Color) #endif +// Some Basic Colors +// NOTE: Custom raylib color palette for amazing visuals on WHITE background +#define LIGHTGRAY CLITERAL{ 200, 200, 200, 255 } // Light Gray +#define GRAY CLITERAL{ 130, 130, 130, 255 } // Gray +#define DARKGRAY CLITERAL{ 80, 80, 80, 255 } // Dark Gray +#define YELLOW CLITERAL{ 253, 249, 0, 255 } // Yellow +#define GOLD CLITERAL{ 255, 203, 0, 255 } // Gold +#define ORANGE CLITERAL{ 255, 161, 0, 255 } // Orange +#define PINK CLITERAL{ 255, 109, 194, 255 } // Pink +#define RED CLITERAL{ 230, 41, 55, 255 } // Red +#define MAROON CLITERAL{ 190, 33, 55, 255 } // Maroon +#define GREEN CLITERAL{ 0, 228, 48, 255 } // Green +#define LIME CLITERAL{ 0, 158, 47, 255 } // Lime +#define DARKGREEN CLITERAL{ 0, 117, 44, 255 } // Dark Green +#define SKYBLUE CLITERAL{ 102, 191, 255, 255 } // Sky Blue +#define BLUE CLITERAL{ 0, 121, 241, 255 } // Blue +#define DARKBLUE CLITERAL{ 0, 82, 172, 255 } // Dark Blue +#define PURPLE CLITERAL{ 200, 122, 255, 255 } // Purple +#define VIOLET CLITERAL{ 135, 60, 190, 255 } // Violet +#define DARKPURPLE CLITERAL{ 112, 31, 126, 255 } // Dark Purple +#define BEIGE CLITERAL{ 211, 176, 131, 255 } // Beige +#define BROWN CLITERAL{ 127, 106, 79, 255 } // Brown +#define DARKBROWN CLITERAL{ 76, 63, 47, 255 } // Dark Brown + +#define WHITE CLITERAL{ 255, 255, 255, 255 } // White +#define BLACK CLITERAL{ 0, 0, 0, 255 } // Black +#define BLANK CLITERAL{ 0, 0, 0, 0 } // Blank (Transparent) +#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta +#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo) + //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- @@ -342,9 +319,6 @@ typedef struct Color { unsigned char g; unsigned char b; unsigned char a; -#ifdef __cplusplus - Color(unsigned char cr, unsigned char cg, unsigned char cb, unsigned char ca) : r(cr), g(cg), b(cb), a(ca) { } -#endif } Color; // Rectangle type -- cgit v1.2.3 From eb9072a2f133cdad9fb4fed4c8b80aca04770d55 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 10 Aug 2016 12:20:46 +0200 Subject: Renamed functions for consistency --- src/models.c | 14 +++++++------- src/raylib.h | 4 ++-- src/rlua.h | 56 ++++++++++++++++++++++++++++++-------------------------- 3 files changed, 39 insertions(+), 35 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index b194a0db..7f248aa2 100644 --- a/src/models.c +++ b/src/models.c @@ -66,7 +66,7 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); //---------------------------------------------------------------------------------- // Draw a line in 3D world space -void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color) +void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) { rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); @@ -76,7 +76,7 @@ void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color) } // Draw a circle in 3D world space -void Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color) +void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color) { rlPushMatrix(); rlTranslatef(center.x, center.y, center.z); @@ -578,19 +578,19 @@ void DrawLight(Light light) case LIGHT_POINT: { DrawSphereWires(light->position, 0.3f*light->intensity, 4, 8, (light->enabled ? light->diffuse : BLACK)); - Draw3DCircle(light->position, light->radius, 0.0f, (Vector3){ 0, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); - Draw3DCircle(light->position, light->radius, 90.0f, (Vector3){ 1, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); - Draw3DCircle(light->position, light->radius, 90.0f, (Vector3){ 0, 1, 0 }, (light->enabled ? light->diffuse : BLACK)); + DrawCircle3D(light->position, light->radius, 0.0f, (Vector3){ 0, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); + DrawCircle3D(light->position, light->radius, 90.0f, (Vector3){ 1, 0, 0 }, (light->enabled ? light->diffuse : BLACK)); + DrawCircle3D(light->position, light->radius, 90.0f, (Vector3){ 0, 1, 0 }, (light->enabled ? light->diffuse : BLACK)); } break; case LIGHT_DIRECTIONAL: { - Draw3DLine(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); + DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); DrawSphereWires(light->position, 0.3f*light->intensity, 4, 8, (light->enabled ? light->diffuse : BLACK)); DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); } break; case LIGHT_SPOT: { - Draw3DLine(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); + DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : BLACK)); DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); } break; diff --git a/src/raylib.h b/src/raylib.h index 41c32476..1673578d 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -800,6 +800,8 @@ const char *SubText(const char *text, int position, int length); //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) //------------------------------------------------------------------------------------ +void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space +void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle 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 @@ -814,8 +816,6 @@ void DrawRay(Ray ray, Color color); void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) void DrawGizmo(Vector3 position); // Draw simple gizmo void DrawLight(Light light); // Draw light in 3D world -void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space -void Draw3DCircle(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle in 3D world space //DrawTorus(), DrawTeapot() are useless... //------------------------------------------------------------------------------------ diff --git a/src/rlua.h b/src/rlua.h index 849c1c64..b100b06d 100644 --- a/src/rlua.h +++ b/src/rlua.h @@ -2239,6 +2239,29 @@ int lua_DrawFPS(lua_State* L) // NOTE: FormatText() can be replaced by Lua function: string.format() // NOTE: SubText() can be replaced by Lua function: string.sub() +//------------------------------------------------------------------------------------ +// raylib [models] module functions - Basic 3d Shapes Drawing Functions +//------------------------------------------------------------------------------------ +int lua_DrawLine3D(lua_State* L) +{ + Vector3 arg1 = LuaGetArgument_Vector3(L, 1); + Vector3 arg2 = LuaGetArgument_Vector3(L, 2); + Color arg3 = LuaGetArgument_Color(L, 3); + DrawLine3D(arg1, arg2, arg3); + return 0; +} + +int lua_DrawCircle3D(lua_State* L) +{ + Vector3 arg1 = LuaGetArgument_Vector3(L, 1); + float arg2 = LuaGetArgument_float(L, 2); + float arg3 = LuaGetArgument_float(L, 3); + Vector3 arg4 = LuaGetArgument_Vector3(L, 4); + Color arg5 = LuaGetArgument_Color(L, 5); + DrawCircle3D(arg1, arg2, arg3, arg4, arg5); + return 0; +} + int lua_DrawCube(lua_State* L) { Vector3 arg1 = LuaGetArgument_Vector3(L, 1); @@ -2376,26 +2399,6 @@ int lua_DrawLight(lua_State* L) return 0; } -int lua_Draw3DLine(lua_State* L) -{ - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - Vector3 arg2 = LuaGetArgument_Vector3(L, 2); - Color arg3 = LuaGetArgument_Color(L, 3); - Draw3DLine(arg1, arg2, arg3); - return 0; -} - -int lua_Draw3DCircle(lua_State* L) -{ - Vector3 arg1 = LuaGetArgument_Vector3(L, 1); - float arg2 = LuaGetArgument_float(L, 2); - float arg3 = LuaGetArgument_float(L, 3); - Vector3 arg4 = LuaGetArgument_Vector3(L, 4); - Color arg5 = LuaGetArgument_Color(L, 5); - Draw3DCircle(arg1, arg2, arg3, arg4, arg5); - return 0; -} - //------------------------------------------------------------------------------------ // raylib [models] module functions //------------------------------------------------------------------------------------ @@ -3725,6 +3728,8 @@ static luaL_Reg raylib_functions[] = { REG(MeasureTextEx) REG(DrawFPS) + REG(DrawLine3D) + REG(DrawCircle3D) REG(DrawCube) REG(DrawCubeV) REG(DrawCubeWires) @@ -3738,8 +3743,7 @@ static luaL_Reg raylib_functions[] = { REG(DrawRay) REG(DrawGrid) REG(DrawGizmo) - - REG(DrawLight) + REG(DrawLight) REG(LoadModel) REG(LoadModelEx) @@ -3747,10 +3751,10 @@ static luaL_Reg raylib_functions[] = { REG(LoadHeightmap) REG(LoadCubicmap) REG(UnloadModel) - REG(LoadMaterial) - REG(LoadDefaultMaterial) - REG(LoadStandardMaterial) - REG(UnloadMaterial) + REG(LoadMaterial) + REG(LoadDefaultMaterial) + REG(LoadStandardMaterial) + REG(UnloadMaterial) //REG(GenMesh*) // Not ready yet... REG(DrawModel) -- cgit v1.2.3 From 3377a4485b309ef52092cdf4da608313b266d919 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 13 Aug 2016 11:31:15 +0200 Subject: Support shared/dynamic raylib compilation Generates: Win32: raylib.dll, libraylibdll.a (import library) Linux: libraylib.so --- src/Makefile | 35 ++-- src/raylib.h | 574 ++++++++++++++++++++++++++++++----------------------------- 2 files changed, 312 insertions(+), 297 deletions(-) (limited to 'src/raylib.h') diff --git a/src/Makefile b/src/Makefile index b4eccdb2..75812566 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,7 +35,7 @@ # possible platforms: PLATFORM_DESKTOP PLATFORM_RPI PLATFORM_WEB PLATFORM ?= PLATFORM_DESKTOP -# define if you want shared or static version of library. +# define YES if you want shared/dynamic version of library instead of static (default) SHARED ?= NO # determine if the file has root access (only for installing raylib) @@ -95,8 +95,11 @@ endif # -Wno-missing-braces ignore invalid warning (GCC bug 53119) CFLAGS = -O1 -Wall -std=gnu99 -fgnu89-inline -Wno-missing-braces +# if shared library required, make sure code is compiled as position independent ifeq ($(SHARED),YES) CFLAGS += -fPIC + SHAREDFLAG = BUILDING_DLL + SHAREDLIBS = -Lexternal/glfw3/lib/win32 -Lexternal/openal_soft/lib/win32 -lglfw3 -lopenal32 -lgdi32 endif #CFLAGSEXTRA = -Wextra -Wmissing-prototypes -Wstrict-prototypes @@ -152,12 +155,16 @@ ifeq ($(PLATFORM),PLATFORM_WEB) @echo "libraylib.bc generated (web version)!" else ifeq ($(SHARED),YES) - ifeq ($(PLATFORM_OS),LINUX) - # compile raylib to shared library version for GNU/Linux. - # WARNING: you should type "make clean" before doing this target - $(CC) -shared -o $(OUTPUT_PATH)/libraylib.so $(OBJS) - @echo "libraylib.so generated (shared library)!" - endif + ifeq ($(PLATFORM_OS),LINUX) + # compile raylib to shared library version for GNU/Linux. + # WARNING: you should type "make clean" before doing this target + $(CC) -shared -o $(OUTPUT_PATH)/libraylib.so $(OBJS) + @echo "raylib shared library (libraylib.so) generated!" + endif + ifeq ($(PLATFORM_OS),WINDOWS) + $(CC) -shared -o $(OUTPUT_PATH)/raylib.dll $(OBJS) $(SHAREDLIBS) -Wl,--out-implib,$(OUTPUT_PATH)/libraylibdll.a + @echo "raylib dynamic library (raylib.dll) and MSVC required import library (libraylibdll.a) generated!" + endif else # compile raylib static library for desktop platforms. ar rcs $(OUTPUT_PATH)/libraylib.a $(OBJS) @@ -169,7 +176,7 @@ endif # compile core module core.o : core.c raylib.h rlgl.h utils.h raymath.h gestures.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(SHAREDFLAG) # compile rlgl module rlgl.o : rlgl.c rlgl.h raymath.h @@ -177,23 +184,23 @@ rlgl.o : rlgl.c rlgl.h raymath.h # compile shapes module shapes.o : shapes.c raylib.h rlgl.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(SHAREDFLAG) # compile textures module textures.o : textures.c rlgl.h utils.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(GRAPHICS) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(GRAPHICS) -D$(SHAREDFLAG) # compile text module text.o : text.c raylib.h utils.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(SHAREDFLAG) # compile models module models.o : models.c raylib.h rlgl.h raymath.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(SHAREDFLAG) # compile audio module audio.o : audio.c raylib.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(SHAREDFLAG) # compile stb_vorbis library external/stb_vorbis.o: external/stb_vorbis.c external/stb_vorbis.h @@ -201,7 +208,7 @@ external/stb_vorbis.o: external/stb_vorbis.c external/stb_vorbis.h # compile utils module utils.o : utils.c utils.h - $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + $(CC) -c $< $(CFLAGS) $(INCLUDES) -D$(PLATFORM) -D$(SHAREDFLAG) # It installs generated and needed files to compile projects using raylib. # The installation works manually. diff --git a/src/raylib.h b/src/raylib.h index 1673578d..c2e65b68 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -81,6 +81,14 @@ typedef struct android_app; // Define android_app struct (android_native_app_glue.h) #endif +#if defined(_WIN32) && defined(BUILDING_DLL) + #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL +#elif defined(_WIN32) && defined(RAYLIB_DLL) + #define RLAPI __declspec(dllimport) // We are using raylib as a Win32 DLL +#else + #define RLAPI // We are building or using raylib as a static library (or Linux shared library) +#endif + //---------------------------------------------------------------------------------- // Some basic Defines //---------------------------------------------------------------------------------- @@ -576,94 +584,94 @@ extern "C" { // Prevents name mangling of functions // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_ANDROID) -void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics +RLAPI void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics #elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics +RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif -void CloseWindow(void); // Close Window and Terminate Context -bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed -bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) -void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) -int GetScreenWidth(void); // Get current screen width -int GetScreenHeight(void); // Get current screen height - -void ShowCursor(void); // Shows cursor -void HideCursor(void); // Hides cursor -bool IsCursorHidden(void); // Returns true if cursor is not visible -void EnableCursor(void); // Enables cursor -void DisableCursor(void); // Disables cursor - -void ClearBackground(Color color); // Sets Background Color -void BeginDrawing(void); // Setup drawing canvas to start drawing -void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) - -void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera -void End2dMode(void); // Ends 2D mode custom camera usage -void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) -void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode -void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing -void EndTextureMode(void); // Ends drawing to render texture - -Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position -Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position -Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) - -void SetTargetFPS(int fps); // Set target FPS (maximum) -float GetFPS(void); // Returns current FPS -float GetFrameTime(void); // Returns time in seconds for one frame - -Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -int GetHexValue(Color color); // Returns hexadecimal value for a Color -float *ColorToFloat(Color color); // Converts Color to float array and normalizes -float *VectorToFloat(Vector3 vec); // Converts Vector3 to float array -float *MatrixToFloat(Matrix mat); // Converts Matrix to float array - -int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) -Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f - -void SetConfigFlags(char flags); // Setup some window configuration flags -void ShowLogo(void); // Activates raylib logo at startup (can be done with flags) - -bool IsFileDropped(void); // Check if a file have been dropped into window -char **GetDroppedFiles(int *count); // Retrieve dropped files into window -void ClearDroppedFiles(void); // Clear dropped files paths buffer - -void StorageSaveValue(int position, int value); // Storage save integer value (to defined position) -int StorageLoadValue(int position); // Storage load integer value (from defined position) +RLAPI void CloseWindow(void); // Close Window and Terminate Context +RLAPI bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed +RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) +RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) +RLAPI int GetScreenWidth(void); // Get current screen width +RLAPI int GetScreenHeight(void); // Get current screen height + +RLAPI void ShowCursor(void); // Shows cursor +RLAPI void HideCursor(void); // Hides cursor +RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible +RLAPI void EnableCursor(void); // Enables cursor +RLAPI void DisableCursor(void); // Disables cursor + +RLAPI void ClearBackground(Color color); // Sets Background Color +RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing +RLAPI void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering) + +RLAPI void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera +RLAPI void End2dMode(void); // Ends 2D mode custom camera usage +RLAPI void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup) +RLAPI void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode +RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing +RLAPI void EndTextureMode(void); // Ends drawing to render texture + +RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position +RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position +RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) + +RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) +RLAPI float GetFPS(void); // Returns current FPS +RLAPI float GetFrameTime(void); // Returns time in seconds for one frame + +RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color +RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes +RLAPI float *VectorToFloat(Vector3 vec); // Converts Vector3 to float array +RLAPI float *MatrixToFloat(Matrix mat); // Converts Matrix to float array + +RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) +RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f + +RLAPI void SetConfigFlags(char flags); // Setup some window configuration flags +RLAPI void ShowLogo(void); // Activates raylib logo at startup (can be done with flags) + +RLAPI bool IsFileDropped(void); // Check if a file have been dropped into window +RLAPI char **GetDroppedFiles(int *count); // Retrieve dropped files into window +RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer + +RLAPI void StorageSaveValue(int position, int value); // Storage save integer value (to defined position) +RLAPI int StorageLoadValue(int position); // Storage load integer value (from defined position) //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) -bool IsKeyPressed(int key); // Detect if a key has been pressed once -bool IsKeyDown(int key); // Detect if a key is being pressed -bool IsKeyReleased(int key); // Detect if a key has been released once -bool IsKeyUp(int key); // Detect if a key is NOT being pressed -int GetKeyPressed(void); // Get latest key pressed -void SetExitKey(int key); // Set a custom key to exit program (default is ESC) - -bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available -float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis -bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once -bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed -bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once -bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed +RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once +RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed +RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once +RLAPI bool IsKeyUp(int key); // Detect if a key is NOT being pressed +RLAPI int GetKeyPressed(void); // Get latest key pressed +RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) + +RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis +RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once +RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed +RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once +RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed #endif -bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once -bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed -bool IsMouseButtonReleased(int button); // Detect if a mouse button has been released once -bool IsMouseButtonUp(int button); // Detect if a mouse button is NOT being pressed -int GetMouseX(void); // Returns mouse position X -int GetMouseY(void); // Returns mouse position Y -Vector2 GetMousePosition(void); // Returns mouse position XY -void SetMousePosition(Vector2 position); // Set mouse position XY -int GetMouseWheelMove(void); // Returns mouse wheel movement Y +RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once +RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed +RLAPI bool IsMouseButtonReleased(int button); // Detect if a mouse button has been released once +RLAPI bool IsMouseButtonUp(int button); // Detect if a mouse button is NOT being pressed +RLAPI int GetMouseX(void); // Returns mouse position X +RLAPI int GetMouseY(void); // Returns mouse position Y +RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY +RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY +RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y -int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) -int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) -Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) +RLAPI int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size) +RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) +RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) #if defined(PLATFORM_ANDROID) bool IsButtonPressed(int button); // Detect if an android physic button has been pressed @@ -674,264 +682,264 @@ bool IsButtonReleased(int button); // Detect if an android //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ -void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture -int GetTouchPointsCount(void); // Get touch points count -float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds -Vector2 GetGestureDragVector(void); // Get gesture drag vector -float GetGestureDragAngle(void); // Get gesture drag angle -Vector2 GetGesturePinchVector(void); // Get gesture pinch delta -float GetGesturePinchAngle(void); // Get gesture pinch angle +RLAPI void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags +RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected +RLAPI int GetGestureDetected(void); // Get latest detected gesture +RLAPI int GetTouchPointsCount(void); // Get touch points count +RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds +RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector +RLAPI float GetGestureDragAngle(void); // Get gesture drag angle +RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta +RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) //------------------------------------------------------------------------------------ -void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) -void UpdateCamera(Camera *camera); // Update camera (player position is ignored) -void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and player position (1st person and 3rd person cameras) +RLAPI void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) +RLAPI void UpdateCamera(Camera *camera); // Update camera (player position is ignored) +RLAPI void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and player position (1st person and 3rd person cameras) -void SetCameraPosition(Vector3 position); // Set internal camera position -void SetCameraTarget(Vector3 target); // Set internal camera target -void SetCameraFovy(float fovy); // Set internal camera field-of-view-y +RLAPI void SetCameraPosition(Vector3 position); // Set internal camera position +RLAPI void SetCameraTarget(Vector3 target); // Set internal camera target +RLAPI void SetCameraFovy(float fovy); // Set internal camera field-of-view-y -void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) -void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) -void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) +RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) +RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) +RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int frontKey, int backKey, +RLAPI void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, - int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) -void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) + int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) +RLAPI void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) //------------------------------------------------------------------------------------ -void DrawPixel(int posX, int posY, Color color); // Draw a pixel -void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) -void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line -void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version) -void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle -void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle -void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) -void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline -void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle -void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle -void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2); // Draw a gradient-filled rectangle -void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) -void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline -void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle -void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline -void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) -void DrawPolyEx(Vector2 *points, int numPoints, Color color); // Draw a closed polygon defined by points -void DrawPolyExLines(Vector2 *points, int numPoints, Color color); // Draw polygon lines - -bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles -bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles -bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle -Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision -bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle -bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle -bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle +RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel +RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) +RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line +RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version) +RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle +RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle +RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) +RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline +RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2); // Draw a gradient-filled rectangle +RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) +RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline +RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle +RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline +RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) +RLAPI void DrawPolyEx(Vector2 *points, int numPoints, Color color); // Draw a closed polygon defined by points +RLAPI void DrawPolyExLines(Vector2 *points, int numPoints, Color color); // Draw polygon lines + +RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles +RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles +RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle +RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision +RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle +RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle //------------------------------------------------------------------------------------ // Texture Loading and Drawing Functions (Module: textures) //------------------------------------------------------------------------------------ -Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) -Image LoadImageEx(Color *pixels, int width, int height); // Load image data from Color array data (RGBA - 32bit) -Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file -Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) -Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory -Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory -Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) -Texture2D LoadTextureFromImage(Image image); // Load a texture from image data -RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering -void UnloadImage(Image image); // Unload image from CPU memory (RAM) -void UnloadTexture(Texture2D texture); // Unload texture from GPU memory -void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory -Color *GetImageData(Image image); // Get pixel data from image as a Color struct array -Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image -void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) -void ImageFormat(Image *image, int newFormat); // Convert image data to desired format -void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) -void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle -void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) -void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) -Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) -Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) -void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image -void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) -void ImageFlipVertical(Image *image); // Flip image vertically -void ImageFlipHorizontal(Image *image); // Flip image horizontally -void ImageColorTint(Image *image, Color color); // Modify image color: tint -void ImageColorInvert(Image *image); // Modify image color: invert -void ImageColorGrayscale(Image *image); // Modify image color: grayscale -void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) -void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) -void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data - -void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D -void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 -void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters -void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters +RLAPI Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) +RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image data from Color array data (RGBA - 32bit) +RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file +RLAPI Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) +RLAPI Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory +RLAPI Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory +RLAPI Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) +RLAPI Texture2D LoadTextureFromImage(Image image); // Load a texture from image data +RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering +RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) +RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory +RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory +RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array +RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image +RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) +RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format +RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) +RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle +RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering) +RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm) +RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) +RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) +RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image +RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) +RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) +RLAPI void ImageFlipVertical(Image *image); // Flip image vertically +RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint +RLAPI void ImageColorInvert(Image *image); // Modify image color: invert +RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale +RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) +RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) +RLAPI void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture +RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data + +RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D +RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 +RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters +RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle +RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters float rotation, Color tint); //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ -SpriteFont GetDefaultFont(void); // Get the default SpriteFont -SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory -void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory +RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont +RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory +RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory -void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters float fontSize, int spacing, Color tint); -int MeasureText(const char *text, int fontSize); // Measure string width for default font -Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont -void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner -const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -const char *SubText(const char *text, int position, int length); // Get a piece of a text string +RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner +RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' +RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string //------------------------------------------------------------------------------------ // Basic 3d Shapes Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space -void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle 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 -void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float lenght, Color color); // Draw cube textured -void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere -void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters -void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires -void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone -void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires -void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ -void DrawRay(Ray ray, Color color); // Draw a ray line -void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) -void DrawGizmo(Vector3 position); // Draw simple gizmo -void DrawLight(Light light); // Draw light in 3D world +RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space +RLAPI void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle in 3D world space +RLAPI void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube +RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) +RLAPI void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires +RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float lenght, Color color); // Draw cube textured +RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere +RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters +RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires +RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone +RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires +RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ +RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line +RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) +RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo +RLAPI void DrawLight(Light light); // Draw light in 3D world //DrawTorus(), DrawTeapot() are useless... //------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) -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) -void UnloadModel(Model model); // Unload 3d model from memory - -Mesh GenMeshCube(float width, float height, float depth); // Generate mesh: cube - -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) -void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters -void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) - -void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture -void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec - -BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits -bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres -bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes -bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere -bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere -bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection -bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box -Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap +RLAPI Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) +RLAPI Model LoadModelEx(Mesh data, bool dynamic); // Load a 3d model (from mesh data) +RLAPI Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource) +RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model +RLAPI Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) +RLAPI void UnloadModel(Model model); // Unload 3d model from memory + +RLAPI Mesh GenMeshCube(float width, float height, float depth); // Generate mesh: cube + +RLAPI Material LoadMaterial(const char *fileName); // Load material data (from file) +RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) +RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) +RLAPI void UnloadMaterial(Material material); // Unload material textures from VRAM + +RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters +RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) + +RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec + +RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits +RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres +RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes +RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere +RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere +RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection +RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box +RLAPI Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap // NOTE: Return the normal vector of the impacted surface //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ -Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -void UnloadShader(Shader shader); // Unload a custom shader from memory +RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations +RLAPI void UnloadShader(Shader shader); // Unload a custom shader from memory -Shader GetDefaultShader(void); // Get default shader -Shader GetStandardShader(void); // Get standard shader -Texture2D GetDefaultTexture(void); // Get default texture +RLAPI Shader GetDefaultShader(void); // Get default shader +RLAPI Shader GetStandardShader(void); // Get standard shader +RLAPI Texture2D GetDefaultTexture(void); // Get default texture -int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location -void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) -void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) -void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) +RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location +RLAPI void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float) +RLAPI void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int) +RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4) -void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) -void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) -void BeginShaderMode(Shader shader); // Begin custom shader drawing -void EndShaderMode(void); // End custom shader drawing (use default shader) -void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) -void EndBlendMode(void); // End blending mode (reset to default: alpha blending) +RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing +RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) +RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) +RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -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 +RLAPI Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool +RLAPI void DestroyLight(Light light); // Destroy a light and take it out of the list //------------------------------------------------------------------------------------ // VR experience Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ -void InitVrDevice(int vdDevice); // Init VR device -void CloseVrDevice(void); // Close VR device -bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready -void UpdateVrTracking(void); // Update VR tracking (position and orientation) -void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) +RLAPI void InitVrDevice(int vdDevice); // Init VR device +RLAPI void CloseVrDevice(void); // Close VR device +RLAPI bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +RLAPI void UpdateVrTracking(void); // Update VR tracking (position and orientation) +RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) //------------------------------------------------------------------------------------ // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ -void InitAudioDevice(void); // Initialize audio device and context -void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully - -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) -void UnloadSound(Sound sound); // Unload sound -void PlaySound(Sound sound); // Play a sound -void PauseSound(Sound sound); // Pause a sound -void ResumeSound(Sound sound); // Resume a paused sound -void StopSound(Sound sound); // Stop playing a sound -bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing -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) - -Music LoadMusicStream(char *fileName); // Load music stream from file -void UnloadMusicStream(Music music); // Unload music stream -void PlayMusicStream(Music music); // Start music playing (open stream) -void UpdateMusicStream(Music music); // Updates buffers for music streaming -void StopMusicStream(Music music); // Stop music playing (close stream) -void PauseMusicStream(Music music); // Pause music playing -void ResumeMusicStream(Music music); // Resume playing paused music -bool IsMusicPlaying(Music music); // Check if music is playing -void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) -void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(Music music); // Get music time length (in seconds) -float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) - -AudioStream InitAudioStream(unsigned int sampleRate, - unsigned int sampleSize, - unsigned int channels); // Init audio stream (to stream audio pcm data) -void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data -void CloseAudioStream(AudioStream stream); // Close audio stream and free memory -bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill -void PlayAudioStream(AudioStream stream); // Play audio stream -void PauseAudioStream(AudioStream stream); // Pause audio stream -void ResumeAudioStream(AudioStream stream); // Resume audio stream -void StopAudioStream(AudioStream stream); // Stop audio stream +RLAPI void InitAudioDevice(void); // Initialize audio device and context +RLAPI void CloseAudioDevice(void); // Close the audio device and context (and music stream) +RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully + +RLAPI Sound LoadSound(char *fileName); // Load sound to memory +RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data +RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) +RLAPI void UnloadSound(Sound sound); // Unload sound +RLAPI void PlaySound(Sound sound); // Play a sound +RLAPI void PauseSound(Sound sound); // Pause a sound +RLAPI void ResumeSound(Sound sound); // Resume a paused sound +RLAPI void StopSound(Sound sound); // Stop playing a sound +RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing +RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) +RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) + +RLAPI Music LoadMusicStream(char *fileName); // Load music stream from file +RLAPI void UnloadMusicStream(Music music); // Unload music stream +RLAPI void PlayMusicStream(Music music); // Start music playing (open stream) +RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming +RLAPI void StopMusicStream(Music music); // Stop music playing (close stream) +RLAPI void PauseMusicStream(Music music); // Pause music playing +RLAPI void ResumeMusicStream(Music music); // Resume playing paused music +RLAPI bool IsMusicPlaying(Music music); // Check if music is playing +RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) +RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) + +RLAPI AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, + unsigned int channels); // Init audio stream (to stream audio pcm data) +RLAPI void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream +RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream +RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream +RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream #ifdef __cplusplus } -- cgit v1.2.3 From 342b89c5b920ceec8cd41a8f4cf5ab69f2d825f6 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 15 Aug 2016 16:35:11 +0200 Subject: Review Wave struct --- src/audio.c | 62 +++++++++++++++++++++++++++++++----------------------------- src/audio.h | 8 ++++---- src/raylib.h | 8 ++++---- 3 files changed, 40 insertions(+), 38 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 4b8641ab..683ee66b 100644 --- a/src/audio.c +++ b/src/audio.c @@ -233,18 +233,30 @@ Sound LoadSoundFromWave(Wave wave) if (wave.data != NULL) { ALenum format = 0; - // The OpenAL format is worked out by looking at the number of channels and the bits per sample + + // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample) if (wave.channels == 1) { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; + switch (wave.sampleSize) + { + case 8: format = AL_FORMAT_MONO8; break; + case 16: format = AL_FORMAT_MONO16; break; + case 32: format = AL_FORMAT_MONO_FLOAT32; break; + default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; + } } else if (wave.channels == 2) { - if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; - else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; + switch (wave.sampleSize) + { + case 8: format = AL_FORMAT_STEREO8; break; + case 16: format = AL_FORMAT_STEREO16; break; + case 32: format = AL_FORMAT_STEREO_FLOAT32; break; + default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break; + } } - + else TraceLog(WARNING, "Wave number of channels not supported: %i", wave.channels); + // Create an audio source ALuint source; alGenSources(1, &source); // Generate pointer to audio source @@ -259,14 +271,16 @@ Sound LoadSoundFromWave(Wave wave) //---------------------------------------- ALuint buffer; alGenBuffers(1, &buffer); // Generate pointer to buffer + + unsigned int dataSize = wave.sampleCount*wave.sampleSize/8; // Size in bytes // Upload sound data to buffer - alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate); + alBufferData(buffer, format, wave.data, dataSize, wave.sampleRate); // Attach sound buffer to source alSourcei(source, AL_BUFFER, buffer); - TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.sampleSize, wave.channels); sound.source = source; sound.buffer = buffer; @@ -341,8 +355,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) fread(&reserved, 1, 1, rresFile); // wave.sampleRate = sampleRate; - wave.dataSize = infoHeader.srcSize; - wave.bitsPerSample = bps; + wave.sampleSize = bps; wave.channels = (short)channels; unsigned char *data = malloc(infoHeader.size); @@ -948,18 +961,18 @@ static Wave LoadWAV(const char *fileName) else { // Allocate memory for data - wave.data = (unsigned char *)malloc(sizeof(unsigned char) * waveData.subChunkSize); + wave.data = (unsigned char *)malloc(sizeof(unsigned char)*waveData.subChunkSize); // Read in the sound data into the soundData variable fread(wave.data, waveData.subChunkSize, 1, wavFile); // Now we set the variables that we need later - wave.dataSize = waveData.subChunkSize; + wave.sampleCount = waveData.subChunkSize; wave.sampleRate = waveFormat.sampleRate; + wave.sampleSize = waveFormat.bitsPerSample; wave.channels = waveFormat.numChannels; - wave.bitsPerSample = waveFormat.bitsPerSample; - TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels); } } } @@ -988,35 +1001,24 @@ static Wave LoadOGG(char *fileName) stb_vorbis_info info = stb_vorbis_get_info(oggFile); wave.sampleRate = info.sample_rate; - wave.bitsPerSample = 16; + wave.sampleSize = 16; // 16 bit per sample (short) wave.channels = info.channels; - TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); - TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); - int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile)*info.channels); - - wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes - - TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength); - float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); - TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds); - if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); int totalSamples = totalSeconds*info.sample_rate*info.channels; + wave.sampleCount = totalSamples; - TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples); - - wave.data = malloc(sizeof(short)*totalSamplesLength); + wave.data = (short *)malloc(totalSamplesLength*sizeof(short)); - int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength); + int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, totalSamplesLength); TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained); - TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, BitRate: %i, Channels: %i)", fileName, wave.sampleRate, wave.bitsPerSample, wave.channels); + TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels); stb_vorbis_close(oggFile); } diff --git a/src/audio.h b/src/audio.h index dbd88939..4ee9559e 100644 --- a/src/audio.h +++ b/src/audio.h @@ -68,11 +68,11 @@ typedef struct Sound { // Wave type, defines audio wave data typedef struct Wave { + unsigned int sampleCount; // Number of samples + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) void *data; // Buffer data pointer - unsigned int dataSize; // Data size in bytes - unsigned int sampleRate; // Samples per second to be played - short bitsPerSample; // Sample size in bits - short channels; } Wave; // Music type (file streaming from memory) diff --git a/src/raylib.h b/src/raylib.h index c2e65b68..22494aec 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -490,11 +490,11 @@ typedef struct Sound { // Wave type, defines audio wave data typedef struct Wave { + unsigned int sampleCount; // Number of samples + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) void *data; // Buffer data pointer - unsigned int dataSize; // Data size in bytes - unsigned int sampleRate; // Samples per second to be played - short bitsPerSample; // Sample size in bits - short channels; } Wave; // Music type (file streaming from memory) -- cgit v1.2.3 From 959a228815edcecdde692fcd47a7b540844c5712 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 16 Aug 2016 11:09:55 +0200 Subject: Removed useless spacing --- src/audio.c | 74 +++++------ src/core.c | 342 ++++++++++++++++++++++++------------------------- src/models.c | 134 +++++++++---------- src/raylib.h | 4 +- src/rlgl.h | 26 ++-- src/rlua.h | 72 +++++------ src/text.c | 146 ++++++++++----------- src/textures.c | 398 ++++++++++++++++++++++++++++----------------------------- 8 files changed, 598 insertions(+), 598 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 683ee66b..1772196f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -183,7 +183,7 @@ void CloseAudioDevice(void) alcMakeContextCurrent(NULL); alcDestroyContext(context); alcCloseDevice(device); - + TraceLog(INFO, "Audio device closed successfully"); } @@ -217,7 +217,7 @@ Sound LoadSound(char *fileName) else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); Sound sound = LoadSoundFromWave(wave); - + // Sound is loaded, we can unload wave UnloadWave(wave); @@ -233,7 +233,7 @@ Sound LoadSoundFromWave(Wave wave) if (wave.data != NULL) { ALenum format = 0; - + // The OpenAL format is worked out by looking at the number of channels and the sample size (bits per sample) if (wave.channels == 1) { @@ -256,7 +256,7 @@ Sound LoadSoundFromWave(Wave wave) } } else TraceLog(WARNING, "Wave number of channels not supported: %i", wave.channels); - + // Create an audio source ALuint source; alGenSources(1, &source); // Generate pointer to audio source @@ -271,7 +271,7 @@ Sound LoadSoundFromWave(Wave wave) //---------------------------------------- ALuint buffer; alGenBuffers(1, &buffer); // Generate pointer to buffer - + unsigned int dataSize = wave.sampleCount*wave.sampleSize/8; // Size in bytes // Upload sound data to buffer @@ -367,7 +367,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId) free(data); sound = LoadSoundFromWave(wave); - + // Sound is loaded, we can unload wave data UnloadWave(wave); } @@ -506,13 +506,13 @@ Music LoadMusicStream(char *fileName) TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); TraceLog(DEBUG, "[%s] OGG channels: %i", fileName, info.channels); TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); - + } } else if (strcmp(GetExtension(fileName), "xm") == 0) { int result = jar_xm_create_context_from_file(&music->ctxXm, 48000, fileName); - + if (!result) // XM context created successfully { jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops @@ -523,7 +523,7 @@ Music LoadMusicStream(char *fileName) music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_XM; music->loop = true; - + TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); } @@ -555,11 +555,11 @@ Music LoadMusicStream(char *fileName) void UnloadMusicStream(Music music) { CloseAudioStream(music->stream); - + if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); else if (music->ctxType == MUSIC_MODULE_XM) jar_xm_free_context(music->ctxXm); else if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_unload(&music->ctxMod); - + free(music); } @@ -597,58 +597,58 @@ void UpdateMusicStream(Music music) // Determine if music stream is ready to be written alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - + int numBuffersToProcess = processed; - + if (processed > 0) { bool active = true; short pcm[AUDIO_BUFFER_SIZE]; float pcmf[AUDIO_BUFFER_SIZE]; - - int numSamples = 0; // Total size of data steamed in L+R samples for xm floats, + + int numSamples = 0; // Total size of data steamed in L+R samples for xm floats, // individual L or R for ogg shorts for (int i = 0; i < numBuffersToProcess; i++) { switch (music->ctxType) { - case MUSIC_AUDIO_OGG: + case MUSIC_AUDIO_OGG: { if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE; else numSamples = music->samplesLeft; - + // NOTE: Returns the number of samples to process (should be the same as numSamples -> it is) int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, numSamples); // TODO: Review stereo channels Ogg, not enough samples served! UpdateAudioStream(music->stream, pcm, numSamplesOgg*music->stream.channels); music->samplesLeft -= (numSamplesOgg*music->stream.channels); - + } break; - case MUSIC_MODULE_XM: + case MUSIC_MODULE_XM: { if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; else numSamples = music->samplesLeft; - + // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) jar_xm_generate_samples(music->ctxXm, pcmf, numSamples); UpdateAudioStream(music->stream, pcmf, numSamples*2); // Using 32bit PCM data music->samplesLeft -= numSamples; - + //TraceLog(INFO, "Samples left: %i", music->samplesLeft); - + } break; - case MUSIC_MODULE_MOD: + case MUSIC_MODULE_MOD: { if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; else numSamples = music->samplesLeft; - + // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) - jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); + jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); UpdateAudioStream(music->stream, pcm, numSamples*2); music->samplesLeft -= numSamples; - + } break; default: break; } @@ -659,15 +659,15 @@ void UpdateMusicStream(Music music) break; } } - + // Reset audio stream for looping if (!active && music->loop) { // Restart music context (if required) - //if (music->ctxType == MUSIC_MODULE_XM) + //if (music->ctxType == MUSIC_MODULE_XM) if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_seek_start(&music->ctxMod); else if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_seek_start(music->ctxOgg); - + // Reset samples left to total samples music->samplesLeft = music->totalSamples; } @@ -713,7 +713,7 @@ void SetMusicPitch(Music music, float pitch) float GetMusicTimeLength(Music music) { float totalSeconds = (float)music->totalSamples/music->stream.sampleRate; - + return totalSeconds; } @@ -732,7 +732,7 @@ float GetMusicTimePlayed(Music music) AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) { AudioStream stream = { 0 }; - + stream.sampleRate = sampleRate; stream.sampleSize = sampleSize; stream.channels = channels; @@ -791,7 +791,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un } alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); - + TraceLog(INFO, "[AUD ID %i] Audio stream loaded successfully", stream.source); return stream; @@ -806,9 +806,9 @@ void CloseAudioStream(AudioStream stream) // Flush out all queued buffers int queued = 0; alGetSourcei(stream.source, AL_BUFFERS_QUEUED, &queued); - + ALuint buffer = 0; - + while (queued > 0) { alSourceUnqueueBuffers(stream.source, 1, &buffer); @@ -818,7 +818,7 @@ void CloseAudioStream(AudioStream stream) // Delete source and buffers alDeleteSources(1, &stream.source); alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers); - + TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } @@ -828,14 +828,14 @@ void UpdateAudioStream(AudioStream stream, void *data, int numSamples) { ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); - + // Check if any buffer was available for unqueue if (alGetError() != AL_INVALID_VALUE) { if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); - + alSourceQueueBuffers(stream.source, 1, &buffer); } } diff --git a/src/core.c b/src/core.c index 2b5329e3..a76fe0be 100644 --- a/src/core.c +++ b/src/core.c @@ -120,9 +120,9 @@ //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN" //#define DEFAULT_MOUSE_DEV "/dev/input/eventN" //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN" - + #define MOUSE_SENSITIVITY 0.8f - + #define MAX_GAMEPADS 2 // Max number of gamepads supported #define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) @@ -333,7 +333,7 @@ void InitWindow(int width, int height, const char *title) emscripten_set_touchend_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback); emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback); - + // TODO: Add gamepad support (not provided by GLFW3 on emscripten) //emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenInputCallback); //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback); @@ -394,7 +394,7 @@ void InitWindow(int width, int height, struct android_app *state) //state->userData = &engine; app->onAppCmd = AndroidCommandCallback; app->onInputEvent = AndroidInputCallback; - + InitAssetManager(app->activity->assetManager); TraceLog(INFO, "Android app initialized successfully"); @@ -447,7 +447,7 @@ void CloseWindow(void) eglTerminate(display); display = EGL_NO_DISPLAY; - } + } #endif #if defined(PLATFORM_RPI) @@ -527,7 +527,7 @@ void BeginDrawing(void) currentTime = GetTime(); // Number of elapsed seconds since InitTimer() was called updateTime = currentTime - previousTime; previousTime = currentTime; - + rlClearScreenBuffers(); // Clear current framebuffers rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlMultMatrixf(MatrixToFloat(downscaleView)); // If downscale required, apply it here @@ -543,7 +543,7 @@ void EndDrawing(void) SwapBuffers(); // Copy back buffer to front buffer PollInputEvents(); // Poll user events - + // Frame time control system currentTime = GetTime(); drawTime = currentTime - previousTime; @@ -575,9 +575,9 @@ void Begin2dMode(Camera2D camera) Matrix matRotation = MatrixRotate((Vector3){ 0.0f, 0.0f, 1.0f }, camera.rotation*DEG2RAD); Matrix matScale = MatrixScale(camera.zoom, camera.zoom, 1.0f); Matrix matTranslation = MatrixTranslate(camera.offset.x + camera.target.x, camera.offset.y + camera.target.y, 0.0f); - + Matrix matTransform = MatrixMultiply(MatrixMultiply(matOrigin, MatrixMultiply(matScale, matRotation)), matTranslation); - + rlMultMatrixf(MatrixToFloat(matTransform)); } @@ -593,14 +593,14 @@ void End2dMode(void) void Begin3dMode(Camera camera) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - + if (IsVrDeviceReady()) BeginVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlLoadIdentity(); // Reset current matrix (PROJECTION) - + // Setup perspective projection float aspect = (float)screenWidth/(float)screenHeight; double top = 0.01*tan(camera.fovy*PI/360.0); @@ -615,15 +615,15 @@ void Begin3dMode(Camera camera) // Setup Camera view Matrix cameraView = MatrixLookAt(camera.position, camera.target, camera.up); rlMultMatrixf(MatrixToFloat(cameraView)); // Multiply MODELVIEW matrix by view matrix (camera) - + rlEnableDepthTest(); // Enable DEPTH_TEST for 3D } // Ends 3D mode and returns to default 2D orthographic mode void End3dMode(void) -{ +{ rlglDraw(); // Process internal buffers (update + draw) - + if (IsVrDeviceReady()) EndVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix @@ -633,7 +633,7 @@ void End3dMode(void) rlLoadIdentity(); // Reset current matrix (MODELVIEW) //rlTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode) - + rlDisableDepthTest(); // Disable DEPTH_TEST for 2D } @@ -645,16 +645,16 @@ void BeginTextureMode(RenderTexture2D target) rlEnableRenderTexture(target.id); // Enable render target rlClearScreenBuffers(); // Clear render texture buffers - + // Set viewport to framebuffer size - rlViewport(0, 0, target.texture.width, target.texture.height); - + rlViewport(0, 0, target.texture.width, target.texture.height); + rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix rlLoadIdentity(); // Reset current matrix (PROJECTION) // Set orthographic projection to current framebuffer size // NOTE: Configured top-left corner as (0, 0) - rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f); + rlOrtho(0, target.texture.width, target.texture.height, 0, 0.0f, 1.0f); rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -672,10 +672,10 @@ void EndTextureMode(void) // Set viewport to default framebuffer size (screen size) // TODO: consider possible viewport offsets rlViewport(0, 0, GetScreenWidth(), GetScreenHeight()); - + rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix rlLoadIdentity(); // Reset current matrix (PROJECTION) - + // Set orthographic projection to current framebuffer size // NOTE: Configured top-left corner as (0, 0) rlOrtho(0, GetScreenWidth(), GetScreenHeight(), 0, 0.0f, 1.0f); @@ -701,7 +701,7 @@ float GetFPS(void) // Returns time in seconds for one frame float GetFrameTime(void) { - // As we are operate quite a lot with frameTime, + // As we are operate quite a lot with frameTime, // it could be no stable, so we round it before passing it around // NOTE: There are still problems with high framerates (>500fps) double roundedFrameTime = round(frameTime*10000)/10000.0; @@ -735,7 +735,7 @@ float *VectorToFloat(Vector3 vec) } // Converts Matrix to float array -// NOTE: Returned vector is a transposed version of the Matrix struct, +// NOTE: Returned vector is a transposed version of the Matrix struct, // it should be this way because, despite raymath use OpenGL column-major convention, // Matrix struct memory alignment and variables naming are not coherent float *MatrixToFloat(Matrix mat) @@ -799,7 +799,7 @@ Color Fade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; - + float colorAlpha = (float)color.a*alpha; return (Color){color.r, color.g, color.b, (unsigned char)colorAlpha}; @@ -841,9 +841,9 @@ void ClearDroppedFiles(void) if (dropFilesCount > 0) { for (int i = 0; i < dropFilesCount; i++) free(dropFilesPath[i]); - + free(dropFilesPath); - + dropFilesCount = 0; } } @@ -854,7 +854,7 @@ void ClearDroppedFiles(void) void StorageSaveValue(int position, int value) { FILE *storageFile = NULL; - + char path[128]; #if defined(PLATFORM_ANDROID) strcpy(path, internalDataPath); @@ -865,7 +865,7 @@ void StorageSaveValue(int position, int value) #endif // Try open existing file to append data - storageFile = fopen(path, "rb+"); + storageFile = fopen(path, "rb+"); // If file doesn't exist, create a new storage data file if (!storageFile) storageFile = fopen(path, "wb"); @@ -877,14 +877,14 @@ void StorageSaveValue(int position, int value) fseek(storageFile, 0, SEEK_END); int fileSize = ftell(storageFile); // Size in bytes fseek(storageFile, 0, SEEK_SET); - + if (fileSize < (position*4)) TraceLog(WARNING, "Storage position could not be found"); else { fseek(storageFile, (position*4), SEEK_SET); fwrite(&value, 1, 4, storageFile); } - + fclose(storageFile); } } @@ -894,7 +894,7 @@ void StorageSaveValue(int position, int value) int StorageLoadValue(int position) { int value = 0; - + char path[128]; #if defined(PLATFORM_ANDROID) strcpy(path, internalDataPath); @@ -903,9 +903,9 @@ int StorageLoadValue(int position) #else strcpy(path, STORAGE_FILENAME); #endif - + // Try open existing file to append data - FILE *storageFile = fopen(path, "rb"); + FILE *storageFile = fopen(path, "rb"); if (!storageFile) TraceLog(WARNING, "Storage data file could not be found"); else @@ -914,42 +914,42 @@ int StorageLoadValue(int position) fseek(storageFile, 0, SEEK_END); int fileSize = ftell(storageFile); // Size in bytes rewind(storageFile); - + if (fileSize < (position*4)) TraceLog(WARNING, "Storage position could not be found"); else { fseek(storageFile, (position*4), SEEK_SET); fread(&value, 1, 4, storageFile); } - + fclose(storageFile); } - + return value; } // Returns a ray trace from mouse position Ray GetMouseRay(Vector2 mousePosition, Camera camera) -{ +{ Ray ray; - + // Calculate normalized device coordinates // NOTE: y value is negative float x = (2.0f*mousePosition.x)/(float)GetScreenWidth() - 1.0f; float y = 1.0f - (2.0f*mousePosition.y)/(float)GetScreenHeight(); float z = 1.0f; - + // Store values in a vector Vector3 deviceCoords = { x, y, z }; - + TraceLog(DEBUG, "Device coordinates: (%f, %f, %f)", deviceCoords.x, deviceCoords.y, deviceCoords.z); - + // Calculate projection matrix (from perspective instead of frustum) Matrix matProj = MatrixPerspective(camera.fovy, ((double)GetScreenWidth()/(double)GetScreenHeight()), 0.01, 1000.0); - + // Calculate view matrix from camera look at Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); - + // Do I need to transpose it? It seems that yes... // NOTE: matrix order may be incorrect... In OpenGL to get world position from // camera view it just needs to get inverted, but here we need to transpose it too. @@ -957,10 +957,10 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) // to a vector, you will get its 3d world position coordinates (camera.position). // If you don't transpose, final position will be wrong. MatrixTranspose(&matView); - + //#define USE_RLGL_UNPROJECT #if defined(USE_RLGL_UNPROJECT) // OPTION 1: Use rlglUnproject() - + Vector3 nearPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 0.0f }, matProj, matView); Vector3 farPoint = rlglUnproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView); @@ -969,56 +969,56 @@ Ray GetMouseRay(Vector2 mousePosition, Camera camera) // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it Matrix matProjView = MatrixMultiply(matProj, matView); MatrixInvert(&matProjView); - + // Calculate far and near points Quaternion near = { deviceCoords.x, deviceCoords.y, 0.0f, 1.0f }; Quaternion far = { deviceCoords.x, deviceCoords.y, 1.0f, 1.0f }; - + // Multiply points by unproject matrix QuaternionTransform(&near, matProjView); QuaternionTransform(&far, matProjView); - + // Calculate normalized world points in vectors Vector3 nearPoint = { near.x/near.w, near.y/near.w, near.z/near.w}; Vector3 farPoint = { far.x/far.w, far.y/far.w, far.z/far.w}; #endif - + // Calculate normalized direction vector Vector3 direction = VectorSubtract(farPoint, nearPoint); VectorNormalize(&direction); - + // Apply calculated vectors to ray ray.position = camera.position; ray.direction = direction; - + return ray; } // Returns the screen space position from a 3d world space position Vector2 GetWorldToScreen(Vector3 position, Camera camera) -{ +{ // Calculate projection matrix (from perspective instead of frustum Matrix matProj = MatrixPerspective(camera.fovy, (double)GetScreenWidth()/(double)GetScreenHeight(), 0.01, 1000.0); - + // Calculate view matrix from camera look at (and transpose it) Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); MatrixTranspose(&matView); - + // Convert world position vector to quaternion Quaternion worldPos = { position.x, position.y, position.z, 1.0f }; - + // Transform world position to view QuaternionTransform(&worldPos, matView); - + // Transform result to projection (clip space position) QuaternionTransform(&worldPos, matProj); - + // Calculate normalized device coordinates (inverted y) Vector3 ndcPos = { worldPos.x / worldPos.w, -worldPos.y / worldPos.w, worldPos.z / worldPos.z }; - + // Calculate 2d screen position vector Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)GetScreenWidth(), (ndcPos.y + 1.0f)/2.0f*(float)GetScreenHeight() }; - + return screenPosition; } @@ -1144,7 +1144,7 @@ bool IsCursorHidden() bool IsGamepadAvailable(int gamepad) { bool result = false; - + #if defined(PLATFORM_RPI) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; #else @@ -1158,7 +1158,7 @@ bool IsGamepadAvailable(int gamepad) float GetGamepadAxisMovement(int gamepad, int axis) { float value = 0; - + #if defined(PLATFORM_RPI) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) { @@ -1167,9 +1167,9 @@ float GetGamepadAxisMovement(int gamepad, int axis) #else const float *axes; int axisCount = 0; - + axes = glfwGetJoystickAxes(gamepad, &axisCount); - + if (axis < axisCount) value = axes[axis]; #endif @@ -1197,7 +1197,7 @@ bool IsGamepadButtonPressed(int gamepad, int button) bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; - + #if defined(PLATFORM_RPI) // Get gamepad buttons information if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (gamepadButtons[gamepad][button] == 1)) result = true; @@ -1205,13 +1205,13 @@ bool IsGamepadButtonDown(int gamepad, int button) #else const unsigned char *buttons; int buttonsCount; - + buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true; else result = false; #endif - + return result; } @@ -1260,7 +1260,7 @@ bool IsGamepadButtonUp(int gamepad, int button) bool IsMouseButtonPressed(int button) { bool pressed = false; - + #if defined(PLATFORM_ANDROID) if (IsGestureDetected(GESTURE_TAP)) pressed = true; #else @@ -1274,13 +1274,13 @@ bool IsMouseButtonPressed(int button) bool IsMouseButtonDown(int button) { bool down = false; - + #if defined(PLATFORM_ANDROID) if (IsGestureDetected(GESTURE_HOLD)) down = true; #else if (GetMouseButtonStatus(button) == 1) down = true; #endif - + return down; } @@ -1288,7 +1288,7 @@ bool IsMouseButtonDown(int button) bool IsMouseButtonReleased(int button) { bool released = false; - + #if !defined(PLATFORM_ANDROID) if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 0)) released = true; #endif @@ -1300,7 +1300,7 @@ bool IsMouseButtonReleased(int button) bool IsMouseButtonUp(int button) { bool up = false; - + #if !defined(PLATFORM_ANDROID) if (GetMouseButtonStatus(button) == 0) up = true; #endif @@ -1385,7 +1385,7 @@ int GetTouchY(void) Vector2 GetTouchPosition(int index) { Vector2 position = { -1.0f, -1.0f }; - + #if defined(PLATFORM_ANDROID) || defined(PLATFORM_WEB) if (index < MAX_TOUCH_POINTS) position = touchPosition[index]; else TraceLog(WARNING, "Required touch point out of range (Max touch points: %i)", MAX_TOUCH_POINTS); @@ -1493,7 +1493,7 @@ static void InitGraphicsDevice(int width, int height) // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version // with forward compatibility to older OpenGL versions. // For example, if using OpenGL 1.1, driver can provide a 3.3 context fordward compatible. - + if (configFlags & FLAG_MSAA_4X_HINT) { glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 @@ -1513,7 +1513,7 @@ static void InitGraphicsDevice(int width, int height) glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Profiles Hint: Only 3.3 and above! // Other values: GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE #ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // OSX Requires #else glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE); // Fordward Compatibility Hint: Only 3.3 and above! #endif @@ -1523,9 +1523,9 @@ static void InitGraphicsDevice(int width, int height) if (fullscreen) { // Obtain recommended displayWidth/displayHeight from a valid videomode for the monitor - int count; + int count; const GLFWvidmode *modes = glfwGetVideoModes(glfwGetPrimaryMonitor(), &count); - + // Get closest videomode to desired screenWidth/screenHeight for (int i = 0; i < count; i++) { @@ -1539,7 +1539,7 @@ static void InitGraphicsDevice(int width, int height) } } } - + TraceLog(WARNING, "Closest fullscreen videomode: %i x %i", displayWidth, displayHeight); // NOTE: ISSUE: Closest videomode could not match monitor aspect-ratio, for example, @@ -1548,12 +1548,12 @@ static void InitGraphicsDevice(int width, int height) // by the sides to fit all monitor space... // At this point we need to manage render size vs screen size - // NOTE: This function uses and modifies global module variables: + // NOTE: This function uses and modifies global module variables: // screenWidth/screenHeight - renderWidth/renderHeight - downscaleView SetupFramebufferSize(displayWidth, displayHeight); window = glfwCreateWindow(displayWidth, displayHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); - + // NOTE: Full-screen change, not working properly... //glfwSetWindowMonitor(window, glfwGetPrimaryMonitor(), 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); } @@ -1561,15 +1561,15 @@ static void InitGraphicsDevice(int width, int height) { // No-fullscreen window creation window = glfwCreateWindow(screenWidth, screenHeight, windowTitle, NULL, NULL); - + #if defined(PLATFORM_DESKTOP) // Center window on screen int windowPosX = displayWidth/2 - screenWidth/2; int windowPosY = displayHeight/2 - screenHeight/2; - + if (windowPosX < 0) windowPosX = 0; if (windowPosY < 0) windowPosY = 0; - + glfwSetWindowPos(window, windowPosX, windowPosY); #endif renderWidth = screenWidth; @@ -1612,7 +1612,7 @@ static void InitGraphicsDevice(int width, int height) // NOTE: GLFW loader function is passed as parameter rlglLoadExtensions(glfwGetProcAddress); #endif - + // Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS) // If not set, swap interval uses GPU v-sync configuration // Framerate can be setup using SetTargetFPS() @@ -1620,7 +1620,7 @@ static void InitGraphicsDevice(int width, int height) { glfwSwapInterval(1); TraceLog(INFO, "Trying to enable VSYNC"); - } + } #endif // defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -1643,13 +1643,13 @@ static void InitGraphicsDevice(int width, int height) EGLint samples = 0; EGLint sampleBuffer = 0; - if (configFlags & FLAG_MSAA_4X_HINT) + if (configFlags & FLAG_MSAA_4X_HINT) { samples = 4; sampleBuffer = 1; TraceLog(INFO, "Trying to enable MSAA x4"); } - + const EGLint framebufferAttribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // Type of context support -> Required on RPI? @@ -1773,10 +1773,10 @@ static void InitGraphicsDevice(int width, int height) // Initialize OpenGL context (states and resources) // NOTE: screenWidth and screenHeight not used, just stored as globals rlglInit(screenWidth, screenHeight); - + #ifdef __APPLE__ // Get framebuffer size of current window - // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer + // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer // is automatically reasized to adapt to new DPI. // When OS does that, it can be detected using GLFW3 callback: glfwSetFramebufferSizeCallback() int fbWidth, fbHeight; @@ -1792,7 +1792,7 @@ static void InitGraphicsDevice(int width, int height) // NOTE: Default to orthographic projection mode with top-left corner at (0,0) rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix rlLoadIdentity(); // Reset current matrix (PROJECTION) - rlOrtho(0, renderWidth - renderOffsetX, renderHeight - renderOffsetY, 0, 0.0f, 1.0f); + rlOrtho(0, renderWidth - renderOffsetX, renderHeight - renderOffsetY, 0, 0.0f, 1.0f); rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix rlLoadIdentity(); // Reset current matrix (MODELVIEW) @@ -1806,7 +1806,7 @@ static void InitGraphicsDevice(int width, int height) // Compute framebuffer size relative to screen size and display size // NOTE: Global variables renderWidth/renderHeight and renderOffsetX/renderOffsetY can be modified static void SetupFramebufferSize(int displayWidth, int displayHeight) -{ +{ // Calculate renderWidth and renderHeight, we have the display size (input params) and the desired screen size (global var) if ((screenWidth > displayWidth) || (screenHeight > displayHeight)) { @@ -1945,7 +1945,7 @@ static void PollInputEvents(void) // NOTE: Gestures update must be called every frame to reset gestures correctly // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); - + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling double mouseX; @@ -2025,7 +2025,7 @@ static void TakeScreenshot(void) unsigned char *imgData = rlglReadScreenPixels(renderWidth, renderHeight); sprintf(buffer, "screenshot%03i.png", shotNum); - + // Save image as PNG WritePNG(buffer, imgData, renderWidth, renderHeight, 4); @@ -2062,7 +2062,7 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i #if defined(PLATFORM_DESKTOP) else if (key == GLFW_KEY_F12 && action == GLFW_PRESS) TakeScreenshot(); #endif - else + else { currentKeyState[key] = action; if (action == GLFW_PRESS) lastKeyPressed = key; @@ -2073,27 +2073,27 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { currentMouseState[button] = action; - + #define ENABLE_MOUSE_GESTURES #if defined(ENABLE_MOUSE_GESTURES) // Process mouse events as touches to be able to use mouse-gestures GestureEvent gestureEvent; - + // Register touch actions if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_DOWN; else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) gestureEvent.touchAction = TOUCH_UP; - + // NOTE: TOUCH_MOVE event is registered in MouseCursorPosCallback() - + // Assign a pointer ID gestureEvent.pointerId[0] = 0; - + // Register touch points count gestureEvent.pointCount = 1; - + // Register touch points position, only one point registered gestureEvent.position[0] = GetMousePosition(); - + // Normalize gestureEvent.position[0] for screenWidth and screenHeight gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); @@ -2112,20 +2112,20 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y) GestureEvent gestureEvent; gestureEvent.touchAction = TOUCH_MOVE; - + // Assign a pointer ID gestureEvent.pointerId[0] = 0; // Register touch points count gestureEvent.pointCount = 1; - + // Register touch points position, only one point registered gestureEvent.position[0] = (Vector2){ (float)x, (float)y }; - + touchPosition[0] = gestureEvent.position[0]; - + // Normalize gestureEvent.position[0] for screenWidth and screenHeight - gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); // Gesture data is sent to gestures system for processing @@ -2166,7 +2166,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height) screenHeight = height; renderWidth = width; renderHeight = height; - + // NOTE: Postprocessing texture is not scaled to new size } @@ -2185,9 +2185,9 @@ static void WindowIconifyCallback(GLFWwindow* window, int iconified) static void WindowDropCallback(GLFWwindow *window, int count, const char **paths) { ClearDroppedFiles(); - + dropFilesPath = (char **)malloc(sizeof(char *)*count); - + for (int i = 0; i < count; i++) { dropFilesPath[i] = (char *)malloc(sizeof(char)*256); // Max path length set to 256 char @@ -2249,7 +2249,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) for (int i = 0; i < assetsCount; i++) { // TODO: Unload old asset if required - + // Load texture again to pointed texture (*textureAsset + i) = LoadTexture(assetPath[i]); } @@ -2292,7 +2292,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // NOTE 2: In some cases (too many context loaded), OS could unload context automatically... :( eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(display, surface); - + contextRebindRequired = true; TraceLog(INFO, "APP_CMD_TERM_WINDOW"); @@ -2329,7 +2329,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) { //http://developer.android.com/ndk/reference/index.html - + int type = AInputEvent_getType(event); if (type == AINPUT_EVENT_TYPE_MOTION) @@ -2337,7 +2337,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // Get first touch position touchPosition[0].x = AMotionEvent_getX(event, 0); touchPosition[0].y = AMotionEvent_getY(event, 0); - + // Get second touch position touchPosition[1].x = AMotionEvent_getX(event, 1); touchPosition[1].y = AMotionEvent_getY(event, 1); @@ -2346,7 +2346,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) { int32_t keycode = AKeyEvent_getKeyCode(event); //int32_t AKeyEvent_getMetaState(event); - + // Save current button and its state currentButtonState[keycode] = AKeyEvent_getAction(event); // Down = 0, Up = 1 @@ -2358,7 +2358,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) // NOTE: AndroidManifest.xml must have // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour return 0; - } + } else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU)) { // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS! @@ -2370,36 +2370,36 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) return 0; } } - + int32_t action = AMotionEvent_getAction(event); unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; - + GestureEvent gestureEvent; - + // Register touch actions if (flags == AMOTION_EVENT_ACTION_DOWN) gestureEvent.touchAction = TOUCH_DOWN; else if (flags == AMOTION_EVENT_ACTION_UP) gestureEvent.touchAction = TOUCH_UP; else if (flags == AMOTION_EVENT_ACTION_MOVE) gestureEvent.touchAction = TOUCH_MOVE; - + // Register touch points count gestureEvent.pointCount = AMotionEvent_getPointerCount(event); - + // Register touch points id gestureEvent.pointerId[0] = AMotionEvent_getPointerId(event, 0); gestureEvent.pointerId[1] = AMotionEvent_getPointerId(event, 1); - + // Register touch points position // NOTE: Only two points registered gestureEvent.position[0] = (Vector2){ AMotionEvent_getX(event, 0), AMotionEvent_getY(event, 0) }; gestureEvent.position[1] = (Vector2){ AMotionEvent_getX(event, 1), AMotionEvent_getY(event, 1) }; - + // Normalize gestureEvent.position[x] for screenWidth and screenHeight - gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - - gestureEvent.position[1].x /= (float)GetScreenWidth(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); gestureEvent.position[1].y /= (float)GetScreenHeight(); - + // Gesture data is sent to gestures system for processing ProcessGestureEvent(gestureEvent); @@ -2410,13 +2410,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) #if defined(PLATFORM_WEB) static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData) { - //isFullscreen: int e->isFullscreen - //fullscreenEnabled: int e->fullscreenEnabled + //isFullscreen: int e->isFullscreen + //fullscreenEnabled: int e->fullscreenEnabled //fs element nodeName: (char *) e->nodeName //fs element id: (char *) e->id //Current element size: (int) e->elementWidth, (int) e->elementHeight //Screen size:(int) e->screenWidth, (int) e->screenHeight - + if (e->isFullscreen) { TraceLog(INFO, "Canvas scaled to fullscreen. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); @@ -2425,7 +2425,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte { TraceLog(INFO, "Canvas scaled to windowed. ElementSize: (%ix%i), ScreenSize(%ix%i)", e->elementWidth, e->elementHeight, e->screenWidth, e->screenHeight); } - + // TODO: Depending on scaling factor (screen vs element), calculate factor to scale mouse/touch input return 0; @@ -2445,33 +2445,33 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent x = touchEvent->touches[i].canvasX; y = touchEvent->touches[i].canvasY; } - + printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, event->ctrlKey ? " CTRL" : "", event->shiftKey ? " SHIFT" : "", event->altKey ? " ALT" : "", event->metaKey ? " META" : ""); for(int i = 0; i < event->numTouches; ++i) { const EmscriptenTouchPoint *t = &event->touches[i]; - + printf(" %ld: screen: (%ld,%ld), client: (%ld,%ld), page: (%ld,%ld), isChanged: %d, onTarget: %d, canvas: (%ld, %ld)\n", t->identifier, t->screenX, t->screenY, t->clientX, t->clientY, t->pageX, t->pageY, t->isChanged, t->onTarget, t->canvasX, t->canvasY); } */ - + GestureEvent gestureEvent; // Register touch actions if (eventType == EMSCRIPTEN_EVENT_TOUCHSTART) gestureEvent.touchAction = TOUCH_DOWN; else if (eventType == EMSCRIPTEN_EVENT_TOUCHEND) gestureEvent.touchAction = TOUCH_UP; else if (eventType == EMSCRIPTEN_EVENT_TOUCHMOVE) gestureEvent.touchAction = TOUCH_MOVE; - + // Register touch points count gestureEvent.pointCount = touchEvent->numTouches; - + // Register touch points id gestureEvent.pointerId[0] = touchEvent->touches[0].identifier; gestureEvent.pointerId[1] = touchEvent->touches[1].identifier; - + // Register touch points position // NOTE: Only two points registered // TODO: Touch data should be scaled accordingly! @@ -2482,12 +2482,12 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent touchPosition[0] = gestureEvent.position[0]; touchPosition[1] = gestureEvent.position[1]; - + // Normalize gestureEvent.position[x] for screenWidth and screenHeight - gestureEvent.position[0].x /= (float)GetScreenWidth(); + gestureEvent.position[0].x /= (float)GetScreenWidth(); gestureEvent.position[0].y /= (float)GetScreenHeight(); - - gestureEvent.position[1].x /= (float)GetScreenWidth(); + + gestureEvent.position[1].x /= (float)GetScreenWidth(); gestureEvent.position[1].y /= (float)GetScreenHeight(); // Gesture data is sent to gestures system for processing @@ -2533,7 +2533,7 @@ static void InitKeyboard(void) else { // We reconfigure keyboard mode to get: - // - scancodes (K_RAW) + // - scancodes (K_RAW) // - keycodes (K_MEDIUMRAW) // - ASCII chars (K_XLATE) // - UNICODE chars (K_UNICODE) @@ -2549,7 +2549,7 @@ static void InitKeyboard(void) static void ProcessKeyboard(void) { #define MAX_KEYBUFFER_SIZE 32 // Max size in bytes to read - + // Keyboard input polling (fill keys[256] array with status) int bufferByteCount = 0; // Bytes available on the buffer char keysBuffer[MAX_KEYBUFFER_SIZE]; // Max keys to be read at a time @@ -2564,7 +2564,7 @@ static void ProcessKeyboard(void) for (int i = 0; i < bufferByteCount; i++) { TraceLog(DEBUG, "Bytes on keysBuffer: %i", bufferByteCount); - + //printf("Key(s) bytes: "); //for (int i = 0; i < bufferByteCount; i++) printf("0x%02x ", keysBuffer[i]); //printf("\n"); @@ -2598,7 +2598,7 @@ static void ProcessKeyboard(void) case 0x34: currentKeyState[301] = 1; break; // raylib KEY_F12 default: break; } - + if (keysBuffer[i + 2] == 0x5b) i += 4; else if ((keysBuffer[i + 2] == 0x31) || (keysBuffer[i + 2] == 0x32)) i += 5; } @@ -2615,7 +2615,7 @@ static void ProcessKeyboard(void) i += 3; // Jump to next key } - + // NOTE: Some keys are not directly keymapped (CTRL, ALT, SHIFT) } } @@ -2625,7 +2625,7 @@ static void ProcessKeyboard(void) else { TraceLog(DEBUG, "Pressed key (ASCII): 0x%02x", keysBuffer[i]); - + // Translate lowercase a-z letters to A-Z if ((keysBuffer[i] >= 97) && (keysBuffer[i] <= 122)) { @@ -2634,10 +2634,10 @@ static void ProcessKeyboard(void) else currentKeyState[(int)keysBuffer[i]] = 1; } } - + // Check exit key (same functionality as GLFW3 KeyCallback()) if (currentKeyState[exitKey] == 1) windowShouldClose = true; - + // Check screen capture key if (currentKeyState[301] == 1) TakeScreenshot(); // raylib key: KEY_F12 (GLFW_KEY_F12) } @@ -2647,7 +2647,7 @@ static void RestoreKeyboard(void) { // Reset to default keyboard settings tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings); - + // Reconfigure keyboard to default mode ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode); } @@ -2677,14 +2677,14 @@ static void InitMouse(void) static void *MouseThread(void *arg) { const unsigned char XSIGN = 1<<4, YSIGN = 1<<5; - - typedef struct { + + typedef struct { char buttons; - char dx, dy; + char dx, dy; } MouseEvent; - + MouseEvent mouse; - + int mouseRelX = 0; int mouseRelY = 0; @@ -2693,7 +2693,7 @@ static void *MouseThread(void *arg) if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent)) { if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set - + // Check Left button pressed if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1; else currentMouseState[0] = 0; @@ -2701,27 +2701,27 @@ static void *MouseThread(void *arg) // Check Right button pressed if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1; else currentMouseState[1] = 0; - + // Check Middle button pressed if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1; else currentMouseState[2] = 0; - + mouseRelX = (int)mouse.dx; mouseRelY = (int)mouse.dy; - + if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX); if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY); - + // NOTE: Mouse movement is normalized to not be screen resolution dependant // We suppose 2*255 (max relative movement) is equivalent to screenWidth (max pixels width) // Result after normalization is multiplied by MOUSE_SENSITIVITY factor mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY; mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY; - + if (mousePosition.x < 0) mousePosition.x = 0; if (mousePosition.y < 0) mousePosition.y = 0; - + if (mousePosition.x > screenWidth) mousePosition.x = screenWidth; if (mousePosition.y > screenHeight) mousePosition.y = screenHeight; } @@ -2735,12 +2735,12 @@ static void *MouseThread(void *arg) static void InitGamepad(void) { char gamepadDev[128] = ""; - + for (int i = 0; i < MAX_GAMEPADS; i++) { sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i); - - if ((gamepadStream[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0) + + if ((gamepadStream[i] = open(gamepadDev, O_RDONLY|O_NONBLOCK)) < 0) { // NOTE: Only show message for first gamepad if (i == 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available"); @@ -2758,7 +2758,7 @@ static void InitGamepad(void) else TraceLog(INFO, "Gamepad device initialized successfully"); } } - } + } } // Process Gamepad (/dev/input/js0) @@ -2777,7 +2777,7 @@ static void *GamepadThread(void *arg) // Read gamepad event struct js_event gamepadEvent; - + while (!windowShouldClose) { for (int i = 0; i < MAX_GAMEPADS; i++) @@ -2785,22 +2785,22 @@ static void *GamepadThread(void *arg) if (read(gamepadStream[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event)) { gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events - + // Process gamepad events by type - if (gamepadEvent.type == JS_EVENT_BUTTON) + if (gamepadEvent.type == JS_EVENT_BUTTON) { TraceLog(DEBUG, "Gamepad button: %i, value: %i", gamepadEvent.number, gamepadEvent.value); - - if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) + + if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) { // 1 - button pressed, 0 - button released gamepadButtons[i][gamepadEvent.number] = (int)gamepadEvent.value; } } - else if (gamepadEvent.type == JS_EVENT_AXIS) + else if (gamepadEvent.type == JS_EVENT_AXIS) { TraceLog(DEBUG, "Gamepad axis: %i, value: %i", gamepadEvent.number, gamepadEvent.value); - + if (gamepadEvent.number < MAX_GAMEPAD_AXIS) { // NOTE: Scaling of gamepadEvent.value to get values between -1..1 diff --git a/src/models.c b/src/models.c index 24238ed2..e9044e96 100644 --- a/src/models.c +++ b/src/models.c @@ -81,12 +81,12 @@ void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rot rlPushMatrix(); rlTranslatef(center.x, center.y, center.z); rlRotatef(rotationAngle, rotation.x, rotation.y, rotation.z); - + rlBegin(RL_LINES); for (int i = 0; i < 360; i += 10) { rlColor4ub(color.r, color.g, color.b, color.a); - + rlVertex3f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius, 0.0f); rlVertex3f(sin(DEG2RAD*(i + 10)) * radius, cos(DEG2RAD*(i + 10)) * radius, 0.0f); } @@ -583,13 +583,13 @@ void DrawLight(Light light) DrawCircle3D(light->position, light->radius, 90.0f, (Vector3){ 0, 1, 0 }, (light->enabled ? light->diffuse : BLACK)); } break; case LIGHT_DIRECTIONAL: - { + { DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); DrawSphereWires(light->position, 0.3f*light->intensity, 4, 8, (light->enabled ? light->diffuse : BLACK)); DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); } break; case LIGHT_SPOT: - { + { DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : BLACK)); DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : BLACK)); DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : BLACK)); @@ -602,7 +602,7 @@ void DrawLight(Light light) Model LoadModel(const char *fileName) { Model model = { 0 }; - + // TODO: Initialize default data for model in case loading fails, maybe a cube? if (strcmp(GetExtension(fileName), "obj") == 0) model.mesh = LoadOBJ(fileName); @@ -612,7 +612,7 @@ Model LoadModel(const char *fileName) else { rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model) - + model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); } @@ -626,12 +626,12 @@ Model LoadModelEx(Mesh data, bool dynamic) Model model = { 0 }; model.mesh = data; - + rlglLoadMesh(&model.mesh, dynamic); // Upload vertex data to GPU - + model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); - + return model; } @@ -723,11 +723,11 @@ Model LoadModelFromRES(const char *rresName, int resId) Model LoadHeightmap(Image heightmap, Vector3 size) { Model model = { 0 }; - + model.mesh = GenMeshHeightmap(heightmap, size); - + rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model) - + model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); @@ -738,11 +738,11 @@ Model LoadHeightmap(Image heightmap, Vector3 size) Model LoadCubicmap(Image cubicmap) { Model model = { 0 }; - + model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0f, 1.5f, 1.0f }); - + rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model) - + model.transform = MatrixIdentity(); model.material = LoadDefaultMaterial(); @@ -755,7 +755,7 @@ void UnloadModel(Model model) rlglUnloadMesh(&model.mesh); UnloadMaterial(model.material); - + TraceLog(INFO, "Unloaded model data from RAM and VRAM"); } @@ -763,10 +763,10 @@ void UnloadModel(Model model) Material LoadMaterial(const char *fileName) { Material material = { 0 }; - + if (strcmp(GetExtension(fileName), "mtl") == 0) material = LoadMTL(fileName); else TraceLog(WARNING, "[%s] Material extension not recognized, it can't be loaded", fileName); - + return material; } @@ -774,7 +774,7 @@ Material LoadMaterial(const char *fileName) Material LoadDefaultMaterial(void) { Material material = { 0 }; - + material.shader = GetDefaultShader(); material.texDiffuse = GetDefaultTexture(); // White texture (1x1 pixel) //material.texNormal; // NOTE: By default, not set @@ -783,9 +783,9 @@ Material LoadDefaultMaterial(void) material.colDiffuse = WHITE; // Diffuse color material.colAmbient = WHITE; // Ambient color material.colSpecular = WHITE; // Specular color - + material.glossiness = 100.0f; // Glossiness level - + return material; } @@ -794,7 +794,7 @@ Material LoadDefaultMaterial(void) Material LoadStandardMaterial(void) { Material material = LoadDefaultMaterial(); - + material.shader = GetStandardShader(); return material; @@ -812,12 +812,12 @@ void UnloadMaterial(Material material) static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) { #define GRAY_VALUE(c) ((c.r+c.g+c.b)/3) - + Mesh mesh = { 0 }; int mapX = heightmap.width; int mapZ = heightmap.height; - + Color *pixels = GetImageData(heightmap); // NOTE: One vertex per pixel @@ -908,7 +908,7 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size) trisCounter += 2; } } - + free(pixels); return mesh; @@ -919,7 +919,7 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) Mesh mesh = { 0 }; Color *cubicmapPixels = GetImageData(cubicmap); - + int mapWidth = cubicmap.width; int mapHeight = cubicmap.height; @@ -1262,9 +1262,9 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize) free(mapVertices); free(mapNormals); free(mapTexcoords); - + free(cubicmapPixels); // Free image pixel data - + return mesh; } @@ -1273,7 +1273,7 @@ void DrawModel(Model model, Vector3 position, float scale, Color tint) { Vector3 vScale = { scale, scale, scale }; Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f }; - + DrawModelEx(model, position, rotationAxis, 0.0f, vScale, tint); } @@ -1285,13 +1285,13 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); - + // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) //Matrix matModel = MatrixMultiply(model.transform, matTransform); // Transform to world-space coordinates - + model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); model.material.colDiffuse = tint; // TODO: Multiply tint color by diffuse color? - + rlglDrawMesh(model.mesh, model.material, model.transform); } @@ -1299,9 +1299,9 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota void DrawModelWires(Model model, Vector3 position, float scale, Color tint) { rlEnableWireMode(); - + DrawModel(model, position, scale, tint); - + rlDisableWireMode(); } @@ -1309,9 +1309,9 @@ void DrawModelWires(Model model, Vector3 position, float scale, Color tint) void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint) { rlEnableWireMode(); - + DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint); - + rlDisableWireMode(); } @@ -1319,7 +1319,7 @@ void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint) { Rectangle sourceRec = { 0, 0, texture.width, texture.height }; - + DrawBillboardRec(camera, texture, sourceRec, center, size, tint); } @@ -1334,7 +1334,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec Vector3 right = { viewMatrix.m0, viewMatrix.m4, viewMatrix.m8 }; //Vector3 up = { viewMatrix.m1, viewMatrix.m5, viewMatrix.m9 }; - + // NOTE: Billboard locked on axis-Y Vector3 up = { 0.0f, 1.0f, 0.0f }; /* @@ -1384,13 +1384,13 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec void DrawBoundingBox(BoundingBox box, Color color) { Vector3 size; - + size.x = fabsf(box.max.x - box.min.x); size.y = fabsf(box.max.y - box.min.y); size.z = fabsf(box.max.z - box.min.z); - + Vector3 center = { box.min.x + size.x/2.0f, box.min.y + size.y/2.0f, box.min.z + size.z/2.0f }; - + DrawCubeWires(center, size.x, size.y, size.z, color); } @@ -1451,14 +1451,14 @@ bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radius bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius) { bool collision = false; - + Vector3 raySpherePos = VectorSubtract(spherePosition, ray.position); float distance = VectorLength(raySpherePos); float vector = VectorDotProduct(raySpherePos, ray.direction); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); - + if (d >= 0.0f) collision = true; - + return collision; } @@ -1466,29 +1466,29 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint) { bool collision = false; - + Vector3 raySpherePos = VectorSubtract(spherePosition, ray.position); float distance = VectorLength(raySpherePos); float vector = VectorDotProduct(raySpherePos, ray.direction); float d = sphereRadius*sphereRadius - (distance*distance - vector*vector); - + 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); else collisionDistance = vector - sqrt(d); - + VectorScale(&offset, collisionDistance); Vector3 cPoint = VectorAdd(ray.position, offset); - + collisionPoint->x = cPoint.x; collisionPoint->y = cPoint.y; collisionPoint->z = cPoint.z; - + return collision; } @@ -1496,7 +1496,7 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi bool CheckCollisionRayBox(Ray ray, BoundingBox box) { bool collision = false; - + float t[8]; t[0] = (box.min.x - ray.position.x)/ray.direction.x; t[1] = (box.max.x - ray.position.x)/ray.direction.x; @@ -1506,9 +1506,9 @@ bool CheckCollisionRayBox(Ray ray, BoundingBox box) t[5] = (box.max.z - ray.position.z)/ray.direction.z; t[6] = fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])); t[7] = fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])); - + collision = !(t[7] < 0 || t[6] > t[7]); - + return collision; } @@ -1524,19 +1524,19 @@ BoundingBox CalculateBoundingBox(Mesh mesh) { minVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; maxVertex = (Vector3){ mesh.vertices[0], mesh.vertices[1], mesh.vertices[2] }; - + for (int i = 1; i < mesh.vertexCount; i++) { minVertex = VectorMin(minVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); maxVertex = VectorMax(maxVertex, (Vector3){ mesh.vertices[i*3], mesh.vertices[i*3 + 1], mesh.vertices[i*3 + 2] }); } } - + // Create the bounding box BoundingBox box; box.min = minVertex; box.max = maxVertex; - + return box; } @@ -1546,9 +1546,9 @@ BoundingBox CalculateBoundingBox(Mesh mesh) Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius) { #define CUBIC_MAP_HALF_BLOCK_SIZE 0.5 - + Color *cubicmapPixels = GetImageData(cubicmap); - + // Detect the cell where the player is located Vector3 impactDirection = { 0.0f, 0.0f, 0.0f }; @@ -1784,7 +1784,7 @@ Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *p playerPosition->y = (1.5f - radius) - 0.01f; impactDirection = (Vector3) { impactDirection.x, 1, impactDirection.z}; } - + free(cubicmapPixels); return impactDirection; @@ -2049,9 +2049,9 @@ static Mesh LoadOBJ(const char *fileName) static Material LoadMTL(const char *fileName) { #define MAX_BUFFER_SIZE 128 - + Material material = { 0 }; // LoadDefaultMaterial(); - + char buffer[MAX_BUFFER_SIZE]; Vector3 color = { 1.0f, 1.0f, 1.0f }; char *mapFileName = NULL; @@ -2069,14 +2069,14 @@ static Material LoadMTL(const char *fileName) while (!feof(mtlFile)) { fgets(buffer, MAX_BUFFER_SIZE, mtlFile); - + switch (buffer[0]) { case 'n': // newmtl string Material name. Begins a new material description. { // TODO: Support multiple materials in a single .mtl sscanf(buffer, "newmtl %s", mapFileName); - + TraceLog(INFO, "[%s] Loading material...", mapFileName); } case 'i': // illum int Illumination model @@ -2123,7 +2123,7 @@ static Material LoadMTL(const char *fileName) { int shininess = 0; sscanf(buffer, "Ns %i", &shininess); - + material.glossiness = (float)shininess; } else if (buffer[1] == 'i') // Ni int Refraction index. @@ -2192,7 +2192,7 @@ static Material LoadMTL(const char *fileName) float ialpha = 0.0f; sscanf(buffer, "Tr %f", &ialpha); material.colDiffuse.a = (unsigned char)((1.0f - ialpha)*255); - + } break; case 'r': // refl string Reflection texture map default: break; @@ -2203,6 +2203,6 @@ static Material LoadMTL(const char *fileName) // NOTE: At this point we have all material data TraceLog(INFO, "[%s] Material loaded successfully", fileName); - + return material; } diff --git a/src/raylib.h b/src/raylib.h index 22494aec..7b7348c8 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -930,8 +930,8 @@ RLAPI void SetMusicPitch(Music music, float pitch); // Set pit RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) -RLAPI AudioStream InitAudioStream(unsigned int sampleRate, - unsigned int sampleSize, +RLAPI AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream audio pcm data) RLAPI void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory diff --git a/src/rlgl.h b/src/rlgl.h index bcb7c24f..3fc54219 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -107,7 +107,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // byte type typedef unsigned char byte; - + // Color type, RGBA (32bit) typedef struct Color { unsigned char r; @@ -117,7 +117,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; } Color; // Texture formats (support depends on OpenGL version) - typedef enum { + typedef enum { UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) UNCOMPRESSED_GRAY_ALPHA, UNCOMPRESSED_R5G6B5, // 16 bpp @@ -157,7 +157,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Shader type (generic shader) typedef struct Shader { unsigned int id; // Shader program id - + // Vertex attributes locations (default locations) int vertexLoc; // Vertex attribute location point (default-location = 0) int texcoordLoc; // Texcoord attribute location point (default-location = 1) @@ -169,7 +169,7 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) int tintColorLoc; // Color uniform location point (fragment shader) - + // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1) @@ -185,14 +185,14 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; int mipmaps; // Mipmap levels, 1 by default int format; // Data format (TextureFormat) } Texture2D; - + // RenderTexture2D type, for texture rendering typedef struct RenderTexture2D { unsigned int id; // Render texture (fbo) id Texture2D texture; // Color buffer attachment texture Texture2D depth; // Depth buffer attachment texture } RenderTexture2D; - + // Material type typedef struct Material { Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular) @@ -204,10 +204,10 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; Color colDiffuse; // Diffuse color Color colAmbient; // Ambient color Color colSpecular; // Specular color - + float glossiness; // Glossiness level (Ranges from 0 to 1000) } Material; - + // Camera type, defines a camera position/orientation in 3d space typedef struct Camera { Vector3 position; // Camera position @@ -225,22 +225,22 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; Vector3 position; // Light position Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) float radius; // Light attenuation radius light intensity reduced with distance (world distance) - + Color diffuse; // Light diffuse color float intensity; // Light intensity level - + float coneAngle; // Light cone max angle: LIGHT_SPOT } LightData, *Light; - + // Light types typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; - + // TraceLog message types typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; - + // VR Head Mounted Display devices typedef enum { HMD_DEFAULT_DEVICE = 0, diff --git a/src/rlua.h b/src/rlua.h index b100b06d..1c8c7b38 100644 --- a/src/rlua.h +++ b/src/rlua.h @@ -6,7 +6,7 @@ * The following types: * Color, Vector2, Vector3, Rectangle, Ray, Camera, Camera2D * are treated as objects with named fields, same as in C. -* +* * Lua defines utility functions for creating those objects. * Usage: * local cl = Color(255,255,255,255) @@ -27,7 +27,7 @@ * NOTE 02: * Some raylib functions take a pointer to an array, and the size of that array. * The equivalent Lua functions take only an array table of the specified type UNLESS -* it's a pointer to a large char array (e.g. for images), then it takes (and potentially returns) +* it's a pointer to a large char array (e.g. for images), then it takes (and potentially returns) * a Lua string (without the size argument, as Lua strings are sized by default). * * NOTE 03: @@ -362,7 +362,7 @@ static void LuaBuildOpaqueMetatables(void) lua_pushcfunction(L, &LuaIndexTexture2D); lua_setfield(L, -2, "__index"); lua_pop(L, 1); - + luaL_newmetatable(L, "RenderTexture2D"); lua_pushcfunction(L, &LuaIndexRenderTexture2D); lua_setfield(L, -2, "__index"); @@ -3112,7 +3112,7 @@ int lua_TraceLog(lua_State* L) lua_getfield(L, 1, "format"); /// fmt, args..., [string], format() lua_rotate(L, 1, 2); /// [string], format(), fmt, args... lua_call(L, num_args, 1); /// [string], formatted_string - + TraceLog(arg1, "%s", luaL_checkstring(L,-1)); return 0; } @@ -3525,7 +3525,7 @@ int lua_QuaternionTransform(lua_State* L) // raylib Functions (and data types) list static luaL_Reg raylib_functions[] = { - + // Register non-opaque data types REG(Color) REG(Vector2) @@ -3547,7 +3547,7 @@ static luaL_Reg raylib_functions[] = { REG(ToggleFullscreen) REG(GetScreenWidth) REG(GetScreenHeight) - + REG(ShowCursor) REG(HideCursor) REG(IsCursorHidden) @@ -3563,11 +3563,11 @@ static luaL_Reg raylib_functions[] = { REG(End3dMode) REG(BeginTextureMode) REG(EndTextureMode) - + REG(GetMouseRay) REG(GetWorldToScreen) REG(GetCameraMatrix) - + #if defined(PLATFORM_WEB) REG(SetDrawingLoop) #else @@ -3575,7 +3575,7 @@ static luaL_Reg raylib_functions[] = { #endif REG(GetFPS) REG(GetFrameTime) - + REG(GetColor) REG(GetHexValue) REG(ColorToFloat) @@ -3585,13 +3585,13 @@ static luaL_Reg raylib_functions[] = { REG(Fade) REG(SetConfigFlags) REG(ShowLogo) - + REG(IsFileDropped) REG(GetDroppedFiles) REG(ClearDroppedFiles) REG(StorageSaveValue) REG(StorageLoadValue) - + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) REG(IsKeyPressed) REG(IsKeyDown) @@ -3599,7 +3599,7 @@ static luaL_Reg raylib_functions[] = { REG(IsKeyUp) REG(GetKeyPressed) REG(SetExitKey) - + REG(IsGamepadAvailable) REG(GetGamepadAxisMovement) REG(IsGamepadButtonPressed) @@ -3643,13 +3643,13 @@ static luaL_Reg raylib_functions[] = { REG(SetCameraPosition) REG(SetCameraTarget) REG(SetCameraFovy) - + REG(SetCameraPanControl) REG(SetCameraAltControl) REG(SetCameraSmoothZoomControl) REG(SetCameraMoveControls) REG(SetCameraMouseSensitivity) - + REG(DrawPixel) REG(DrawPixelV) REG(DrawLine) @@ -3668,7 +3668,7 @@ static luaL_Reg raylib_functions[] = { REG(DrawPoly) REG(DrawPolyEx) REG(DrawPolyExLines) - + REG(CheckCollisionRecs) REG(CheckCollisionCircles) REG(CheckCollisionCircleRec) @@ -3676,7 +3676,7 @@ static luaL_Reg raylib_functions[] = { REG(CheckCollisionPointRec) REG(CheckCollisionPointCircle) REG(CheckCollisionPointTriangle) - + REG(LoadImage) REG(LoadImageEx) REG(LoadImageRaw) @@ -3712,13 +3712,13 @@ static luaL_Reg raylib_functions[] = { REG(ImageColorBrightness) REG(GenTextureMipmaps) REG(UpdateTexture) - + REG(DrawTexture) REG(DrawTextureV) REG(DrawTextureEx) REG(DrawTextureRec) REG(DrawTexturePro) - + REG(GetDefaultFont) REG(LoadSpriteFont) REG(UnloadSpriteFont) @@ -3727,7 +3727,7 @@ static luaL_Reg raylib_functions[] = { REG(MeasureText) REG(MeasureTextEx) REG(DrawFPS) - + REG(DrawLine3D) REG(DrawCircle3D) REG(DrawCube) @@ -3744,7 +3744,7 @@ static luaL_Reg raylib_functions[] = { REG(DrawGrid) REG(DrawGizmo) REG(DrawLight) - + REG(LoadModel) REG(LoadModelEx) REG(LoadModelFromRES) @@ -3756,7 +3756,7 @@ static luaL_Reg raylib_functions[] = { REG(LoadStandardMaterial) REG(UnloadMaterial) //REG(GenMesh*) // Not ready yet... - + REG(DrawModel) REG(DrawModelEx) REG(DrawModelWires) @@ -3771,7 +3771,7 @@ static luaL_Reg raylib_functions[] = { REG(CheckCollisionRaySphereEx) REG(CheckCollisionRayBox) REG(ResolveCollisionCubicmap) - + REG(LoadShader) REG(UnloadShader) REG(GetDefaultShader) @@ -3789,13 +3789,13 @@ static luaL_Reg raylib_functions[] = { REG(EndBlendMode) REG(CreateLight) REG(DestroyLight) - + REG(InitVrDevice) REG(CloseVrDevice) REG(IsVrDeviceReady) REG(UpdateVrTracking) REG(ToggleVrMode) - + REG(InitAudioDevice) REG(CloseAudioDevice) REG(IsAudioDeviceReady) @@ -3810,7 +3810,7 @@ static luaL_Reg raylib_functions[] = { REG(IsSoundPlaying) REG(SetSoundVolume) REG(SetSoundPitch) - + REG(LoadMusicStream) REG(UnloadMusicStream) REG(UpdateMusicStream) @@ -3823,7 +3823,7 @@ static luaL_Reg raylib_functions[] = { REG(SetMusicPitch) REG(GetMusicTimeLength) REG(GetMusicTimePlayed) - + REG(InitAudioStream) REG(UpdateAudioStream) REG(CloseAudioStream) @@ -3906,7 +3906,7 @@ RLUADEF void InitLuaDevice(void) { mainLuaState = luaL_newstate(); L = mainLuaState; - + LuaStartEnum(); LuaSetEnum("FULLSCREEN_MODE", 1); LuaSetEnum("SHOW_LOGO", 2); @@ -4001,7 +4001,7 @@ RLUADEF void InitLuaDevice(void) LuaSetEnum("PS3_BUTTON_L2", 8); LuaSetEnum("PS3_BUTTON_SELECT", 9); LuaSetEnum("PS3_BUTTON_START", 10); - + LuaSetEnum("XBOX_BUTTON_A", 0); LuaSetEnum("XBOX_BUTTON_B", 1); LuaSetEnum("XBOX_BUTTON_X", 2); @@ -4086,9 +4086,9 @@ RLUADEF void InitLuaDevice(void) LuaSetEnum("ADDITIVE", BLEND_ADDITIVE); LuaSetEnum("MULTIPLIED", BLEND_MULTIPLIED); LuaEndEnum("BlendMode"); - + LuaStartEnum(); - LuaSetEnum("POINT", LIGHT_POINT); + LuaSetEnum("POINT", LIGHT_POINT); LuaSetEnum("DIRECTIONAL", LIGHT_DIRECTIONAL); LuaSetEnum("SPOT", LIGHT_SPOT); LuaEndEnum("LightType"); @@ -4114,7 +4114,7 @@ RLUADEF void InitLuaDevice(void) LuaSetEnum("FIRST_PERSON", CAMERA_FIRST_PERSON); LuaSetEnum("THIRD_PERSON", CAMERA_THIRD_PERSON); LuaEndEnum("CameraMode"); - + LuaStartEnum(); LuaSetEnum("DEFAULT_DEVICE", HMD_DEFAULT_DEVICE); LuaSetEnum("OCULUS_RIFT_DK2", HMD_OCULUS_RIFT_DK2); @@ -4138,9 +4138,9 @@ RLUADEF void InitLuaDevice(void) lua_pushboolean(L, true); #if defined(PLATFORM_DESKTOP) lua_setglobal(L, "PLATFORM_DESKTOP"); -#elif defined(PLATFORM_ANDROID) +#elif defined(PLATFORM_ANDROID) lua_setglobal(L, "PLATFORM_ANDROID"); -#elif defined(PLATFORM_RPI) +#elif defined(PLATFORM_RPI) lua_setglobal(L, "PLATFORM_RPI"); #elif defined(PLATFORM_WEB) lua_setglobal(L, "PLATFORM_WEB"); @@ -4148,7 +4148,7 @@ RLUADEF void InitLuaDevice(void) luaL_openlibs(L); LuaBuildOpaqueMetatables(); - + LuaRegisterRayLib(0); } @@ -4173,7 +4173,7 @@ RLUADEF void ExecuteLuaCode(const char *code) } int result = luaL_dostring(L, code); - + switch (result) { case LUA_OK: break; @@ -4193,7 +4193,7 @@ RLUADEF void ExecuteLuaFile(const char *filename) } int result = luaL_dofile(L, filename); - + switch (result) { case LUA_OK: break; diff --git a/src/text.c b/src/text.c index 2f347b5d..8dc55455 100644 --- a/src/text.c +++ b/src/text.c @@ -151,7 +151,7 @@ extern void LoadDefaultFont(void) //---------------------------------------------------------------------- int imWidth = 128; int imHeight = 128; - + Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color)); for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array @@ -174,7 +174,7 @@ extern void LoadDefaultFont(void) //FILE *myimage = fopen("default_font.raw", "wb"); //fwrite(image.pixels, 1, 128*128*4, myimage); //fclose(myimage); - + Image image = LoadImageEx(imagePixels, imWidth, imHeight); ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA); @@ -185,13 +185,13 @@ extern void LoadDefaultFont(void) // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars //------------------------------------------------------------------------------ - defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int)); + defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int)); defaultFont.charRecs = (Rectangle *)malloc(defaultFont.numChars*sizeof(Rectangle)); // Allocate space for our character rectangle data // This memory should be freed at end! --> Done on CloseWindow() - + defaultFont.charOffsets = (Vector2 *)malloc(defaultFont.numChars*sizeof(Vector2)); defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int)); - + int currentLine = 0; int currentPosX = charsDivisor; int testPosX = charsDivisor; @@ -199,7 +199,7 @@ extern void LoadDefaultFont(void) for (int i = 0; i < defaultFont.numChars; i++) { defaultFont.charValues[i] = FONT_FIRST_CHAR + i; // First char is 32 - + defaultFont.charRecs[i].x = currentPosX; defaultFont.charRecs[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor); defaultFont.charRecs[i].width = charsWidth[i]; @@ -217,12 +217,12 @@ extern void LoadDefaultFont(void) defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); } else currentPosX = testPosX; - + // NOTE: On default font character offsets and xAdvance are not required defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; defaultFont.charAdvanceX[i] = 0; } - + defaultFont.size = defaultFont.charRecs[0].height; TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); @@ -262,7 +262,7 @@ SpriteFont LoadSpriteFont(const char *fileName) if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, FONT_FIRST_CHAR); UnloadImage(image); } - + if (spriteFont.texture.id == 0) { TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); @@ -316,15 +316,15 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float scaleFactor = fontSize/spriteFont.size; - // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly + // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // written in C code files (codified by default as UTF-8) - + for(int i = 0; i < length; i++) { // TODO: Right now we are supposing characters that follow a continous order and start at FONT_FIRST_CHAR, // this sytem can be improved to support any characters order and init value... // An intermediate table could be created to link char values with predefined char position index in chars rectangle array - + if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! { // Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿) @@ -353,8 +353,8 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float if (rec.x > 0) { - DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor, + DrawTexturePro(spriteFont.texture, rec, (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].x*scaleFactor, + position.y + textOffsetY + spriteFont.charOffsets[(int)text[i] - FONT_FIRST_CHAR].y*scaleFactor, rec.width*scaleFactor, rec.height*scaleFactor} , (Vector2){ 0, 0 }, 0.0f, tint); if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] == 0) textOffsetX += (rec.width*scaleFactor + spacing); @@ -381,15 +381,15 @@ const char *SubText(const char *text, int position, int length) { static char buffer[MAX_SUBTEXT_LENGTH]; int textLength = strlen(text); - + if (position >= textLength) { position = textLength - 1; length = 0; } - + if (length >= textLength) length = textLength; - + for (int c = 0 ; c < length ; c++) { *(buffer+c) = *(text+position); @@ -421,17 +421,17 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int int len = strlen(text); int tempLen = 0; // Used to count longer text line num chars int lenCounter = 0; - + int textWidth = 0; int tempTextWidth = 0; // Used to count longer text line width - + int textHeight = spriteFont.size; float scaleFactor; for (int i = 0; i < len; i++) { lenCounter++; - + if (text[i] != '\n') { if (spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR] != 0) textWidth += spriteFont.charAdvanceX[(int)text[i] - FONT_FIRST_CHAR]; @@ -444,10 +444,10 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int textWidth = 0; textHeight += (spriteFont.size + spriteFont.size/2); // NOTE: Fixed line spacing of 1.5 lines } - + if (tempLen < lenCounter) tempLen = lenCounter; } - + if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (fontSize <= spriteFont.size) scaleFactor = 1.0f; @@ -496,21 +496,21 @@ void DrawFPS(int posX, int posY) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) - + int charSpacing = 0; int lineSpacing = 0; int x = 0; int y = 0; - + // Default number of characters expected supported #define MAX_FONTCHARS 128 - // We allocate a temporal arrays for chars data measures, + // We allocate a temporal arrays for chars data measures, // once we get the actual number of chars, we copy data to a sized arrays int tempCharValues[MAX_FONTCHARS]; Rectangle tempCharRecs[MAX_FONTCHARS]; - + Color *pixels = GetImageData(image); // Parse image data to get charSpacing and lineSpacing @@ -545,7 +545,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) !COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key)) { tempCharValues[index] = firstChar + index; - + tempCharRecs[index].x = xPosToRead; tempCharRecs[index].y = lineSpacing + lineToRead * (charHeight + lineSpacing); tempCharRecs[index].height = charHeight; @@ -564,14 +564,14 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) lineToRead++; xPosToRead = charSpacing; } - + free(pixels); - + TraceLog(DEBUG, "SpriteFont data parsed correctly from image"); - + // Create spritefont with all data parsed from image SpriteFont spriteFont = { 0 }; - + spriteFont.texture = LoadTextureFromImage(image); // Convert loaded image to OpenGL texture spriteFont.numChars = index; @@ -586,12 +586,12 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { spriteFont.charValues[i] = tempCharValues[i]; spriteFont.charRecs[i] = tempCharRecs[i]; - + // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; spriteFont.charAdvanceX[i] = 0; } - + spriteFont.size = spriteFont.charRecs[0].height; return spriteFont; @@ -631,7 +631,7 @@ static SpriteFont LoadRBMF(const char *fileName) if (rbmfFile == NULL) { TraceLog(WARNING, "[%s] rBMF font file could not be opened, using default font", fileName); - + spriteFont = GetDefaultFont(); } else @@ -670,10 +670,10 @@ static SpriteFont LoadRBMF(const char *fileName) counter++; } - + Image image = LoadImageEx(imagePixels, rbmfHeader.imgWidth, rbmfHeader.imgHeight); ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA); - + free(imagePixels); TraceLog(DEBUG, "[%s] Image reconstructed correctly, now converting it to texture", fileName); @@ -685,7 +685,7 @@ static SpriteFont LoadRBMF(const char *fileName) //TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName); // Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars - spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); + spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2)); spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int)); @@ -697,12 +697,12 @@ static SpriteFont LoadRBMF(const char *fileName) for (int i = 0; i < spriteFont.numChars; i++) { spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i; - + spriteFont.charRecs[i].x = currentPosX; spriteFont.charRecs[i].y = charsDivisor + currentLine * ((int)rbmfHeader.charHeight + charsDivisor); spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i]; spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight; - + // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; spriteFont.charAdvanceX[i] = 0; @@ -720,7 +720,7 @@ static SpriteFont LoadRBMF(const char *fileName) } else currentPosX = testPosX; } - + spriteFont.size = spriteFont.charRecs[0].height; TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName); @@ -738,20 +738,20 @@ static SpriteFont LoadRBMF(const char *fileName) static SpriteFont LoadBMFont(const char *fileName) { #define MAX_BUFFER_SIZE 256 - + SpriteFont font = { 0 }; font.texture.id = 0; - + char buffer[MAX_BUFFER_SIZE]; char *searchPoint = NULL; - + int fontSize = 0; int texWidth, texHeight; char texFileName[128]; int numChars = 0; int base; // Useless data - + FILE *fntFile; fntFile = fopen(fileName, "rt"); @@ -766,42 +766,42 @@ static SpriteFont LoadBMFont(const char *fileName) fgets(buffer, MAX_BUFFER_SIZE, fntFile); //searchPoint = strstr(buffer, "size"); //sscanf(searchPoint, "size=%i", &fontSize); - + fgets(buffer, MAX_BUFFER_SIZE, fntFile); searchPoint = strstr(buffer, "lineHeight"); sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight); - + TraceLog(DEBUG, "[%s] Font size: %i", fileName, fontSize); TraceLog(DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight); - + fgets(buffer, MAX_BUFFER_SIZE, fntFile); searchPoint = strstr(buffer, "file"); sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName); - + TraceLog(DEBUG, "[%s] Font texture filename: %s", fileName, texFileName); - + fgets(buffer, MAX_BUFFER_SIZE, fntFile); searchPoint = strstr(buffer, "count"); sscanf(searchPoint, "count=%i", &numChars); - + TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars); - + // Compose correct path using route of .fnt file (fileName) and texFileName char *texPath = NULL; char *lastSlash = NULL; lastSlash = strrchr(fileName, '/'); - + // NOTE: We need some extra space to avoid memory corruption on next allocations! texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); - + // NOTE: strcat() and strncat() required a '\0' terminated string to work! *texPath = '\0'; strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1); strncat(texPath, texFileName, strlen(texFileName)); TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath); - + font.texture = LoadTexture(texPath); font.size = fontSize; font.numChars = numChars; @@ -809,35 +809,35 @@ static SpriteFont LoadBMFont(const char *fileName) font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle)); font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2)); font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); - + free(texPath); - + int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - + bool unorderedChars = false; int firstChar = 0; - + for (int i = 0; i < numChars; i++) { fgets(buffer, MAX_BUFFER_SIZE, fntFile); - sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", + sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); - + if (i == 0) firstChar = charId; else if (i != (charId - firstChar)) unorderedChars = true; - + // Save data properly in sprite font font.charValues[i] = charId; font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY }; font.charAdvanceX[i] = charAdvanceX; } - + fclose(fntFile); - + if (firstChar != FONT_FIRST_CHAR) TraceLog(WARNING, "BMFont not supported: expected SPACE(32) as first character, falling back to default font"); else if (unorderedChars) TraceLog(WARNING, "BMFont not supported: unordered chars data, falling back to default font"); - + // NOTE: Font data could be not ordered by charId: 32,33,34,35... raylib does not support unordered BMFonts if ((firstChar != FONT_FIRST_CHAR) || (unorderedChars) || (font.texture.id == 0)) { @@ -862,9 +862,9 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); SpriteFont font = { 0 }; - + FILE *ttfFile = fopen(fileName, "rb"); - + if (ttfFile == NULL) { TraceLog(WARNING, "[%s] FNT file could not be opened", fileName); @@ -877,11 +877,11 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, firstChar, numChars, charData); free(ttfBuffer); - + // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA unsigned char *dataGrayAlpha = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)*2); // Two channels int k = 0; - + for (int i = 0; i < FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT; i++) { dataGrayAlpha[k] = 255; @@ -889,9 +889,9 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int k += 2; } - + free(dataBitmap); - + // Sprite font generation from TTF extracted data Image image; image.width = FONT_TEXTURE_WIDTH; @@ -909,7 +909,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle)); font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2)); font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int)); - + for (int i = 0; i < font.numChars; i++) { font.charValues[i] = i + firstChar; @@ -918,11 +918,11 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int font.charRecs[i].y = (int)charData[i].y0; font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0; font.charRecs[i].height = (int)charData[i].y1 - (int)charData[i].y0; - + font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff }; font.charAdvanceX[i] = (int)charData[i].xadvance; } - + free(charData); return font; diff --git a/src/textures.c b/src/textures.c index c6b7e0bb..8f4fa301 100644 --- a/src/textures.c +++ b/src/textures.c @@ -33,7 +33,7 @@ #include // Required for: strcmp(), strrchr(), strncmp() #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 - // Required: rlglLoadTexture() rlDeleteTextures(), + // Required: rlglLoadTexture() rlDeleteTextures(), // rlglGenerateMipmaps(), some funcs for DrawTexturePro() #include "utils.h" // rRES data decompression utility function @@ -44,7 +44,7 @@ // NOTE: Used to read image data (multiple formats support) #define STB_IMAGE_RESIZE_IMPLEMENTATION -#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() +#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() // NOTE: Used for image scaling on ImageResize() //---------------------------------------------------------------------------------- @@ -103,14 +103,14 @@ Image LoadImage(const char *fileName) int imgWidth = 0; int imgHeight = 0; int imgBpp = 0; - + // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) image.data = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 0); image.width = imgWidth; image.height = imgHeight; image.mipmaps = 1; - + if (imgBpp == 1) image.format = UNCOMPRESSED_GRAYSCALE; else if (imgBpp == 2) image.format = UNCOMPRESSED_GRAY_ALPHA; else if (imgBpp == 3) image.format = UNCOMPRESSED_R8G8B8; @@ -121,12 +121,12 @@ Image LoadImage(const char *fileName) else if (strcmp(GetExtension(fileName),"ktx") == 0) image = LoadKTX(fileName); else if (strcmp(GetExtension(fileName),"pvr") == 0) image = LoadPVR(fileName); else if (strcmp(GetExtension(fileName),"astc") == 0) image = LoadASTC(fileName); - + if (image.data != NULL) - { + { TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height); } - else TraceLog(WARNING, "[%s] Image could not be loaded, file not recognized", fileName); + else TraceLog(WARNING, "[%s] Image could not be loaded, file not recognized", fileName); return image; } @@ -141,11 +141,11 @@ Image LoadImageEx(Color *pixels, int width, int height) image.height = height; image.mipmaps = 1; image.format = UNCOMPRESSED_R8G8B8A8; - + int k = 0; image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); - + for (int i = 0; i < image.width*image.height*4; i += 4) { ((unsigned char *)image.data)[i] = pixels[k].r; @@ -180,7 +180,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int if (headerSize > 0) fseek(rawFile, headerSize, SEEK_SET); unsigned int size = width*height; - + switch (format) { case UNCOMPRESSED_GRAYSCALE: image.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha) @@ -192,16 +192,16 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int case UNCOMPRESSED_R8G8B8A8: image.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp default: TraceLog(WARNING, "Image format not suported"); break; } - + fread(image.data, size, 1, rawFile); - + // TODO: Check if data have been read - + image.width = width; image.height = height; image.mipmaps = 0; image.format = format; - + fclose(rawFile); } @@ -326,9 +326,9 @@ Texture2D LoadTexture(const char *fileName) Texture2D texture; Image image = LoadImage(fileName); - + if (image.data != NULL) - { + { texture = LoadTextureFromImage(image); UnloadImage(image); } @@ -350,9 +350,9 @@ Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat) texture.height = height; texture.mipmaps = 1; texture.format = textureFormat; - + texture.id = rlglLoadTexture(data, width, height, textureFormat, 1); - + return texture; } @@ -380,7 +380,7 @@ Texture2D LoadTextureFromImage(Image image) texture.height = 0; texture.mipmaps = 0; texture.format = 0; - + texture.id = rlglLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps); texture.width = image.width; @@ -395,7 +395,7 @@ Texture2D LoadTextureFromImage(Image image) RenderTexture2D LoadRenderTexture(int width, int height) { RenderTexture2D target = rlglLoadRenderTexture(width, height); - + return target; } @@ -403,7 +403,7 @@ RenderTexture2D LoadRenderTexture(int width, int height) void UnloadImage(Image image) { free(image.data); - + // NOTE: It becomes anoying every time a texture is loaded //TraceLog(INFO, "Unloaded image data"); } @@ -414,7 +414,7 @@ void UnloadTexture(Texture2D texture) if (texture.id != 0) { rlDeleteTextures(texture.id); - + TraceLog(INFO, "[TEX ID %i] Unloaded texture data from VRAM (GPU)", texture.id); } } @@ -429,7 +429,7 @@ void UnloadRenderTexture(RenderTexture2D target) Color *GetImageData(Image image) { Color *pixels = (Color *)malloc(image.width*image.height*sizeof(Color)); - + int k = 0; for (int i = 0; i < image.width*image.height; i++) @@ -442,7 +442,7 @@ Color *GetImageData(Image image) pixels[i].g = ((unsigned char *)image.data)[k]; pixels[i].b = ((unsigned char *)image.data)[k]; pixels[i].a = 255; - + k++; } break; case UNCOMPRESSED_GRAY_ALPHA: @@ -451,7 +451,7 @@ Color *GetImageData(Image image) pixels[i].g = ((unsigned char *)image.data)[k]; pixels[i].b = ((unsigned char *)image.data)[k]; pixels[i].a = ((unsigned char *)image.data)[k + 1]; - + k += 2; } break; case UNCOMPRESSED_R5G5B5A1: @@ -462,7 +462,7 @@ Color *GetImageData(Image image) pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111000000) >> 6)*(255/31)); pixels[i].b = (unsigned char)((float)((pixel & 0b0000000000111110) >> 1)*(255/31)); pixels[i].a = (unsigned char)((pixel & 0b0000000000000001)*255); - + k++; } break; case UNCOMPRESSED_R5G6B5: @@ -473,18 +473,18 @@ Color *GetImageData(Image image) pixels[i].g = (unsigned char)((float)((pixel & 0b0000011111100000) >> 5)*(255/63)); pixels[i].b = (unsigned char)((float)(pixel & 0b0000000000011111)*(255/31)); pixels[i].a = 255; - + k++; } break; case UNCOMPRESSED_R4G4B4A4: { unsigned short pixel = ((unsigned short *)image.data)[k]; - + pixels[i].r = (unsigned char)((float)((pixel & 0b1111000000000000) >> 12)*(255/15)); pixels[i].g = (unsigned char)((float)((pixel & 0b0000111100000000) >> 8)*(255/15)); pixels[i].b = (unsigned char)((float)((pixel & 0b0000000011110000) >> 4)*(255/15)); pixels[i].a = (unsigned char)((float)(pixel & 0b0000000000001111)*(255/15)); - + k++; } break; case UNCOMPRESSED_R8G8B8A8: @@ -493,7 +493,7 @@ Color *GetImageData(Image image) pixels[i].g = ((unsigned char *)image.data)[k + 1]; pixels[i].b = ((unsigned char *)image.data)[k + 2]; pixels[i].a = ((unsigned char *)image.data)[k + 3]; - + k += 4; } break; case UNCOMPRESSED_R8G8B8: @@ -502,11 +502,11 @@ Color *GetImageData(Image image) pixels[i].g = (unsigned char)((unsigned char *)image.data)[k + 1]; pixels[i].b = (unsigned char)((unsigned char *)image.data)[k + 2]; pixels[i].a = 255; - + k += 3; } break; default: TraceLog(WARNING, "Format not supported for pixel data retrieval"); break; - } + } } return pixels; @@ -522,7 +522,7 @@ Image GetTextureData(Texture2D texture) if (texture.format < 8) { image.data = rlglReadTexturePixels(texture); - + if (image.data != NULL) { image.width = texture.width; @@ -551,29 +551,29 @@ void ImageFormat(Image *image, int newFormat) if ((image->format < 8) && (newFormat < 8)) { Color *pixels = GetImageData(*image); - + free(image->data); - + image->format = newFormat; int k = 0; - + switch (image->format) { case UNCOMPRESSED_GRAYSCALE: { image->data = (unsigned char *)malloc(image->width*image->height*sizeof(unsigned char)); - + for (int i = 0; i < image->width*image->height; i++) { ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[i].r*0.299f + (float)pixels[i].g*0.587f + (float)pixels[i].b*0.114f); } - + } break; case UNCOMPRESSED_GRAY_ALPHA: { image->data = (unsigned char *)malloc(image->width*image->height*2*sizeof(unsigned char)); - + for (int i = 0; i < image->width*image->height*2; i += 2) { ((unsigned char *)image->data)[i] = (unsigned char)((float)pixels[k].r*0.299f + (float)pixels[k].g*0.587f + (float)pixels[k].b*0.114f); @@ -585,17 +585,17 @@ void ImageFormat(Image *image, int newFormat) case UNCOMPRESSED_R5G6B5: { image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - + unsigned char r = 0; unsigned char g = 0; unsigned char b = 0; - + for (int i = 0; i < image->width*image->height; i++) { r = (unsigned char)(round((float)pixels[k].r*31/255)); g = (unsigned char)(round((float)pixels[k].g*63/255)); b = (unsigned char)(round((float)pixels[k].b*31/255)); - + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 5 | (unsigned short)b; } @@ -603,7 +603,7 @@ void ImageFormat(Image *image, int newFormat) case UNCOMPRESSED_R8G8B8: { image->data = (unsigned char *)malloc(image->width*image->height*3*sizeof(unsigned char)); - + for (int i = 0; i < image->width*image->height*3; i += 3) { ((unsigned char *)image->data)[i] = pixels[k].r; @@ -615,49 +615,49 @@ void ImageFormat(Image *image, int newFormat) case UNCOMPRESSED_R5G5B5A1: { #define ALPHA_THRESHOLD 50 - + image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - + unsigned char r = 0; unsigned char g = 0; unsigned char b = 0; unsigned char a = 0; - + for (int i = 0; i < image->width*image->height; i++) { r = (unsigned char)(round((float)pixels[i].r*31/255)); g = (unsigned char)(round((float)pixels[i].g*31/255)); b = (unsigned char)(round((float)pixels[i].b*31/255)); a = (pixels[i].a > ALPHA_THRESHOLD) ? 1 : 0; - + ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; } - + } break; case UNCOMPRESSED_R4G4B4A4: { image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - + unsigned char r = 0; unsigned char g = 0; unsigned char b = 0; unsigned char a = 0; - + for (int i = 0; i < image->width*image->height; i++) { r = (unsigned char)(round((float)pixels[i].r*15/255)); g = (unsigned char)(round((float)pixels[i].g*15/255)); b = (unsigned char)(round((float)pixels[i].b*15/255)); a = (unsigned char)(round((float)pixels[i].a*15/255)); - + ((unsigned short *)image->data)[i] = (unsigned short)r << 12 | (unsigned short)g << 8| (unsigned short)b << 4| (unsigned short)a; } - + } break; case UNCOMPRESSED_R8G8B8A8: { image->data = (unsigned char *)malloc(image->width*image->height*4*sizeof(unsigned char)); - + for (int i = 0; i < image->width*image->height*4; i += 4) { ((unsigned char *)image->data)[i] = pixels[k].r; @@ -669,7 +669,7 @@ void ImageFormat(Image *image, int newFormat) } break; default: break; } - + free(pixels); } else TraceLog(WARNING, "Image data format is compressed, can not be converted"); @@ -677,7 +677,7 @@ void ImageFormat(Image *image, int newFormat) } // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) -// NOTE: In case selected bpp do not represent an known 16bit format, +// NOTE: In case selected bpp do not represent an known 16bit format, // dithered data is stored in the LSB part of the unsigned short void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { @@ -694,14 +694,14 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) else { Color *pixels = GetImageData(*image); - + free(image->data); // free old image data - + if ((image->format != UNCOMPRESSED_R8G8B8) && (image->format != UNCOMPRESSED_R8G8B8A8)) { TraceLog(WARNING, "Image format is already 16bpp or lower, dithering could have no effect"); } - + // Define new image format, check if desired bpp match internal known format if ((rBpp == 5) && (gBpp == 6) && (bBpp == 5) && (aBpp == 0)) image->format = UNCOMPRESSED_R5G6B5; else if ((rBpp == 5) && (gBpp == 5) && (bBpp == 5) && (aBpp == 1)) image->format = UNCOMPRESSED_R5G5B5A1; @@ -714,13 +714,13 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) // NOTE: We will store the dithered data as unsigned short (16bpp) image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short)); - + Color oldpixel = WHITE; Color newpixel = WHITE; - + int error_r, error_g, error_b; unsigned short pixel_r, pixel_g, pixel_b, pixel_a; // Used for 16bit pixel composition - + #define MIN(a,b) (((a)<(b))?(a):(b)) for (int y = 0; y < image->height; y++) @@ -728,7 +728,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) for (int x = 0; x < image->width; x++) { oldpixel = pixels[y*image->width + x]; - + // NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat()) newpixel.r = oldpixel.r>>(8 - rBpp); // R bits newpixel.g = oldpixel.g>>(8 - gBpp); // G bits @@ -740,7 +740,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) error_r = (int)oldpixel.r - (int)(newpixel.r<<(8 - rBpp)); error_g = (int)oldpixel.g - (int)(newpixel.g<<(8 - gBpp)); error_b = (int)oldpixel.b - (int)(newpixel.b<<(8 - bBpp)); - + pixels[y*image->width + x] = newpixel; // NOTE: Some cases are out of the array and should be ignored @@ -750,21 +750,21 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)error_g*7.0f/16), 0xff); pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)error_b*7.0f/16), 0xff); } - + if ((x > 0) && (y < (image->height - 1))) { pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)error_r*3.0f/16), 0xff); pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)error_g*3.0f/16), 0xff); pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)error_b*3.0f/16), 0xff); } - + if (y < (image->height - 1)) { pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)error_r*5.0f/16), 0xff); pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)error_g*5.0f/16), 0xff); pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)error_b*5.0f/16), 0xff); } - + if ((x < (image->width - 1)) && (y < (image->height - 1))) { pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)error_r*1.0f/16), 0xff); @@ -776,7 +776,7 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) pixel_g = (unsigned short)newpixel.g; pixel_b = (unsigned short)newpixel.b; pixel_a = (unsigned short)newpixel.a; - + ((unsigned short *)image->data)[y*image->width + x] = (pixel_r<<(gBpp + bBpp + aBpp)) | (pixel_g<<(bBpp + aBpp)) | (pixel_b<width); int potHeight = GetNextPOT(image->height); @@ -816,13 +816,13 @@ void ImageToPOT(Image *image, Color fillColor) free(pixels); // Free pixels data free(image->data); // Free old image data - + int format = image->format; // Store image data format to reconvert later - + // TODO: Image width and height changes... do we want to store new values or keep the old ones? // NOTE: Issues when using image.width and image.height for sprite animations... *image = LoadImageEx(pixelsPOT, potWidth, potHeight); - + free(pixelsPOT); // Free POT pixels data ImageFormat(image, format); // Reconvert image to previous format @@ -833,9 +833,9 @@ void ImageToPOT(Image *image, Color fillColor) Image ImageCopy(Image image) { Image newImage; - + int size = image.width*image.height; - + switch (image.format) { case UNCOMPRESSED_GRAYSCALE: newImage.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha) @@ -847,24 +847,24 @@ Image ImageCopy(Image image) case UNCOMPRESSED_R8G8B8A8: newImage.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp default: TraceLog(WARNING, "Image format not suported for copy"); break; } - + if (newImage.data != NULL) { // NOTE: Size must be provided in bytes memcpy(newImage.data, image.data, size); - + newImage.width = image.width; newImage.height = image.height; newImage.mipmaps = image.mipmaps; newImage.format = image.format; } - + return newImage; } // Crop an image to area defined by a rectangle // NOTE: Security checks are performed in case rectangle goes out of bounds -void ImageCrop(Image *image, Rectangle crop) +void ImageCrop(Image *image, Rectangle crop) { // Security checks to make sure cropping rectangle is inside margins if ((crop.x + crop.width) > image->width) @@ -872,13 +872,13 @@ void ImageCrop(Image *image, Rectangle crop) crop.width = image->width - crop.x; TraceLog(WARNING, "Crop rectangle width out of bounds, rescaled crop width: %i", crop.width); } - + if ((crop.y + crop.height) > image->height) { crop.height = image->height - crop.y; TraceLog(WARNING, "Crop rectangle height out of bounds, rescaled crop height: %i", crop.height); } - + if ((crop.x < image->width) && (crop.y < image->height)) { // Start the cropping process @@ -903,7 +903,7 @@ void ImageCrop(Image *image, Rectangle crop) free(cropPixels); - // Reformat 32bit RGBA image to original format + // Reformat 32bit RGBA image to original format ImageFormat(image, format); } else @@ -916,7 +916,7 @@ void ImageCrop(Image *image, Rectangle crop) // NOTE: Uses stb default scaling filters (both bicubic): // STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM // STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL (high-quality Catmull-Rom) -void ImageResize(Image *image, int newWidth, int newHeight) +void ImageResize(Image *image, int newWidth, int newHeight) { // Get data as Color pixels array to work with it Color *pixels = GetImageData(*image); @@ -930,81 +930,81 @@ void ImageResize(Image *image, int newWidth, int newHeight) UnloadImage(*image); *image = LoadImageEx(output, newWidth, newHeight); - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + free(output); free(pixels); } // Resize and image to new size using Nearest-Neighbor scaling algorithm -void ImageResizeNN(Image *image,int newWidth,int newHeight) +void ImageResizeNN(Image *image,int newWidth,int newHeight) { Color *pixels = GetImageData(*image); Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color)); - + // EDIT: added +1 to account for an early rounding problem int x_ratio = (int)((image->width<<16)/newWidth) + 1; int y_ratio = (int)((image->height<<16)/newHeight) + 1; - + int x2, y2; - for (int i = 0; i < newHeight; i++) + for (int i = 0; i < newHeight; i++) { - for (int j = 0; j < newWidth; j++) + for (int j = 0; j < newWidth; j++) { x2 = ((j*x_ratio) >> 16); y2 = ((i*y_ratio) >> 16); - + output[(i*newWidth) + j] = pixels[(y2*image->width) + x2] ; - } - } + } + } int format = image->format; UnloadImage(*image); *image = LoadImageEx(output, newWidth, newHeight); - ImageFormat(image, format); // Reformat 32bit RGBA image to original format - + ImageFormat(image, format); // Reformat 32bit RGBA image to original format + free(output); free(pixels); } // Draw an image (source) within an image (destination) -void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) +void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) { // Security checks to avoid size and rectangle issues (out of bounds) // Check that srcRec is inside src image if (srcRec.x < 0) srcRec.x = 0; if (srcRec.y < 0) srcRec.y = 0; - + if ((srcRec.x + srcRec.width) > src.width) { srcRec.width = src.width - srcRec.x; TraceLog(WARNING, "Source rectangle width out of bounds, rescaled width: %i", srcRec.width); } - + if ((srcRec.y + srcRec.height) > src.height) { srcRec.height = src.height - srcRec.y; TraceLog(WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height); } - + // Check that dstRec is inside dst image if (dstRec.x < 0) dstRec.x = 0; if (dstRec.y < 0) dstRec.y = 0; - + if ((dstRec.x + dstRec.width) > dst->width) { dstRec.width = dst->width - dstRec.x; TraceLog(WARNING, "Destination rectangle width out of bounds, rescaled width: %i", dstRec.width); } - + if ((dstRec.y + dstRec.height) > dst->height) { dstRec.height = dst->height - dstRec.y; TraceLog(WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height); } - + // Get dstination image data as Color pixels array to work with it Color *dstPixels = GetImageData(*dst); @@ -1012,14 +1012,14 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle // Scale source image in case destination rec size is different than source rec size - if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) + if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) { ImageResize(&srcCopy, dstRec.width, dstRec.height); } // Get source image data as Color array Color *srcPixels = GetImageData(srcCopy); - + UnloadImage(srcCopy); // Blit pixels, copy source image into destination @@ -1030,7 +1030,7 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) dstPixels[j*dst->width + i] = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)]; } } - + UnloadImage(*dst); // NOTE: Only dst->data is unloaded *dst = LoadImageEx(dstPixels, dst->width, dst->height); @@ -1046,9 +1046,9 @@ Image ImageText(const char *text, int fontSize, Color color) int defaultFontSize = 10; // Default Font chars height in pixel if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize / defaultFontSize; - + Image imText = ImageTextEx(GetDefaultFont(), text, fontSize, spacing, color); - + return imText; } @@ -1062,19 +1062,19 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); - + ImageFormat(&imFont, UNCOMPRESSED_R8G8B8A8); // Required for color tint ImageColorTint(&imFont, tint); // Apply color tint to font Color *fontPixels = GetImageData(imFont); - + // Create image to store text Color *pixels = (Color *)malloc(sizeof(Color)*(int)imSize.x*(int)imSize.y); - + for (int i = 0; i < length; i++) { Rectangle letterRec = font.charRecs[(int)text[i] - 32]; - + for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++) { for (int x = posX; x < (posX + letterRec.width); x++) @@ -1082,28 +1082,28 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing pixels[(y - letterRec.y)*(int)imSize.x + x] = fontPixels[y*font.texture.width + (x - posX + letterRec.x)]; } } - + posX += letterRec.width + spacing; } - + UnloadImage(imFont); - + Image imText = LoadImageEx(pixels, (int)imSize.x, (int)imSize.y); - + // Scale image depending on text size if (fontSize > imSize.y) { float scaleFactor = fontSize/imSize.y; TraceLog(INFO, "Scalefactor: %f", scaleFactor); - + // Using nearest-neighbor scaling algorithm for default font if (font.texture.id == GetDefaultFont().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor)); } - + free(pixels); free(fontPixels); - + return imText; } @@ -1117,12 +1117,12 @@ void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color) { Image imText = ImageTextEx(font, text, fontSize, spacing, color); - + Rectangle srcRec = { 0, 0, imText.width, imText.height }; Rectangle dstRec = { (int)position.x, (int)position.y, imText.width, imText.height }; - + ImageDraw(dst, imText, srcRec, dstRec); - + UnloadImage(imText); } @@ -1131,7 +1131,7 @@ void ImageFlipVertical(Image *image) { Color *srcPixels = GetImageData(*image); Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1139,14 +1139,14 @@ void ImageFlipVertical(Image *image) dstPixels[y*image->width + x] = srcPixels[(image->height - 1 - y)*image->width + x]; } } - + Image processed = LoadImageEx(dstPixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - + free(srcPixels); free(dstPixels); - + image->data = processed.data; } @@ -1155,7 +1155,7 @@ void ImageFlipHorizontal(Image *image) { Color *srcPixels = GetImageData(*image); Color *dstPixels = (Color *)malloc(sizeof(Color)*image->width*image->height); - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1163,14 +1163,14 @@ void ImageFlipHorizontal(Image *image) dstPixels[y*image->width + x] = srcPixels[y*image->width + (image->width - 1 - x)]; } } - + Image processed = LoadImageEx(dstPixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); - + free(srcPixels); free(dstPixels); - + image->data = processed.data; } @@ -1178,12 +1178,12 @@ void ImageFlipHorizontal(Image *image) void ImageColorTint(Image *image, Color color) { Color *pixels = GetImageData(*image); - + float cR = (float)color.r/255; float cG = (float)color.g/255; float cB = (float)color.b/255; float cA = (float)color.a/255; - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1204,7 +1204,7 @@ void ImageColorTint(Image *image, Color color) ImageFormat(&processed, image->format); UnloadImage(*image); free(pixels); - + image->data = processed.data; } @@ -1212,7 +1212,7 @@ void ImageColorTint(Image *image, Color color) void ImageColorInvert(Image *image) { Color *pixels = GetImageData(*image); - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1222,12 +1222,12 @@ void ImageColorInvert(Image *image) pixels[y*image->width + x].b = 255 - pixels[y*image->width + x].b; } } - + Image processed = LoadImageEx(pixels, image->width, image->height); ImageFormat(&processed, image->format); UnloadImage(*image); free(pixels); - + image->data = processed.data; } @@ -1243,12 +1243,12 @@ void ImageColorContrast(Image *image, float contrast) { if (contrast < -100) contrast = -100; if (contrast > 100) contrast = 100; - + contrast = (100.0 + contrast)/100.0; contrast *= contrast; - + Color *pixels = GetImageData(*image); - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1287,7 +1287,7 @@ void ImageColorContrast(Image *image, float contrast) ImageFormat(&processed, image->format); UnloadImage(*image); free(pixels); - + image->data = processed.data; } @@ -1297,9 +1297,9 @@ void ImageColorBrightness(Image *image, int brightness) { if (brightness < -255) brightness = -255; if (brightness > 255) brightness = 255; - + Color *pixels = GetImageData(*image); - + for (int y = 0; y < image->height; y++) { for (int x = 0; x < image->width; x++) @@ -1316,7 +1316,7 @@ void ImageColorBrightness(Image *image, int brightness) if (cB < 0) cB = 1; if (cB > 255) cB = 255; - + pixels[y*image->width + x].r = (unsigned char)cR; pixels[y*image->width + x].g = (unsigned char)cG; pixels[y*image->width + x].b = (unsigned char)cB; @@ -1327,7 +1327,7 @@ void ImageColorBrightness(Image *image, int brightness) ImageFormat(&processed, image->format); UnloadImage(*image); free(pixels); - + image->data = processed.data; } @@ -1396,7 +1396,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V { if (sourceRec.width < 0) sourceRec.x -= sourceRec.width; if (sourceRec.height < 0) sourceRec.y -= sourceRec.height; - + rlEnableTexture(texture.id); rlPushMatrix(); @@ -1439,13 +1439,13 @@ static Image LoadDDS(const char *fileName) { // Required extension: // GL_EXT_texture_compression_s3tc - + // Supported tokens (defined by extensions) // GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 - + #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII @@ -1508,7 +1508,7 @@ static Image LoadDDS(const char *fileName) else { ddsHeader header; - + // Get the image header fread(&header, sizeof(ddsHeader), 1, ddsFile); @@ -1537,9 +1537,9 @@ static Image LoadDDS(const char *fileName) { image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); - + unsigned char alpha = 0; - + // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1 for (int i = 0; i < image.width*image.height; i++) { @@ -1554,9 +1554,9 @@ static Image LoadDDS(const char *fileName) { image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short)); fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile); - + unsigned char alpha = 0; - + // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4 for (int i = 0; i < image.width*image.height; i++) { @@ -1564,7 +1564,7 @@ static Image LoadDDS(const char *fileName) ((unsigned short *)image.data)[i] = ((unsigned short *)image.data)[i] << 4; ((unsigned short *)image.data)[i] += alpha; } - + image.format = UNCOMPRESSED_R4G4B4A4; } } @@ -1574,14 +1574,14 @@ static Image LoadDDS(const char *fileName) // NOTE: not sure if this case exists... image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char)); fread(image.data, image.width*image.height*3, 1, ddsFile); - + image.format = UNCOMPRESSED_R8G8B8; } else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed { image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char)); fread(image.data, image.width*image.height*4, 1, ddsFile); - + unsigned char blue = 0; // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment) @@ -1593,7 +1593,7 @@ static Image LoadDDS(const char *fileName) ((unsigned char *)image.data)[i] = ((unsigned char *)image.data)[i + 2]; ((unsigned char *)image.data)[i + 2] = blue; } - + image.format = UNCOMPRESSED_R8G8B8A8; } else if (((header.ddspf.flags == 0x04) || (header.ddspf.flags == 0x05)) && (header.ddspf.fourCC > 0)) // Compressed @@ -1603,7 +1603,7 @@ static Image LoadDDS(const char *fileName) // Calculate data size, including all mipmaps if (header.mipmapCount > 1) bufsize = header.pitchOrLinearSize*2; else bufsize = header.pitchOrLinearSize; - + TraceLog(DEBUG, "Pitch or linear size: %i", header.pitchOrLinearSize); image.data = (unsigned char*)malloc(bufsize*sizeof(unsigned char)); @@ -1625,7 +1625,7 @@ static Image LoadDDS(const char *fileName) } } } - + fclose(ddsFile); // Close file pointer } @@ -1640,9 +1640,9 @@ static Image LoadPKM(const char *fileName) // Required extensions: // GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0) // GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0) - + // Supported tokens (defined by extensions) - // GL_ETC1_RGB8_OES 0x8D64 + // GL_ETC1_RGB8_OES 0x8D64 // GL_COMPRESSED_RGB8_ETC2 0x9274 // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 @@ -1656,7 +1656,7 @@ static Image LoadPKM(const char *fileName) unsigned short origWidth; // Original width (big-endian) unsigned short origHeight; // Original height (big-endian) } pkmHeader; - + // Formats list // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used) // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R @@ -1665,7 +1665,7 @@ static Image LoadPKM(const char *fileName) // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels) Image image; - + image.data = NULL; image.width = 0; image.height = 0; @@ -1695,18 +1695,18 @@ static Image LoadPKM(const char *fileName) header.format = ((header.format & 0x00FF) << 8) | ((header.format & 0xFF00) >> 8); header.width = ((header.width & 0x00FF) << 8) | ((header.width & 0xFF00) >> 8); header.height = ((header.height & 0x00FF) << 8) | ((header.height & 0xFF00) >> 8); - + TraceLog(DEBUG, "PKM (ETC) image width: %i", header.width); TraceLog(DEBUG, "PKM (ETC) image height: %i", header.height); TraceLog(DEBUG, "PKM (ETC) image format: %i", header.format); - + image.width = header.width; image.height = header.height; image.mipmaps = 1; - + int bpp = 4; if (header.format == 3) bpp = 8; - + int size = image.width*image.height*bpp/8; // Total data size in bytes image.data = (unsigned char*)malloc(size * sizeof(unsigned char)); @@ -1717,7 +1717,7 @@ static Image LoadPKM(const char *fileName) else if (header.format == 1) image.format = COMPRESSED_ETC2_RGB; else if (header.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA; } - + fclose(pkmFile); // Close file pointer } @@ -1730,12 +1730,12 @@ static Image LoadKTX(const char *fileName) // Required extensions: // GL_OES_compressed_ETC1_RGB8_texture (ETC1) // GL_ARB_ES3_compatibility (ETC2/EAC) - + // Supported tokens (defined by extensions) // GL_ETC1_RGB8_OES 0x8D64 // GL_COMPRESSED_RGB8_ETC2 0x9274 // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 - + // KTX file Header (64 bytes) // https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ typedef struct { @@ -1754,16 +1754,16 @@ static Image LoadKTX(const char *fileName) unsigned int mipmapLevels; // Non-mipmapped textures = 1 unsigned int keyValueDataSize; // Used to encode any arbitrary data... } ktxHeader; - + // NOTE: Before start of every mipmap data block, we have: unsigned int dataSize - + Image image; image.width = 0; image.height = 0; image.mipmaps = 0; image.format = 0; - + FILE *ktxFile = fopen(fileName, "rb"); if (ktxFile == NULL) @@ -1783,22 +1783,22 @@ static Image LoadKTX(const char *fileName) TraceLog(WARNING, "[%s] KTX file does not seem to be a valid file", fileName); } else - { + { image.width = header.width; image.height = header.height; image.mipmaps = header.mipmapLevels; - + TraceLog(DEBUG, "KTX (ETC) image width: %i", header.width); TraceLog(DEBUG, "KTX (ETC) image height: %i", header.height); TraceLog(DEBUG, "KTX (ETC) image format: 0x%x", header.glInternalFormat); - + unsigned char unused; - + if (header.keyValueDataSize > 0) { for (int i = 0; i < header.keyValueDataSize; i++) fread(&unused, 1, 1, ktxFile); } - + int dataSize; fread(&dataSize, sizeof(unsigned int), 1, ktxFile); @@ -1810,10 +1810,10 @@ static Image LoadKTX(const char *fileName) else if (header.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB; else if (header.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA; } - + fclose(ktxFile); // Close file pointer } - + return image; } @@ -1823,11 +1823,11 @@ static Image LoadPVR(const char *fileName) { // Required extension: // GL_IMG_texture_compression_pvrtc - + // Supported tokens (defined by extensions) // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 - + #if 0 // Not used... // PVR file v2 Header (52 bytes) typedef struct { @@ -1864,7 +1864,7 @@ static Image LoadPVR(const char *fileName) unsigned int numMipmaps; unsigned int metaDataSize; } pvrHeaderV3; - + #if 0 // Not used... // Metadata (usually 15 bytes) typedef struct { @@ -1872,7 +1872,7 @@ static Image LoadPVR(const char *fileName) unsigned int key; unsigned int dataSize; // Not used? unsigned char *data; // Not used? - } pvrMetadata; + } pvrMetadata; #endif Image image; @@ -1895,15 +1895,15 @@ static Image LoadPVR(const char *fileName) unsigned char pvrVersion = 0; fread(&pvrVersion, sizeof(unsigned char), 1, pvrFile); fseek(pvrFile, 0, SEEK_SET); - + // Load different PVR data formats if (pvrVersion == 0x50) { pvrHeaderV3 header; - + // Get PVR image header fread(&header, sizeof(pvrHeaderV3), 1, pvrFile); - + if ((header.id[0] != 'P') || (header.id[1] != 'V') || (header.id[2] != 'R') || (header.id[3] != 3)) { TraceLog(WARNING, "[%s] PVR file does not seem to be a valid image", fileName); @@ -1913,7 +1913,7 @@ static Image LoadPVR(const char *fileName) image.width = header.width; image.height = header.height; image.mipmaps = header.numMipmaps; - + // Check data format if (((header.channels[0] == 'l') && (header.channels[1] == 0)) && (header.channelDepth[0] == 8)) image.format = UNCOMPRESSED_GRAYSCALE; else if (((header.channels[0] == 'l') && (header.channels[1] == 'a')) && ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8))) image.format = UNCOMPRESSED_GRAY_ALPHA; @@ -1933,14 +1933,14 @@ static Image LoadPVR(const char *fileName) } else if (header.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB; else if (header.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA; - + // Skip meta data header unsigned char unused = 0; for (int i = 0; i < header.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile); - + // Calculate data size (depends on format) int bpp = 0; - + switch (image.format) { case UNCOMPRESSED_GRAYSCALE: bpp = 8; break; @@ -1954,7 +1954,7 @@ static Image LoadPVR(const char *fileName) case COMPRESSED_PVRT_RGBA: bpp = 4; break; default: break; } - + int dataSize = image.width*image.height*bpp/8; // Total data size in bytes image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char)); @@ -1976,11 +1976,11 @@ static Image LoadASTC(const char *fileName) // Required extensions: // GL_KHR_texture_compression_astc_hdr // GL_KHR_texture_compression_astc_ldr - + // Supported tokens (defined by extensions) // GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 // GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 - + // ASTC file Header (16 bytes) typedef struct { unsigned char id[4]; // Signature: 0x13 0xAB 0xA1 0x5C @@ -1999,7 +1999,7 @@ static Image LoadASTC(const char *fileName) image.height = 0; image.mipmaps = 0; image.format = 0; - + FILE *astcFile = fopen(fileName, "rb"); if (astcFile == NULL) @@ -2012,7 +2012,7 @@ static Image LoadASTC(const char *fileName) // Get ASTC image header fread(&header, sizeof(astcHeader), 1, astcFile); - + if ((header.id[3] != 0x5c) || (header.id[2] != 0xa1) || (header.id[1] != 0xab) || (header.id[0] != 0x13)) { TraceLog(WARNING, "[%s] ASTC file does not seem to be a valid image", fileName); @@ -2022,31 +2022,31 @@ static Image LoadASTC(const char *fileName) // NOTE: Assuming Little Endian (could it be wrong?) image.width = 0x00000000 | ((int)header.width[2] << 16) | ((int)header.width[1] << 8) | ((int)header.width[0]); image.height = 0x00000000 | ((int)header.height[2] << 16) | ((int)header.height[1] << 8) | ((int)header.height[0]); - + // NOTE: ASTC format only contains one mipmap level image.mipmaps = 1; - + TraceLog(DEBUG, "ASTC image width: %i", image.width); TraceLog(DEBUG, "ASTC image height: %i", image.height); TraceLog(DEBUG, "ASTC image blocks: %ix%i", header.blockX, header.blockY); - + // NOTE: Each block is always stored in 128bit so we can calculate the bpp int bpp = 128/(header.blockX*header.blockY); // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8 - if ((bpp == 8) || (bpp == 2)) + if ((bpp == 8) || (bpp == 2)) { int dataSize = image.width*image.height*bpp/8; // Data size in bytes - + image.data = (unsigned char *)malloc(dataSize*sizeof(unsigned char)); fread(image.data, dataSize, 1, astcFile); - + if (bpp == 8) image.format = COMPRESSED_ASTC_4x4_RGBA; else if (bpp == 2) image.format = COMPRESSED_ASTC_4x4_RGBA; } else TraceLog(WARNING, "[%s] ASTC block size configuration not supported", fileName); } - + fclose(astcFile); } -- cgit v1.2.3 From 1d71e1b7542b88c2d5a690d09c0d2a5411549527 Mon Sep 17 00:00:00 2001 From: Wilhem Barbier Date: Thu, 25 Aug 2016 14:18:43 +0200 Subject: Fix a typo in the DrawCube, DrawCubeWires and DrawCubeTexture definitions --- src/raylib.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 7b7348c8..68cddc5a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -810,10 +810,10 @@ RLAPI const char *SubText(const char *text, int position, int length); //------------------------------------------------------------------------------------ RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space RLAPI void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle in 3D world space -RLAPI void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube +RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) -RLAPI void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires -RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float lenght, Color color); // Draw cube textured +RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires +RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires -- cgit v1.2.3 From be97583f00997fa918a15d0164190ae6876d0571 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 29 Aug 2016 11:17:58 +0200 Subject: Added function: UpdateSound() --- src/audio.c | 28 ++++++++++++++++++++++++++++ src/audio.h | 1 + src/raylib.h | 2 ++ 3 files changed, 31 insertions(+) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 1772196f..3bace5f7 100644 --- a/src/audio.c +++ b/src/audio.c @@ -284,6 +284,7 @@ Sound LoadSoundFromWave(Wave wave) sound.source = source; sound.buffer = buffer; + sound.format = format; } return sound; @@ -409,6 +410,33 @@ void UnloadSound(Sound sound) TraceLog(INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer); } +// Update sound buffer with new data +// NOTE: data must match sound.format +void UpdateSound(Sound sound, void *data, int numSamples) +{ + ALint sampleRate, sampleSize, channels; + alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); + alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format + alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format + + TraceLog(DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate); + TraceLog(DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize); + TraceLog(DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels); + + unsigned int dataSize = numSamples*sampleSize/8; // Size of data in bytes + + alSourceStop(sound.source); // Stop sound + alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update + //alDeleteBuffers(1, &sound.buffer); // Delete current buffer data + //alGenBuffers(1, &sound.buffer); // Generate new buffer + + // Upload new data to sound buffer + alBufferData(sound.buffer, sound.format, data, dataSize, sampleRate); + + // Attach sound buffer to source again + alSourcei(sound.source, AL_BUFFER, sound.buffer); +} + // Play a sound void PlaySound(Sound sound) { diff --git a/src/audio.h b/src/audio.h index 4ee9559e..923492ca 100644 --- a/src/audio.h +++ b/src/audio.h @@ -110,6 +110,7 @@ bool IsAudioDeviceReady(void); // Check if audi 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) +void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound void PauseSound(Sound sound); // Pause a sound diff --git a/src/raylib.h b/src/raylib.h index 68cddc5a..d295ef90 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -486,6 +486,7 @@ typedef struct Ray { typedef struct Sound { unsigned int source; // OpenAL audio source id unsigned int buffer; // OpenAL audio buffer id + int format; // OpenAL audio format specifier } Sound; // Wave type, defines audio wave data @@ -908,6 +909,7 @@ RLAPI bool IsAudioDeviceReady(void); // Check i RLAPI Sound LoadSound(char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) +RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound RLAPI void PauseSound(Sound sound); // Pause a sound -- cgit v1.2.3 From 9d66bc4a05f17f5dfe0e81b9be38f044b0dc16d4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 5 Sep 2016 10:08:28 +0200 Subject: Added function: ImageAlphaMask() --- src/raylib.h | 1 + src/textures.c | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index d295ef90..d86b1745 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -762,6 +762,7 @@ RLAPI Color *GetImageData(Image image); RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format +RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle diff --git a/src/textures.c b/src/textures.c index 4d9fc6b0..87ac1f85 100644 --- a/src/textures.c +++ b/src/textures.c @@ -548,7 +548,7 @@ void ImageFormat(Image *image, int newFormat) { if (image->format != newFormat) { - if ((image->format < 8) && (newFormat < 8)) + if ((image->format < COMPRESSED_DXT1_RGB) && (newFormat < COMPRESSED_DXT1_RGB)) { Color *pixels = GetImageData(*image); @@ -676,12 +676,40 @@ void ImageFormat(Image *image, int newFormat) } } +// Apply alpha mask to image +// NOTE: alphaMask must be should be same size as image +void ImageAlphaMask(Image *image, Image alphaMask) +{ + if (image->format >= COMPRESSED_DXT1_RGB) + { + TraceLog(WARNING, "Alpha mask can not be applied to compressed data formats"); + return; + } + else + { + // Force mask to be Grayscale + Image mask = ImageCopy(alphaMask); + ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); + + // Convert image to RGBA + if (image->format != UNCOMPRESSED_R8G8B8A8) ImageFormat(image, UNCOMPRESSED_R8G8B8A8); + + // Apply alpha mask to alpha channel + for (int i = 0, k = 3; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 4) + { + ((unsigned char *)image->data)[k] = ((unsigned char *)mask.data)[i]; + } + + UnloadImage(mask); + } +} + // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) // NOTE: In case selected bpp do not represent an known 16bit format, // dithered data is stored in the LSB part of the unsigned short void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp) { - if (image->format >= 8) + if (image->format >= COMPRESSED_DXT1_RGB) { TraceLog(WARNING, "Compressed data formats can not be dithered"); return; -- cgit v1.2.3 From 36f20376e67c8f281467df74b82759c9a05d7018 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 5 Sep 2016 20:15:21 +0200 Subject: Redesigned lighting shader system --- src/raylib.h | 6 +- src/rlgl.c | 209 +++++++++++++++++++++++++++++++++++------------------------ src/rlgl.h | 4 +- 3 files changed, 130 insertions(+), 89 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index d86b1745..dff69705 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -427,7 +427,9 @@ typedef struct Shader { // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Diffuse color uniform location point (fragment shader) + int colDiffuseLoc; // Diffuse color uniform location point (fragment shader) + int colAmbientLoc; // Ambient color uniform location point (fragment shader) + int colSpecularLoc; // Specular color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) @@ -464,7 +466,7 @@ typedef struct LightData { int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT Vector3 position; // Light position - Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + Vector3 target; // Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) float radius; // Light attenuation radius light intensity reduced with distance (world distance) Color diffuse; // Light diffuse color diff --git a/src/rlgl.c b/src/rlgl.c index 68d562c7..1b3d9898 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -337,6 +337,8 @@ static int screenHeight; // Default framebuffer height // Lighting data static Light lights[MAX_LIGHTS]; // Lights pool static int lightsCount = 0; // Enabled lights counter +static int lightsLocs[MAX_LIGHTS][8]; // 8 possible location points per light: + // enabled, type, position, target, radius, diffuse, intensity, coneAngle //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -362,9 +364,10 @@ static void SetStereoConfig(VrDeviceInfo info); // Set internal projection and modelview matrix depending on eyes tracking data static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); -static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array +static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS) +static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights -static char *ReadTextFile(const char *fileName); // Read chars array from text file +static char *ReadTextFile(const char *fileName); // Read chars array from text file #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -1939,9 +1942,14 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glUseProgram(material.shader.id); // 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); + glUniform4f(material.shader.colDiffuseLoc, (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255); + // Upload to shader material.colAmbient (if available) + if (material.shader.colAmbientLoc != -1) glUniform4f(material.shader.colAmbientLoc, (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 (if available) + if (material.shader.colSpecularLoc != -1) glUniform4f(material.shader.colSpecularLoc, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); + // 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) @@ -1950,32 +1958,35 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Calculate model-view matrix combining matModel and matView Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates - // 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) + // If not using default shader, we check for some additional location points + // NOTE: This method is quite inefficient... it's a temporal solution while looking for a better one + if (material.shader.id != defaultShader.id) { - // Transpose and inverse model transformations matrix for fragment normal calculations - Matrix transInvTransform = transform; - MatrixTranspose(&transInvTransform); - MatrixInvert(&transInvTransform); - - // Send model transformations matrix to shader - glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transInvTransform)); - - // 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); + // Check if model matrix is located in shader and upload value + int modelMatrixLoc = glGetUniformLocation(material.shader.id, "modelMatrix"); + if (modelMatrixLoc != -1) + { + // Transpose and inverse model transformations matrix for fragment normal calculations + Matrix transInvTransform = transform; + MatrixTranspose(&transInvTransform); + MatrixInvert(&transInvTransform); + + // Send model transformations matrix to shader + glUniformMatrix4fv(modelMatrixLoc, 1, false, MatrixToFloat(transInvTransform)); + } + + // Check if view direction is located in shader and upload value + // NOTE: View matrix values m8, m9 and m10 are view direction vector axis (target - position) + int viewDirLoc = glGetUniformLocation(material.shader.id, "viewDir"); + if (viewDirLoc != -1) glUniform3f(viewDirLoc, matView.m8, matView.m9, matView.m10); + + // Check if glossiness is located in shader and upload value + int glossinessLoc = glGetUniformLocation(material.shader.id, "glossiness"); + if (glossinessLoc != -1) glUniform1f(glossinessLoc, material.glossiness); + + // Set shader lights values for enabled lights + // NOTE: Lights array location points are obtained on shader loading (if available) + if (lightsCount > 0) SetShaderLightsValues(material.shader); } // Set shader textures (diffuse, normal, specular) @@ -3100,7 +3111,7 @@ static Shader LoadStandardShader(void) shader = GetDefaultShader(); } #else - shader = defaultShader; + shader = GetDefaultShader(); TraceLog(WARNING, "[SHDR ID %i] Standard shader not available, using default shader", shader.id); #endif @@ -3112,12 +3123,12 @@ static Shader LoadStandardShader(void) static void LoadDefaultShaderLocations(Shader *shader) { // NOTE: Default shader attrib locations have been fixed before linking: - // vertex position location = 0 - // vertex texcoord location = 1 - // vertex normal location = 2 - // vertex color location = 3 - // vertex tangent location = 4 - // vertex texcoord2 location = 5 + // vertex position location = 0 + // vertex texcoord location = 1 + // vertex normal location = 2 + // vertex color location = 3 + // vertex tangent location = 4 + // vertex texcoord2 location = 5 // Get handles to GLSL input attibute locations shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME); @@ -3131,10 +3142,18 @@ static void LoadDefaultShaderLocations(Shader *shader) shader->mvpLoc = glGetUniformLocation(shader->id, "mvpMatrix"); // Get handles to GLSL uniform locations (fragment shader) - shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse"); + shader->colDiffuseLoc = glGetUniformLocation(shader->id, "colDiffuse"); + shader->colAmbientLoc = glGetUniformLocation(shader->id, "colAmbient"); + shader->colSpecularLoc = glGetUniformLocation(shader->id, "colSpecular"); + shader->mapTexture0Loc = glGetUniformLocation(shader->id, "texture0"); shader->mapTexture1Loc = glGetUniformLocation(shader->id, "texture1"); shader->mapTexture2Loc = glGetUniformLocation(shader->id, "texture2"); + + // TODO: Try to find all expected/recognized shader locations (predefined names, must be documented) + + // Try to get lights location points (if available) + GetShaderLightsLocations(*shader); } // Unload default shader @@ -3425,7 +3444,7 @@ static void DrawDefaultBuffers(int eyesCount) Matrix matMVP = MatrixMultiply(modelview, projection); glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); - glUniform4f(currentShader.tintColorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glUniform4f(currentShader.colDiffuseLoc, 1.0f, 1.0f, 1.0f, 1.0f); glUniform1i(currentShader.mapTexture0Loc, 0); // NOTE: Additional map textures not considered for default buffers drawing @@ -3620,82 +3639,100 @@ static void UnloadDefaultBuffers(void) free(quads.indices); } -// Setup 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) +// Get shader locations for lights (up to MAX_LIGHTS) +static void GetShaderLightsLocations(Shader shader) { - int locPoint = -1; - char locName[32] = "lights[x].position\0"; - + char locName[32] = "lights[x].\0"; + char locNameUpdated[64]; + for (int i = 0; i < MAX_LIGHTS; i++) { locName[7] = '0' + i; + + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "enabled\0"); + lightsLocs[i][0] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "type\0"); + lightsLocs[i][1] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "position\0"); + lightsLocs[i][2] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "direction\0"); + lightsLocs[i][3] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "radius\0"); + lightsLocs[i][4] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "diffuse\0"); + lightsLocs[i][5] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "intensity\0"); + lightsLocs[i][6] = glGetUniformLocation(shader.id, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "coneAngle\0"); + lightsLocs[i][7] = glGetUniformLocation(shader.id, locNameUpdated); + } +} - if (lights[i] != NULL) // Only upload registered lights data +// Set shader uniform values for lights +// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0 +static void SetShaderLightsValues(Shader shader) +{ + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (i < lightsCount) { - 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); + glUniform1i(lightsLocs[i][0], lights[i]->enabled); + + glUniform1i(lightsLocs[i][1], lights[i]->type); + glUniform4f(lightsLocs[i][5], (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); + glUniform1f(lightsLocs[i][6], 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], "radius\0", strlen("radius\0") + 2); - locPoint = GetShaderLocation(shader, locName); - glUniform1f(locPoint, lights[i]->radius); + glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + glUniform1f(lightsLocs[i][4], lights[i]->radius); } 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); + glUniform3f(lightsLocs[i][3], 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); + glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); 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); + glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); - memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0")); - locPoint = GetShaderLocation(shader, locName); - glUniform1f(locPoint, lights[i]->coneAngle); + glUniform1f(lightsLocs[i][7], lights[i]->coneAngle); } break; default: break; } - - // TODO: Pass to the shader any other required data from LightData struct } - else // Not enabled lights + else { - memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1); - locPoint = GetShaderLocation(shader, locName); - glUniform1i(locPoint, 0); + glUniform1i(lightsLocs[i][0], 0); // Light disabled } } } diff --git a/src/rlgl.h b/src/rlgl.h index 3fc54219..5fc9f8b9 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -168,7 +168,9 @@ typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion; // Uniform locations int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader) - int tintColorLoc; // Color uniform location point (fragment shader) + int colDiffuseLoc; // Color uniform location point (fragment shader) + int colAmbientLoc; // Ambient color uniform location point (fragment shader) + int colSpecularLoc; // Specular color uniform location point (fragment shader) // Texture map locations (generic for any kind of map) int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0) -- cgit v1.2.3 From 8b35de3276d0fbf0487ed73fe2c2dfb2340e0431 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 8 Sep 2016 00:20:06 +0200 Subject: Added new audio functions -IN PROGRESS- - LoadWave() - LoadWaveEx() - UnloadWave() - WaveFormat() - WaveCopy() - WaveCrop() - GetWaveData() --- src/audio.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- src/raylib.h | 26 +++++++---- 2 files changed, 144 insertions(+), 30 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index ea14d77d..11d0d6b9 100644 --- a/src/audio.c +++ b/src/audio.c @@ -126,9 +126,8 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; //---------------------------------------------------------------------------------- // 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(const char *fileName); // Load OGG file #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename @@ -206,20 +205,39 @@ bool IsAudioDeviceReady(void) // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- -// Load sound to memory -// NOTE: The entire file is loaded to memory to be played (no-streaming) -Sound LoadSound(char *fileName) +// Load wave data from file into RAM +Wave LoadWave(const char *fileName) { Wave wave = { 0 }; if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName); else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName); - else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); + else TraceLog(WARNING, "[%s] File extension not recognized, it can't be loaded", fileName); - Sound sound = LoadSoundFromWave(wave); + return wave; +} - // Sound is loaded, we can unload wave - UnloadWave(wave); +// Load wave data from float array data (32bit) +Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels) +{ + Wave wave; + + wave.data = data; + + WaveFormat(&wave, sampleRate, sampleSize, channels); + + return wave; +} + +// Load sound to memory +// NOTE: The entire file is loaded to memory to be played (no-streaming) +Sound LoadSound(const char *fileName) +{ + Wave wave = LoadWave(fileName); + + Sound sound = LoadSoundFromWave(wave); + + UnloadWave(wave); // Sound is loaded, we can unload wave return sound; } @@ -401,6 +419,14 @@ Sound LoadSoundFromRES(const char *rresName, int resId) return sound; } +// Unload Wave data +void UnloadWave(Wave wave) +{ + free(wave.data); + + TraceLog(INFO, "Unloaded wave data from RAM"); +} + // Unload sound void UnloadSound(Sound sound) { @@ -504,12 +530,102 @@ void SetSoundPitch(Sound sound, float pitch) alSourcef(sound.source, AL_PITCH, pitch); } +// Convert wave data to desired format +void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) +{ + if (wave->sampleSize != sampleSize) + { + float *samples = GetWaveData(*wave); //Color *pixels = GetImageData(*image); + + free(wave->data); + + //image->format = newFormat; + + if (sampleSize == 8) + { + wave->data = (unsigned char *)malloc(wave->sampleCount*sizeof(unsigned char)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((unsigned char *)wave->data)[i] = (unsigned char)((float)samples[i]); // TODO: review conversion + } + } + else if (sampleSize == 16) + { + wave->data = (short *)malloc(wave->sampleCount*sizeof(short)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((short *)wave->data)[i] = (short)((float)samples[i]); // TODO: review conversion + } + } + else if (sampleSize == 32) + { + wave->data = (float *)malloc(wave->sampleCount*sizeof(float)); + + for (int i = 0; i < wave->sampleCount; i++) + { + ((float *)wave->data)[i] = (float)samples[i]; // TODO: review conversion + } + } + else TraceLog(WARNING, "Wave formatting: Sample size not supported"); + } + + // TODO: Consider channels (mono vs stereo) +} + +// Copy a wave to a new wave +Wave WaveCopy(Wave wave) +{ + Wave newWave; + + if (wave.sampleSize == 8) newWave.data = (unsigned char *)malloc(wave.sampleCount*sizeof(unsigned char)); + else if (wave.sampleSize == 16) newWave.data = (short *)malloc(wave.sampleCount*sizeof(short)); + else if (wave.sampleSize == 32) newWave.data = (float *)malloc(wave.sampleCount*sizeof(float)); + else TraceLog(WARNING, "Wave sample size not supported for copy"); + + if (newWave.data != NULL) + { + // NOTE: Size must be provided in bytes + memcpy(newWave.data, wave.data, wave.sampleCount); + + newWave.sampleCount = wave.sampleCount; + newWave.sampleRate = wave.sampleRate; + newWave.sampleSize = wave.sampleSize; + newWave.channels = wave.channels; + } + + return newWave; +} + +// Crop a wave to defined samples range +// NOTE: Security check in case of out-of-range +void WaveCrop(Wave *wave, int initSample, int finalSample) +{ + // TODO: Crop wave to a samples range +} + +// Get samples data from wave as a floats array +float *GetWaveData(Wave wave) +{ + float *samples = (float *)malloc(wave.sampleCount*sizeof(float)); + + for (int i = 0; i < wave.sampleCount; i++) + { + if (wave.sampleSize == 8) samples[i] = (float)((unsigned char *)wave.data)[i]; // TODO: review conversion + else if (wave.sampleSize == 16) samples[i] = (float)((short *)wave.data)[i]; // TODO: review conversion + else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i]; // TODO: review conversion + } + + return samples; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Music loading and stream playing (.OGG) //---------------------------------------------------------------------------------- // Load music stream from file -Music LoadMusicStream(char *fileName) +Music LoadMusicStream(const char *fileName) { Music music = (MusicData *)malloc(sizeof(MusicData)); @@ -1013,7 +1129,7 @@ static Wave LoadWAV(const char *fileName) // Load OGG file into Wave structure // NOTE: Using stb_vorbis library -static Wave LoadOGG(char *fileName) +static Wave LoadOGG(const char *fileName) { Wave wave; @@ -1054,14 +1170,6 @@ static Wave LoadOGG(char *fileName) return wave; } -// Unload Wave data -static void UnloadWave(Wave wave) -{ - free(wave.data); - - TraceLog(INFO, "Unloaded wave data from RAM"); -} - // Some required functions for audio standalone module version #if defined(AUDIO_STANDALONE) // Get the extension for a filename diff --git a/src/raylib.h b/src/raylib.h index dff69705..ae3de038 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -484,13 +484,6 @@ typedef struct Ray { Vector3 direction; // Ray direction } Ray; -// Sound source type -typedef struct Sound { - unsigned int source; // OpenAL audio source id - unsigned int buffer; // OpenAL audio buffer id - int format; // OpenAL audio format specifier -} Sound; - // Wave type, defines audio wave data typedef struct Wave { unsigned int sampleCount; // Number of samples @@ -500,6 +493,13 @@ typedef struct Wave { void *data; // Buffer data pointer } Wave; +// Sound source type +typedef struct Sound { + unsigned int source; // OpenAL audio source id + unsigned int buffer; // OpenAL audio buffer id + int format; // OpenAL audio format specifier +} Sound; + // Music type (file streaming from memory) // NOTE: Anything longer than ~10 seconds should be streamed typedef struct MusicData *Music; @@ -909,10 +909,13 @@ RLAPI void InitAudioDevice(void); // Initial RLAPI void CloseAudioDevice(void); // Close the audio device and context (and music stream) RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully -RLAPI Sound LoadSound(char *fileName); // Load sound to memory +RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM +RLAPI Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) +RLAPI Sound LoadSound(const char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data +RLAPI void UnloadWave(Wave wave); RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound RLAPI void PauseSound(Sound sound); // Pause a sound @@ -921,8 +924,11 @@ RLAPI void StopSound(Sound sound); // Stop pl RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) - -RLAPI Music LoadMusicStream(char *fileName); // Load music stream from file +RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave +RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range +RLAPI float *GetWaveData(Wave wave); // Get samples data from wave as a floats array +RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI void UnloadMusicStream(Music music); // Unload music stream RLAPI void PlayMusicStream(Music music); // Start music playing (open stream) RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming -- cgit v1.2.3 From 0c58c1198f51c8c8799490bbb6f1b224a43278b2 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 8 Sep 2016 01:03:05 +0200 Subject: Working on new audio functions... --- src/audio.c | 32 ++++++++++++++++++++++++++------ src/raylib.h | 2 +- 2 files changed, 27 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 11d0d6b9..7ef5afe1 100644 --- a/src/audio.c +++ b/src/audio.c @@ -218,11 +218,15 @@ Wave LoadWave(const char *fileName) } // Load wave data from float array data (32bit) -Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels) +Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels) { Wave wave; wave.data = data; + wave.sampleCount = sampleCount; + wave.sampleRate = sampleRate; + wave.sampleSize = sampleSize; + wave.channels = channels; WaveFormat(&wave, sampleRate, sampleSize, channels); @@ -579,15 +583,15 @@ Wave WaveCopy(Wave wave) { Wave newWave; - if (wave.sampleSize == 8) newWave.data = (unsigned char *)malloc(wave.sampleCount*sizeof(unsigned char)); - else if (wave.sampleSize == 16) newWave.data = (short *)malloc(wave.sampleCount*sizeof(short)); - else if (wave.sampleSize == 32) newWave.data = (float *)malloc(wave.sampleCount*sizeof(float)); + if (wave.sampleSize == 8) newWave.data = (unsigned char *)malloc(wave.sampleCount*wave.channels*sizeof(unsigned char)); + else if (wave.sampleSize == 16) newWave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short)); + else if (wave.sampleSize == 32) newWave.data = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float)); else TraceLog(WARNING, "Wave sample size not supported for copy"); if (newWave.data != NULL) { // NOTE: Size must be provided in bytes - memcpy(newWave.data, wave.data, wave.sampleCount); + memcpy(newWave.data, wave.data, wave.sampleCount*wave.channels*wave.sampleSize/8); newWave.sampleCount = wave.sampleCount; newWave.sampleRate = wave.sampleRate; @@ -602,7 +606,23 @@ Wave WaveCopy(Wave wave) // NOTE: Security check in case of out-of-range void WaveCrop(Wave *wave, int initSample, int finalSample) { - // TODO: Crop wave to a samples range + if ((initSample >= 0) && (finalSample > 0) && (finalSample < wave->sampleCount)) + { + // TODO: Review cropping (it could be simplified...) + + float *samples = GetWaveData(*wave); + float *cropSamples = (float *)malloc((finalSample - initSample)*sizeof(float)); + + for (int i = initSample; i < finalSample; i++) cropSamples[i] = samples[i]; + + free(wave->data); + wave->data = cropSamples; + int sampleSize = wave->sampleSize; + wave->sampleSize = 32; + + WaveFormat(wave, wave->sampleRate, sampleSize, wave->channels); + } + else TraceLog(WARNING, "Wave crop range out of bounds"); } // Get samples data from wave as a floats array diff --git a/src/raylib.h b/src/raylib.h index ae3de038..3c815031 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -910,7 +910,7 @@ RLAPI void CloseAudioDevice(void); // Close t RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM -RLAPI Wave LoadWaveEx(float *data, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) +RLAPI Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) RLAPI Sound LoadSound(const char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) -- cgit v1.2.3 From 753b549aa5c6a010fc4de8acc2f64afdfce69cee Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 25 Sep 2016 14:28:24 +0200 Subject: Improving camera system -IN PROGRESS- --- examples/core_3d_camera_first_person.c | 9 +- examples/core_3d_camera_free.c | 5 +- examples/models_cubicmap.c | 10 +- src/camera.h | 280 ++++++++++++++------------------- src/raylib.h | 17 +- 5 files changed, 131 insertions(+), 190 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_3d_camera_first_person.c b/examples/core_3d_camera_first_person.c index 56e38a23..3675d46a 100644 --- a/examples/core_3d_camera_first_person.c +++ b/examples/core_3d_camera_first_person.c @@ -23,7 +23,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); // Define the camera to look into our 3d world (position, target, up vector) - Camera camera = {{ 0.0f, 10.0f, 10.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 60.0f }; + Camera camera = {{ 4.0f, 2.0f, 4.0f }, { 0.0f, 2.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 60.0f }; // Generates some random columns float heights[MAX_COLUMNS]; @@ -37,10 +37,7 @@ int main() colors[i] = (Color){ GetRandomValue(20, 255), GetRandomValue(10, 55), 30, 255 }; } - Vector3 playerPosition = { 4.0f, 2.0f, 4.0f }; // Define player position - - SetCameraMode(CAMERA_FIRST_PERSON); // Set a first person camera mode - SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y + SetCameraMode(camera, CAMERA_FIRST_PERSON); // Set a first person camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- @@ -50,7 +47,7 @@ int main() { // Update //---------------------------------------------------------------------------------- - UpdateCameraPlayer(&camera, &playerPosition); // Update camera and player position + UpdateCamera(&camera); // Update camera and player position //---------------------------------------------------------------------------------- // Draw diff --git a/examples/core_3d_camera_free.c b/examples/core_3d_camera_free.c index fa7ad85f..257bb789 100644 --- a/examples/core_3d_camera_free.c +++ b/examples/core_3d_camera_free.c @@ -29,10 +29,7 @@ int main() Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; - SetCameraMode(CAMERA_FREE); // Set a free 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 - SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y + SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- diff --git a/examples/models_cubicmap.c b/examples/models_cubicmap.c index 89bc75cf..df700d65 100644 --- a/examples/models_cubicmap.c +++ b/examples/models_cubicmap.c @@ -35,19 +35,17 @@ int main() UnloadImage(image); // Unload cubesmap image from RAM, already uploaded to VRAM - SetCameraMode(CAMERA_ORBITAL); // Set an orbital camera mode - SetCameraPosition(camera.position); // Set internal camera position to match our custom camera position - SetCameraFovy(camera.fovy); // Set internal camera field-of-view Y + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); // Update internal camera and our camera + UpdateCamera(&camera); // Update internal camera and our camera //---------------------------------------------------------------------------------- // Draw diff --git a/src/camera.h b/src/camera.h index cda09df4..0c7b5a13 100644 --- a/src/camera.h +++ b/src/camera.h @@ -47,7 +47,13 @@ //---------------------------------------------------------------------------------- #if defined(CAMERA_STANDALONE) // Camera modes - typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; + typedef enum { + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON + } CameraMode; // Vector2 type typedef struct Vector2 { @@ -67,6 +73,7 @@ Vector3 position; Vector3 target; Vector3 up; + float fovy; } Camera; #endif @@ -83,22 +90,16 @@ extern "C" { // Prevents name mangling of functions // Module Functions Declaration //---------------------------------------------------------------------------------- #if defined(CAMERA_STANDALONE) -void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) +void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) void UpdateCamera(Camera *camera); // Update camera (player position is ignored) -void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and player position (1st person and 3rd person cameras) - -void SetCameraPosition(Vector3 position); // Set internal camera position -void SetCameraTarget(Vector3 target); // Set internal camera target -void SetCameraFovy(float fovy); // Set internal camera field-of-view-y +// TODO: Do we really need all those functions? void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) - void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) -void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) #endif #ifdef __cplusplus @@ -133,8 +134,10 @@ void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- -// CAMERA_GENERIC -#define CAMERA_SCROLL_SENSITIVITY 1.5f +// Camera mouse movement sensitivity +#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f +#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f + // FREE_CAMERA #define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f @@ -182,20 +185,15 @@ typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_D //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Vector2 cameraAngle = { 0.0f, 0.0f }; -static float cameraTargetDistance = 5.0f; // TODO: Remove! Use predefined camera->target to camera->position distance -static Vector2 cameraMousePosition = { 0.0f, 0.0f }; -static Vector2 cameraMouseVariation = { 0.0f, 0.0f }; +static Vector2 cameraAngle = { 0.0f, 0.0f }; // TODO: Remove! Compute it in UpdateCamera() using camera->target and camera->position +static float cameraTargetDistance = 5.0f; // TODO: Remove! Compute it in UpdateCamera() using camera->target and camera->position static int cameraMoveControl[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' }; static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON static int cameraAltControlKey = 342; // raylib: KEY_LEFT_ALT static int cameraSmoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL -static int cameraMoveCounter = 0; // Used for 1st person swinging movement -static float cameraMouseSensitivity = 0.003f; // How sensible is camera movement to mouse movement - -static int cameraMode = CAMERA_CUSTOM; // Current internal camera mode +static int cameraMode = CAMERA_CUSTOM; // Current camera mode //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -219,45 +217,21 @@ static int IsKeyDown(int key) { return 0; } //---------------------------------------------------------------------------------- // Select camera mode (multiple camera modes available) -// TODO: Review hardcoded values when changing modes... -void SetCameraMode(int mode) +void SetCameraMode(Camera camera, int mode) { - if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_FREE)) - { - cameraTargetDistance = 5.0f; // TODO: Review hardcode! - cameraAngle.y = -40*DEG2RAD; - } - else if ((cameraMode == CAMERA_FIRST_PERSON) && (mode == CAMERA_ORBITAL)) - { - cameraTargetDistance = 5.0f; // TODO: Review hardcode! - cameraAngle.y = -40*DEG2RAD; - } - else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_FREE)) - { - cameraTargetDistance = 10.0f; // TODO: Review hardcode! - cameraAngle.x = 45*DEG2RAD; - cameraAngle.y = -40*DEG2RAD; - - ShowCursor(); - } - else if ((cameraMode == CAMERA_CUSTOM) && (mode == CAMERA_ORBITAL)) - { - //cameraTargetDistance = 10.0f; // TODO: Review hardcode! - cameraAngle.x = 225*DEG2RAD; - cameraAngle.y = -40*DEG2RAD; - } - - /* - Vector3 v1 = internalCamera.position; - Vector3 v2 = internalCamera.target; + // TODO: cameraTargetDistance and cameraAngle should be + // calculated using camera parameters on UpdateCamera() + + Vector3 v1 = camera.position; + Vector3 v2 = camera.target; float dx = v2.x - v1.x; float dy = v2.y - v1.y; float dz = v2.z - v1.z; cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); - */ - + cameraAngle.y = -40*DEG2RAD; + cameraMode = mode; } @@ -266,48 +240,73 @@ void SetCameraMode(int mode) // Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove() // System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor() // Keys: IsKeyDown() +// TODO: Consider touch inputs for camera! +// TODO: Port to quaternion-based camera! void UpdateCamera(Camera *camera) { + static int swingCounter = 0; // Used for 1st person swinging movement + static Vector2 previousMousePosition = { 0.0f, 0.0f }; + + // TODO: Compute cameraTargetDistance and cameraAngle + // NOTE: If cameraTargetDistance and cameraAngle change, camera->position is accordingly updated /* - if (cameraMode != CAMERA_CUSTOM) - { - - } + Vector2 cameraAngle = { 0.0f, 0.0f }; + float cameraTargetDistance = 0.0f; + + float dx = camera->target.x - camera->position.x; + float dy = camera->target.y - camera->position.y; + float dz = camera->target.z - camera->position.z; + + cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); + + Vector2 distance = { 0.0f, 0.0f }; + distance.x = sqrt(dx*dx + dy*dy); + distance.y = sqrt(dx*dx + dz*dz); + + cameraAngle.x = asin(fabs(dx)/distance.x); + cameraAngle.y = asin(fabs(dz)/distance.y); */ + // Mouse movement detection + Vector2 mousePositionDelta = { 0.0f, 0.0f }; Vector2 mousePosition = GetMousePosition(); int mouseWheelMove = GetMouseWheelMove(); int panKey = IsMouseButtonDown(cameraPanControlKey); // bool value - int screenWidth = GetScreenWidth(); - int screenHeight = GetScreenHeight(); - - if ((cameraMode != CAMERA_FREE) && (cameraMode != CAMERA_ORBITAL)) + if (cameraMode != CAMERA_CUSTOM) { - HideCursor(); + // Get screen size + int screenWidth = GetScreenWidth(); + int screenHeight = GetScreenHeight(); + + if ((cameraMode == CAMERA_FIRST_PERSON) || + (cameraMode == CAMERA_THIRD_PERSON)) + { + HideCursor(); - if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y}); - else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3}); - else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y}); - else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3}); - else + if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y}); + else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3}); + else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y}); + else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3}); + else + { + mousePositionDelta.x = mousePosition.x - previousMousePosition.x; + mousePositionDelta.y = mousePosition.y - previousMousePosition.y; + } + } + else // CAMERA_FREE, CAMERA_ORBITAL { - cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x; - cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y; + ShowCursor(); + + mousePositionDelta.x = mousePosition.x - previousMousePosition.x; + mousePositionDelta.y = mousePosition.y - previousMousePosition.y; } - } - else - { - ShowCursor(); - cameraMouseVariation.x = mousePosition.x - cameraMousePosition.x; - cameraMouseVariation.y = mousePosition.y - cameraMousePosition.y; + // NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call + // If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON + previousMousePosition = GetMousePosition(); } - // NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call - // If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON - cameraMousePosition = GetMousePosition(); - // Support for multiple automatic camera modes switch (cameraMode) { @@ -316,48 +315,48 @@ void UpdateCamera(Camera *camera) // Camera zoom if ((cameraTargetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) { - cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); if (cameraTargetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; } // Camera looking down else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; } else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; // if (camera->target.y < 0) camera->target.y = -0.001; } else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) { - cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; } // Camera looking up else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; } else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; + camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance; // if (camera->target.y > 0) camera->target.y = 0.001; } else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) { - cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; } @@ -367,15 +366,15 @@ void UpdateCamera(Camera *camera) if (IsKeyDown(cameraSmoothZoomControlKey)) { // Camera smooth zoom - if (panKey) cameraTargetDistance += (cameraMouseVariation.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); + if (panKey) cameraTargetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); } // Camera orientation calculation else if (panKey) { // Camera orientation calculation // Get the mouse sensitivity - cameraAngle.x += cameraMouseVariation.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - cameraAngle.y += cameraMouseVariation.y*-CAMERA_FREE_MOUSE_SENSITIVITY; + cameraAngle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; + cameraAngle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; // Angle clamp if (cameraAngle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; @@ -385,9 +384,9 @@ void UpdateCamera(Camera *camera) // Paning else if (panKey) { - camera->target.x += ((cameraMouseVariation.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((cameraMouseVariation.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (cameraMouseVariation.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.x += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); + camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); } // Focus to center @@ -396,10 +395,8 @@ void UpdateCamera(Camera *camera) // Camera position update camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } break; @@ -408,7 +405,7 @@ void UpdateCamera(Camera *camera) cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera zoom - cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera distance clamp if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; @@ -417,19 +414,20 @@ void UpdateCamera(Camera *camera) if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera position update + // TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target... camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } break; case CAMERA_FIRST_PERSON: case CAMERA_THIRD_PERSON: { - bool isMoving = false; + bool isMoving = false; // TODO: Really required for swinging? + // TODO: Get movement direction value [-1, 0, 1] in XZ and just multiply + // Keyboard inputs if (IsKeyDown(cameraMoveControl[MOVE_FRONT])) { @@ -469,15 +467,15 @@ void UpdateCamera(Camera *camera) if (cameraMode == CAMERA_THIRD_PERSON) { // Camera orientation calculation - cameraAngle.x += cameraMouseVariation.x*-cameraMouseSensitivity; - cameraAngle.y += cameraMouseVariation.y*-cameraMouseSensitivity; + cameraAngle.x += mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY; + cameraAngle.y += mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY; // Angle clamp if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; // Camera zoom - cameraTargetDistance -= (mouseWheelMove*CAMERA_SCROLL_SENSITIVITY); + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera distance clamp if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; @@ -489,19 +487,17 @@ void UpdateCamera(Camera *camera) // Camera position update camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } else // CAMERA_FIRST_PERSON { - if (isMoving) cameraMoveCounter++; + if (isMoving) swingCounter++; // Camera orientation calculation - cameraAngle.x += (cameraMouseVariation.x*-cameraMouseSensitivity); - cameraAngle.y += (cameraMouseVariation.y*-cameraMouseSensitivity); + cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); // Angle clamp if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; @@ -514,67 +510,27 @@ void UpdateCamera(Camera *camera) // Camera position update //camera->position.y = (playerPosition.y + PLAYER_HEIGHT*CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) - // - sin(cameraMoveCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; + // - sin(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; // TODO: Review limits, avoid moving under the ground (y = 0.0f) and over the 'eyes position', weird movement (rounding issues...) - camera->position.y -= sin(cameraMoveCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; + camera->position.y -= sin(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; - camera->up.x = sin(cameraMoveCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - camera->up.z = -sin(cameraMoveCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + camera->up.x = sin(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; + camera->up.z = -sin(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; } } break; default: break; } } -/* -// Set internal camera position -void SetCameraPosition(Vector3 position) -{ - internalCamera.position = position; - - Vector3 v1 = internalCamera.position; - Vector3 v2 = internalCamera.target; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); -} - -// Set internal camera target -void SetCameraTarget(Vector3 target) -{ - internalCamera.target = target; - - Vector3 v1 = internalCamera.position; - Vector3 v2 = internalCamera.target; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); -} -*/ // Set camera pan key to combine with mouse movement (free camera) -void SetCameraPanControl(int panKey) -{ - cameraPanControlKey = panKey; -} +void SetCameraPanControl(int panKey) { cameraPanControlKey = panKey; } // Set camera alt key to combine with mouse movement (free camera) -void SetCameraAltControl(int altKey) -{ - cameraAltControlKey = altKey; -} +void SetCameraAltControl(int altKey) { cameraAltControlKey = altKey; } // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraSmoothZoomControl(int szKey) -{ - cameraSmoothZoomControlKey = szKey; -} +void SetCameraSmoothZoomControl(int szKey) { cameraSmoothZoomControlKey = szKey; } // Set camera move controls (1st person and 3rd person cameras) void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey) @@ -587,10 +543,4 @@ void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, cameraMoveControl[MOVE_DOWN] = downKey; } -// Set camera mouse sensitivity (1st person and 3rd person cameras) -void SetCameraMouseSensitivity(float sensitivity) -{ - cameraMouseSensitivity = (sensitivity/10000.0f); -} - #endif // CAMERA_IMPLEMENTATION diff --git a/src/raylib.h b/src/raylib.h index 3c815031..66260ca2 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -559,7 +559,13 @@ typedef enum { } Gestures; // Camera system modes -typedef enum { CAMERA_CUSTOM = 0, CAMERA_FREE, CAMERA_ORBITAL, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON } CameraMode; +typedef enum { + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON +} CameraMode; // Head Mounted Display devices typedef enum { @@ -698,22 +704,15 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pin //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) //------------------------------------------------------------------------------------ -RLAPI void SetCameraMode(int mode); // Set camera mode (multiple camera modes available) +RLAPI void SetCameraMode(Camera, int mode); // Set camera mode (multiple camera modes available) RLAPI void UpdateCamera(Camera *camera); // Update camera (player position is ignored) -RLAPI void UpdateCameraPlayer(Camera *camera, Vector3 *position); // Update camera and player position (1st person and 3rd person cameras) - -RLAPI void SetCameraPosition(Vector3 position); // Set internal camera position -RLAPI void SetCameraTarget(Vector3 target); // Set internal camera target -RLAPI void SetCameraFovy(float fovy); // Set internal camera field-of-view-y RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) - RLAPI void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) -RLAPI void SetCameraMouseSensitivity(float sensitivity); // Set camera mouse sensitivity (1st person and 3rd person cameras) //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) -- cgit v1.2.3 From 978c49472a1cdffa0bf12aba1638806c65e3f8ba Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 26 Sep 2016 19:15:44 +0200 Subject: Working on camera system... --- examples/core_3d_camera_first_person.c | 2 +- examples/core_3d_camera_free.c | 4 +- examples/shaders_model_shader.c | 17 ++- src/camera.h | 215 +++++++++++++-------------------- src/raylib.h | 6 +- 5 files changed, 98 insertions(+), 146 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_3d_camera_first_person.c b/examples/core_3d_camera_first_person.c index 3675d46a..27ff5135 100644 --- a/examples/core_3d_camera_first_person.c +++ b/examples/core_3d_camera_first_person.c @@ -23,7 +23,7 @@ int main() InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d camera first person"); // Define the camera to look into our 3d world (position, target, up vector) - Camera camera = {{ 4.0f, 2.0f, 4.0f }, { 0.0f, 2.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 60.0f }; + Camera camera = {{ 4.0f, 2.0f, 4.0f }, { 0.0f, 1.8f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 60.0f }; // Generates some random columns float heights[MAX_COLUMNS]; diff --git a/examples/core_3d_camera_free.c b/examples/core_3d_camera_free.c index 257bb789..c798f225 100644 --- a/examples/core_3d_camera_free.c +++ b/examples/core_3d_camera_free.c @@ -22,7 +22,7 @@ int main() // Define the camera to look into our 3d world Camera camera; - camera.position = (Vector3){ 0.0f, 10.0f, 10.0f }; // Camera position + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y @@ -40,6 +40,8 @@ int main() // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update internal camera and our camera + + if (IsKeyDown('Z')) camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; //---------------------------------------------------------------------------------- // Draw diff --git a/examples/shaders_model_shader.c b/examples/shaders_model_shader.c index a1e00671..a5516eba 100644 --- a/examples/shaders_model_shader.c +++ b/examples/shaders_model_shader.c @@ -37,25 +37,22 @@ int main() Shader shader = LoadShader("resources/shaders/glsl330/base.vs", "resources/shaders/glsl330/grayscale.fs"); // Load model shader - dwarf.material.shader = shader; // Set shader effect to 3d model - dwarf.material.texDiffuse = texture; // Bind texture to model + dwarf.material.shader = shader; // Set shader effect to 3d model + dwarf.material.texDiffuse = texture; // Bind texture to model - Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position + Vector3 position = { 0.0f, 0.0f, 0.0f }; // Set model position - // Setup orbital camera - SetCameraMode(CAMERA_ORBITAL); // Set an 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 + SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key + while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- - UpdateCamera(&camera); // Update internal camera and our camera + UpdateCamera(&camera); // Update internal camera and our camera //---------------------------------------------------------------------------------- // Draw diff --git a/src/camera.h b/src/camera.h index 0c7b5a13..9bf9132b 100644 --- a/src/camera.h +++ b/src/camera.h @@ -11,7 +11,7 @@ * If defined, the library can be used as standalone as a camera system but some * functions must be redefined to manage inputs accordingly. * -* NOTE: Memory footprint of this library is aproximately 112 bytes +* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) * * Initial design by Marc Palau (2014) * Reviewed by Ramon Santamaria (2015-2016) @@ -91,14 +91,13 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- #if defined(CAMERA_STANDALONE) void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -void UpdateCamera(Camera *camera); // Update camera (player position is ignored) +void UpdateCamera(Camera *camera); // Update camera position for selected mode -// TODO: Do we really need all those functions? void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) void SetCameraMoveControls(int frontKey, int backKey, - int leftKey, int rightKey, + int rightKey, int leftKey, int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) #endif @@ -138,7 +137,6 @@ void SetCameraMoveControls(int frontKey, int backKey, #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f - // FREE_CAMERA #define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f #define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f @@ -171,24 +169,21 @@ void SetCameraMoveControls(int frontKey, int backKey, #define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } // PLAYER (used by camera) -#define PLAYER_WIDTH 0.4f -#define PLAYER_HEIGHT 0.9f -#define PLAYER_DEPTH 0.4f -#define PLAYER_MOVEMENT_DIVIDER 20.0f +#define PLAYER_MOVEMENT_DIVIDER 20.0f //---------------------------------------------------------------------------------- // Types and Structures Definition //---------------------------------------------------------------------------------- // Camera move modes (first person and third person cameras) -typedef enum { MOVE_FRONT = 0, MOVE_LEFT, MOVE_BACK, MOVE_RIGHT, MOVE_UP, MOVE_DOWN } CameraMove; +typedef enum { MOVE_FRONT = 0, MOVE_BACK, MOVE_RIGHT, MOVE_LEFT, MOVE_UP, MOVE_DOWN } CameraMove; //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- -static Vector2 cameraAngle = { 0.0f, 0.0f }; // TODO: Remove! Compute it in UpdateCamera() using camera->target and camera->position -static float cameraTargetDistance = 5.0f; // TODO: Remove! Compute it in UpdateCamera() using camera->target and camera->position +static Vector2 cameraAngle = { 0.0f, 0.0f }; // TODO: Remove! Compute it in UpdateCamera() +static float cameraTargetDistance = 0.0f; // TODO: Remove! Compute it in UpdateCamera() -static int cameraMoveControl[6] = { 'W', 'A', 'S', 'D', 'E', 'Q' }; +static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' }; static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON static int cameraAltControlKey = 342; // raylib: KEY_LEFT_ALT static int cameraSmoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL @@ -200,7 +195,7 @@ static int cameraMode = CAMERA_CUSTOM; // Current camera mode //---------------------------------------------------------------------------------- #if defined(CAMERA_STANDALONE) // NOTE: Camera controls depend on some raylib input functions -// TODO: Set your own input functions (used in ProcessCamera()) +// TODO: Set your own input functions (used in UpdateCamera()) static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } static void SetMousePosition(Vector2 pos) {} static int IsMouseButtonDown(int button) { return 0;} @@ -230,7 +225,18 @@ void SetCameraMode(Camera camera, int mode) float dz = v2.z - v1.z; cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); - cameraAngle.y = -40*DEG2RAD; + + Vector2 distance = { 0.0f, 0.0f }; + distance.x = sqrt(dx*dx + dy*dy); + distance.y = sqrt(dx*dx + dz*dz); + + // TODO: Review cameraAngle calculation + //cameraAngle.x = asin(fabs(dx)/distance.x); + //cameraAngle.y = -asin(fabs(dz)/distance.y); + + // NOTE: Just testing what cameraAngle means + cameraAngle.x = 90.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW) + cameraAngle.y = -80.0f*DEG2RAD; // Camera angle in plane XY (0 aligned with X, move positive CW) cameraMode = mode; } @@ -240,39 +246,33 @@ void SetCameraMode(Camera camera, int mode) // Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove() // System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor() // Keys: IsKeyDown() -// TODO: Consider touch inputs for camera! -// TODO: Port to quaternion-based camera! +// TODO: Port to quaternion-based camera void UpdateCamera(Camera *camera) { static int swingCounter = 0; // Used for 1st person swinging movement static Vector2 previousMousePosition = { 0.0f, 0.0f }; - // TODO: Compute cameraTargetDistance and cameraAngle - // NOTE: If cameraTargetDistance and cameraAngle change, camera->position is accordingly updated - /* - Vector2 cameraAngle = { 0.0f, 0.0f }; - float cameraTargetDistance = 0.0f; - - float dx = camera->target.x - camera->position.x; - float dy = camera->target.y - camera->position.y; - float dz = camera->target.z - camera->position.z; - - cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz); - - Vector2 distance = { 0.0f, 0.0f }; - distance.x = sqrt(dx*dx + dy*dy); - distance.y = sqrt(dx*dx + dz*dz); - - cameraAngle.x = asin(fabs(dx)/distance.x); - cameraAngle.y = asin(fabs(dz)/distance.y); - */ + // TODO: Compute cameraTargetDistance and cameraAngle here // Mouse movement detection Vector2 mousePositionDelta = { 0.0f, 0.0f }; Vector2 mousePosition = GetMousePosition(); int mouseWheelMove = GetMouseWheelMove(); - int panKey = IsMouseButtonDown(cameraPanControlKey); // bool value + // Keys input detection + bool panKey = IsMouseButtonDown(cameraPanControlKey); + bool altKey = IsKeyDown(cameraAltControlKey); + bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey); + + bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]), + IsKeyDown(cameraMoveControl[MOVE_BACK]), + IsKeyDown(cameraMoveControl[MOVE_RIGHT]), + IsKeyDown(cameraMoveControl[MOVE_LEFT]), + IsKeyDown(cameraMoveControl[MOVE_UP]), + IsKeyDown(cameraMoveControl[MOVE_DOWN]) }; + + // TODO: Consider touch inputs for camera + if (cameraMode != CAMERA_CUSTOM) { // Get screen size @@ -284,10 +284,10 @@ void UpdateCamera(Camera *camera) { HideCursor(); - if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y}); - else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3}); - else if (mousePosition.x > screenWidth - screenHeight/3) SetMousePosition((Vector2) { screenHeight/3, mousePosition.y}); - else if (mousePosition.y > screenHeight - screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3}); + if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y }); + else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3 }); + else if (mousePosition.x > (screenWidth - screenHeight/3)) SetMousePosition((Vector2){ screenHeight/3, mousePosition.y }); + else if (mousePosition.y > (screenHeight - screenHeight/3)) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3 }); else { mousePositionDelta.x = mousePosition.x - previousMousePosition.x; @@ -360,19 +360,15 @@ void UpdateCamera(Camera *camera) if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; } - // Inputs - if (IsKeyDown(cameraAltControlKey)) + // Input keys checks + if (altKey) { - if (IsKeyDown(cameraSmoothZoomControlKey)) + if (szoomKey) // Camera smooth zoom { - // Camera smooth zoom if (panKey) cameraTargetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); } - // Camera orientation calculation else if (panKey) { - // Camera orientation calculation - // Get the mouse sensitivity cameraAngle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; cameraAngle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; @@ -381,95 +377,50 @@ void UpdateCamera(Camera *camera) else if (cameraAngle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; } } - // Paning - else if (panKey) + else if (panKey) // Paning { camera->target.x += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER); } - // Focus to center - // TODO: Move this function out of this module? - if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; - - // Camera position update - camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; - } break; case CAMERA_ORBITAL: { - cameraAngle.x += CAMERA_ORBITAL_SPEED; - - // Camera zoom - cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); + cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle + cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom // Camera distance clamp if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Focus to center - if (IsKeyDown('Z')) camera->target = (Vector3){ 0.0f, 0.0f, 0.0f }; - - // Camera position update - // TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target... - camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; - + } break; case CAMERA_FIRST_PERSON: case CAMERA_THIRD_PERSON: { + camera->position.x += (sin(cameraAngle.x)*direction[MOVE_BACK] - + sin(cameraAngle.x)*direction[MOVE_FRONT] - + cos(cameraAngle.x)*direction[MOVE_LEFT] + + cos(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_DIVIDER; + + camera->position.y += (sin(cameraAngle.y)*direction[MOVE_FRONT] - + sin(cameraAngle.y)*direction[MOVE_BACK] + + 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_DIVIDER; + + camera->position.z += (cos(cameraAngle.x)*direction[MOVE_BACK] - + cos(cameraAngle.x)*direction[MOVE_FRONT] + + sin(cameraAngle.x)*direction[MOVE_LEFT] - + sin(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_DIVIDER; + bool isMoving = false; // TODO: Really required for swinging? - // TODO: Get movement direction value [-1, 0, 1] in XZ and just multiply + //for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; } + + // Camera orientation calculation + cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); + cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - // Keyboard inputs - if (IsKeyDown(cameraMoveControl[MOVE_FRONT])) - { - camera->position.x -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - camera->position.y += sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER; - camera->position.z -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - - isMoving = true; - } - else if (IsKeyDown(cameraMoveControl[MOVE_BACK])) - { - camera->position.x += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - camera->position.y -= sin(cameraAngle.y)/PLAYER_MOVEMENT_DIVIDER; - camera->position.z += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - - isMoving = true; - } - - if (IsKeyDown(cameraMoveControl[MOVE_LEFT])) - { - camera->position.x -= cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - camera->position.z += sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - - isMoving = true; - } - else if (IsKeyDown(cameraMoveControl[MOVE_RIGHT])) - { - camera->position.x += cos(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - camera->position.z -= sin(cameraAngle.x)/PLAYER_MOVEMENT_DIVIDER; - - isMoving = true; - } - - if (IsKeyDown(cameraMoveControl[MOVE_UP])) camera->position.y += 1.0f/PLAYER_MOVEMENT_DIVIDER; - else if (IsKeyDown(cameraMoveControl[MOVE_DOWN])) camera->position.y -= 1.0f/PLAYER_MOVEMENT_DIVIDER; - if (cameraMode == CAMERA_THIRD_PERSON) { - // Camera orientation calculation - cameraAngle.x += mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY; - cameraAngle.y += mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY; - // Angle clamp if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; @@ -482,23 +433,11 @@ void UpdateCamera(Camera *camera) // Camera is always looking at player camera->target.x = camera->position.x + CAMERA_THIRD_PERSON_OFFSET.x*cos(cameraAngle.x) + CAMERA_THIRD_PERSON_OFFSET.z*sin(cameraAngle.x); - camera->target.y = camera->position.y + PLAYER_HEIGHT*CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + CAMERA_THIRD_PERSON_OFFSET.y; + camera->target.y = camera->position.y + CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION + CAMERA_THIRD_PERSON_OFFSET.y; camera->target.z = camera->position.z + CAMERA_THIRD_PERSON_OFFSET.z*sin(cameraAngle.x) - CAMERA_THIRD_PERSON_OFFSET.x*sin(cameraAngle.x); - - // Camera position update - camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; - if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; - camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; } else // CAMERA_FIRST_PERSON { - if (isMoving) swingCounter++; - - // Camera orientation calculation - cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - // Angle clamp if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; @@ -507,6 +446,8 @@ void UpdateCamera(Camera *camera) camera->target.x = camera->position.x - sin(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; camera->target.y = camera->position.y + sin(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; camera->target.z = camera->position.z - cos(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE; + + if (isMoving) swingCounter++; // Camera position update //camera->position.y = (playerPosition.y + PLAYER_HEIGHT*CAMERA_FIRST_PERSON_HEIGHT_RELATIVE_EYES_POSITION) @@ -521,6 +462,18 @@ void UpdateCamera(Camera *camera) } break; default: break; } + + // Update camera position with changes + if ((cameraMode == CAMERA_FREE) || + (cameraMode == CAMERA_ORBITAL) || + (cameraMode == CAMERA_THIRD_PERSON)) + { + // TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target... + camera->position.x = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x; + if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; + else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y; + camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z; + } } // Set camera pan key to combine with mouse movement (free camera) @@ -533,12 +486,12 @@ void SetCameraAltControl(int altKey) { cameraAltControlKey = altKey; } void SetCameraSmoothZoomControl(int szKey) { cameraSmoothZoomControlKey = szKey; } // Set camera move controls (1st person and 3rd person cameras) -void SetCameraMoveControls(int frontKey, int backKey, int leftKey, int rightKey, int upKey, int downKey) +void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey) { cameraMoveControl[MOVE_FRONT] = frontKey; - cameraMoveControl[MOVE_LEFT] = leftKey; cameraMoveControl[MOVE_BACK] = backKey; cameraMoveControl[MOVE_RIGHT] = rightKey; + cameraMoveControl[MOVE_LEFT] = leftKey; cameraMoveControl[MOVE_UP] = upKey; cameraMoveControl[MOVE_DOWN] = downKey; } diff --git a/src/raylib.h b/src/raylib.h index 66260ca2..35319d6a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -705,14 +705,14 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pin // Camera System Functions (Module: camera) //------------------------------------------------------------------------------------ RLAPI void SetCameraMode(Camera, int mode); // Set camera mode (multiple camera modes available) -RLAPI void UpdateCamera(Camera *camera); // Update camera (player position is ignored) +RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera) RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera) RLAPI void SetCameraMoveControls(int frontKey, int backKey, - int leftKey, int rightKey, - int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) + int rightKey, int leftKey, + int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras) //------------------------------------------------------------------------------------ // Basic Shapes Drawing Functions (Module: shapes) -- cgit v1.2.3 From b082807b0b90bce07e15098d6d0a17574d100277 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 3 Oct 2016 13:29:01 +0200 Subject: Removed function: ResolveCollisionCubicmap() Function was inefficient and should be rewritten from scratch, it probably neither belongs to this module but an example... --- src/models.c | 250 ----------------------------------------------------------- src/raylib.h | 7 +- 2 files changed, 2 insertions(+), 255 deletions(-) (limited to 'src/raylib.h') diff --git a/src/models.c b/src/models.c index 8195c5f6..822da6e9 100644 --- a/src/models.c +++ b/src/models.c @@ -1548,256 +1548,6 @@ BoundingBox CalculateBoundingBox(Mesh mesh) return box; } -// Detect and resolve cubicmap collisions -// NOTE: player position (or camera) is modified inside this function -// TODO: This functions needs to be completely reviewed! -Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius) -{ - #define CUBIC_MAP_HALF_BLOCK_SIZE 0.5 - - Color *cubicmapPixels = GetImageData(cubicmap); - - // Detect the cell where the player is located - Vector3 impactDirection = { 0.0f, 0.0f, 0.0f }; - - int locationCellX = 0; - int locationCellY = 0; - - locationCellX = floor(playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE); - locationCellY = floor(playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE); - - if ((locationCellX >= 0) && (locationCellY >= 0) && (locationCellX < cubicmap.width) && (locationCellY < cubicmap.height)) - { - // Multiple Axis -------------------------------------------------------------------------------------------- - - // Axis x-, y- - if ((locationCellX > 0) && (locationCellY > 0)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX - 1)].r != 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius)) - { - playerPosition->x = locationCellX + mapPosition.x - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - playerPosition->z = locationCellY + mapPosition.z - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - - // Axis x-, y+ - if ((locationCellX > 0) && (locationCellY < cubicmap.height - 1)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX - 1)].r != 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius)) - { - playerPosition->x = locationCellX + mapPosition.x - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - playerPosition->z = locationCellY + mapPosition.z + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - - // Axis x+, y- - if ((locationCellX < cubicmap.width - 1) && (locationCellY > 0)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX + 1)].r != 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius)) - { - playerPosition->x = locationCellX + mapPosition.x + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - playerPosition->z = locationCellY + mapPosition.z - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - - // Axis x+, y+ - if ((locationCellX < cubicmap.width - 1) && (locationCellY < cubicmap.height - 1)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX + 1)].r != 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius)) - { - playerPosition->x = locationCellX + mapPosition.x + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - playerPosition->z = locationCellY + mapPosition.z + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - - // Single Axis --------------------------------------------------------------------------------------------------- - - // Axis x- - if (locationCellX > 0) - { - if (cubicmapPixels[locationCellY*cubicmap.width + (locationCellX - 1)].r != 0) - { - if ((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) - { - playerPosition->x = locationCellX + mapPosition.x - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 0.0f }; - } - } - } - // Axis x+ - if (locationCellX < cubicmap.width - 1) - { - if (cubicmapPixels[locationCellY*cubicmap.width + (locationCellX + 1)].r != 0) - { - if ((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) - { - playerPosition->x = locationCellX + mapPosition.x + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 1.0f, 0.0f, 0.0f }; - } - } - } - // Axis y- - if (locationCellY > 0) - { - if (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX)].r != 0) - { - if ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius) - { - playerPosition->z = locationCellY + mapPosition.z - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 0.0f, 0.0f, 1.0f }; - } - } - } - // Axis y+ - if (locationCellY < cubicmap.height - 1) - { - if (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX)].r != 0) - { - if ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius) - { - playerPosition->z = locationCellY + mapPosition.z + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - impactDirection = (Vector3){ 0.0f, 0.0f, 1.0f }; - } - } - } - - // Diagonals ------------------------------------------------------------------------------------------------------- - - // Axis x-, y- - if ((locationCellX > 0) && (locationCellY > 0)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX - 1)].r == 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX)].r == 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX - 1)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX) > ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY)) playerPosition->x = locationCellX + mapPosition.x - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - else playerPosition->z = locationCellY + mapPosition.z - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - - // Return ricochet - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius/3) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius/3)) - { - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - } - - // Axis x-, y+ - if ((locationCellX > 0) && (locationCellY < cubicmap.height - 1)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX - 1)].r == 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX)].r == 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX - 1)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX) > (1 - ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY))) playerPosition->x = locationCellX + mapPosition.x - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - else playerPosition->z = locationCellY + mapPosition.z + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - - // Return ricochet - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX < radius/3) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius/3)) - { - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - } - - // Axis x+, y- - if ((locationCellX < cubicmap.width - 1) && (locationCellY > 0)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX + 1)].r == 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX)].r == 0) && - (cubicmapPixels[(locationCellY - 1)*cubicmap.width + (locationCellX + 1)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX) < (1 - ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY))) playerPosition->x = locationCellX + mapPosition.x + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - else playerPosition->z = locationCellY + mapPosition.z - (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - - // Return ricochet - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius/3) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY < radius/3)) - { - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - } - - // Axis x+, y+ - if ((locationCellX < cubicmap.width - 1) && (locationCellY < cubicmap.height - 1)) - { - if ((cubicmapPixels[locationCellY*cubicmap.width + (locationCellX + 1)].r == 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX)].r == 0) && - (cubicmapPixels[(locationCellY + 1)*cubicmap.width + (locationCellX + 1)].r != 0)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius)) - { - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX) < ((playerPosition->z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY)) playerPosition->x = locationCellX + mapPosition.x + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - else playerPosition->z = locationCellY + mapPosition.z + (CUBIC_MAP_HALF_BLOCK_SIZE - radius); - - // Return ricochet - if (((playerPosition->x - mapPosition.x + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellX > 1 - radius/3) && - ((playerPosition->z - mapPosition.z + CUBIC_MAP_HALF_BLOCK_SIZE) - locationCellY > 1 - radius/3)) - { - impactDirection = (Vector3){ 1.0f, 0.0f, 1.0f }; - } - } - } - } - } - - // Floor collision - if (playerPosition->y <= radius) - { - playerPosition->y = radius + 0.01f; - impactDirection = (Vector3) { impactDirection.x, 1, impactDirection.z}; - } - // Roof collision - else if (playerPosition->y >= (1.5f - radius)) - { - playerPosition->y = (1.5f - radius) - 0.01f; - impactDirection = (Vector3) { impactDirection.x, 1, impactDirection.z}; - } - - free(cubicmapPixels); - - return impactDirection; -} - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- diff --git a/src/raylib.h b/src/raylib.h index 35319d6a..d022e8f5 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -839,9 +839,7 @@ RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load a RLAPI Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) RLAPI void UnloadModel(Model model); // Unload 3d model from memory -RLAPI Mesh GenMeshCube(float width, float height, float depth); // Generate mesh: cube - -RLAPI Material LoadMaterial(const char *fileName); // Load material data (from file) +RLAPI Material LoadMaterial(const char *fileName); // Load material data (.MTL) RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) RLAPI void UnloadMaterial(Material material); // Unload material textures from VRAM @@ -862,8 +860,7 @@ RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box -RLAPI Vector3 ResolveCollisionCubicmap(Image cubicmap, Vector3 mapPosition, Vector3 *playerPosition, float radius); // Detect collision of player radius with cubicmap - // NOTE: Return the normal vector of the impacted surface + //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 -- cgit v1.2.3 From db6538859cd2fabb44f1f29cd87f5b498ca0c2c8 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 5 Oct 2016 00:48:44 +0200 Subject: Added flag to allow resizable window --- src/core.c | 21 +++++++++++++-------- src/raylib.h | 11 ++++++----- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 63c880f1..0db1c573 100644 --- a/src/core.c +++ b/src/core.c @@ -1483,15 +1483,20 @@ static void InitGraphicsDevice(int width, int height) displayHeight = screenHeight; #endif // defined(PLATFORM_WEB) - glfwDefaultWindowHints(); // Set default windows hints + glfwDefaultWindowHints(); // Set default windows hints - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable - //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window - //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits - //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default) - //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window + if (configFlags & FLAG_RESIZABLE_WINDOW) + { + glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window + } + else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable + + //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window + //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits + //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default) + //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window //glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); // Default OpenGL API to use. Alternative: GLFW_OPENGL_ES_API - //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers + //glfwWindowHint(GLFW_AUX_BUFFERS, 0); // Number of auxiliar buffers // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version // with forward compatibility to older OpenGL versions. @@ -1499,7 +1504,7 @@ static void InitGraphicsDevice(int width, int height) if (configFlags & FLAG_MSAA_4X_HINT) { - glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 + glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 TraceLog(INFO, "Trying to enable MSAA x4"); } diff --git a/src/raylib.h b/src/raylib.h index d022e8f5..e6e510a9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -101,11 +101,12 @@ // raylib Config Flags #define FLAG_FULLSCREEN_MODE 1 -#define FLAG_SHOW_LOGO 2 -#define FLAG_SHOW_MOUSE_CURSOR 4 -#define FLAG_CENTERED_MODE 8 -#define FLAG_MSAA_4X_HINT 16 -#define FLAG_VSYNC_HINT 32 +#define FLAG_RESIZABLE_WINDOW 2 +#define FLAG_SHOW_LOGO 4 +#define FLAG_SHOW_MOUSE_CURSOR 8 +#define FLAG_CENTERED_MODE 16 +#define FLAG_MSAA_4X_HINT 32 +#define FLAG_VSYNC_HINT 64 // Keyboard Function Keys #define KEY_SPACE 32 -- cgit v1.2.3 From 3396743aba163545eb186beb47667d55d38528e9 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 9 Oct 2016 13:25:50 +0200 Subject: Corrected old issue with mouse buttons on web --- src/raylib.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index e6e510a9..3b752785 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -176,13 +176,8 @@ // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 -#if defined(PLATFORM_WEB) - #define MOUSE_RIGHT_BUTTON 2 - #define MOUSE_MIDDLE_BUTTON 1 -#else - #define MOUSE_RIGHT_BUTTON 1 - #define MOUSE_MIDDLE_BUTTON 2 -#endif +#define MOUSE_RIGHT_BUTTON 1 +#define MOUSE_MIDDLE_BUTTON 2 // Touch points registered #define MAX_TOUCH_POINTS 2 -- cgit v1.2.3 From 5af1b4a7c9119cf438e4cb5303009fbe9a25c6d7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 9 Oct 2016 20:56:58 +0200 Subject: Added simulated head-tracking on VR simulator A simple 1st person camera... still requires some work... --- examples/core_oculus_rift.c | 7 +++++-- src/raylib.h | 1 + src/rlgl.c | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/core_oculus_rift.c b/examples/core_oculus_rift.c index 88e411d4..3d8bb278 100644 --- a/examples/core_oculus_rift.c +++ b/examples/core_oculus_rift.c @@ -37,6 +37,8 @@ int main() Vector3 cubePosition = { 0.0f, 0.0f, 0.0f }; + SetCameraMode(camera, CAMERA_FIRST_PERSON); + SetTargetFPS(90); // Set our game to run at 90 frames-per-second //-------------------------------------------------------------------------------------- @@ -45,7 +47,8 @@ int main() { // Update //---------------------------------------------------------------------------------- - UpdateVrTracking(); + if (IsVrSimulator()) UpdateCamera(&camera); + else UpdateVrTracking(); if (IsKeyPressed(KEY_SPACE)) ToggleVrMode(); //---------------------------------------------------------------------------------- @@ -61,7 +64,7 @@ int main() DrawCube(cubePosition, 2.0f, 2.0f, 2.0f, RED); DrawCubeWires(cubePosition, 2.0f, 2.0f, 2.0f, MAROON); - DrawGrid(10, 1.0f); + DrawGrid(40, 1.0f); End3dMode(); diff --git a/src/raylib.h b/src/raylib.h index 3b752785..df0ee7bc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -891,6 +891,7 @@ RLAPI void DestroyLight(Light light); // Des RLAPI void InitVrDevice(int vdDevice); // Init VR device RLAPI void CloseVrDevice(void); // Close VR device RLAPI bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +RLAPI bool IsVrSimulator(void); // Detect if VR simulator is running RLAPI void UpdateVrTracking(void); // Update VR tracking (position and orientation) RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) diff --git a/src/rlgl.c b/src/rlgl.c index 244de52c..702edb18 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2710,6 +2710,12 @@ bool IsVrDeviceReady(void) return (vrDeviceReady || vrSimulator) && vrEnabled; } +// Detect if VR simulator is running +bool IsVrSimulator(void) +{ + return vrSimulator; +} + // Enable/Disable VR experience (device or simulator) void ToggleVrMode(void) { -- cgit v1.2.3 From 5fecf5c088122dc409bd209b08627e671cbdc175 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 10 Oct 2016 19:42:59 +0200 Subject: Review UpdateVrTracking() and rlglLoadRenderTexture() --- src/raylib.h | 2 +- src/rlgl.c | 17 +++++++++-------- src/rlgl.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index df0ee7bc..9bc89130 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -892,7 +892,7 @@ RLAPI void InitVrDevice(int vdDevice); // Init VR device RLAPI void CloseVrDevice(void); // Close VR device RLAPI bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready RLAPI bool IsVrSimulator(void); // Detect if VR simulator is running -RLAPI void UpdateVrTracking(void); // Update VR tracking (position and orientation) +RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) //------------------------------------------------------------------------------------ diff --git a/src/rlgl.c b/src/rlgl.c index 702edb18..e8607925 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1522,7 +1522,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) target.texture.id = 0; target.texture.width = width; target.texture.height = height; - target.texture.format = UNCOMPRESSED_R8G8B8; + target.texture.format = UNCOMPRESSED_R8G8B8A8; target.texture.mipmaps = 1; target.depth.id = 0; @@ -1539,7 +1539,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); #if defined(GRAPHICS_API_OPENGL_33) @@ -2734,16 +2734,17 @@ void ToggleVrMode(void) #endif } -// Update VR tracking (position and orientation) -void UpdateVrTracking(void) +// Update VR tracking (position and orientation) and camera +void UpdateVrTracking(Camera *camera) { #if defined(RLGL_OCULUS_SUPPORT) - if (vrDeviceReady) UpdateOculusTracking(); - else -#endif + if (vrDeviceReady) { - // TODO: Use alternative inputs (mouse, keyboard) to simulate tracking data (eyes position/orientation) + UpdateOculusTracking(); + + // TODO: Update camera data (position, target, up) with tracking data } +#endif } // Begin Oculus drawing configuration diff --git a/src/rlgl.h b/src/rlgl.h index 5fc9f8b9..3a47b4c8 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -375,7 +375,7 @@ float *MatrixToFloat(Matrix mat); void InitVrDevice(int vrDevice); // Init VR device void CloseVrDevice(void); // Close VR device bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready -void UpdateVrTracking(void); // Update VR tracking (position and orientation) +void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) // Oculus Rift API for direct access the device (no simulator) -- cgit v1.2.3 From 76a67a149e07225c66275f8657a5928e03234d90 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 12 Oct 2016 10:27:14 +0200 Subject: Added new wave functions to lua binding --- src/raylib.h | 2 +- src/rlua.h | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 9bc89130..4a807d58 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -908,7 +908,7 @@ RLAPI Sound LoadSound(const char *fileName); // Load so RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data -RLAPI void UnloadWave(Wave wave); +RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound RLAPI void PauseSound(Sound sound); // Pause a sound diff --git a/src/rlua.h b/src/rlua.h index 1c8c7b38..97d22922 100644 --- a/src/rlua.h +++ b/src/rlua.h @@ -2824,6 +2824,28 @@ int lua_IsAudioDeviceReady(lua_State* L) return 1; } +int lua_LoadWave(lua_State* L) +{ + const char * arg1 = LuaGetArgument_string(L, 1); + Wave result = LoadWave((char *)arg1); + LuaPush_Wave(L, result); + return 1; +} + +int lua_LoadWaveEx(lua_State* L) +{ + // TODO: Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); + + int arg1 = 0; + int arg2 = LuaGetArgument_int(L, 2); + int arg3 = LuaGetArgument_int(L, 3); + int arg4 = LuaGetArgument_int(L, 4); + int arg5 = LuaGetArgument_int(L, 5); + Wave result = LoadWaveEx(arg1, arg2, arg3, arg4, arg5); + LuaPush_Wave(L, result); + return 1; +} + int lua_LoadSound(lua_State* L) { const char * arg1 = LuaGetArgument_string(L, 1); @@ -2849,6 +2871,22 @@ int lua_LoadSoundFromRES(lua_State* L) return 1; } +int lua_UpdateSound(lua_State* L) +{ + Sound arg1 = LuaGetArgument_Sound(L, 1); + const char * arg2 = LuaGetArgument_string(L, 2); + int * arg3 = LuaGetArgument_int(L, 3); + UpdateSound(arg1, arg2, arg3); + return 0; +} + +int lua_UnloadWave(lua_State* L) +{ + Wave arg1 = LuaGetArgument_Wave(L, 1); + UnloadWave(arg1); + return 0; +} + int lua_UnloadSound(lua_State* L) { Sound arg1 = LuaGetArgument_Sound(L, 1); @@ -2908,6 +2946,43 @@ int lua_SetSoundPitch(lua_State* L) return 0; } +int lua_WaveFormat(lua_State* L) +{ + Wave arg1 = LuaGetArgument_Wave(L, 1); + int arg2 = LuaGetArgument_int(L, 2); + int arg3 = LuaGetArgument_int(L, 3); + int arg4 = LuaGetArgument_int(L, 4); + WaveFormat(arg1, arg2, arg3, arg4); + return 0; +} + +int lua_LoadMusicStream(lua_State* L) +{ + Wave arg1 = LuaGetArgument_Wave(L, 1); + Wave result = WaveCopy(arg1); + LuaPush_Wave(L, result); + return 1; +} + +int lua_WaveCrop(lua_State* L) +{ + Wave arg1 = LuaGetArgument_Wave(L, 1); + int arg2 = LuaGetArgument_int(L, 2); + int arg3 = LuaGetArgument_int(L, 3); + WaveCrop(arg1, arg2, arg3); + return 0; +} + +int lua_GetWaveData(lua_State* L) +{ + // TODO: float *GetWaveData(Wave wave); + + Wave arg1 = LuaGetArgument_Wave(L, 1); + float result = GetWaveData(arg1); + LuaPush_float(L, result); + return 1; +} + int lua_LoadMusicStream(lua_State* L) { const char * arg1 = LuaGetArgument_string(L, 1); @@ -3799,9 +3874,13 @@ static luaL_Reg raylib_functions[] = { REG(InitAudioDevice) REG(CloseAudioDevice) REG(IsAudioDeviceReady) + REG(LoadWave) + REG(LoadWaveEx) REG(LoadSound) REG(LoadSoundFromWave) REG(LoadSoundFromRES) + REG(UpdateSound) + REG(UnloadWave) REG(UnloadSound) REG(PlaySound) REG(PauseSound) @@ -3810,6 +3889,10 @@ static luaL_Reg raylib_functions[] = { REG(IsSoundPlaying) REG(SetSoundVolume) REG(SetSoundPitch) + REG(WaveFormat) + REG(WaveCopy) + REG(WaveCrop) + REG(GetWaveData) REG(LoadMusicStream) REG(UnloadMusicStream) -- cgit v1.2.3 From b3bc4b21d17f7e434e21684ca6a2c111ea150fbb Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 14 Oct 2016 00:47:43 +0200 Subject: Working on better gamepad support --- src/core.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/raylib.h | 1 + 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index a35dbae0..b07179d4 100644 --- a/src/core.c +++ b/src/core.c @@ -1166,6 +1166,17 @@ bool IsGamepadAvailable(int gamepad) return result; } +// Return gamepad internal name id +const char *GetGamepadName(int gamepad) +{ +#if defined(PLATFORM_DESKTOP) + if (glfwJoystickPresent(gamepad) == 1) return glfwGetJoystickName(gamepad); + else return NULL; +#else + return NULL; +#endif +} + // Return axis movement vector for a gamepad float GetGamepadAxisMovement(int gamepad, int axis) { @@ -1192,7 +1203,11 @@ float GetGamepadAxisMovement(int gamepad, int axis) bool IsGamepadButtonPressed(int gamepad, int button) { bool pressed = false; + + if ((currentGamepadState[button] != previousGamepadState[button]) && (currentGamepadState[button] == 1)) pressed = true; + else pressed = false; + /* currentGamepadState[button] = IsGamepadButtonDown(gamepad, button); if (currentGamepadState[button] != previousGamepadState[button]) @@ -1201,6 +1216,7 @@ bool IsGamepadButtonPressed(int gamepad, int button) previousGamepadState[button] = currentGamepadState[button]; } else pressed = false; + */ return pressed; } @@ -1222,6 +1238,8 @@ bool IsGamepadButtonDown(int gamepad, int button) if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true; else result = false; + + //result = currentGamepadState[button]; #endif return result; @@ -1233,14 +1251,19 @@ bool IsGamepadButtonReleased(int gamepad, int button) bool released = false; currentGamepadState[button] = IsGamepadButtonUp(gamepad, button); + + if ((currentGamepadState[button] != previousGamepadState[button]) && (currentGamepadState[button] == 0)) released = true; + else released = false; + /* if (currentGamepadState[button] != previousGamepadState[button]) { if (currentGamepadState[button]) released = true; previousGamepadState[button] = currentGamepadState[button]; } else released = false; - + */ + return released; } @@ -1984,8 +2007,26 @@ static void PollInputEvents(void) previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; + + // Register previous gamepad states + for (int i = 0; i < 32; i++) previousGamepadState[i] = currentGamepadState[i]; + + // Get current gamepad state (no callback) + if (glfwJoystickPresent(GAMEPAD_PLAYER1)) + { + const unsigned char *buttons; + int buttonsCount; + + buttons = glfwGetJoystickButtons(GAMEPAD_PLAYER1, &buttonsCount); + + for (int i = 0; (buttons != NULL) && (buttonsCount < 32) && (i < buttonsCount); i++) + { + if (buttons[i] == GLFW_PRESS) currentGamepadState[i] = true; + else currentGamepadState[i] = false; + } + } - glfwPollEvents(); // Register keyboard/mouse events... and window events! + glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! #endif #if defined(PLATFORM_ANDROID) diff --git a/src/raylib.h b/src/raylib.h index 9bc89130..0d6f4326 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -657,6 +657,7 @@ RLAPI int GetKeyPressed(void); // Get latest key RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed -- cgit v1.2.3 From 98d7a10c087f14b55e2dfb5f07eb6f95899ba959 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 14 Oct 2016 11:14:41 +0200 Subject: Improved gamepad system - Support up to 4 gamepads - Unified system between platforms - Corrected some bugs --- src/core.c | 169 +++++++++++++++++++++++------------------------------------ src/raylib.h | 4 +- 2 files changed, 68 insertions(+), 105 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index b07179d4..78629e8f 100644 --- a/src/core.c +++ b/src/core.c @@ -128,12 +128,12 @@ //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN" #define MOUSE_SENSITIVITY 0.8f - - #define MAX_GAMEPADS 2 // Max number of gamepads supported - #define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) - #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #endif +#define MAX_GAMEPADS 4 // Max number of gamepads supported +#define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) +#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) + #define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) //---------------------------------------------------------------------------------- @@ -174,15 +174,11 @@ static int defaultKeyboardMode; // Used to store default keyboar // Mouse input variables static int mouseStream = -1; // Mouse device file descriptor static bool mouseReady = false; // Flag to know if mouse is ready -pthread_t mouseThreadId; // Mouse reading thread id +static pthread_t mouseThreadId; // Mouse reading thread id // Gamepad input variables -static int gamepadStream[MAX_GAMEPADS] = { -1 }; // Gamepad device file descriptor (two gamepads supported) -static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready (two gamepads supported) -pthread_t gamepadThreadId; // Gamepad reading thread id - -int gamepadButtons[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS]; // Gamepad buttons state -float gamepadAxisValues[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state +static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor +static pthread_t gamepadThreadId; // Gamepad reading thread id #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -207,18 +203,23 @@ static Matrix downscaleView; // Matrix to downscale view (in case static const char *windowTitle; // Window text title... static bool cursorOnScreen = false; // Tracks if cursor is inside client area -static char previousKeyState[512] = { 0 }; // Required to check if key pressed/released once -static char currentKeyState[512] = { 0 }; // Required to check if key pressed/released once +// Register keyboard states +static char previousKeyState[512] = { 0 }; // Registers previous frame key state +static char currentKeyState[512] = { 0 }; // Registers current frame key state -static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once -static char currentGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once +// Register mouse states +static char previousMouseState[3] = { 0 }; // Registers previous mouse button state +static char currentMouseState[3] = { 0 }; // Registers current mouse button state +static int previousMouseWheelY = 0; // Registers previous mouse wheel variation +static int currentMouseWheelY = 0; // Registers current mouse wheel variation -static char previousMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once -static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pressed/released once - -static int previousMouseWheelY = 0; // Required to track mouse wheel variation -static int currentMouseWheelY = 0; // Required to track mouse wheel variation +// Register gamepads states +static bool gamepadReady[MAX_GAMEPADS] = { false }; // Flag to know if gamepad is ready +static float gamepadAxisState[MAX_GAMEPADS][MAX_GAMEPAD_AXIS]; // Gamepad axis state +static char previousGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; +static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; +// Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) static int lastKeyPressed = -1; // Register last key pressed @@ -1157,11 +1158,7 @@ bool IsGamepadAvailable(int gamepad) { bool result = false; -#if defined(PLATFORM_RPI) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; -#else - if (glfwJoystickPresent(gamepad) == 1) result = true; -#endif return result; } @@ -1182,19 +1179,10 @@ float GetGamepadAxisMovement(int gamepad, int axis) { float value = 0; -#if defined(PLATFORM_RPI) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) { - if (axis < MAX_GAMEPAD_AXIS) value = gamepadAxisValues[gamepad][axis]; + if (axis < MAX_GAMEPAD_AXIS) value = gamepadAxisState[gamepad][axis]; } -#else - const float *axes; - int axisCount = 0; - - axes = glfwGetJoystickAxes(gamepad, &axisCount); - - if (axis < axisCount) value = axes[axis]; -#endif return value; } @@ -1204,19 +1192,9 @@ bool IsGamepadButtonPressed(int gamepad, int button) { bool pressed = false; - if ((currentGamepadState[button] != previousGamepadState[button]) && (currentGamepadState[button] == 1)) pressed = true; - else pressed = false; - - /* - currentGamepadState[button] = IsGamepadButtonDown(gamepad, button); - - if (currentGamepadState[button] != previousGamepadState[button]) - { - if (currentGamepadState[button]) pressed = true; - previousGamepadState[button] = currentGamepadState[button]; - } - else pressed = false; - */ + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && + (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && + (currentGamepadState[gamepad][button] == 1)) pressed = true; return pressed; } @@ -1226,21 +1204,8 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; -#if defined(PLATFORM_RPI) - // Get gamepad buttons information - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (gamepadButtons[gamepad][button] == 1)) result = true; - else result = false; -#else - const unsigned char *buttons; - int buttonsCount; - - buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - - if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true; - else result = false; - - //result = currentGamepadState[button]; -#endif + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && + (currentGamepadState[gamepad][button] == 1)) result = true; return result; } @@ -1249,21 +1214,11 @@ bool IsGamepadButtonDown(int gamepad, int button) bool IsGamepadButtonReleased(int gamepad, int button) { bool released = false; - - currentGamepadState[button] = IsGamepadButtonUp(gamepad, button); - if ((currentGamepadState[button] != previousGamepadState[button]) && (currentGamepadState[button] == 0)) released = true; - else released = false; + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && + (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && + (currentGamepadState[gamepad][button] == 0)) released = true; - /* - if (currentGamepadState[button] != previousGamepadState[button]) - { - if (currentGamepadState[button]) released = true; - previousGamepadState[button] = currentGamepadState[button]; - } - else released = false; - */ - return released; } @@ -1272,19 +1227,8 @@ bool IsGamepadButtonUp(int gamepad, int button) { bool result = false; -#if defined(PLATFORM_RPI) - // Get gamepad buttons information - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (gamepadButtons[gamepad][button] == 0)) result = true; - else result = false; -#else - const unsigned char *buttons; - int buttonsCount; - - buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); - - if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) result = true; - else result = false; -#endif + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && + (currentGamepadState[gamepad][button] == 0)) result = true; return result; } @@ -2008,22 +1952,41 @@ static void PollInputEvents(void) previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; - // Register previous gamepad states - for (int i = 0; i < 32; i++) previousGamepadState[i] = currentGamepadState[i]; - - // Get current gamepad state (no callback) - if (glfwJoystickPresent(GAMEPAD_PLAYER1)) + // Register gamepads buttons events + for (int i = 0; i < MAX_GAMEPADS; i++) { - const unsigned char *buttons; - int buttonsCount; - - buttons = glfwGetJoystickButtons(GAMEPAD_PLAYER1, &buttonsCount); - - for (int i = 0; (buttons != NULL) && (buttonsCount < 32) && (i < buttonsCount); i++) + if (glfwJoystickPresent(i)) // Check if gamepad is available { - if (buttons[i] == GLFW_PRESS) currentGamepadState[i] = true; - else currentGamepadState[i] = false; + gamepadReady[i] = true; + + // Register previous gamepad states + for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; + + // Get current gamepad state + // NOTE: There is no callback available, so we get it manually + const unsigned char *buttons; + int buttonsCount; + + buttons = glfwGetJoystickButtons(i, &buttonsCount); + + for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) + { + if (buttons[i] == GLFW_PRESS) currentGamepadState[i][k] = 1; + else currentGamepadState[i][k] = 0; + } + + // Get current axis state + const float *axes; + int axisCount = 0; + + axes = glfwGetJoystickAxes(i, &axisCount); + + for (int k = 0; (axes != NULL) && (k < axisCount) && (k < MAX_GAMEPAD_AXIS); k++) + { + gamepadAxisState[i][k] = axes[k]; + } } + else gamepadReady[i] = false; } glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! @@ -2854,7 +2817,7 @@ static void *GamepadThread(void *arg) if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS) { // 1 - button pressed, 0 - button released - gamepadButtons[i][gamepadEvent.number] = (int)gamepadEvent.value; + currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; } } else if (gamepadEvent.type == JS_EVENT_AXIS) @@ -2864,7 +2827,7 @@ static void *GamepadThread(void *arg) if (gamepadEvent.number < MAX_GAMEPAD_AXIS) { // NOTE: Scaling of gamepadEvent.value to get values between -1..1 - gamepadAxisValues[i][gamepadEvent.number] = (float)gamepadEvent.value/32768; + gamepadAxisState[i][gamepadEvent.number] = (float)gamepadEvent.value/32768; } } } diff --git a/src/raylib.h b/src/raylib.h index 9ca77d69..5834d1c9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -185,8 +185,8 @@ // Gamepad Number #define GAMEPAD_PLAYER1 0 #define GAMEPAD_PLAYER2 1 -#define GAMEPAD_PLAYER3 2 // Not supported -#define GAMEPAD_PLAYER4 3 // Not supported +#define GAMEPAD_PLAYER3 2 +#define GAMEPAD_PLAYER4 3 // Gamepad Buttons -- cgit v1.2.3 From 8f60996b6482246cb8f66d0ba8f6aa1604e6dd01 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 17 Oct 2016 00:03:38 +0200 Subject: Corrected some warnings --- src/audio.c | 6 +-- src/models.c | 122 ++++++++++++++++++++++++++++----------------------------- src/raylib.h | 2 +- src/rlgl.c | 10 ++--- src/shapes.c | 22 +++++------ src/textures.c | 12 +++--- 6 files changed, 87 insertions(+), 87 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 9d2eeb47..3684e10a 100644 --- a/src/audio.c +++ b/src/audio.c @@ -706,7 +706,7 @@ Music LoadMusicStream(const char *fileName) else { music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels); - music->totalSamples = music->ctxFlac->totalSampleCount; + music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; music->loop = true; // We loop by default @@ -853,7 +853,7 @@ void UpdateMusicStream(Music music) int pcmi[AUDIO_BUFFER_SIZE]; // NOTE: Returns the number of samples to process (should be the same as numSamples) - int numSamplesFlac = drflac_read_s32(music->ctxFlac, numSamples, pcmi); + unsigned int numSamplesFlac = (unsigned int)drflac_read_s32(music->ctxFlac, numSamples, pcmi); UpdateAudioStream(music->stream, pcmi, numSamplesFlac*music->stream.channels); music->samplesLeft -= (numSamples*music->stream.channels); @@ -1237,7 +1237,7 @@ static Wave LoadOGG(const char *fileName) if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); - int totalSamples = totalSeconds*info.sample_rate*info.channels; + int totalSamples = (int)(totalSeconds*info.sample_rate*info.channels); wave.sampleCount = totalSamples; wave.data = (short *)malloc(totalSamplesLength*sizeof(short)); diff --git a/src/models.c b/src/models.c index 822da6e9..55ac7893 100644 --- a/src/models.c +++ b/src/models.c @@ -87,8 +87,8 @@ void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rot { rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex3f(sin(DEG2RAD*i)*radius, cos(DEG2RAD*i)*radius, 0.0f); - rlVertex3f(sin(DEG2RAD*(i + 10))*radius, cos(DEG2RAD*(i + 10))*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius, 0.0f); + rlVertex3f(sinf(DEG2RAD*(i + 10))*radius, cosf(DEG2RAD*(i + 10))*radius, 0.0f); } rlEnd(); rlPopMatrix(); @@ -325,25 +325,25 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color { 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)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); } } rlEnd(); @@ -364,26 +364,26 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col { 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)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*((j+1)*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*((j+1)*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*(i+1))), - cos(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cos(DEG2RAD*(j*360/slices))); - rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i))*sin(DEG2RAD*(j*360/slices)), - sin(DEG2RAD*(270+(180/(rings + 1))*i)), - cos(DEG2RAD*(270+(180/(rings + 1))*i))*cos(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), + cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); + rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), + sinf(DEG2RAD*(270+(180/(rings + 1))*i)), + cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); } } rlEnd(); @@ -407,21 +407,21 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h // Draw Body ------------------------------------------------------------------------------------- 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 - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); //Bottom Right + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); //Top Left - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); //Bottom Left - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); //Top Right + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); //Top Left + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); //Bottom Left + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); //Top Right } // Draw Cap -------------------------------------------------------------------------------------- for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); } } else @@ -430,8 +430,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h for (int i = 0; i < 360; i += 360/sides) { rlVertex3f(0, height, 0); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); } } @@ -439,8 +439,8 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h 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); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); @@ -460,17 +460,17 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl 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); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusBottom, 0, cos(DEG2RAD*(i+360/sides))*radiusBottom); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusBottom, 0, cosf(DEG2RAD*(i+360/sides))*radiusBottom); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*(i+360/sides))*radiusTop, height, cos(DEG2RAD*(i+360/sides))*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*(i+360/sides))*radiusTop, height, cosf(DEG2RAD*(i+360/sides))*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusTop, height, cos(DEG2RAD*i)*radiusTop); - rlVertex3f(sin(DEG2RAD*i)*radiusBottom, 0, cos(DEG2RAD*i)*radiusBottom); + rlVertex3f(sinf(DEG2RAD*i)*radiusTop, height, cosf(DEG2RAD*i)*radiusTop); + rlVertex3f(sinf(DEG2RAD*i)*radiusBottom, 0, cosf(DEG2RAD*i)*radiusBottom); } rlEnd(); rlPopMatrix(); diff --git a/src/raylib.h b/src/raylib.h index 5834d1c9..1433268b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -93,7 +93,7 @@ // Some basic Defines //---------------------------------------------------------------------------------- #ifndef PI - #define PI 3.14159265358979323846 + #define PI 3.14159265358979323846f #endif #define DEG2RAD (PI/180.0f) diff --git a/src/rlgl.c b/src/rlgl.c index e8607925..a754678c 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2653,7 +2653,7 @@ void InitVrDevice(int vrDevice) hmd.hResolution = 2160; // HMD horizontal resolution in pixels hmd.vResolution = 1200; // HMD vertical resolution in pixels hmd.hScreenSize = 0.133793f; // HMD horizontal size in meters - hmd.vScreenSize = 0.0669; // HMD vertical size in meters + hmd.vScreenSize = 0.0669f; // HMD vertical size in meters hmd.vScreenCenter = 0.04678f; // HMD screen center in meters hmd.eyeToScreenDistance = 0.041f; // HMD distance between eye and display in meters hmd.lensSeparationDistance = 0.07f; // HMD lens separation distance in meters @@ -3786,8 +3786,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) // Compute lens parameters float lensShift = (hmd.hScreenSize*0.25f - hmd.lensSeparationDistance*0.5f)/hmd.hScreenSize; - float leftLensCenter[2] = { 0.25 + lensShift, 0.5f }; - float rightLensCenter[2] = { 0.75 - lensShift, 0.5f }; + float leftLensCenter[2] = { 0.25f + lensShift, 0.5f }; + float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; float leftScreenCenter[2] = { 0.25f, 0.5f }; float rightScreenCenter[2] = { 0.75f, 0.5f }; @@ -3804,8 +3804,8 @@ static void SetStereoConfig(VrDeviceInfo hmd) float normScreenWidth = 0.5f; float normScreenHeight = 1.0f; - float scaleIn[2] = { 2/normScreenWidth, 2/normScreenHeight/aspect }; - float scale[2] = { normScreenWidth*0.5/distortionScale, normScreenHeight*0.5*aspect/distortionScale }; + float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; + float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; TraceLog(DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); TraceLog(DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); diff --git a/src/shapes.c b/src/shapes.c index 9fcbeff7..62076b2c 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -71,7 +71,7 @@ void DrawPixelV(Vector2 position, Color color) rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(position.x, position.y); - rlVertex2i(position.x + 1, position.y + 1); + rlVertex2f(position.x + 1.0f, position.y + 1.0f); rlEnd(); } @@ -98,7 +98,7 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color) // Draw a color-filled circle void DrawCircle(int centerX, int centerY, float radius, Color color) { - DrawCircleV((Vector2){ centerX, centerY }, radius, color); + DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color); } // Draw a gradient-filled circle @@ -111,9 +111,9 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(centerX, centerY); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlColor4ub(color2.r, color2.g, color2.b, color2.a); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -130,8 +130,8 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } @@ -145,9 +145,9 @@ void DrawCircleV(Vector2 center, float radius, Color color) rlColor4ub(color.r, color.g, color.b, color.a); rlVertex2f(center.x, center.y); - rlVertex2f(center.x + sin(DEG2RAD*i)*radius, center.y + cos(DEG2RAD*i)*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 10))*radius, center.y + cos(DEG2RAD*(i + 10))*radius); - rlVertex2f(center.x + sin(DEG2RAD*(i + 20))*radius, center.y + cos(DEG2RAD*(i + 20))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius); + rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius); } rlEnd(); @@ -164,8 +164,8 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) for (int i = 0; i < 360; i += 10) { - rlVertex2f(centerX + sin(DEG2RAD*i)*radius, centerY + cos(DEG2RAD*i)*radius); - rlVertex2f(centerX + sin(DEG2RAD*(i + 10))*radius, centerY + cos(DEG2RAD*(i + 10))*radius); + rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); + rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); } rlEnd(); } diff --git a/src/textures.c b/src/textures.c index fd5bdd80..323c0a8a 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1118,7 +1118,7 @@ Image ImageText(const char *text, int fontSize, Color color) if (fontSize < defaultFontSize) fontSize = defaultFontSize; int spacing = fontSize/defaultFontSize; - Image imText = ImageTextEx(GetDefaultFont(), text, fontSize, spacing, color); + Image imText = ImageTextEx(GetDefaultFont(), text, (float)fontSize, spacing, color); return imText; } @@ -1183,7 +1183,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color) { // NOTE: For default font, sapcing is set to desired font size / default font size (10) - ImageDrawTextEx(dst, position, GetDefaultFont(), text, fontSize, fontSize/10, color); + ImageDrawTextEx(dst, position, GetDefaultFont(), text, (float)fontSize, fontSize/10, color); } // Draw text (custom sprite font) within an image (destination) @@ -1317,7 +1317,7 @@ void ImageColorContrast(Image *image, float contrast) if (contrast < -100) contrast = -100; if (contrast > 100) contrast = 100; - contrast = (100.0 + contrast)/100.0; + contrast = (100.0f + contrast)/100.0f; contrast *= contrast; Color *pixels = GetImageData(*image); @@ -1326,7 +1326,7 @@ void ImageColorContrast(Image *image, float contrast) { for (int x = 0; x < image->width; x++) { - float pR = (float)pixels[y*image->width + x].r/255.0; + float pR = (float)pixels[y*image->width + x].r/255.0f; pR -= 0.5; pR *= contrast; pR += 0.5; @@ -1334,7 +1334,7 @@ void ImageColorContrast(Image *image, float contrast) if (pR < 0) pR = 0; if (pR > 255) pR = 255; - float pG = (float)pixels[y*image->width + x].g/255.0; + float pG = (float)pixels[y*image->width + x].g/255.0f; pG -= 0.5; pG *= contrast; pG += 0.5; @@ -1342,7 +1342,7 @@ void ImageColorContrast(Image *image, float contrast) if (pG < 0) pG = 0; if (pG > 255) pG = 255; - float pB = (float)pixels[y*image->width + x].b/255.0; + float pB = (float)pixels[y*image->width + x].b/255.0f; pB -= 0.5; pB *= contrast; pB += 0.5; -- cgit v1.2.3 From 0ce7f0c4094fa8a6cc74c410aee37413034cb0b9 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 17 Oct 2016 18:18:13 +0200 Subject: Some work on multiple inputs... - Corrected bug and tested new gamepad system - Reviewed Android key inputs system, unified with desktop - Reorganize mouse functions on core --- src/core.c | 199 ++++++++++++++++++++++++++++------------------------------- src/raylib.h | 36 +++++------ 2 files changed, 110 insertions(+), 125 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 3bd85fdd..d044a66e 100644 --- a/src/core.c +++ b/src/core.c @@ -131,7 +131,7 @@ #endif #define MAX_GAMEPADS 4 // Max number of gamepads supported -#define MAX_GAMEPAD_BUTTONS 11 // Max bumber of buttons supported (per gamepad) +#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) #define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) @@ -158,9 +158,6 @@ static const char *internalDataPath; // Android internal data path to static bool windowReady = false; // Used to detect display initialization static bool appEnabled = true; // Used to detec if app is active static bool contextRebindRequired = false; // Used to know context rebind required - -static int previousButtonState[128] = { 1 }; // Required to check if button pressed/released once -static int currentButtonState[128] = { 1 }; // Required to check if button pressed/released once #endif #if defined(PLATFORM_RPI) @@ -203,10 +200,6 @@ static Matrix downscaleView; // Matrix to downscale view (in case static const char *windowTitle; // Window text title... static bool cursorOnScreen = false; // Tracks if cursor is inside client area -// Register keyboard states -static char previousKeyState[512] = { 0 }; // Registers previous frame key state -static char currentKeyState[512] = { 0 }; // Registers current frame key state - // Register mouse states static char previousMouseState[3] = { 0 }; // Registers previous mouse button state static char currentMouseState[3] = { 0 }; // Registers current mouse button state @@ -221,11 +214,16 @@ static char currentGamepadState[MAX_GAMEPADS][MAX_GAMEPAD_BUTTONS] = { 0 }; // Keyboard configuration static int exitKey = KEY_ESCAPE; // Default exit key (ESC) -static int lastKeyPressed = -1; // Register last key pressed static bool cursorHidden; // Track if cursor is hidden #endif +// Register keyboard states +static char previousKeyState[512] = { 0 }; // Registers previous frame key state +static char currentKeyState[512] = { 0 }; // Registers current frame key state + +static int lastKeyPressed = -1; // Register last key pressed + static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -526,6 +524,63 @@ int GetScreenHeight(void) return screenHeight; } +// Show mouse cursor +void ShowCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + #endif +#endif + cursorHidden = false; +} + +// Hide mouse cursor +void HideCursor() +{ +#if defined(PLATFORM_DESKTOP) + #ifdef __linux + XColor Col; + const char Nil[] = {0}; + + Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); + Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); + + XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); + XFreeCursor(glfwGetX11Display(), Cur); + #else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + #endif +#endif + cursorHidden = true; +} + +// Check if mouse cursor is hidden +bool IsCursorHidden() +{ + return cursorHidden; +} + +// Enable mouse cursor +void EnableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif + cursorHidden = false; +} + +// Disable mouse cursor +void DisableCursor() +{ +#if defined(PLATFORM_DESKTOP) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif + cursorHidden = true; +} + // Sets Background Color void ClearBackground(Color color) { @@ -1050,8 +1105,13 @@ bool IsKeyPressed(int key) { bool pressed = false; +#if defined(PLATFORM_ANDROID) + if ((currentButtonState[key] != previousButtonState[key]) && (currentButtonState[key] == 0)) pressed = true; + else pressed = false; +#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true; else pressed = false; +#endif return pressed; } @@ -1067,9 +1127,14 @@ bool IsKeyDown(int key) bool IsKeyReleased(int key) { bool released = false; - + +#if defined(PLATFORM_ANDROID) + if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; + else released = false; +#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; +#endif return released; } @@ -1091,64 +1156,9 @@ int GetKeyPressed(void) // NOTE: default exitKey is ESCAPE void SetExitKey(int key) { +#if !defined(PLATFORM_ANDROID) exitKey = key; -} - -// Hide mouse cursor -void HideCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XColor Col; - const char Nil[] = {0}; - - Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1); - Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0); - - XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur); - XFreeCursor(glfwGetX11Display(), Cur); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - #endif #endif - cursorHidden = true; -} - -// Show mouse cursor -void ShowCursor() -{ -#if defined(PLATFORM_DESKTOP) - #ifdef __linux - XUndefineCursor(glfwGetX11Display(), glfwGetX11Window(window)); - #else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - #endif -#endif - cursorHidden = false; -} - -// Disable mouse cursor -void DisableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif - cursorHidden = true; -} - -// Enable mouse cursor -void EnableCursor() -{ -#if defined(PLATFORM_DESKTOP) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif - cursorHidden = false; -} - -// Check if mouse cursor is hidden -bool IsCursorHidden() -{ - return cursorHidden; } // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) @@ -1204,7 +1214,7 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool result = false; - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 1)) result = true; return result; @@ -1387,37 +1397,6 @@ Vector2 GetTouchPosition(int index) return position; } -#if defined(PLATFORM_ANDROID) -// Detect if a button has been pressed once -bool IsButtonPressed(int button) -{ - bool pressed = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 0)) pressed = true; - else pressed = false; - - return pressed; -} - -// Detect if a button is being pressed (button held down) -bool IsButtonDown(int button) -{ - if (currentButtonState[button] == 0) return true; - else return false; -} - -// Detect if a button has been released once -bool IsButtonReleased(int button) -{ - bool released = false; - - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; - else released = false; - - return released; -} -#endif - //---------------------------------------------------------------------------------- // Module specific Functions Definition //---------------------------------------------------------------------------------- @@ -1900,8 +1879,9 @@ static bool GetKeyStatus(int key) #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) return glfwGetKey(window, key); #elif defined(PLATFORM_ANDROID) - // TODO: Check for virtual keyboard - return false; + // NOTE: Android supports up to 260 keys + if (key < 0 || key > 260) return false; + else return currentKeyState[key]; #elif defined(PLATFORM_RPI) // NOTE: Keys states are filled in PollInputEvents() if (key < 0 || key > 511) return false; @@ -1929,6 +1909,9 @@ static void PollInputEvents(void) // NOTE: Gestures update must be called every frame to reset gestures correctly // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); + + // Reset last key pressed registered + lastKeyPressed = -1; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1939,9 +1922,8 @@ static void PollInputEvents(void) mousePosition.x = (float)mouseX; mousePosition.y = (float)mouseY; - + // Keyboard input polling (automatically managed by GLFW3 through callback) - lastKeyPressed = -1; // Register previous keys states for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i]; @@ -1971,7 +1953,7 @@ static void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { - if (buttons[i] == GLFW_PRESS) currentGamepadState[i][k] = 1; + if (buttons[k] == GLFW_PRESS) currentGamepadState[i][k] = 1; else currentGamepadState[i][k] = 0; } @@ -1994,7 +1976,8 @@ static void PollInputEvents(void) #if defined(PLATFORM_ANDROID) // Register previous keys states - for (int i = 0; i < 128; i++) previousButtonState[i] = currentButtonState[i]; + // NOTE: Android supports up to 260 keys + for (int i = 0; i < 260; i++) previousKeyState[i] = currentKeyState[i]; // Poll Events (registered events) // NOTE: Activity is paused if not enabled (appEnabled) @@ -2371,7 +2354,13 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event) //int32_t AKeyEvent_getMetaState(event); // Save current button and its state - currentButtonState[keycode] = AKeyEvent_getAction(event); // Down = 0, Up = 1 + // NOTE: Android key action is 0 for down and 1 for up + if (AKeyEvent_getAction(event) == 0) + { + currentKeyState[keycode] = 1; // Key down + lastKeyPressed = keycode; + } + else currentKeyState[keycode] = 0; // Key up if (keycode == AKEYCODE_POWER) { diff --git a/src/raylib.h b/src/raylib.h index 1433268b..c1ac2416 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -174,6 +174,14 @@ #define KEY_Y 89 #define KEY_Z 90 +#if defined(PLATFORM_ANDROID) + // Android Physical Buttons + #define KEY_BACK 4 + #define KEY_MENU 82 + #define KEY_VOLUME_UP 24 + #define KEY_VOLUME_DOWN 25 +#endif + // Mouse Buttons #define MOUSE_LEFT_BUTTON 0 #define MOUSE_RIGHT_BUTTON 1 @@ -213,6 +221,13 @@ #define GAMEPAD_XBOX_BUTTON_RB 5 #define GAMEPAD_XBOX_BUTTON_SELECT 6 #define GAMEPAD_XBOX_BUTTON_START 7 +#define GAMEPAD_XBOX_BUTTON_UP 10 +#define GAMEPAD_XBOX_BUTTON_RIGHT 11 +#define GAMEPAD_XBOX_BUTTON_DOWN 12 +#define GAMEPAD_XBOX_BUTTON_LEFT 13 + +#define GAMEPAD_XBOX_AXIS_LEFT_X 0 +#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 #if defined(PLATFORM_RPI) #define GAMEPAD_XBOX_AXIS_DPAD_X 7 @@ -222,24 +237,11 @@ #define GAMEPAD_XBOX_AXIS_LT 2 #define GAMEPAD_XBOX_AXIS_RT 5 #else - #define GAMEPAD_XBOX_BUTTON_UP 10 - #define GAMEPAD_XBOX_BUTTON_DOWN 12 - #define GAMEPAD_XBOX_BUTTON_LEFT 13 - #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 #define GAMEPAD_XBOX_AXIS_LT_RT 2 #endif -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 - -// Android Physic Buttons -#define ANDROID_BACK 4 -#define ANDROID_MENU 82 -#define ANDROID_VOLUME_UP 24 -#define ANDROID_VOLUME_DOWN 25 - // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. #ifdef __cplusplus @@ -648,7 +650,6 @@ RLAPI int StorageLoadValue(int position); // Storage loa //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) //------------------------------------------------------------------------------------ -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once @@ -656,6 +657,7 @@ RLAPI bool IsKeyUp(int key); // Detect if a key RLAPI int GetKeyPressed(void); // Get latest key pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis @@ -679,12 +681,6 @@ RLAPI int GetTouchX(void); // Returns touch p RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size) RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size) -#if defined(PLATFORM_ANDROID) -bool IsButtonPressed(int button); // Detect if an android physic button has been pressed -bool IsButtonDown(int button); // Detect if an android physic button is being pressed -bool IsButtonReleased(int button); // Detect if an android physic button has been released -#endif - //------------------------------------------------------------------------------------ // Gestures and Touch Handling Functions (Module: gestures) //------------------------------------------------------------------------------------ -- cgit v1.2.3 From b8ce6805117bcd28f80ae92f7faa14abdcb2f741 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 18 Oct 2016 00:15:23 +0200 Subject: Improved Android support --- src/core.c | 21 ++++++--------------- src/raylib.h | 8 +++----- 2 files changed, 9 insertions(+), 20 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index d044a66e..b8a8ac05 100644 --- a/src/core.c +++ b/src/core.c @@ -79,8 +79,7 @@ #endif #if defined(PLATFORM_ANDROID) - #include // Java native interface - #include // Android sensors functions + //#include // Android sensors functions (accelerometer, gyroscope, light...) #include // Defines AWINDOW_FLAG_FULLSCREEN and others #include // Defines basic app state struct and manages activity @@ -361,7 +360,7 @@ void InitWindow(int width, int height, const char *title) #if defined(PLATFORM_ANDROID) // Android activity initialization -void InitWindow(int width, int height, struct android_app *state) +void InitWindow(int width, int height, void *state) { TraceLog(INFO, "Initializing raylib (v1.6.0)"); @@ -370,7 +369,7 @@ void InitWindow(int width, int height, struct android_app *state) screenWidth = width; screenHeight = height; - app = state; + app = (struct android_app *)state; internalDataPath = app->activity->internalDataPath; // Set desired windows flags before initializing anything @@ -524,6 +523,7 @@ int GetScreenHeight(void) return screenHeight; } +#if !defined(PLATFORM_ANDROID) // Show mouse cursor void ShowCursor() { @@ -580,6 +580,7 @@ void DisableCursor() #endif cursorHidden = true; } +#endif // !defined(PLATFORM_ANDROID) // Sets Background Color void ClearBackground(Color color) @@ -1099,19 +1100,13 @@ Matrix GetCameraMatrix(Camera camera) //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // Detect if a key has been pressed once bool IsKeyPressed(int key) { bool pressed = false; -#if defined(PLATFORM_ANDROID) - if ((currentButtonState[key] != previousButtonState[key]) && (currentButtonState[key] == 0)) pressed = true; - else pressed = false; -#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 1)) pressed = true; else pressed = false; -#endif return pressed; } @@ -1128,13 +1123,8 @@ bool IsKeyReleased(int key) { bool released = false; -#if defined(PLATFORM_ANDROID) - if ((currentButtonState[button] != previousButtonState[button]) && (currentButtonState[button] == 1)) released = true; - else released = false; -#else if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; -#endif return released; } @@ -1161,6 +1151,7 @@ void SetExitKey(int key) #endif } +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) // NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB) // Detect if a gamepad is available diff --git a/src/raylib.h b/src/raylib.h index c1ac2416..efb9a71c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -77,10 +77,6 @@ #define PLATFORM_DESKTOP #endif -#if defined(PLATFORM_ANDROID) - typedef struct android_app; // Define android_app struct (android_native_app_glue.h) -#endif - #if defined(_WIN32) && defined(BUILDING_DLL) #define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL #elif defined(_WIN32) && defined(RAYLIB_DLL) @@ -591,7 +587,7 @@ extern "C" { // Prevents name mangling of functions // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ #if defined(PLATFORM_ANDROID) -RLAPI void InitWindow(int width, int height, struct android_app *state); // Init Android Activity and OpenGL Graphics +RLAPI void InitWindow(int width, int height, void *state); // Init Android Activity and OpenGL Graphics (struct android_app) #elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics #endif @@ -603,11 +599,13 @@ RLAPI void ToggleFullscreen(void); // Fullscreen RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height +#if !defined(PLATFORM_ANDROID) RLAPI void ShowCursor(void); // Shows cursor RLAPI void HideCursor(void); // Hides cursor RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible RLAPI void EnableCursor(void); // Enables cursor RLAPI void DisableCursor(void); // Disables cursor +#endif RLAPI void ClearBackground(Color color); // Sets Background Color RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing -- cgit v1.2.3 From 02842a3e2fefe122baaf40da1bcae5548239d570 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 27 Oct 2016 13:41:43 +0200 Subject: Review gamepad inputs Added funtion: GetGamepadButtonPressed() - This function can be useful for custom gamepad configuration --- src/core.c | 19 ++++++++++++++++++- src/raylib.h | 61 ++++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 19 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index dd005836..8646bf8f 100644 --- a/src/core.c +++ b/src/core.c @@ -222,6 +222,7 @@ static char previousKeyState[512] = { 0 }; // Registers previous frame key stat static char currentKeyState[512] = { 0 }; // Registers current frame key state static int lastKeyPressed = -1; // Register last key pressed +static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -1236,6 +1237,13 @@ bool IsGamepadButtonUp(int gamepad, int button) return result; } + +// Get the last gamepad button pressed +int GetGamepadButtonPressed(void) +{ + return lastGamepadButtonPressed; +} + #endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) @@ -1906,6 +1914,9 @@ static void PollInputEvents(void) // Reset last key pressed registered lastKeyPressed = -1; + + // Reset last gamepad button pressed registered + lastGamepadButtonPressed = -1; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1947,7 +1958,11 @@ static void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { - if (buttons[k] == GLFW_PRESS) currentGamepadState[i][k] = 1; + if (buttons[k] == GLFW_PRESS) + { + currentGamepadState[i][k] = 1; + lastGamepadButtonPressed = k; + } else currentGamepadState[i][k] = 0; } @@ -2801,6 +2816,8 @@ static void *GamepadThread(void *arg) { // 1 - button pressed, 0 - button released currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; + + if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; } } else if (gamepadEvent.type == JS_EVENT_AXIS) diff --git a/src/raylib.h b/src/raylib.h index efb9a71c..491923dc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -192,21 +192,32 @@ #define GAMEPAD_PLAYER3 2 #define GAMEPAD_PLAYER4 3 -// Gamepad Buttons +// Gamepad Buttons/Axis -// PS3 USB Controller -#define GAMEPAD_PS3_BUTTON_A 2 -#define GAMEPAD_PS3_BUTTON_B 1 -#define GAMEPAD_PS3_BUTTON_X 3 -#define GAMEPAD_PS3_BUTTON_Y 4 +// PS3 USB Controller Buttons +#define GAMEPAD_PS3_BUTTON_TRIANGLE 0 +#define GAMEPAD_PS3_BUTTON_CIRCLE 1 +#define GAMEPAD_PS3_BUTTON_CROSS 2 +#define GAMEPAD_PS3_BUTTON_SQUARE 3 +#define GAMEPAD_PS3_BUTTON_L1 6 #define GAMEPAD_PS3_BUTTON_R1 7 +#define GAMEPAD_PS3_BUTTON_L2 4 #define GAMEPAD_PS3_BUTTON_R2 5 -#define GAMEPAD_PS3_BUTTON_L1 6 -#define GAMEPAD_PS3_BUTTON_L2 8 +#define GAMEPAD_PS3_BUTTON_START 8 #define GAMEPAD_PS3_BUTTON_SELECT 9 -#define GAMEPAD_PS3_BUTTON_START 10 - -// TODO: Add PS3 d-pad axis +#define GAMEPAD_PS3_BUTTON_UP 24 +#define GAMEPAD_PS3_BUTTON_RIGHT 25 +#define GAMEPAD_PS3_BUTTON_DOWN 26 +#define GAMEPAD_PS3_BUTTON_LEFT 27 +#define GAMEPAD_PS3_BUTTON_PS 12 + +// PS3 USB Controller Axis +#define GAMEPAD_PS3_AXIS_LEFT_X 0 +#define GAMEPAD_PS3_AXIS_LEFT_Y 1 +#define GAMEPAD_PS3_AXIS_RIGHT_X 2 +#define GAMEPAD_PS3_AXIS_RIGHT_Y 5 +#define GAMEPAD_PS3_AXIS_L2 3 // 1.0(not pressed) --> -1.0(completely pressed) +#define GAMEPAD_PS3_AXIS_R2 4 // 1.0(not pressed) --> -1.0(completely pressed) // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -221,22 +232,27 @@ #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_BUTTON_DOWN 12 #define GAMEPAD_XBOX_BUTTON_LEFT 13 +#define GAMEPAD_XBOX_BUTTON_HOME 9 +// Xbox360 USB Controller Axis #define GAMEPAD_XBOX_AXIS_LEFT_X 0 #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 +#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 +#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 +#define GAMEPAD_XBOX_AXIS_LT 4 // -1.0(not pressed) --> 1.0(completely pressed) +#define GAMEPAD_XBOX_AXIS_RT 5 // -1.0(not pressed) --> 1.0(completely pressed) +/* +// NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_DPAD_X 7 - #define GAMEPAD_XBOX_AXIS_DPAD_Y 6 + #define GAMEPAD_XBOX_AXIS_LEFT_X 7 + #define GAMEPAD_XBOX_AXIS_LEFT_Y 6 #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 #define GAMEPAD_XBOX_AXIS_LT 2 #define GAMEPAD_XBOX_AXIS_RT 5 -#else - #define GAMEPAD_XBOX_AXIS_RIGHT_X 4 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 - #define GAMEPAD_XBOX_AXIS_LT_RT 2 #endif +*/ // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. @@ -533,6 +549,12 @@ typedef enum { COMPRESSED_ASTC_8x8_RGBA // 2 bpp } TextureFormat; +// Texture parameters: filter mode +typedef enum { FILTER_POINT = 0, FILTER_BILINEAR, FILTER_TRILINEAR } TextureFilterMode; + +// Texture parameters: wrap mode +typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; + // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; @@ -663,6 +685,7 @@ RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gam RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed +RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed #endif RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once @@ -752,6 +775,7 @@ RLAPI void UnloadTexture(Texture2D texture); RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image +RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image @@ -773,7 +797,8 @@ RLAPI void ImageColorGrayscale(Image *image); RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) RLAPI void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data +RLAPI void SetTextureFilter(Texture2D texture, int filterMode); +RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 -- cgit v1.2.3 From 988d39029f9c562ae044e4b5b0d129c367ffbe16 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 29 Oct 2016 22:17:19 +0200 Subject: Support textures filtering --- src/raylib.h | 15 ++++++++-- src/rlgl.c | 88 +++++++++++++++++++++++++++++++++++----------------------- src/rlgl.h | 35 ++++++++++++++++++++--- src/textures.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 178 insertions(+), 48 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 491923dc..b0ee96bb 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -550,7 +550,16 @@ typedef enum { } TextureFormat; // Texture parameters: filter mode -typedef enum { FILTER_POINT = 0, FILTER_BILINEAR, FILTER_TRILINEAR } TextureFilterMode; +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} TextureFilterMode; // Texture parameters: wrap mode typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; @@ -797,8 +806,8 @@ RLAPI void ImageColorGrayscale(Image *image); RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) RLAPI void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture -RLAPI void SetTextureFilter(Texture2D texture, int filterMode); -RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); +RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode +RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 diff --git a/src/rlgl.c b/src/rlgl.c index 0a7e3583..492ca3a6 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -140,6 +140,14 @@ #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 #endif +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#endif + #if defined(GRAPHICS_API_OPENGL_11) #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 @@ -283,14 +291,21 @@ static Shader standardShader; // Shader with support for lighting static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded -// Flags for supported extensions +// Extension supported flag: VAO static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) -// Compressed textures support flags +// Extension supported flag: Compressed textures 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 + +// Extension supported flag: Anisotropic filtering +static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support +static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supported (minimum is 2.0f) + +// Extension supported flag: Clamp mirror wrap mode +static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -871,45 +886,34 @@ void rlDisableTexture(void) #endif } -// Set texture parameters -// TODO: Review this function to choose right filter/wrap value +// Set texture parameters (wrap mode/filter mode) void rlTextureParameters(unsigned int id, int param, int value) { -/* -// TextureWrapMode -#define GL_REPEAT 0x2901 -#define GL_CLAMP_TO_EDGE 0x812F - -// TextureMagFilter -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 - -// TextureMinFilter -#define GL_NEAREST 0x2600 -#define GL_LINEAR 0x2601 -#define GL_NEAREST_MIPMAP_NEAREST 0x2700 -#define GL_LINEAR_MIPMAP_NEAREST 0x2701 -#define GL_NEAREST_MIPMAP_LINEAR 0x2702 -#define GL_LINEAR_MIPMAP_LINEAR 0x2703 -*/ - - int glValue = 0; - glBindTexture(GL_TEXTURE_2D, id); - - switch (value) + + switch (param) { - case FILTER_POINT: glValue = GL_NEAREST; break; - case FILTER_BILINEAR: glValue = GL_LINEAR; break; - case FILTER_TRILINEAR: glValue = GL_LINEAR; break; - //case WRAP_REPEAT: glValue = GL_REPEAT; break; - //case WRAP_CLAMP: glValue = GL_CLAMP_TO_EDGE; break; - //case WRAP_MIRROR: glValue = GL_NEAREST; break; + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if ((value == RL_WRAP_CLAMP_MIRROR) && !texClampMirrorSupported) TraceLog(WARNING, "Clamp mirror wrap mode not supported"); + else glTexParameteri(GL_TEXTURE_2D, param, value); + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; + case RL_TEXTURE_ANISOTROPIC_FILTER: + { + if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + else if (maxAnisotropicLevel > 0.0f) + { + TraceLog(WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value); + } + else TraceLog(WARNING, "Anisotropic filtering not supported"); + } break; default: break; } - glTexParameteri(GL_TEXTURE_2D, param, glValue); - glBindTexture(GL_TEXTURE_2D, 0); } @@ -1166,7 +1170,7 @@ void rlglInit(int width, int height) // Check NPOT textures support // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true; -#endif +#endif // DDS texture compression support if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || @@ -1185,6 +1189,16 @@ void rlglInit(int width, int height) // ASTC texture compression support if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true; + + // Anisotropic texture filter support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) + { + texAnisotropicFilterSupported = true; + glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + } + + // Clamp mirror wrap mode supported + if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; } #ifdef _MSC_VER @@ -1204,6 +1218,9 @@ void rlglInit(int width, int height) if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported"); if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported"); if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported"); + + if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); + if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); // Initialize buffers, default shaders and default textures //---------------------------------------------------------- @@ -1729,6 +1746,7 @@ void rlglGenerateMipmaps(Texture2D texture) #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id); diff --git a/src/rlgl.h b/src/rlgl.h index b6679ef6..9be73f36 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -91,10 +91,22 @@ #endif // Texture parameters (equivalent to OpenGL defines) -#define RL_TEXTURE_MAG_FILTER 0x2800 -#define RL_TEXTURE_MIN_FILTER 0x2801 -#define RL_TEXTURE_WRAP_S 0x2802 -#define RL_TEXTURE_WRAP_T 0x2803 +#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S +#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T +#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER +#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER +#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier) + +#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST +#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR +#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST +#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR +#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST +#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR + +#define RL_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -242,6 +254,21 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; // Light types typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + + // Texture parameters: filter mode + // NOTE 1: Filtering considers mipmaps if available in the texture + // NOTE 2: Filter is accordingly set for minification and magnification + typedef enum { + FILTER_POINT = 0, // No filter, just pixel aproximation + FILTER_BILINEAR, // Linear filtering + FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x + } TextureFilterMode; + + // Texture parameters: wrap mode + typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode; // Color blending modes (pre-defined) typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode; diff --git a/src/textures.c b/src/textures.c index 867e565d..729756a5 100644 --- a/src/textures.c +++ b/src/textures.c @@ -442,18 +442,94 @@ void UnloadRenderTexture(RenderTexture2D target) if (target.id != 0) rlDeleteRenderTextures(target); } -// Set texture scale filter +// Set texture scaling filter mode void SetTextureFilter(Texture2D texture, int filterMode) { - rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, filterMode); - rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, filterMode); + switch (filterMode) + { + case FILTER_POINT: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST); + + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + else + { + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); + } + } break; + case FILTER_BILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) + // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_TRILINEAR: + { + if (texture.mipmaps > 1) + { + // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + else + { + TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id); + + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps + rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); + rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); + } + } break; + case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break; + case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break; + case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break; + default: break; + } } -// Set texture wrap mode +// Set texture wrapping mode void SetTextureWrap(Texture2D texture, int wrapMode) { - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, wrapMode); - rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, wrapMode); + switch (wrapMode) + { + case WRAP_REPEAT: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT); + } break; + case WRAP_CLAMP: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP); + } break; + case WRAP_MIRROR: + { + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR); + rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR); + } break; + default: break; + } } // Get pixel data from image in the form of Color struct array -- cgit v1.2.3 From cc917fbac6e7007fdb744afaf8f0879c984d95af Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 31 Oct 2016 15:38:15 +0100 Subject: Improve SpriteFont support LoadSpriteFontTTF() - TTF font loading with custom parameters --- src/raylib.h | 3 +-- src/text.c | 74 +++++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 23 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index b0ee96bb..4996bb2b 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -686,7 +686,6 @@ RLAPI bool IsKeyUp(int key); // Detect if a key RLAPI int GetKeyPressed(void); // Get latest key pressed RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis @@ -695,7 +694,6 @@ RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gam RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed -#endif RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed @@ -821,6 +819,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load a SpriteFont from TTF font with parameters RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) diff --git a/src/text.c b/src/text.c index 5e978823..7707db7c 100644 --- a/src/text.c +++ b/src/text.c @@ -33,6 +33,7 @@ #include "utils.h" // Required for: GetExtension() // Following libs are used on LoadTTF() +//#define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() @@ -268,20 +269,35 @@ SpriteFont LoadSpriteFont(const char *fileName) TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName); spriteFont = GetDefaultFont(); } + else SetTextureFilter(spriteFont.texture, FILTER_BILINEAR); return spriteFont; } -// Generate SpriteFont from TTF file +// Load SpriteFont from TTF file with custom parameters // NOTE: You can pass an array with desired characters, those characters should be available in the font // if array is NULL, default char set is selected 32..126 -SpriteFont GenSpriteFont(const char *fileName, int fontSize, int *fontChars) +SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) { SpriteFont spriteFont = { 0 }; if (strcmp(GetExtension(fileName),"ttf") == 0) { - spriteFont = LoadTTF(fileName, fontSize, FONT_FIRST_CHAR, DEFAULT_TTF_NUMCHARS); + int firstChar = 0; + int totalChars = 0; + + if ((fontChars == NULL) || (numChars == 0)) + { + firstChar = 32; // Default first character: SPACE[32] + totalChars = 95; // Default charset [32..126] + } + else + { + firstChar = fontChars[0]; + totalChars = numChars; + } + + spriteFont = LoadTTF(fileName, fontSize, firstChar, totalChars); } if (spriteFont.texture.id == 0) @@ -522,7 +538,7 @@ void DrawFPS(int posX, int posY) // Module specific Functions Definition //---------------------------------------------------------------------------------- -// Load a Image font file (XNA style) +// Load an Image font file (XNA style) static SpriteFont LoadImageFont(Image image, Color key, int firstChar) { #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) @@ -595,15 +611,24 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) xPosToRead = charSpacing; } - free(pixels); - TraceLog(DEBUG, "SpriteFont data parsed correctly from image"); + + // NOTE: We need to remove key color borders from image to avoid weird + // artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR + for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; + + // Create a new image with the processed color data (key color replaced by BLANK) + Image fontClear = LoadImageEx(pixels, image.width, image.height); + + free(pixels); // Free pixels array memory // Create spritefont with all data parsed from image SpriteFont spriteFont = { 0 }; - spriteFont.texture = LoadTextureFromImage(image); // Convert loaded image to OpenGL texture + spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture spriteFont.numChars = index; + + UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays @@ -900,12 +925,15 @@ static SpriteFont LoadBMFont(const char *fileName) // TODO: Review texture packing method and generation (use oversampling) static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int numChars) { - // NOTE: Generated font uses some hardcoded values - #define FONT_TEXTURE_WIDTH 512 // Font texture width - #define FONT_TEXTURE_HEIGHT 512 // Font texture height + // NOTE: Font texture size is predicted (being as much conservative as possible) + // Predictive method consist of supposing same number of chars by line-column (sqrtf) + // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... + int textureSize = GetNextPOT(ceil((float)fontSize*3/4)*ceil(sqrtf((float)numChars))); + + TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); - unsigned char *dataBitmap = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)); // One channel bitmap returned! + unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); SpriteFont font = { 0 }; @@ -914,40 +942,44 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int firstChar, int if (ttfFile == NULL) { - TraceLog(WARNING, "[%s] FNT file could not be opened", fileName); + TraceLog(WARNING, "[%s] TTF file could not be opened", fileName); return font; } fread(ttfBuffer, 1, 1<<25, ttfFile); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... - stbtt_BakeFontBitmap(ttfBuffer,0, fontSize, dataBitmap, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, firstChar, numChars, charData); + // TODO: Replace this function by a proper packing method and support random chars order + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, firstChar, numChars, charData); + //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); + if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); + free(ttfBuffer); // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA - unsigned char *dataGrayAlpha = (unsigned char *)malloc(FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT*sizeof(unsigned char)*2); // Two channels - int k = 0; + unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels - for (int i = 0; i < FONT_TEXTURE_WIDTH*FONT_TEXTURE_HEIGHT; i++) + for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2) { dataGrayAlpha[k] = 255; dataGrayAlpha[k + 1] = dataBitmap[i]; - - k += 2; } free(dataBitmap); // Sprite font generation from TTF extracted data Image image; - image.width = FONT_TEXTURE_WIDTH; - image.height = FONT_TEXTURE_HEIGHT; + image.width = textureSize; + image.height = textureSize; image.mipmaps = 1; image.format = UNCOMPRESSED_GRAY_ALPHA; image.data = dataGrayAlpha; - + font.texture = LoadTextureFromImage(image); + + //WritePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2); + UnloadImage(image); // Unloads dataGrayAlpha font.size = fontSize; -- cgit v1.2.3 From 64f67f6e9f414a54dfc3fb519b892ecd5517f2cf Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 1 Nov 2016 14:39:57 +0100 Subject: Improved gamepad support new function: GetGamepadAxisCount() new function: IsGamepadName() --- src/core.c | 50 +++++++++++++++++++++++++++++++++++++++----------- src/raylib.h | 4 +++- 2 files changed, 42 insertions(+), 12 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 8850eefa..3bade07b 100644 --- a/src/core.c +++ b/src/core.c @@ -58,12 +58,12 @@ #endif #include // Standard input / output lib -#include // Declares malloc() and free() for memory management, rand(), atexit() -#include // Required for typedef unsigned long long int uint64_t, used by hi-res timer -#include // Useful to initialize random seed - Android/RPI hi-res timer (NOTE: Linux only!) -#include // Math related functions, tan() used to set perspective -#include // String function definitions, memset() -#include // Macros for reporting and retrieving error conditions through error codes +#include // Required for: malloc(), free(), rand(), atexit() +#include // Required for: typedef unsigned long long int uint64_t, used by hi-res timer +#include // Required for: time() - Android/RPI hi-res timer (NOTE: Linux only!) +#include // Required for: tan() [Used in Begin3dMode() to set perspective] +#include // Required for: strcmp() +//#include // Macros for reporting and retrieving error conditions through error codes #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 @@ -222,6 +222,7 @@ static char currentKeyState[512] = { 0 }; // Registers current frame key state static int lastKeyPressed = -1; // Register last key pressed static int lastGamepadButtonPressed = -1; // Register last gamepad button pressed +static int gamepadAxisCount = 0; // Register number of available gamepad axis static Vector2 mousePosition; // Mouse position on screen static Vector2 touchPosition[MAX_TOUCH_POINTS]; // Touch position on screen @@ -1168,17 +1169,36 @@ bool IsGamepadAvailable(int gamepad) return result; } +// Check gamepad name (if available) +bool IsGamepadName(int gamepad, const char *name) +{ + bool result = false; + const char *gamepadName = NULL; + + if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad); + + if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0); + + return result; +} + // Return gamepad internal name id const char *GetGamepadName(int gamepad) { #if defined(PLATFORM_DESKTOP) - if (glfwJoystickPresent(gamepad) == 1) return glfwGetJoystickName(gamepad); + if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; #else return NULL; #endif } +// Return gamepad axis count +int GetGamepadAxisCount(int gamepad) +{ + return gamepadAxisCount; +} + // Return axis movement vector for a gamepad float GetGamepadAxisMovement(int gamepad, int axis) { @@ -1921,6 +1941,7 @@ static void PollInputEvents(void) // Reset last gamepad button pressed registered lastGamepadButtonPressed = -1; + gamepadAxisCount = 0; #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -1943,13 +1964,19 @@ static void PollInputEvents(void) previousMouseWheelY = currentMouseWheelY; currentMouseWheelY = 0; + // Check if gamepads are ready + // NOTE: We do it here in case of disconection + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (glfwJoystickPresent(i)) gamepadReady[i] = true; + else gamepadReady[i] = false; + } + // Register gamepads buttons events for (int i = 0; i < MAX_GAMEPADS; i++) { - if (glfwJoystickPresent(i)) // Check if gamepad is available + if (gamepadReady[i]) // Check if gamepad is available { - gamepadReady[i] = true; - // Register previous gamepad states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; @@ -1980,8 +2007,9 @@ static void PollInputEvents(void) { gamepadAxisState[i][k] = axes[k]; } + + gamepadAxisCount = axisCount; } - else gamepadReady[i] = false; } glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events! diff --git a/src/raylib.h b/src/raylib.h index 4996bb2b..58037770 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -687,13 +687,15 @@ RLAPI int GetKeyPressed(void); // Get latest key RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available +RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available) RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id -RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed +RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed -- cgit v1.2.3 From f2d61d4d432ff302c57d0869d75e72c6462658f5 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 2 Nov 2016 13:39:48 +0100 Subject: Improved gamepad support on Raspberry Pi --- src/core.c | 19 ++++++++++++++++--- src/raylib.h | 34 ++++++++++++++++------------------ 2 files changed, 32 insertions(+), 21 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 3bade07b..8e15eb96 100644 --- a/src/core.c +++ b/src/core.c @@ -96,8 +96,8 @@ #include // UNIX System call for device-specific input/output operations - ioctl() #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include // Linux: Keycodes constants definition (KEY_A, ...) - #include - + #include // Linux: Joystick support library + #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions @@ -175,6 +175,7 @@ static pthread_t mouseThreadId; // Mouse reading thread id // Gamepad input variables static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor static pthread_t gamepadThreadId; // Gamepad reading thread id +static char gamepadName[64]; // Gamepad name holder #endif #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) @@ -1188,6 +1189,10 @@ const char *GetGamepadName(int gamepad) #if defined(PLATFORM_DESKTOP) if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; +#elif defined(PLATFORM_RPI) + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); + + return gamepadName; #else return NULL; #endif @@ -1196,6 +1201,11 @@ const char *GetGamepadName(int gamepad) // Return gamepad axis count int GetGamepadAxisCount(int gamepad) { +#if defined(PLATFORM_RPI) + int axisCount = 0; + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGAXES, &axisCount); + gamepadAxisCount = axisCount; +#endif return gamepadAxisCount; } @@ -1939,9 +1949,11 @@ static void PollInputEvents(void) // Reset last key pressed registered lastKeyPressed = -1; - // Reset last gamepad button pressed registered +#if !defined(PLATFORM_RPI) + // Reset last gamepad button/axis registered state lastGamepadButtonPressed = -1; gamepadAxisCount = 0; +#endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) // Mouse input polling @@ -2850,6 +2862,7 @@ static void *GamepadThread(void *arg) currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; + else lastGamepadButtonPressed = -1; } } else if (gamepadEvent.type == JS_EVENT_AXIS) diff --git a/src/raylib.h b/src/raylib.h index 58037770..08acafdd 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -216,8 +216,8 @@ #define GAMEPAD_PS3_AXIS_LEFT_Y 1 #define GAMEPAD_PS3_AXIS_RIGHT_X 2 #define GAMEPAD_PS3_AXIS_RIGHT_Y 5 -#define GAMEPAD_PS3_AXIS_L2 3 // 1.0(not pressed) --> -1.0(completely pressed) -#define GAMEPAD_PS3_AXIS_R2 4 // 1.0(not pressed) --> -1.0(completely pressed) +#define GAMEPAD_PS3_AXIS_L2 3 // [1..-1] (pressure-level) +#define GAMEPAD_PS3_AXIS_R2 4 // [1..-1] (pressure-level) // Xbox360 USB Controller Buttons #define GAMEPAD_XBOX_BUTTON_A 0 @@ -232,27 +232,25 @@ #define GAMEPAD_XBOX_BUTTON_RIGHT 11 #define GAMEPAD_XBOX_BUTTON_DOWN 12 #define GAMEPAD_XBOX_BUTTON_LEFT 13 -#define GAMEPAD_XBOX_BUTTON_HOME 9 +#define GAMEPAD_XBOX_BUTTON_HOME 8 // Xbox360 USB Controller Axis -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 -#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 -#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 -#define GAMEPAD_XBOX_AXIS_LT 4 // -1.0(not pressed) --> 1.0(completely pressed) -#define GAMEPAD_XBOX_AXIS_RT 5 // -1.0(not pressed) --> 1.0(completely pressed) - -/* +#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) +#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) +#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) +#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) +#define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) +#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) + // NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) - #define GAMEPAD_XBOX_AXIS_LEFT_X 7 - #define GAMEPAD_XBOX_AXIS_LEFT_Y 6 - #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 - #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 - #define GAMEPAD_XBOX_AXIS_LT 2 - #define GAMEPAD_XBOX_AXIS_RT 5 + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 3 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #endif -*/ // NOTE: MSC C++ compiler does not support compound literals (C99 feature) // Plain structures in C++ (without constructors) can be initialized from { } initializers. -- cgit v1.2.3 From ca96122a7b8291f0761fd34f1997e1a051b907f2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 3 Nov 2016 18:57:16 +0100 Subject: Raspberry Pi custom gamepad axis --- src/raylib.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 08acafdd..00d27466 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -235,13 +235,6 @@ #define GAMEPAD_XBOX_BUTTON_HOME 8 // Xbox360 USB Controller Axis -#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) -#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) -#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) -#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) -#define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) -#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) - // NOTE: For Raspberry Pi, axis must be reconfigured #if defined(PLATFORM_RPI) #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) @@ -250,6 +243,13 @@ #define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down) #define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level) #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) +#else + #define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right) + #define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down) + #define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level) + #define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level) #endif // NOTE: MSC C++ compiler does not support compound literals (C99 feature) -- cgit v1.2.3 From 9fb6eda5f103e383f3a15d7c2a4d014752dce087 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 13 Nov 2016 23:54:36 +0100 Subject: Improved text measurement --- src/raylib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 00d27466..f6243304 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -826,7 +826,7 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters float fontSize, int spacing, Color tint); RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font -RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont +RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed' -- cgit v1.2.3 From 9d3ad52160a0e32271a8e3d76d9ea95e9bd0684a Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 15 Nov 2016 19:15:25 +0100 Subject: Removed byte typedef --- src/raylib.h | 3 --- src/rlgl.h | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index f6243304..2e3112cf 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -305,9 +305,6 @@ #endif #endif -// byte type -typedef unsigned char byte; - // Vector2 type typedef struct Vector2 { float x; diff --git a/src/rlgl.h b/src/rlgl.h index 9be73f36..78ea6727 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -117,15 +117,14 @@ typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode; typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode; +typedef unsigned char byte; + #if defined(RLGL_STANDALONE) #ifndef __cplusplus // Boolean type typedef enum { false, true } bool; #endif - // byte type - typedef unsigned char byte; - // Color type, RGBA (32bit) typedef struct Color { unsigned char r; -- cgit v1.2.3 From 6d1b712a9678a7e1d57d994ab51afafbe06ec5fb Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 16 Nov 2016 18:46:13 +0100 Subject: Reviewed modules comments --- src/audio.c | 19 ++++++++++++------- src/audio.h | 16 +++++++++------- src/core.c | 25 +++++++++++++------------ src/external/stb_image.h | 4 ++-- src/models.c | 9 +++++++-- src/raylib.h | 34 ++++++++++++++++++---------------- src/rlgl.c | 29 ++++++++++++++++++++++++----- src/rlgl.h | 26 +++++++++++++++++++++----- src/shapes.c | 10 ++++++++-- src/text.c | 8 +++++++- src/textures.c | 10 +++++++--- src/utils.c | 14 ++++++++++---- src/utils.h | 6 ++---- 13 files changed, 140 insertions(+), 70 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 3684e10a..3ddbf0ce 100644 --- a/src/audio.c +++ b/src/audio.c @@ -2,18 +2,22 @@ * * raylib.audio * -* Basic functions to manage Audio: +* This module provides basic functionality to work with audio: * Manage audio device (init/close) -* Load and Unload audio files +* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) * Play/Stop/Pause/Resume loaded audio * Manage mixing channels * Manage raw audio context * -* Uses external lib: -* OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) -* stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) -* jar_xm - XM module file loading -* jar_mod - MOD audio file loading +* External libs: +* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) +* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) +* jar_xm - XM module file loading +* jar_mod - MOD audio file loading +* dr_flac - FLAC audio file loading +* +* Module Configuration Flags: +* AUDIO_STANDALONE - Use this module as standalone library (independently of raylib) * * Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: * XM audio module support (jar_xm) @@ -21,6 +25,7 @@ * Mixing channels support * Raw audio context support * +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event diff --git a/src/audio.h b/src/audio.h index 923492ca..5de8f613 100644 --- a/src/audio.h +++ b/src/audio.h @@ -2,18 +2,19 @@ * * raylib.audio * -* Basic functions to manage Audio: +* This module provides basic functionality to work with audio: * Manage audio device (init/close) -* Load and Unload audio files +* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) * Play/Stop/Pause/Resume loaded audio * Manage mixing channels * Manage raw audio context * -* Uses external lib: -* OpenAL Soft - Audio device management lib (http://kcat.strangesoft.net/openal.html) -* stb_vorbis - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) -* jar_xm - XM module file loading -* jar_mod - MOD audio file loading +* External libs: +* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) +* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) +* jar_xm - XM module file loading +* jar_mod - MOD audio file loading +* dr_flac - FLAC audio file loading * * Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: * XM audio module support (jar_xm) @@ -21,6 +22,7 @@ * Mixing channels support * Raw audio context support * +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event diff --git a/src/core.c b/src/core.c index 8e15eb96..991dd4a0 100644 --- a/src/core.c +++ b/src/core.c @@ -4,24 +4,25 @@ * * Basic functions to manage windows, OpenGL context and input on multiple platforms * -* The following platforms are supported: -* PLATFORM_DESKTOP - Windows, Linux, Mac (OSX) -* PLATFORM_ANDROID - Only OpenGL ES 2.0 devices -* PLATFORM_RPI - Rapsberry Pi (tested on Raspbian) -* PLATFORM_WEB - Emscripten, HTML5 -* Oculus Rift CV1 (with desktop mirror) - View [rlgl] module to enable it +* The following platforms are supported: Windows, Linux, Mac (OSX), Android, Raspberry Pi, HTML5, Oculus Rift CV1 * -* On PLATFORM_DESKTOP, the external lib GLFW3 (www.glfw.com) is used to manage graphic -* device, OpenGL context and input on multiple operating systems (Windows, Linux, OSX). -* -* On PLATFORM_ANDROID, graphic device is managed by EGL and input system by Android activity. -* -* On PLATFORM_RPI, graphic device is managed by EGL and input system is coded in raw mode. +* External libs: +* GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX) +* raymath - 3D math functionality (Vector3, Matrix, Quaternion) +* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) +* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) * * Module Configuration Flags: +* PLATFORM_DESKTOP - Windows, Linux, Mac (OSX) +* PLATFORM_ANDROID - Android (only OpenGL ES 2.0 devices), graphic device is managed by EGL and input system by Android activity. +* PLATFORM_RPI - Rapsberry Pi (tested on Raspbian), graphic device is managed by EGL and input system is coded in raw mode. +* PLATFORM_WEB - HTML5 (using emscripten compiler) * * RL_LOAD_DEFAULT_FONT - Use external module functions to load default raylib font (module: text) * +* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for render mirror - View [rlgl] module to enable it +* +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event diff --git a/src/external/stb_image.h b/src/external/stb_image.h index ce87646d..5572a880 100644 --- a/src/external/stb_image.h +++ b/src/external/stb_image.h @@ -390,7 +390,7 @@ publish, and distribute this file as you see fit. #define STBI_NO_HDR // RaySan: not required by raylib -#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2 +//#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2 #ifndef STBI_NO_STDIO #include @@ -398,7 +398,7 @@ publish, and distribute this file as you see fit. // NOTE: Added to work with raylib on Android #if defined(PLATFORM_ANDROID) - #include "utils.h" // Android fopen function map + #include "utils.h" // RaySan: Android fopen function map #endif #define STBI_VERSION 1 diff --git a/src/models.c b/src/models.c index b7e36b8a..4275f89e 100644 --- a/src/models.c +++ b/src/models.c @@ -4,6 +4,12 @@ * * Basic functions to draw 3d shapes and load/draw 3d models (.OBJ) * +* External libs: +* rlgl - raylib OpenGL abstraction layer +* +* Module Configuration Flags: +* ... +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event @@ -34,8 +40,7 @@ #include // Required for: strcmp() #include // Required for: sin(), cos() -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 -#include "raymath.h" // Matrix data type and Matrix functions +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 //---------------------------------------------------------------------------------- // Defines and Macros diff --git a/src/raylib.h b/src/raylib.h index 2e3112cf..ef393f63 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -6,37 +6,39 @@ * * Features: * Library written in plain C code (C99) -* Uses C# PascalCase/camelCase notation +* Uses PascalCase/camelCase notation * Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) * Unique OpenGL abstraction layer (usable as standalone module): [rlgl] * Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) * Multiple textures support, including compressed formats and mipmaps generation * Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps * Materials (diffuse, normal, specular) and Lighting (point, directional, spot) support -* Powerful math module for Vector, Matrix and Quaternion operations [raymath] -* Audio loading and playing with streaming support and mixing channels (WAV, OGG, XM, MOD) +* Powerful math module for Vector, Matrix and Quaternion operations: [raymath] +* Audio loading and playing with streaming support and mixing channels [audio] * VR stereo rendering support with configurable HMD device parameters * Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1 * Custom color palette for fancy visuals on raywhite background * Minimal external dependencies (GLFW3, OpenGL, OpenAL) +* Complete binding for LUA [rlua] * -* Used external libs: -* GLFW3 (www.glfw.org) for window/context management and input -* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) -* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) -* stb_image_write (Sean Barret) for image writting (PNG) -* stb_vorbis (Sean Barret) for ogg audio loading -* stb_truetype (Sean Barret) for ttf fonts loading -* jar_xm (Joshua Reisenauer) for XM audio module loading -* jar_mod (Joshua Reisenauer) for MOD audio module loading -* OpenAL Soft for audio device/context management -* tinfl for data decompression (DEFLATE algorithm) +* External libs: +* GLFW3 (www.glfw.org) for window/context management and input [core] +* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] +* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures] +* stb_image_write (Sean Barret) for image writting (PNG) [utils] +* stb_truetype (Sean Barret) for ttf fonts loading [text] +* stb_vorbis (Sean Barret) for ogg audio loading [audio] +* jar_xm (Joshua Reisenauer) for XM audio module loading [audio] +* jar_mod (Joshua Reisenauer) for MOD audio module loading [audio] +* dr_flac (David Reid) for FLAC audio file loading [audio] +* OpenAL Soft for audio device/context management [audio] +* tinfl for data decompression (DEFLATE algorithm) [utils] * * Some design decisions: * 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) -* One custom default font is loaded automatically when InitWindow() +* One custom default font could be loaded automatically when InitWindow() [core] * If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads -* If using OpenGL 3.3 or ES2, two default shaders are loaded automatically (internally defined) +* If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined) * * -- LICENSE -- * diff --git a/src/rlgl.c b/src/rlgl.c index d3bba07b..28dc5171 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2,11 +2,30 @@ * * rlgl - raylib OpenGL abstraction layer * -* raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version: -* OpenGL 1.1 - Direct map rl* -> gl* -* OpenGL 2.1 - Vertex data is stored in VBOs, call rlglDraw() to render -* OpenGL 3.3 - Vertex data is stored in VAOs, call rlglDraw() to render -* OpenGL ES 2 - Vertex data is stored in VBOs or VAOs (when available), call rlglDraw() to render +* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to +* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). +* +* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal +* VBO buffers (and VAOs if available). It requires calling 3 functions: +* rlglInit() - Initialize internal buffers and auxiliar resources +* rlglDraw() - Process internal buffers and send required draw calls +* rlglClose() - De-initialize internal buffers data and other auxiliar resources +* +* External libs: +* raymath - 3D math functionality (Vector3, Matrix, Quaternion) +* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) +* +* Module Configuration Flags: +* GRAPHICS_API_OPENGL_11 - Use OpenGL 1.1 backend +* GRAPHICS_API_OPENGL_21 - Use OpenGL 2.1 backend +* GRAPHICS_API_OPENGL_33 - Use OpenGL 3.3 Core profile backend +* GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend +* +* RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency) +* RLGL_NO_STANDARD_SHADER - Avoid standard shader (shader_standard.h) inclusion +* RLGL_NO_DISTORTION_SHADER - Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion +* RLGL_OCULUS_SUPPORT - Enable Oculus Rift CV1 functionality +* * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * diff --git a/src/rlgl.h b/src/rlgl.h index 78ea6727..e4d40714 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2,11 +2,27 @@ * * rlgl - raylib OpenGL abstraction layer * -* raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version: -* OpenGL 1.1 - Direct map rl* -> gl* -* OpenGL 2.1 - Vertex data is stored in VBOs, call rlglDraw() to render -* OpenGL 3.3 - Vertex data is stored in VAOs, call rlglDraw() to render -* OpenGL ES 2 - Vertex data is stored in VBOs or VAOs (when available), call rlglDraw() to render +* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to +* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). +* +* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal +* VBO buffers (and VAOs if available). It requires calling 3 functions: +* rlglInit() - Initialize internal buffers and auxiliar resources +* rlglDraw() - Process internal buffers and send required draw calls +* rlglClose() - De-initialize internal buffers data and other auxiliar resources +* +* External libs: +* raymath - 3D math functionality (Vector3, Matrix, Quaternion) +* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) +* +* Module Configuration Flags: +* GRAPHICS_API_OPENGL_11 - Use OpenGL 1.1 backend +* GRAPHICS_API_OPENGL_21 - Use OpenGL 2.1 backend +* GRAPHICS_API_OPENGL_33 - Use OpenGL 3.3 Core profile backend +* GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend +* +* RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency) +* * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * diff --git a/src/shapes.c b/src/shapes.c index 79cf567a..70aad59a 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -4,6 +4,12 @@ * * Basic functions to draw 2d Shapes and check collisions * +* External libs: +* rlgl - raylib OpenGL abstraction layer +* +* Module Configuration Flags: +* ... +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event @@ -25,11 +31,11 @@ #include "raylib.h" +#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 + #include // Required for: abs() #include // Required for: sinf(), cosf(), sqrtf() -#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 - //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- diff --git a/src/text.c b/src/text.c index 72d273d4..d752f1cb 100644 --- a/src/text.c +++ b/src/text.c @@ -4,6 +4,12 @@ * * Basic functions to load SpriteFonts and draw Text * +* External libs: +* stb_truetype - Load TTF file and rasterize characters data +* +* Module Configuration Flags: +* ... +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event @@ -33,7 +39,7 @@ #include "utils.h" // Required for: GetExtension(), GetNextPOT() // Following libs are used on LoadTTF() -//#define STBTT_STATIC +#define STBTT_STATIC // Define stb_truetype functions static to this module #define STB_TRUETYPE_IMPLEMENTATION #include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap() diff --git a/src/textures.c b/src/textures.c index 5354a74f..af59d035 100644 --- a/src/textures.c +++ b/src/textures.c @@ -4,9 +4,13 @@ * * Basic functions to load and draw Textures (2d) * -* Uses external lib: -* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) -* NOTE: stb_image has been slightly modified, original library: https://github.com/nothings/stb +* External libs: +* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) +* NOTE: stb_image has been slightly modified to support Android platform. +* stb_image_resize - Multiple image resize algorythms +* +* Module Configuration Flags: +* ... * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * diff --git a/src/utils.c b/src/utils.c index b96e2c70..640c5720 100644 --- a/src/utils.c +++ b/src/utils.c @@ -2,12 +2,16 @@ * * raylib.utils * -* Utils Functions Definitions +* Some utility functions * -* Uses external libs: -* tinfl - zlib DEFLATE algorithm decompression lib +* External libs: +* tinfl - zlib DEFLATE algorithm decompression * stb_image_write - PNG writting functions * +* Module Configuration Flags: +* DO_NOT_TRACE_DEBUG_MSGS - Avoid showing DEBUG TraceLog() messages +* +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event @@ -46,7 +50,9 @@ #endif #include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() - // NOTE: Deflate algorythm data decompression + // NOTE: DEFLATE algorythm data decompression + +#define DO_NOT_TRACE_DEBUG_MSGS // Avoid DEBUG messages tracing //---------------------------------------------------------------------------------- // Global Variables Definition diff --git a/src/utils.h b/src/utils.h index 899cf583..045b0692 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,9 +2,9 @@ * * raylib.utils * -* Some utility functions: rRES files data decompression +* Some utility functions * -* Copyright (c) 2014 Ramon Santamaria (@raysan5) +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. @@ -34,8 +34,6 @@ //---------------------------------------------------------------------------------- // Some basic Defines //---------------------------------------------------------------------------------- -#define DO_NOT_TRACE_DEBUG_MSGS // Use this define to avoid DEBUG tracing - #if defined(PLATFORM_ANDROID) #define fopen(name, mode) android_fopen(name, mode) #endif -- cgit v1.2.3 From bee283b12b348b054bde2eae1a449c363ac26fd7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 17 Nov 2016 12:55:30 +0100 Subject: Some tweaks around --- src/Makefile | 5 +++++ src/core.c | 4 ++-- src/models.c | 12 ++++++------ src/raylib.h | 16 ++++++++-------- src/rlgl.c | 4 ++-- src/rlgl.h | 3 ++- 6 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src/raylib.h') diff --git a/src/Makefile b/src/Makefile index feadc424..2433428f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -41,6 +41,11 @@ SHARED ?= NO # define NO to use OpenAL Soft as static library (or shared by default) SHARED_OPENAL ?= NO +# on PLATFORM_WEB force OpenAL Soft shared library +ifeq ($(PLATFORM),PLATFORM_WEB) + SHARED_OPENAL ?= YES +endif + # determine if the file has root access (only for installing raylib) # "whoami" prints the name of the user that calls him (so, if it is the root # user, "whoami" prints "root"). diff --git a/src/core.c b/src/core.c index 991dd4a0..4807b7f6 100644 --- a/src/core.c +++ b/src/core.c @@ -668,7 +668,7 @@ void Begin3dMode(Camera camera) { rlglDraw(); // Draw Buffers (Only OpenGL 3+ and ES2) - if (IsVrDeviceReady()) BeginVrDrawing(); + if (IsVrDeviceReady() || IsVrSimulator()) BeginVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix @@ -698,7 +698,7 @@ void End3dMode(void) { rlglDraw(); // Process internal buffers (update + draw) - if (IsVrDeviceReady()) EndVrDrawing(); + if (IsVrDeviceReady() || IsVrSimulator()) EndVrDrawing(); rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack diff --git a/src/models.c b/src/models.c index 4275f89e..be0e6ea4 100644 --- a/src/models.c +++ b/src/models.c @@ -81,11 +81,11 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color) } // Draw a circle in 3D world space -void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color) +void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) { rlPushMatrix(); rlTranslatef(center.x, center.y, center.z); - rlRotatef(rotationAngle, rotation.x, rotation.y, rotation.z); + rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); rlBegin(RL_LINES); for (int i = 0; i < 360; i += 10) @@ -584,9 +584,9 @@ void DrawLight(Light light) { DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY)); - DrawCircle3D(light->position, light->radius, 0.0f, (Vector3){ 0, 0, 0 }, (light->enabled ? light->diffuse : GRAY)); - DrawCircle3D(light->position, light->radius, 90.0f, (Vector3){ 1, 0, 0 }, (light->enabled ? light->diffuse : GRAY)); - DrawCircle3D(light->position, light->radius, 90.0f, (Vector3){ 0, 1, 0 }, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, light->radius, (Vector3){ 0, 0, 0 }, 0.0f, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, light->radius, (Vector3){ 1, 0, 0 }, 90.0f, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, light->radius, (Vector3){ 0, 1, 0 },90.0f, (light->enabled ? light->diffuse : GRAY)); } break; case LIGHT_DIRECTIONAL: { @@ -602,7 +602,7 @@ void DrawLight(Light light) Vector3 dir = VectorSubtract(light->target, light->position); VectorNormalize(&dir); - DrawCircle3D(light->position, 0.5f, 0.0f, dir, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, 0.5f, dir, 0.0f, (light->enabled ? light->diffuse : GRAY)); //DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : GRAY)); DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY)); diff --git a/src/raylib.h b/src/raylib.h index ef393f63..6d67051e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -724,7 +724,7 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pin //------------------------------------------------------------------------------------ // Camera System Functions (Module: camera) //------------------------------------------------------------------------------------ -RLAPI void SetCameraMode(Camera, int mode); // Set camera mode (multiple camera modes available) +RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera) @@ -835,7 +835,7 @@ RLAPI const char *SubText(const char *text, int position, int length); // Basic 3d Shapes Drawing Functions (Module: models) //------------------------------------------------------------------------------------ RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space -RLAPI void DrawCircle3D(Vector3 center, float radius, float rotationAngle, Vector3 rotation, Color color); // Draw a circle in 3D world space +RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires @@ -850,7 +850,7 @@ RLAPI void DrawRay(Ray ray, Color color); RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo RLAPI void DrawLight(Light light); // Draw light in 3D world -//DrawTorus(), DrawTeapot() are useless... +//DrawTorus(), DrawTeapot() could be useful? //------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) @@ -917,7 +917,7 @@ RLAPI void DestroyLight(Light light); // Des //------------------------------------------------------------------------------------ RLAPI void InitVrDevice(int vdDevice); // Init VR device RLAPI void CloseVrDevice(void); // Close VR device -RLAPI bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +RLAPI bool IsVrDeviceReady(void); // Detect if VR device is ready RLAPI bool IsVrSimulator(void); // Detect if VR simulator is running RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) @@ -926,7 +926,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR experienc // Audio Loading and Playing Functions (Module: audio) //------------------------------------------------------------------------------------ RLAPI void InitAudioDevice(void); // Initialize audio device and context -RLAPI void CloseAudioDevice(void); // Close the audio device and context (and music stream) +RLAPI void CloseAudioDevice(void); // Close the audio device and context RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM @@ -950,9 +950,9 @@ RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a RLAPI float *GetWaveData(Wave wave); // Get samples data from wave as a floats array RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file RLAPI void UnloadMusicStream(Music music); // Unload music stream -RLAPI void PlayMusicStream(Music music); // Start music playing (open stream) +RLAPI void PlayMusicStream(Music music); // Start music playing RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming -RLAPI void StopMusicStream(Music music); // Stop music playing (close stream) +RLAPI void StopMusicStream(Music music); // Stop music playing RLAPI void PauseMusicStream(Music music); // Pause music playing RLAPI void ResumeMusicStream(Music music); // Resume playing paused music RLAPI bool IsMusicPlaying(Music music); // Check if music is playing @@ -963,7 +963,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, - unsigned int channels); // Init audio stream (to stream audio pcm data) + unsigned int channels); // Init audio stream (to stream raw audio pcm data) RLAPI void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill diff --git a/src/rlgl.c b/src/rlgl.c index 28dc5171..b567f8fd 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2786,13 +2786,13 @@ void CloseVrDevice(void) // Detect if VR device is available bool IsVrDeviceReady(void) { - return (vrDeviceReady || vrSimulator) && vrEnabled; + return (vrDeviceReady && vrEnabled); } // Detect if VR simulator is running bool IsVrSimulator(void) { - return vrSimulator; + return (vrSimulator && vrEnabled); } // Enable/Disable VR experience (device or simulator) diff --git a/src/rlgl.h b/src/rlgl.h index e4d40714..7d328a52 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -423,7 +423,8 @@ float *MatrixToFloat(Matrix mat); void InitVrDevice(int vrDevice); // Init VR device void CloseVrDevice(void); // Close VR device -bool IsVrDeviceReady(void); // Detect if VR device (or simulator) is ready +bool IsVrDeviceReady(void); // Detect if VR device is ready +bool IsVrSimulator(void); // Detect if VR simulator is running void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator) -- cgit v1.2.3 From f1bcfc1352f73b9da98601f6b67cd15853b1cb8f Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 22 Nov 2016 12:14:55 +0100 Subject: Corrected bug on GenTextureMipmaps() texture.mipmaps value needs to be updated, so, texture must be passed by reference instead of by value --- src/raylib.h | 2 +- src/rlgl.c | 30 ++++++++++++++++++------------ src/rlgl.h | 2 +- src/textures.c | 8 ++++---- 4 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 6d67051e..d28b07a3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -802,7 +802,7 @@ RLAPI void ImageColorInvert(Image *image); RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) -RLAPI void GenTextureMipmaps(Texture2D texture); // Generate GPU mipmaps for a texture +RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode diff --git a/src/rlgl.c b/src/rlgl.c index b567f8fd..629d7967 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1719,15 +1719,15 @@ void rlglUpdateTexture(unsigned int id, int width, int height, int format, void } // Generate mipmap data for selected texture -void rlglGenerateMipmaps(Texture2D texture) +void rlglGenerateMipmaps(Texture2D *texture) { - glBindTexture(GL_TEXTURE_2D, texture.id); + glBindTexture(GL_TEXTURE_2D, texture->id); // Check if texture is power-of-two (POT) bool texIsPOT = false; - if (((texture.width > 0) && ((texture.width & (texture.width - 1)) == 0)) && - ((texture.height > 0) && ((texture.height & (texture.height - 1)) == 0))) texIsPOT = true; + if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) && + ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true; if ((texIsPOT) || (npotSupported)) { @@ -1737,13 +1737,13 @@ void rlglGenerateMipmaps(Texture2D texture) // NOTE: data size is reallocated to fit mipmaps data // NOTE: CPU mipmap generation only supports RGBA 32bit data - int mipmapCount = GenerateMipmaps(data, texture.width, texture.height); + int mipmapCount = GenerateMipmaps(data, texture->width, texture->height); - int size = texture.width*texture.height*4; // RGBA 32bit only + int size = texture->width*texture->height*4; // RGBA 32bit only int offset = size; - int mipWidth = texture.width/2; - int mipHeight = texture.height/2; + int mipWidth = texture->width/2; + int mipHeight = texture->height/2; // Load the mipmaps for (int level = 1; level < mipmapCount; level++) @@ -1757,23 +1757,29 @@ void rlglGenerateMipmaps(Texture2D texture) mipHeight /= 2; } - TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture.id); + TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture->id); // NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data free(data); + texture->mipmaps = mipmapCount + 1; #endif #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically - TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id); + TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture->id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps (must be available) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps + + #define MIN(a,b) (((a)<(b))?(a):(b)) + #define MAX(a,b) (((a)>(b))?(a):(b)) + + texture->mipmaps = 1 + floor(log2(MAX(texture->width, texture->height))); #endif } - else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", texture.id); + else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", texture->id); glBindTexture(GL_TEXTURE_2D, 0); } diff --git a/src/rlgl.h b/src/rlgl.h index 7d328a52..bc12db0f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -371,7 +371,7 @@ void rlglLoadExtensions(void *loader); // Load OpenGL extensions unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU 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 rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture 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) diff --git a/src/textures.c b/src/textures.c index af59d035..126adad3 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1516,14 +1516,14 @@ void ImageColorBrightness(Image *image, int brightness) } // Generate GPU mipmaps for a texture -void GenTextureMipmaps(Texture2D texture) +void GenTextureMipmaps(Texture2D *texture) { #if PLATFORM_WEB - int potWidth = GetNextPOT(texture.width); - int potHeight = GetNextPOT(texture.height); + int potWidth = GetNextPOT(texture->width); + int potHeight = GetNextPOT(texture->height); // Check if texture is POT - if ((potWidth != texture.width) || (potHeight != texture.height)) + if ((potWidth != texture->width) || (potHeight != texture->height)) { TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures"); } -- cgit v1.2.3 From f5d792e5514188da56bb35c205e058bca473a300 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 25 Nov 2016 22:26:36 +0100 Subject: Update Lua naming Replaced LUA by Lua --- CHANGELOG | 2 +- README.md | 4 ++-- ROADMAP.md | 2 +- src/raylib.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/raylib.h') diff --git a/CHANGELOG b/CHANGELOG index 8b51d799..71f3d071 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,7 +11,7 @@ NOTE: It includes some interesting new features and is a stepping stone towards raylib future. HUGE changes: -[rlua] LUA BINDING: Complete raylib LUA binding, ALL raylib functions ported to LUA plus the +60 code examples. +[rlua] Lua BINDING: Complete raylib Lua binding, ALL raylib functions ported to Lua plus the +60 code examples. [audio] COMPLETE REDESIGN: Improved music support and also raw audio data processing and playing, +20 new functions added. [physac] COMPLETE REWRITE: Improved performance, functionality and simplified usage, moved to own repository and added multiple examples! diff --git a/README.md b/README.md index 0af5ae04..a5ed70f1 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ notes on raylib 1.6 On November 2016, only 4 months after raylib 1.5, arrives raylib 1.6. This new version represents another big review of the library and includes some interesting additions. This version conmmemorates raylib 3rd anniversary (raylib 1.0 was published on November 2013) and it is a stepping stone for raylib future. raylib roadmap has been reviewed and redefined to focus on its primary objective: create a simple and easy-to-use library to learn videogames programming. Some of the new features: -Complete raylib LUA binding. All raylib functions plus the +60 code examples have been ported to LUA, now LUA users can enjoy coding videogames in LUA while using all the internal power of raylib. This addition also open the doors to LUA scripting support for a future raylib-based engine, being able to move game logic (Init, Update, Draw, De-Init) to LUA scripts while keep using raylib functionality. +Complete raylib Lua binding. All raylib functions plus the +60 code examples have been ported to Lua, now Lua users can enjoy coding videogames in Lua while using all the internal power of raylib. This addition also open the doors to Lua scripting support for a future raylib-based engine, being able to move game logic (Init, Update, Draw, De-Init) to Lua scripts while keep using raylib functionality. Completely redesigned audio module. Based on the new direction taken in raylib 1.5, it has been further improved and more functionality added (+20 new functions) to allow raw audio processing and streaming. FLAC file format support has also been added. In the same line, OpenAL Soft backend is now provided as a static library in Windows to allow static linking and get ride of OpenAL32.dll. Now raylib Windows games are completey self-contained, no external libraries required any more! @@ -272,7 +272,7 @@ contributing (in some way or another) to make raylib project better. Huge thanks - [Emanuele Petriglia](https://github.com/LelixSuper) for working on multiple GNU/Linux improvements and developing [TicTacToe](https://github.com/LelixSuper/TicTacToe) raylib game. - [Joshua Reisenauer](https://github.com/kd7tck) for adding audio modules support (XM, MOD) and reviewing audio system. - Marcelo Paez (paezao) for his help on OSX to solve High DPI display issue. Thanks Marcelo! - - [Ghassan Al-Mashareqa](https://github.com/ghassanpl) for his amazing contribution with raylib LUA module, I just work over his code to implement [rlua](https://github.com/raysan5/raylib/blob/master/src/rlua.h) + - [Ghassan Al-Mashareqa](https://github.com/ghassanpl) for his amazing contribution with raylib Lua module, I just work over his code to implement [rlua](https://github.com/raysan5/raylib/blob/master/src/rlua.h) - [Teodor Stoenescu](https://github.com/teodor-stoenescu) for his improvements on OBJ object loading. Please, if I forget someone in this list, excuse me and write me an email to remind me to add you! diff --git a/ROADMAP.md b/ROADMAP.md index 4c153d78..a7d51f0d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -17,7 +17,7 @@ raylib 1.x raylib 1.6 - [DONE] LUA scripting support (raylib lua wrapper) + [DONE] Lua scripting support (raylib Lua wrapper) [DONE] Redesigned audio module raylib 1.5 diff --git a/src/raylib.h b/src/raylib.h index d28b07a3..8f69438f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -19,7 +19,7 @@ * Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1 * Custom color palette for fancy visuals on raywhite background * Minimal external dependencies (GLFW3, OpenGL, OpenAL) -* Complete binding for LUA [rlua] +* Complete binding for Lua [rlua] * * External libs: * GLFW3 (www.glfw.org) for window/context management and input [core] -- cgit v1.2.3 From 814507906f56f346d35ca95e7d9888213d3e5974 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 17 Dec 2016 19:05:40 +0100 Subject: Improving rRES custom format support -IN PROGRESS- Start removing old rRES functions. --- src/audio.c | 116 +------------------------------------------------ src/core.c | 7 +-- src/models.c | 85 ------------------------------------ src/raylib.h | 4 -- src/textures.c | 134 ++------------------------------------------------------- src/utils.c | 42 ------------------ 6 files changed, 9 insertions(+), 379 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index eef07154..4435b760 100644 --- a/src/audio.c +++ b/src/audio.c @@ -52,8 +52,7 @@ #include // Required for: va_list, va_start(), vfprintf(), va_end() #else #include "raylib.h" - #include "utils.h" // Required for: DecompressData() - // NOTE: Includes Android fopen() function map + #include "utils.h" // Required for: fopen() Android mapping, TraceLog() #endif #include "AL/al.h" // OpenAL basic header @@ -324,119 +323,6 @@ Sound LoadSoundFromWave(Wave wave) return sound; } -// Load sound to memory from rRES file (raylib Resource) -// TODO: Maybe rresName could be directly a char array with all the data? -Sound LoadSoundFromRES(const char *rresName, int resId) -{ - Sound sound = { 0 }; - -#if defined(AUDIO_STANDALONE) - TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode"); -#else - - bool found = false; - - char id[4]; // rRES file identifier - unsigned char version; // rRES file version and subversion - char useless; // rRES header reserved data - short numRes; - - ResInfoHeader infoHeader; - - FILE *rresFile = fopen(rresName, "rb"); - - if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); - else - { - // Read rres file (basic file check - id) - fread(&id[0], sizeof(char), 1, rresFile); - fread(&id[1], sizeof(char), 1, rresFile); - fread(&id[2], sizeof(char), 1, rresFile); - fread(&id[3], sizeof(char), 1, rresFile); - fread(&version, sizeof(char), 1, rresFile); - fread(&useless, sizeof(char), 1, rresFile); - - if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) - { - TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); - } - else - { - // Read number of resources embedded - fread(&numRes, sizeof(short), 1, rresFile); - - for (int i = 0; i < numRes; i++) - { - fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); - - if (infoHeader.id == resId) - { - found = true; - - // Check data is of valid SOUND type - if (infoHeader.type == 1) // SOUND data type - { - // TODO: Check data compression type - // NOTE: We suppose compression type 2 (DEFLATE - default) - - // Reading SOUND parameters - Wave wave; - short sampleRate, bps; - char channels, reserved; - - fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency) - fread(&bps, sizeof(short), 1, rresFile); // Bits per sample - fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo) - fread(&reserved, 1, 1, rresFile); // - - wave.sampleRate = sampleRate; - wave.sampleSize = bps; - wave.channels = (short)channels; - - unsigned char *data = malloc(infoHeader.size); - - fread(data, infoHeader.size, 1, rresFile); - - wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize); - - free(data); - - sound = LoadSoundFromWave(wave); - - // Sound is loaded, we can unload wave data - UnloadWave(wave); - } - else TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName); - } - else - { - // Depending on type, skip the right amount of parameters - /* TODO: Review - switch (infoHeader.type) - { - case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters - case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters - case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) - case 3: break; // TEXT: No parameters - case 4: break; // RAW: No parameters - default: break; - } - */ - - // Jump DATA to read next infoHeader - fseek(rresFile, infoHeader.size, SEEK_CUR); - } - } - } - - fclose(rresFile); - } - - if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); -#endif - return sound; -} - // Unload Wave data void UnloadWave(Wave wave) { diff --git a/src/core.c b/src/core.c index 455417d2..1e03b757 100644 --- a/src/core.c +++ b/src/core.c @@ -42,13 +42,14 @@ * **********************************************************************************************/ -#include "raylib.h" // raylib main header +#include "raylib.h" + #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 -#include "utils.h" // Includes Android fopen map, InitAssetManager(), TraceLog() +#include "utils.h" // Required for: fopen() Android mapping, TraceLog() #define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation) #define RAYMATH_EXTERN_INLINE // Compile raymath functions as static inline (remember, it's a compiler hint) -#include "raymath.h" // Required for Vector3 and Matrix functions +#include "raymath.h" // Required for: Vector3 and Matrix functions #define GESTURES_IMPLEMENTATION #include "gestures.h" // Gestures detection functionality diff --git a/src/models.c b/src/models.c index 97c84abc..7edf8750 100644 --- a/src/models.c +++ b/src/models.c @@ -648,91 +648,6 @@ Model LoadModelEx(Mesh data, bool dynamic) return model; } -// Load a 3d model from rRES file (raylib Resource) -Model LoadModelFromRES(const char *rresName, int resId) -{ - Model model = { 0 }; - bool found = false; - - char id[4]; // rRES file identifier - unsigned char version; // rRES file version and subversion - char useless; // rRES header reserved data - short numRes; - - ResInfoHeader infoHeader; - - FILE *rresFile = fopen(rresName, "rb"); - - if (rresFile == NULL) - { - TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); - } - else - { - // Read rres file (basic file check - id) - fread(&id[0], sizeof(char), 1, rresFile); - fread(&id[1], sizeof(char), 1, rresFile); - fread(&id[2], sizeof(char), 1, rresFile); - fread(&id[3], sizeof(char), 1, rresFile); - fread(&version, sizeof(char), 1, rresFile); - fread(&useless, sizeof(char), 1, rresFile); - - if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) - { - TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); - } - else - { - // Read number of resources embedded - fread(&numRes, sizeof(short), 1, rresFile); - - for (int i = 0; i < numRes; i++) - { - fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); - - if (infoHeader.id == resId) - { - found = true; - - // Check data is of valid MODEL type - if (infoHeader.type == 8) - { - // TODO: Load model data - } - else - { - TraceLog(WARNING, "[%s] Required resource do not seem to be a valid MODEL resource", rresName); - } - } - else - { - // Depending on type, skip the right amount of parameters - /* Review - switch (infoHeader.type) - { - case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters - case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters - case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) - case 3: break; // TEXT: No parameters - case 4: break; // RAW: No parameters - default: break; - } - */ - - // Jump DATA to read next infoHeader - fseek(rresFile, infoHeader.size, SEEK_CUR); - } - } - } - - fclose(rresFile); - } - - if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); - - return model; -} - // Load a heightmap image as a 3d model // NOTE: model map size is defined in generic units Model LoadHeightmap(Image heightmap, Vector3 size) diff --git a/src/raylib.h b/src/raylib.h index 8f69438f..e7d2b74a 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -770,10 +770,8 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve RLAPI Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image data from Color array data (RGBA - 32bit) RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file -RLAPI Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) RLAPI Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory RLAPI Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory -RLAPI Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) RLAPI Texture2D LoadTextureFromImage(Image image); // Load a texture from image data RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) @@ -857,7 +855,6 @@ RLAPI void DrawLight(Light light); //------------------------------------------------------------------------------------ RLAPI Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) RLAPI Model LoadModelEx(Mesh data, bool dynamic); // Load a 3d model (from mesh data) -RLAPI Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource) RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model RLAPI Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) RLAPI void UnloadModel(Model model); // Unload 3d model from memory @@ -933,7 +930,6 @@ RLAPI Wave LoadWave(const char *fileName); // Load wa RLAPI Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) RLAPI Sound LoadSound(const char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data -RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound diff --git a/src/textures.c b/src/textures.c index 631468f9..92b22317 100644 --- a/src/textures.c +++ b/src/textures.c @@ -37,11 +37,10 @@ #include // Required for: strcmp(), strrchr(), strncmp() #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2 - // Required: rlglLoadTexture() rlDeleteTextures(), - // rlglGenerateMipmaps(), some funcs for DrawTexturePro() + // Required for: rlglLoadTexture() rlDeleteTextures(), + // rlglGenerateMipmaps(), some funcs for DrawTexturePro() -#include "utils.h" // rRES data decompression utility function - // NOTE: Includes Android fopen function map +#include "utils.h" // Required for: fopen() Android mapping, TraceLog() // Support only desired texture formats, by default: JPEG, PNG, BMP, TGA //#define STBI_NO_JPEG // Image format .jpg and .jpeg @@ -216,7 +215,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int fread(image.data, size, 1, rawFile); - // TODO: Check if data have been read + // TODO: Check if data has been read image.width = width; image.height = height; @@ -229,119 +228,6 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int return image; } -// Load an image from rRES file (raylib Resource) -// TODO: Review function to support multiple color modes -Image LoadImageFromRES(const char *rresName, int resId) -{ - Image image = { 0 }; - bool found = false; - - char id[4]; // rRES file identifier - unsigned char version; // rRES file version and subversion - char useless; // rRES header reserved data - short numRes; - - ResInfoHeader infoHeader; - - FILE *rresFile = fopen(rresName, "rb"); - - if (rresFile == NULL) - { - TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName); - } - else - { - // Read rres file (basic file check - id) - fread(&id[0], sizeof(char), 1, rresFile); - fread(&id[1], sizeof(char), 1, rresFile); - fread(&id[2], sizeof(char), 1, rresFile); - fread(&id[3], sizeof(char), 1, rresFile); - fread(&version, sizeof(char), 1, rresFile); - fread(&useless, sizeof(char), 1, rresFile); - - if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) - { - TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); - } - else - { - // Read number of resources embedded - fread(&numRes, sizeof(short), 1, rresFile); - - for (int i = 0; i < numRes; i++) - { - fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); - - if (infoHeader.id == resId) - { - found = true; - - // Check data is of valid IMAGE type - if (infoHeader.type == 0) // IMAGE data type - { - // TODO: Check data compression type - // NOTE: We suppose compression type 2 (DEFLATE - default) - - short imgWidth, imgHeight; - char colorFormat, mipmaps; - - fread(&imgWidth, sizeof(short), 1, rresFile); // Image width - fread(&imgHeight, sizeof(short), 1, rresFile); // Image height - fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit) - fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0) - - image.width = (int)imgWidth; - image.height = (int)imgHeight; - - unsigned char *compData = malloc(infoHeader.size); - - fread(compData, infoHeader.size, 1, rresFile); - - unsigned char *imgData = DecompressData(compData, infoHeader.size, infoHeader.srcSize); - - // TODO: Review color mode - //image.data = (unsigned char *)malloc(sizeof(unsigned char)*imgWidth*imgHeight*4); - image.data = imgData; - - //free(imgData); - - free(compData); - - TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height); - } - else - { - TraceLog(WARNING, "[%s] Required resource do not seem to be a valid IMAGE resource", rresName); - } - } - else - { - // Depending on type, skip the right amount of parameters - /* TODO: Review - switch (infoHeader.type) - { - case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters - case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters - case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) - case 3: break; // TEXT: No parameters - case 4: break; // RAW: No parameters - default: break; - } - */ - // Jump DATA to read next infoHeader - fseek(rresFile, infoHeader.size, SEEK_CUR); - } - } - } - - fclose(rresFile); - } - - if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); - - return image; -} - // Load an image as texture into GPU memory Texture2D LoadTexture(const char *fileName) { @@ -378,18 +264,6 @@ Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat) return texture; } -// Load an image as texture from rRES file (raylib Resource) -Texture2D LoadTextureFromRES(const char *rresName, int resId) -{ - Texture2D texture; - - Image image = LoadImageFromRES(rresName, resId); - texture = LoadTextureFromImage(image); - UnloadImage(image); - - return texture; -} - // Load a texture from image data // NOTE: image is not unloaded, it must be done manually Texture2D LoadTextureFromImage(Image image) diff --git a/src/utils.c b/src/utils.c index 640c5720..8fedcaad 100644 --- a/src/utils.c +++ b/src/utils.c @@ -49,9 +49,6 @@ #include "external/stb_image_write.h" // Required for: stbi_write_png() #endif -#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() - // NOTE: DEFLATE algorythm data decompression - #define DO_NOT_TRACE_DEBUG_MSGS // Avoid DEBUG messages tracing //---------------------------------------------------------------------------------- @@ -75,45 +72,6 @@ static int android_close(void *cookie); // Module Functions Definition - Utilities //---------------------------------------------------------------------------------- -// Data decompression function -// NOTE: Allocated data MUST be freed! -unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) -{ - int tempUncompSize; - unsigned char *pUncomp; - - // Allocate buffer to hold decompressed data - pUncomp = (mz_uint8 *)malloc((size_t)uncompSize); - - // Check correct memory allocation - if (pUncomp == NULL) - { - TraceLog(WARNING, "Out of memory while decompressing data"); - } - else - { - // Decompress data - tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1); - - if (tempUncompSize == -1) - { - TraceLog(WARNING, "Data decompression failed"); - free(pUncomp); - } - - if (uncompSize != (int)tempUncompSize) - { - TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted"); - TraceLog(WARNING, " -- Expected uncompressed size: %i", uncompSize); - TraceLog(WARNING, " -- Returned uncompressed size: %i", tempUncompSize); - } - - TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); - } - - return pUncomp; -} - #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) // Creates a bitmap (BMP) file from an array of pixel data // NOTE: This function is not explicitly available to raylib users -- cgit v1.2.3 From c394708c438440db1b756bfe7e86a15341a43cb7 Mon Sep 17 00:00:00 2001 From: Saggi Mizrahi Date: Thu, 22 Dec 2016 03:19:49 +0200 Subject: Change UpdateSound() to accept const void * The function means to accept a const * so let's declare it. Will allow passing const buffers in games. Also constness is next to godliness! Signed-off-by: Saggi Mizrahi --- src/audio.c | 2 +- src/audio.h | 2 +- src/raylib.h | 17 +++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index a9c07c39..aa89de02 100644 --- a/src/audio.c +++ b/src/audio.c @@ -342,7 +342,7 @@ void UnloadSound(Sound sound) // Update sound buffer with new data // NOTE: data must match sound.format -void UpdateSound(Sound sound, void *data, int numSamples) +void UpdateSound(Sound sound, const void *data, int numSamples) { ALint sampleRate, sampleSize, channels; alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); diff --git a/src/audio.h b/src/audio.h index 2b3c5933..db1bb694 100644 --- a/src/audio.h +++ b/src/audio.h @@ -115,7 +115,7 @@ Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, in Sound LoadSound(const 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) -void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data +void UpdateSound(Sound sound, const void *data, int numSamples); // Update sound buffer with new data void UnloadWave(Wave wave); // Unload wave data void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound diff --git a/src/raylib.h b/src/raylib.h index e7d2b74a..fff0c928 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -549,7 +549,7 @@ typedef enum { // Texture parameters: filter mode // NOTE 1: Filtering considers mipmaps if available in the texture // NOTE 2: Filter is accordingly set for minification and magnification -typedef enum { +typedef enum { FILTER_POINT = 0, // No filter, just pixel aproximation FILTER_BILINEAR, // Linear filtering FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) @@ -581,12 +581,12 @@ typedef enum { } Gestures; // Camera system modes -typedef enum { - CAMERA_CUSTOM = 0, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON +typedef enum { + CAMERA_CUSTOM = 0, + CAMERA_FREE, + CAMERA_ORBITAL, + CAMERA_FIRST_PERSON, + CAMERA_THIRD_PERSON } CameraMode; // Head Mounted Display devices @@ -930,7 +930,8 @@ RLAPI Wave LoadWave(const char *fileName); // Load wa RLAPI Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) RLAPI Sound LoadSound(const char *fileName); // Load sound to memory RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data -RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data +RLAPI void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data +RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound -- cgit v1.2.3 From 852f3d4fd0eec8fcebcf39dfc19b2ccc5b008ba3 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 25 Dec 2016 02:01:13 +0100 Subject: Review comments and formatting --- src/core.c | 2 +- src/raylib.h | 110 ++++++++++++++++++++++++++++++++--------------------------- src/rlgl.c | 6 ++-- src/rlgl.h | 2 +- src/text.c | 12 +++---- 5 files changed, 70 insertions(+), 62 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 1e03b757..4793e26a 100644 --- a/src/core.c +++ b/src/core.c @@ -1194,7 +1194,7 @@ const char *GetGamepadName(int gamepad) if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad); else return NULL; #elif defined(PLATFORM_RPI) - if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); + if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName); return gamepadName; #else diff --git a/src/raylib.h b/src/raylib.h index fff0c928..6fd960dc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -351,7 +351,7 @@ typedef struct Image { int width; // Image base width int height; // Image base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat) + int format; // Data format (TextureFormat type) } Image; // Texture2D type, bpp always RGBA (32bit) @@ -361,12 +361,12 @@ typedef struct Texture2D { int width; // Texture base width int height; // Texture base height int mipmaps; // Mipmap levels, 1 by default - int format; // Data format (TextureFormat) + int format; // Data format (TextureFormat type) } Texture2D; // RenderTexture2D type, for texture rendering typedef struct RenderTexture2D { - unsigned int id; // Render texture (fbo) id + unsigned int id; // OpenGL Framebuffer Object (FBO) id Texture2D texture; // Color buffer attachment texture Texture2D depth; // Depth buffer attachment texture } RenderTexture2D; @@ -767,19 +767,19 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve //------------------------------------------------------------------------------------ // Texture Loading and Drawing Functions (Module: textures) //------------------------------------------------------------------------------------ -RLAPI Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) -RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image data from Color array data (RGBA - 32bit) -RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file -RLAPI Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory -RLAPI Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory -RLAPI Texture2D LoadTextureFromImage(Image image); // Load a texture from image data -RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering +RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) +RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit) +RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters +RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data +RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM) +RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data +RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) -RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory -RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory +RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) +RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image -RLAPI void UpdateTexture(Texture2D texture, void *pixels); // Update GPU texture with new data +RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two) RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image @@ -792,7 +792,8 @@ RLAPI Image ImageText(const char *text, int fontSize, Color color); RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) +RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, + float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint @@ -815,9 +816,9 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest // Font Loading and Text Drawing Functions (Module: text) //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont -RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory -RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load a SpriteFont from TTF font with parameters -RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory +RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load SpriteFont from TTF font file with generation parameters +RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters @@ -853,40 +854,48 @@ RLAPI void DrawLight(Light light); //------------------------------------------------------------------------------------ // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ -RLAPI Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) -RLAPI Model LoadModelEx(Mesh data, bool dynamic); // Load a 3d model (from mesh data) -RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model -RLAPI Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based) -RLAPI void UnloadModel(Model model); // Unload 3d model from memory - -RLAPI Material LoadMaterial(const char *fileName); // Load material data (.MTL) -RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) -RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) -RLAPI void UnloadMaterial(Material material); // Unload material textures from VRAM - -RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters +RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file +RLAPI Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData); // Load mesh from vertex data +RLAPI Model LoadModel(const char *fileName); // Load model from file +RLAPI Model LoadModelFromMesh(Mesh data, bool dynamic); // Load model from mesh data +RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load heightmap model from image data +RLAPI Model LoadCubicmap(Image cubicmap); // Load cubes-based map model from image data +RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM) +RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM) + +RLAPI Material LoadMaterial(const char *fileName); // Load material from file +RLAPI Material LoadMaterialEx(Shader shader, Texture2D diffuse, Color color); // Load material from basic shading data +RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) +RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) +RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) + +RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, + float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters -RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) - -RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec - -RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits -RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres -RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes -RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere -RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere -RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere with extended parameters and collision point detection -RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, + float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) + +RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, + Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec + +RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits +RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres +RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes +RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere +RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere +RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, + Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point +RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ -RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations -RLAPI void UnloadShader(Shader shader); // Unload a custom shader from memory +RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations +RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetDefaultShader(void); // Get default shader RLAPI Shader GetStandardShader(void); // Get standard shader @@ -926,12 +935,11 @@ RLAPI void InitAudioDevice(void); // Initial RLAPI void CloseAudioDevice(void); // Close the audio device and context RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully -RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM -RLAPI Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit) -RLAPI Sound LoadSound(const char *fileName); // Load sound to memory -RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data +RLAPI Wave LoadWave(const char *fileName); // Load wave data from file +RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data +RLAPI Sound LoadSound(const char *fileName); // Load sound from file +RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data RLAPI void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data -RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound @@ -961,7 +969,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) -RLAPI void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int numSamples); // Update audio stream buffers with data RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream diff --git a/src/rlgl.c b/src/rlgl.c index c694dcdc..ae28d9b6 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -1690,7 +1690,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) } // Update already loaded texture in GPU with new data -void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data) +void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data) { glBindTexture(GL_TEXTURE_2D, id); @@ -2423,7 +2423,7 @@ Texture2D GetDefaultTexture(void) return texture; } -// Load a custom shader and bind default locations +// Load shader from files and bind default locations Shader LoadShader(char *vsFileName, char *fsFileName) { Shader shader = { 0 }; @@ -2455,7 +2455,7 @@ Shader LoadShader(char *vsFileName, char *fsFileName) return shader; } -// Unload a custom shader from memory +// Unload shader from GPU memory (VRAM) void UnloadShader(Shader shader) { if (shader.id != 0) diff --git a/src/rlgl.h b/src/rlgl.h index bc12db0f..b7c9df00 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -370,7 +370,7 @@ void rlglLoadExtensions(void *loader); // Load OpenGL extensions unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments) -void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data); // Update GPU texture with new data +void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data void rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture void rlglLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids diff --git a/src/text.c b/src/text.c index 27b0a9ce..f97b581d 100644 --- a/src/text.c +++ b/src/text.c @@ -249,7 +249,7 @@ SpriteFont GetDefaultFont() return defaultFont; } -// Load a SpriteFont image into GPU memory +// Load SpriteFont from file into GPU memory (VRAM) SpriteFont LoadSpriteFont(const char *fileName) { // Default hardcoded values for ttf file loading @@ -280,7 +280,7 @@ SpriteFont LoadSpriteFont(const char *fileName) return spriteFont; } -// Load SpriteFont from TTF file with custom parameters +// Load SpriteFont from TTF font file with generation parameters // NOTE: You can pass an array with desired characters, those characters should be available in the font // if array is NULL, default char set is selected 32..126 SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) @@ -311,7 +311,7 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i return spriteFont; } -// Unload SpriteFont from GPU memory +// Unload SpriteFont from GPU memory (VRAM) void UnloadSpriteFont(SpriteFont spriteFont) { // NOTE: Make sure spriteFont is not default font (fallback) @@ -460,13 +460,13 @@ int MeasureText(const char *text, int fontSize) Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing) { int len = strlen(text); - int tempLen = 0; // Used to count longer text line num chars + int tempLen = 0; // Used to count longer text line num chars int lenCounter = 0; float textWidth = 0; - float tempTextWidth = 0; // Used to count longer text line width + float tempTextWidth = 0; // Used to count longer text line width - float textHeight = (float)spriteFont.size; + float textHeight = (float)spriteFont.size; float scaleFactor = fontSize/(float)spriteFont.size; for (int i = 0; i < len; i++) -- cgit v1.2.3 From 202f45415c98df2201202ba8edb10b6496cbeb62 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 27 Dec 2016 17:42:22 +0100 Subject: rRES raylib resources custom file format support First version of custom raylib resources file format -IN DEVELOPMENT- --- src/raylib.h | 20 +++ src/rres.h | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 src/rres.h (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index 6fd960dc..e2e4ee13 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -602,6 +602,26 @@ typedef enum { HMD_FOVE_VR, } VrDevice; +// rRES data returned when reading a resource, it contains all required data for user (24 byte) +typedef struct { + unsigned int type; // Resource type (4 byte) + + unsigned int param1; // Resouce parameter 1 (4 byte) + unsigned int param2; // Resouce parameter 2 (4 byte) + unsigned int param3; // Resouce parameter 3 (4 byte) + unsigned int param4; // Resouce parameter 4 (4 byte) + + void *data; // Resource data pointer (4 byte) +} RRESData; + +typedef enum { + RRES_RAW = 0, + RRES_IMAGE, + RRES_WAVE, + RRES_VERTEX, + RRES_TEXT +} RRESDataType; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif diff --git a/src/rres.h b/src/rres.h new file mode 100644 index 00000000..dcf7be3f --- /dev/null +++ b/src/rres.h @@ -0,0 +1,444 @@ +/********************************************************************************************** +* +* rres - raylib Resource custom format management functions +* +* Basic functions to load/save rRES resource files +* +* External libs: +* tinfl - DEFLATE decompression functions +* +* Module Configuration Flags: +* +* #define RREM_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* +* +* Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RRES_H +#define RRES_H + +#if !defined(RRES_STANDALONE) + #include "raylib.h" +#endif + +//#define RRES_STATIC +#ifdef RRES_STATIC + #define RRESDEF static // Functions just visible to module including this file +#else + #ifdef __cplusplus + #define RRESDEF extern "C" // Functions visible from other files (no name mangling of functions in C++) + #else + #define RRESDEF extern // Functions visible from other files + #endif +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define MAX_RESOURCES_SUPPORTED 256 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RRES_STANDALONE) + // rRES data returned when reading a resource, it contains all required data for user (24 byte) + typedef struct { + unsigned int type; // Resource type (4 byte) + + unsigned int param1; // Resouce parameter 1 (4 byte) + unsigned int param2; // Resouce parameter 2 (4 byte) + unsigned int param3; // Resouce parameter 3 (4 byte) + unsigned int param4; // Resouce parameter 4 (4 byte) + + void *data; // Resource data pointer (4 byte) + } RRESData; + + typedef enum { + RRES_RAW = 0, + RRES_IMAGE, + RRES_WAVE, + RRES_VERTEX, + RRES_TEXT + } RRESDataType; +#endif + +//---------------------------------------------------------------------------------- +// Global variables +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +RRESDEF RRESData LoadResource(const char *rresFileName); +RRESDEF RRESData LoadResourceById(const char *rresFileName, int rresId); +RRESDEF void UnloadResource(RRESData rres); + +#endif // RRES_H + + +/*********************************************************************************** +* +* RRES IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RRES_IMPLEMENTATION) + +#include // Required for: FILE, fopen(), fclose() + +// Check if custom malloc/free functions defined, if not, using standard ones +#if !defined(RRES_MALLOC) + #include // Required for: malloc(), free() + + #define RRES_MALLOC(size) malloc(size) + #define RRES_FREE(ptr) free(ptr) +#endif + +#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() + // NOTE: DEFLATE algorythm data decompression + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// rRES file header (8 byte) +typedef struct { + char id[4]; // File identifier: rRES (4 byte) + unsigned short version; // File version and subversion (2 byte) + unsigned short count; // Number of resources in this file (2 byte) +} RRESFileHeader; + +// rRES info header, every resource includes this header (12 byte + 16 byte) +typedef struct { + unsigned short id; // Resource unique identifier (2 byte) + unsigned char dataType; // Resource data type (1 byte) + unsigned char compType; // Resource data compression type (1 byte) + unsigned int dataSize; // Resource data size (compressed or not, only DATA) (4 byte) + unsigned int uncompSize; // Resource data size (uncompressed, only DATA) (4 byte) + + unsigned int param1; // Resouce parameter 1 (4 byte) + unsigned int param2; // Resouce parameter 2 (4 byte) + unsigned int param3; // Resouce parameter 3 (4 byte) + unsigned int param4; // Resouce parameter 4 (4 byte) +} RRESInfoHeader; + +// Compression types +typedef enum { + RRES_COMP_NONE = 0, // No data compression + RRES_COMP_DEFLATE, // DEFLATE compression + RRES_COMP_LZ4, // LZ4 compression + RRES_COMP_LZMA, // LZMA compression + // brotli, zopfli, gzip // Other compression algorythms... +} RRESCompressionType; + +#if defined(RRES_STANDALONE) +typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize); + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Load resource from file (only one) +// NOTE: Returns uncompressed data with parameters, only first resource found +RRESDEF RRESData LoadResource(const char *fileName) +{ + RRESData rres = { 0 }; + + RRESFileHeader fileHeader; + RRESInfoHeader infoHeader; + + FILE *rresFile = fopen(fileName, "rb"); + + if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName); + else + { + // Read rres file info header + fread(&fileHeader.id[0], sizeof(char), 1, rresFile); + fread(&fileHeader.id[1], sizeof(char), 1, rresFile); + fread(&fileHeader.id[2], sizeof(char), 1, rresFile); + fread(&fileHeader.id[3], sizeof(char), 1, rresFile); + fread(&fileHeader.version, sizeof(short), 1, rresFile); + fread(&fileHeader.count, sizeof(short), 1, rresFile); + + // Verify "rRES" identifier + if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) + { + TraceLog(WARNING, "[%s] This is not a valid raylib resource file", fileName); + } + else + { + // Read first resource info and parameters + fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); + + // Register data type and parameters + rres.type = infoHeader.dataType; + rres.param1 = infoHeader.param1; + rres.param2 = infoHeader.param2; + rres.param3 = infoHeader.param3; + rres.param4 = infoHeader.param4; + + // Read resource data block + void *data = RRES_MALLOC(infoHeader.dataSize); + fread(data, infoHeader.dataSize, 1, rresFile); + + if (infoHeader.compType == RRES_COMP_DEFLATE) + { + void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); + + rres.data = uncompData; + + RRES_FREE(data); + } + else rres.data = data; + + if (rres.data != NULL) TraceLog(INFO, "[%s] Resource data loaded successfully", fileName); + } + + fclose(rresFile); + } + + return rres; +} + +// Load resource from file by id +// NOTE: Returns uncompressed data with parameters, search resource by id +RRESDEF RRESData LoadResourceById(const char *fileName, int rresId) +{ + RRESData rres = { 0 }; + + RRESFileHeader fileHeader; + RRESInfoHeader infoHeader; + + FILE *rresFile = fopen(fileName, "rb"); + + if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName); + else + { + // Read rres file info header + fread(&fileHeader.id[0], sizeof(char), 1, rresFile); + fread(&fileHeader.id[1], sizeof(char), 1, rresFile); + fread(&fileHeader.id[2], sizeof(char), 1, rresFile); + fread(&fileHeader.id[3], sizeof(char), 1, rresFile); + fread(&fileHeader.version, sizeof(short), 1, rresFile); + fread(&fileHeader.count, sizeof(short), 1, rresFile); + + // Verify "rRES" identifier + if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) + { + TraceLog(WARNING, "[%s] This is not a valid raylib resource file", fileName); + } + else + { + for (int i = 0; i < fileHeader.count; i++) + { + // Read resource info and parameters + fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); + + if (infoHeader.id == rresId) + { + // Register data type and parameters + rres.type = infoHeader.dataType; + rres.param1 = infoHeader.param1; + rres.param2 = infoHeader.param2; + rres.param3 = infoHeader.param3; + rres.param4 = infoHeader.param4; + + // Read resource data block + void *data = RRES_MALLOC(infoHeader.dataSize); + fread(data, infoHeader.dataSize, 1, rresFile); + + if (infoHeader.compType == RRES_COMP_DEFLATE) + { + void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); + + rres.data = uncompData; + + RRES_FREE(data); + } + else rres.data = data; + + if (rres.data != NULL) TraceLog(INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)rresId); + } + else + { + // Skip required data to read next resource infoHeader + fseek(rresFile, infoHeader.dataSize, SEEK_CUR); + } + } + + if (rres.data == NULL) TraceLog(WARNING, "[%s][ID %i] Requested resource could not be found, wrong id?", fileName, (int)rresId); + } + + fclose(rresFile); + } + + return rres; +} + +RRESDEF void UnloadResource(RRESData rres) +{ + if (rres.data != NULL) free(rres.data); +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + +// Data decompression function +// NOTE: Allocated data MUST be freed by user +static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) +{ + int tempUncompSize; + void *uncompData; + + // Allocate buffer to hold decompressed data + uncompData = (mz_uint8 *)RRES_MALLOC((size_t)uncompSize); + + // Check correct memory allocation + if (uncompData == NULL) + { + TraceLog(WARNING, "Out of memory while decompressing data"); + } + else + { + // Decompress data + tempUncompSize = tinfl_decompress_mem_to_mem(uncompData, (size_t)uncompSize, data, compSize, 1); + + if (tempUncompSize == -1) + { + TraceLog(WARNING, "Data decompression failed"); + RRES_FREE(uncompData); + } + + if (uncompSize != (int)tempUncompSize) + { + TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted"); + TraceLog(WARNING, " -- Expected uncompressed size: %i", uncompSize); + TraceLog(WARNING, " -- Returned uncompressed size: %i", tempUncompSize); + } + + TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); + } + + return uncompData; +} + + +// Some required functions for rres standalone module version +#if defined(RRES_STANDALONE) +// Outputs a trace log message (INFO, ERROR, WARNING) +// NOTE: If a file has been init, output log is written there +void TraceLog(int msgType, const char *text, ...) +{ + va_list args; + int traceDebugMsgs = 0; + +#ifdef DO_NOT_TRACE_DEBUG_MSGS + traceDebugMsgs = 0; +#endif + + switch (msgType) + { + case INFO: fprintf(stdout, "INFO: "); break; + case ERROR: fprintf(stdout, "ERROR: "); break; + case WARNING: fprintf(stdout, "WARNING: "); break; + case DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break; + default: break; + } + + if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) + { + va_start(args, text); + vfprintf(stdout, text, args); + va_end(args); + + fprintf(stdout, "\n"); + } + + if (msgType == ERROR) exit(1); // If ERROR message, exit program +} +#endif + +#endif // RAYGUI_IMPLEMENTATION + + +/* +//T LoadResource(const char *rresFileName, int resId); + +// ASSUMPTION: rRES files only contain one resource (solution to id requirement...) + +// Now, rres file check and data loading can be managed inside each function: +Image LoadImage(); // -> Texture2D +Wave LoadWave() // -> Sound, Music +const char *LoadText(); // -> Shader, Material + +// NOTE: RRESData uses void* data pointer, so we can load to image.data, wave.data, mesh.*, (unsigned char *) + +Image LoadImagePro(void *data, int width, int height, int format); +Image LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); + +Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData); +Mesh LoadMeshEx(rres.param1, rres.data, rres.data + offset, rres.data + offset*2, rres.data + offset*3); + +Shader LoadShaderV(const char *vsText, int vsLength); +Shader LoadShaderV(rres.data, rres.param1); + +Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); +Wave LoadWaveEx(rres.data, rres.param1, (int)rres.param2, (int)rres.param3, (int)rres.param4); + +// Max value for an unsigned short: 65535 + +// Parameters information depending on resource type (IMAGE, WAVE, MESH, TEXT) + +// Image data params +int imgWidth, imgHeight; +char colorFormat, mipmaps; + +// Wave data params +short sampleRate, bps; +char channels, reserved; + +// Mesh data params +int vertexCount, reserved; +short vertexTypesMask, vertexFormatsMask; + +// Text data params +int numChars; +char textFormat, language, charsetCode; +*/ \ No newline at end of file -- cgit v1.2.3 From 037da8879a3ae61b09d8388bc2b4a2fe5359256a Mon Sep 17 00:00:00 2001 From: Joel Davis Date: Sat, 31 Dec 2016 15:06:39 -0800 Subject: Added RaycastGround and ray picking example --- examples/Makefile | 6 +++ examples/core_3d_raypick.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ src/raylib.h | 15 ++++++ src/shapes.c | 20 ++++++++ 4 files changed, 159 insertions(+) create mode 100644 examples/core_3d_raypick.c (limited to 'src/raylib.h') diff --git a/examples/Makefile b/examples/Makefile index 710e97c4..676529c7 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -203,6 +203,7 @@ EXAMPLES = \ core_gestures_detection \ core_3d_mode \ core_3d_picking \ + core_3d_raypick \ core_3d_camera_free \ core_3d_camera_first_person \ core_2d_camera \ @@ -320,6 +321,11 @@ core_3d_mode: core_3d_mode.c core_3d_picking: core_3d_picking.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +# compile [core] example - 3d ray picking +core_3d_raypick: core_3d_raypick.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + + # compile [core] example - 3d camera free core_3d_camera_free: core_3d_camera_free.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) diff --git a/examples/core_3d_raypick.c b/examples/core_3d_raypick.c new file mode 100644 index 00000000..c1c32771 --- /dev/null +++ b/examples/core_3d_raypick.c @@ -0,0 +1,118 @@ +/******************************************************************************************* +* +* raylib [core] example - Ray-Picking in 3d mode, also ground plane +* +* 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) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d ray picking"); + + // Define the camera to look into our 3d world + Camera camera; + camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + + Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; + Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; + Vector3 groundCursorPos = { 0 }; + + Ray ray; // Picking line ray + + bool collision = false; + + SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode + + 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 camera + + // if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) + // { + // // NOTE: This function is NOT WORKING properly! + // ray = GetMouseRay(GetMousePosition(), camera); + + // // Check collision between ray and box + // collision = CheckCollisionRayBox(ray, + // (BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 }, + // (Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }}); + // } + + ray = GetMouseRay(GetMousePosition(), camera); + RayHitInfo hitinfo = RaycastGroundPlane( ray, 0.0 ); + + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + Begin3dMode(camera); + + if (collision) + { + DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED); + DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON); + + DrawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN); + } + else + { + DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, GRAY); + DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY); + } + + if (hitinfo.hit) { + + groundCursorPos = hitinfo.hitPosition; + groundCursorPos.y += 0.25; // Offset so the cube rests on the ground + printf("Hit: groundpos %3.2f %3.2f %3.2f\n", + groundCursorPos.x, groundCursorPos.y, groundCursorPos.z ); + DrawCubeWires( groundCursorPos, 0.5, 0.5, 0.5, RED ); + } + + DrawRay(ray, MAROON); + + DrawGrid(10, 1.0f); + + End3dMode(); + + //DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY); + + //if(collision) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index e2e4ee13..f291ce85 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -97,6 +97,9 @@ #define DEG2RAD (PI/180.0f) #define RAD2DEG (180.0f/PI) +// A small number +#define EPSILON 0.000001 + // raylib Config Flags #define FLAG_FULLSCREEN_MODE 1 #define FLAG_RESIZABLE_WINDOW 2 @@ -491,6 +494,13 @@ typedef struct Ray { Vector3 direction; // Ray direction } Ray; +// Information returned from a raycast +typedef struct RayHitInfo { + bool hit; // Did the ray hit something? + Vector3 hitPosition; // Position of nearest hit + Vector3 hitNormal; // Surface normal of hit +} RayHitInfo; + // Wave type, defines audio wave data typedef struct Wave { unsigned int sampleCount; // Number of samples @@ -910,6 +920,11 @@ RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphe Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box +//------------------------------------------------------------------------------------ +// Ray Casts +//------------------------------------------------------------------------------------ +RLAPI RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ); + //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 diff --git a/src/shapes.c b/src/shapes.c index 3d3333c1..4b2de4f2 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -533,4 +533,24 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) } return retRec; +} + + +RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ) +{ + RayHitInfo result = {0}; + + if (fabs(ray.direction.y) > EPSILON) + { + float t = (ray.position.y - groundHeight) / -ray.direction.y; + if (t >= 0.0) { + Vector3 camDir = ray.direction; + VectorScale( &camDir, t ); + result.hit = true; + result.hitNormal = (Vector3){ 0.0, 1.0, 0.0}; + result.hitPosition = VectorAdd( ray.position, camDir ); + } + } + + return result; } \ No newline at end of file -- cgit v1.2.3 From d5d391faaf69027b8fecb26f30754c3bff83c311 Mon Sep 17 00:00:00 2001 From: Joel Davis Date: Mon, 2 Jan 2017 21:56:25 -0800 Subject: Added RaycastMesh function and example test case --- examples/core_3d_raypick.c | 159 +++++++--- examples/resources/model/lowpoly-tower.obj | 456 +++++++++++++++++++++++++++++ examples/resources/model/lowpoly-tower.png | Bin 0 -> 24939 bytes src/models.c | 38 +++ src/raylib.h | 3 + src/raymath.h | 26 ++ src/shapes.c | 73 ++++- 7 files changed, 708 insertions(+), 47 deletions(-) create mode 100644 examples/resources/model/lowpoly-tower.obj create mode 100644 examples/resources/model/lowpoly-tower.png (limited to 'src/raylib.h') diff --git a/examples/core_3d_raypick.c b/examples/core_3d_raypick.c index c1c32771..cf56b277 100644 --- a/examples/core_3d_raypick.c +++ b/examples/core_3d_raypick.c @@ -1,15 +1,21 @@ /******************************************************************************************* * -* raylib [core] example - Ray-Picking in 3d mode, also ground plane +* raylib [core] example - Ray-Picking in 3d mode, ground plane, triangle, mesh * * 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) 2015 Ramon Santamaria (@raysan5) +* Example contributed by Joel Davis (@joeld42) * ********************************************************************************************/ #include "raylib.h" +#include "raymath.h" + +#include +#include + int main() { @@ -22,24 +28,36 @@ int main() // Define the camera to look into our 3d world Camera camera; - camera.position = (Vector3){ 10.0f, 10.0f, 10.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target) + camera.position = (Vector3){ 10.0f, 8.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.3f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target) camera.fovy = 45.0f; // Camera field-of-view Y Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; - Vector3 groundCursorPos = { 0 }; Ray ray; // Picking line ray - bool collision = false; - + Model tower = LoadModel("resources/model/lowpoly-tower.obj"); // Load OBJ model + Texture2D texture = LoadTexture("resources/model/lowpoly-tower.png"); // Load model texture + tower.material.texDiffuse = texture; // Set model diffuse texture + Vector3 towerPos = { 0.0f, 0.0f, 0.0f }; // Set model position + BoundingBox towerBBox = CalculateBoundingBox( tower.mesh ); + bool hitMeshBBox; + bool hitTriangle; + + // Test triangle + Vector3 ta = (Vector3){ -25.0, 0.5, 0.0 }; + Vector3 tb = (Vector3){ -4.0, 2.5, 1.0 }; + Vector3 tc = (Vector3){ -8.0, 6.5, 0.0 }; + + Vector3 bary = {0}; + SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode SetTargetFPS(60); // Set our game to run at 60 frames-per-second - //-------------------------------------------------------------------------------------- + //-------------------------------------------------------------------------------------- // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { @@ -47,22 +65,52 @@ int main() //---------------------------------------------------------------------------------- UpdateCamera(&camera); // Update camera - // if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - // { - // // NOTE: This function is NOT WORKING properly! - // ray = GetMouseRay(GetMousePosition(), camera); - - // // Check collision between ray and box - // collision = CheckCollisionRayBox(ray, - // (BoundingBox){(Vector3){ cubePosition.x - cubeSize.x/2, cubePosition.y - cubeSize.y/2, cubePosition.z - cubeSize.z/2 }, - // (Vector3){ cubePosition.x + cubeSize.x/2, cubePosition.y + cubeSize.y/2, cubePosition.z + cubeSize.z/2 }}); - // } + // Display information about closest hit + RayHitInfo nearestHit; + char *hitObjectName = "None"; + nearestHit.distance = FLT_MAX; + nearestHit.hit = false; + Color cursorColor = WHITE; + + // Get ray and test against ground, triangle, and mesh ray = GetMouseRay(GetMousePosition(), camera); - RayHitInfo hitinfo = RaycastGroundPlane( ray, 0.0 ); + + RayHitInfo groundHitInfo = RaycastGroundPlane( ray, 0.0 ); + if ((groundHitInfo.hit) && (groundHitInfo.distance < nearestHit.distance)) { + nearestHit = groundHitInfo; + cursorColor = GREEN; + hitObjectName = "Ground"; + } + + RayHitInfo triHitInfo = RaycastTriangle( ray, ta, tb, tc ); + if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance)) { + nearestHit = triHitInfo; + cursorColor = PURPLE; + hitObjectName = "Triangle"; + + bary = Barycentric( nearestHit.hitPosition, ta, tb, tc ); + hitTriangle = true; + } else { + hitTriangle = false; + } + + RayHitInfo meshHitInfo; + + // check the bounding box first, before trying the full ray/mesh test + if (CheckCollisionRayBox( ray, towerBBox )) { + hitMeshBBox = true; + meshHitInfo = RaycastMesh( ray, &tower.mesh ); + if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance)) { + nearestHit = meshHitInfo; + cursorColor = ORANGE; + hitObjectName = "Mesh"; + } + } else { + hitMeshBBox = false; + } //---------------------------------------------------------------------------------- - // Draw //---------------------------------------------------------------------------------- BeginDrawing(); @@ -71,37 +119,66 @@ int main() Begin3dMode(camera); - if (collision) - { - DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, RED); - DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, MAROON); - - DrawCubeWires(cubePosition, cubeSize.x + 0.2f, cubeSize.y + 0.2f, cubeSize.z + 0.2f, GREEN); - } - else - { - DrawCube(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, GRAY); - DrawCubeWires(cubePosition, cubeSize.x, cubeSize.y, cubeSize.z, DARKGRAY); + // Draw the tower + DrawModel( tower, towerPos, 1.0, WHITE ); + + // Draw the test triangle + DrawLine3D( ta, tb, PURPLE ); + DrawLine3D( tb, tc, PURPLE ); + DrawLine3D( tc, ta, PURPLE ); + + // Draw the mesh bbox if we hit it + if (hitMeshBBox) { + DrawBoundingBox( towerBBox, LIME ); } - if (hitinfo.hit) { + // If we hit something, draw the cursor at the hit point + if (nearestHit.hit) { + DrawCube( nearestHit.hitPosition, 0.5, 0.5, 0.5, cursorColor ); + DrawCubeWires( nearestHit.hitPosition, 0.5, 0.5, 0.5, YELLOW ); - groundCursorPos = hitinfo.hitPosition; - groundCursorPos.y += 0.25; // Offset so the cube rests on the ground - printf("Hit: groundpos %3.2f %3.2f %3.2f\n", - groundCursorPos.x, groundCursorPos.y, groundCursorPos.z ); - DrawCubeWires( groundCursorPos, 0.5, 0.5, 0.5, RED ); + Vector3 normalEnd; + normalEnd.x = nearestHit.hitPosition.x + nearestHit.hitNormal.x; + normalEnd.y = nearestHit.hitPosition.y + nearestHit.hitNormal.y; + normalEnd.z = nearestHit.hitPosition.z + nearestHit.hitNormal.z; + DrawLine3D( nearestHit.hitPosition, normalEnd, YELLOW ); } - + DrawRay(ray, MAROON); DrawGrid(10, 1.0f); End3dMode(); - //DrawText("Try selecting the box with mouse!", 240, 10, 20, DARKGRAY); - - //if(collision) DrawText("BOX SELECTED", (screenWidth - MeasureText("BOX SELECTED", 30)) / 2, screenHeight * 0.1f, 30, GREEN); + // Show some debug text + char line[1024]; + sprintf( line, "Hit Object: %s\n", hitObjectName ); + DrawText( line, 10, 30, 15, BLACK ); + + if (nearestHit.hit) { + int ypos = 45; + sprintf( line, "Distance: %3.2f", nearestHit.distance ); + DrawText( line, 10, ypos, 15, BLACK ); + ypos += 15; + + sprintf( line, "Hit Pos: %3.2f %3.2f %3.2f", + nearestHit.hitPosition.x, nearestHit.hitPosition.y, nearestHit.hitPosition.z ); + DrawText( line, 10, ypos, 15, BLACK ); + ypos += 15; + + sprintf( line, "Hit Norm: %3.2f %3.2f %3.2f", + nearestHit.hitNormal.x, nearestHit.hitNormal.y, nearestHit.hitNormal.z ); + DrawText( line, 10, ypos, 15, BLACK ); + ypos += 15; + + if (hitTriangle) { + sprintf( line, "Barycentric: %3.2f %3.2f %3.2f", + bary.x, bary.y, bary.z ); + DrawText( line, 10, ypos, 15, BLACK ); + } + } + + DrawText( "Use Mouse to Move Camera", 10, 420, 15, LIGHTGRAY ); DrawFPS(10, 10); diff --git a/examples/resources/model/lowpoly-tower.obj b/examples/resources/model/lowpoly-tower.obj new file mode 100644 index 00000000..ea03a9fc --- /dev/null +++ b/examples/resources/model/lowpoly-tower.obj @@ -0,0 +1,456 @@ +# Blender v2.78 (sub 0) OBJ File: 'lowpoly-tower.blend' +# www.blender.org +o Grid +v -4.000000 0.000000 4.000000 +v -2.327363 0.000000 4.654725 +v 0.000000 0.000000 4.654725 +v 2.327363 0.000000 4.654725 +v 4.000000 0.000000 4.000000 +v -4.654725 0.955085 2.327363 +v -2.000000 0.815050 2.000000 +v 0.000000 0.476341 2.423448 +v 2.000000 0.476341 2.000000 +v 4.654725 0.000000 2.327363 +v -4.654725 1.649076 0.000000 +v -2.423448 1.092402 0.000000 +v 2.423448 0.198579 0.000000 +v 4.654725 0.000000 0.000000 +v -4.654725 1.649076 -2.327363 +v -2.000000 1.092402 -2.000000 +v 0.000000 0.476341 -2.423448 +v 2.000000 -0.012791 -2.000000 +v 4.654725 0.000000 -2.612731 +v -4.000000 0.955085 -4.000000 +v -2.327363 0.955085 -4.654725 +v 0.000000 0.955085 -4.654725 +v 2.327363 0.000000 -4.654725 +v 4.000000 0.000000 -4.000000 +v 2.423448 0.682825 0.000000 +v 2.000000 0.565423 -2.000000 +v -4.654725 -0.020560 2.327363 +v -4.654725 0.000000 0.000000 +v -4.654725 0.000000 -2.327363 +v -4.000000 0.000000 -4.000000 +v -2.327363 0.000000 -4.654725 +v 0.000000 -0.020560 -4.654725 +v 0.000000 0.709880 -1.230535 +v -0.000000 7.395413 0.000000 +v 0.962071 0.709880 -0.767226 +v -0.533909 0.709880 1.108674 +v -1.199683 0.709880 0.273820 +v -0.962071 0.709880 -0.767226 +v 1.506076 0.859071 1.325337 +v 1.199683 0.709880 0.273820 +v 0.533909 0.709880 1.108674 +v 0.000000 1.875340 -1.177842 +v -0.000000 2.293973 -0.649884 +v -0.000000 4.365648 -0.627970 +v 0.000000 6.167194 -0.942957 +v 0.000000 6.232434 -1.708677 +v 1.335898 6.232434 -1.065343 +v 0.737233 6.167195 -0.587924 +v 0.490966 4.365648 -0.391533 +v 0.508100 2.293973 -0.405196 +v 0.920874 1.875340 -0.734372 +v -0.741367 6.232434 1.539465 +v -0.409133 6.167195 0.849574 +v -0.272466 4.365648 0.565781 +v -0.281974 2.293973 0.585526 +v -0.511047 1.875340 1.061199 +v -1.665837 6.232434 0.380217 +v -0.919314 6.167195 0.209828 +v -0.612225 4.365648 0.139736 +v -0.633590 2.293973 0.144613 +v -1.148311 1.875340 0.262095 +v -1.335898 6.232434 -1.065343 +v -0.737233 6.167195 -0.587924 +v -0.490967 4.365648 -0.391533 +v -0.508100 2.293973 -0.405196 +v -0.920874 1.875340 -0.734372 +v 1.665837 6.232434 0.380216 +v 0.919315 6.167195 0.209828 +v 0.612225 4.365648 0.139736 +v 0.633590 2.293973 0.144613 +v 1.148311 1.875340 0.262095 +v 0.741367 6.232434 1.539465 +v 0.409133 6.167195 0.849575 +v 0.272466 4.365648 0.565781 +v 0.281974 2.293973 0.585526 +v 0.511046 1.875340 1.061199 +v 0.000000 5.012550 -0.969733 +v 0.758168 5.012550 -0.604618 +v -0.420751 5.012550 0.873699 +v -0.945419 5.012550 0.215786 +v -0.758168 5.012550 -0.604618 +v 0.945419 5.012550 0.215786 +v 0.420751 5.012550 0.873699 +vt 0.0523 0.5444 +vt 0.1817 0.4284 +vt 0.1641 0.5859 +vt 0.0177 0.4451 +vt 0.1526 0.3090 +vt 0.0189 0.1737 +vt 0.0188 0.3088 +vt 0.0561 0.0762 +vt 0.1757 0.1924 +vt 0.3024 0.4534 +vt 0.3071 0.5902 +vt 0.3413 0.2459 +vt 0.2906 0.1614 +vt 0.4116 0.1801 +vt 0.2834 0.3774 +vt 0.1526 0.0362 +vt 0.2917 0.1622 +vt 0.4446 0.5865 +vt 0.4443 0.2989 +vt 0.3711 0.3021 +vt 0.4396 0.0275 +vt 0.4094 0.1829 +vt 0.4219 0.4255 +vt 0.5474 0.5381 +vt 0.5811 0.4376 +vt 0.5715 0.1505 +vt 0.5811 0.2997 +vt 0.5272 0.0533 +vt 0.2208 0.2194 +vt 0.3456 0.3610 +vt 0.2878 0.0321 +vt 0.2321 0.3392 +vt 0.4432 0.0177 +vt 0.7347 0.7934 +vt 0.7382 0.7595 +vt 0.8982 0.7768 +vt 0.6169 0.7595 +vt 0.6139 0.7879 +vt 0.4951 0.7634 +vt 0.1551 0.6832 +vt 0.2925 0.6268 +vt 0.2925 0.6832 +vt 0.7795 0.6832 +vt 0.6421 0.6268 +vt 0.7795 0.6255 +vt 0.5046 0.7241 +vt 0.6421 0.7241 +vt 0.3986 0.6268 +vt 0.3986 0.6832 +vt 0.5046 0.6268 +vt 0.0177 0.6268 +vt 0.1551 0.6255 +vt 0.8856 0.6268 +vt 0.1899 0.9579 +vt 0.1194 0.8696 +vt 0.2324 0.8696 +vt 0.1899 0.7813 +vt 0.0943 0.7595 +vt 0.0177 0.8206 +vt 0.0177 0.9186 +vt 0.0943 0.9797 +vt 0.2793 0.2349 +vt 0.2304 0.2758 +vt 0.6597 0.0177 +vt 0.6954 0.0993 +vt 0.6367 0.0768 +vt 0.7558 0.0777 +vt 0.7238 0.0440 +vt 0.8840 0.1330 +vt 0.7385 0.1141 +vt 0.9157 0.0886 +vt 0.9781 0.1232 +vt 0.9224 0.1276 +vt 0.2677 0.8141 +vt 0.3463 0.8037 +vt 0.3086 0.8339 +vt 0.6387 0.3550 +vt 0.7130 0.3801 +vt 0.6596 0.4053 +vt 0.7245 0.3245 +vt 0.6919 0.3383 +vt 0.8655 0.3566 +vt 0.7351 0.3577 +vt 0.9770 0.3365 +vt 0.9078 0.3751 +vt 0.9174 0.3282 +vt 0.2677 0.9018 +vt 0.3086 0.8821 +vt 0.6803 0.2948 +vt 0.6251 0.3035 +vt 0.7194 0.2854 +vt 0.8764 0.2832 +vt 0.9221 0.2861 +vt 0.3363 0.9565 +vt 0.3464 0.9122 +vt 0.6751 0.2482 +vt 0.6178 0.2499 +vt 0.7179 0.2431 +vt 0.9823 0.2484 +vt 0.9247 0.2452 +vt 0.3935 0.9014 +vt 0.6755 0.1996 +vt 0.6164 0.1941 +vt 0.7201 0.1992 +vt 0.8793 0.2446 +vt 0.9823 0.2060 +vt 0.9257 0.2051 +vt 0.4598 0.8580 +vt 0.4144 0.8579 +vt 0.6819 0.1498 +vt 0.6222 0.1361 +vt 0.7266 0.1555 +vt 0.8831 0.1684 +vt 0.9252 0.1659 +vt 0.4218 0.7790 +vt 0.3934 0.8145 +vt 0.3363 0.7595 +vt 0.8815 0.2060 +vt 0.8720 0.3208 +vt 0.8825 0.1012 +vt 0.9735 0.0816 +vt 0.9718 0.3817 +vt 0.9807 0.2918 +vt 0.4218 0.9370 +vt 0.9810 0.1644 +vn 0.1035 0.8806 0.4623 +vn 0.0964 0.9481 0.3030 +vn 0.0000 0.9780 0.2088 +vn 0.0659 0.9835 0.1683 +vn 0.2325 0.9320 0.2779 +vn 0.0553 0.9960 -0.0702 +vn 0.2827 0.9564 0.0728 +vn 0.1873 0.9776 -0.0961 +vn 0.2421 0.9703 0.0000 +vn 0.0921 0.9772 -0.1913 +vn -0.0277 0.9947 -0.0993 +vn 0.2308 0.9274 -0.2944 +vn 0.2771 0.9572 -0.0837 +vn 0.3724 0.9074 0.1947 +vn 0.0777 0.9770 -0.1985 +vn -0.1094 0.9539 0.2794 +vn 0.0364 0.9844 0.1721 +vn 0.1683 0.9835 0.0659 +vn 0.0674 0.9901 0.1230 +vn 0.4338 0.8823 0.1829 +vn 0.2845 0.9565 0.0649 +vn 0.0886 0.9961 0.0000 +vn 0.2000 0.9789 0.0424 +vn 0.1417 0.9830 0.1171 +vn 0.3021 0.9524 0.0412 +vn -0.0193 0.9986 -0.0493 +vn 0.0000 0.9777 0.2098 +vn 0.0005 0.9781 -0.2083 +vn 0.1879 0.9782 -0.0887 +vn 0.2249 0.0000 0.9744 +vn 0.9783 0.0000 -0.2071 +vn 0.9783 0.0000 0.2071 +vn 0.0000 0.0000 -1.0000 +vn -1.0000 0.0000 0.0000 +vn -0.3645 0.0000 -0.9312 +vn -0.9312 0.0000 -0.3645 +vn -0.9312 0.0000 0.3645 +vn 0.2615 0.7979 -0.5431 +vn 0.5877 0.7979 -0.1341 +vn 0.4713 0.7979 0.3758 +vn -0.0000 0.7979 0.6028 +vn -0.4713 0.7979 0.3758 +vn -0.5877 0.7979 -0.1341 +vn -0.2615 0.7979 -0.5431 +vn -0.1285 0.9864 -0.1025 +vn 0.0929 0.8937 0.4389 +vn -0.4335 0.0407 -0.9002 +vn -0.2867 0.7507 -0.5952 +vn -0.4339 0.0095 -0.9009 +vn -0.4338 0.0209 -0.9008 +vn -0.0408 -0.9956 -0.0848 +vn -0.9741 0.0407 -0.2223 +vn -0.6441 0.7507 -0.1470 +vn -0.9749 0.0095 -0.2225 +vn -0.9747 0.0209 -0.2225 +vn -0.0918 -0.9956 -0.0209 +vn -0.7812 0.0407 0.6230 +vn -0.5165 0.7507 0.4119 +vn -0.7818 0.0095 0.6235 +vn -0.7817 0.0209 0.6234 +vn -0.0736 -0.9956 0.0587 +vn -0.0000 0.0407 0.9992 +vn 0.0000 0.7507 0.6607 +vn 0.0000 0.0095 1.0000 +vn -0.0000 0.0209 0.9998 +vn -0.0000 -0.9956 0.0941 +vn 0.7812 0.0407 0.6230 +vn 0.5165 0.7507 0.4119 +vn 0.7818 0.0095 0.6235 +vn 0.7817 0.0209 0.6234 +vn 0.0736 -0.9956 0.0587 +vn 0.9741 0.0407 -0.2223 +vn 0.6441 0.7507 -0.1470 +vn 0.9749 0.0095 -0.2225 +vn 0.9747 0.0209 -0.2225 +vn 0.0918 -0.9956 -0.0209 +vn 0.4335 0.0407 -0.9002 +vn 0.2867 0.7507 -0.5952 +vn 0.4339 0.0095 -0.9009 +vn 0.4338 0.0209 -0.9008 +vn 0.0408 -0.9956 -0.0848 +vn 0.3918 -0.4298 -0.8135 +vn 0.8803 -0.4298 -0.2009 +vn 0.7059 -0.4298 0.5630 +vn -0.0000 -0.4298 0.9029 +vn -0.7059 -0.4298 0.5630 +vn -0.8803 -0.4298 -0.2009 +vn -0.3918 -0.4298 -0.8135 +vn 0.0210 0.9998 -0.0048 +vn 0.0482 0.9981 -0.0385 +vn -0.0166 0.9914 -0.1301 +vn -0.0090 0.9904 -0.1379 +vn 0.2820 0.9576 0.0597 +vn -0.0000 0.9846 0.1749 +vn -0.0921 0.9772 -0.1913 +vn -0.1734 0.9794 0.1036 +s off +f 1/1/1 7/2/1 6/3/1 +f 2/4/2 8/5/2 7/2/2 +f 4/6/3 8/5/3 3/7/3 +f 5/8/4 9/9/4 4/6/4 +f 6/3/5 12/10/5 11/11/5 +f 35/12/6 25/13/6 26/14/6 +f 7/2/7 37/15/7 12/10/7 +f 10/16/8 13/17/8 9/9/8 +f 12/10/9 15/18/9 11/11/9 +f 35/12/10 17/19/10 33/20/10 +f 13/17/11 19/21/11 18/22/11 +f 16/23/12 20/24/12 15/18/12 +f 17/19/13 21/25/13 16/23/13 +f 17/19/14 23/26/14 22/27/14 +f 26/14/15 24/28/15 23/26/15 +f 1/1/16 2/4/16 7/2/16 +f 2/4/3 3/7/3 8/5/3 +f 4/6/17 9/9/17 8/5/17 +f 5/8/18 10/16/18 9/9/18 +f 6/3/19 7/2/19 12/10/19 +f 25/13/20 39/29/20 9/9/20 +f 38/30/21 12/10/21 37/15/21 +f 10/16/22 14/31/22 13/17/22 +f 12/10/23 16/23/23 15/18/23 +f 8/5/24 36/32/24 7/2/24 +f 38/30/25 17/19/25 16/23/25 +f 13/17/22 14/31/22 19/21/22 +f 16/23/26 21/25/26 20/24/26 +f 17/19/27 22/27/27 21/25/27 +f 17/19/28 26/14/28 23/26/28 +f 26/14/29 19/33/29 24/28/29 +f 26/34/30 18/35/30 19/36/30 +f 26/34/31 13/37/31 18/35/31 +f 25/38/32 9/39/32 13/37/32 +f 22/40/33 31/41/33 21/42/33 +f 6/43/34 28/44/34 27/45/34 +f 15/46/34 28/44/34 11/47/34 +f 21/42/35 30/48/35 20/49/35 +f 20/49/36 29/50/36 15/46/36 +f 22/40/33 23/51/33 32/52/33 +f 6/43/37 27/45/37 1/53/37 +f 46/54/38 34/55/38 47/56/38 +f 47/56/39 34/55/39 67/57/39 +f 67/57/40 34/55/40 72/58/40 +f 72/58/41 34/55/41 52/59/41 +f 52/59/42 34/55/42 57/60/42 +f 57/60/43 34/55/43 62/61/43 +f 62/61/44 34/55/44 46/54/44 +f 40/62/45 41/63/45 39/29/45 +f 39/29/46 8/5/46 9/9/46 +f 38/64/47 42/65/47 33/66/47 +f 65/67/48 42/65/48 66/68/48 +f 65/67/49 44/69/49 43/70/49 +f 81/71/50 45/72/50 77/73/50 +f 62/74/51 45/75/51 63/76/51 +f 37/77/52 66/78/52 38/79/52 +f 60/80/53 66/78/53 61/81/53 +f 60/80/54 64/82/54 65/83/54 +f 58/84/55 81/85/55 80/86/55 +f 57/87/56 63/76/56 58/88/56 +f 56/89/57 37/77/57 36/90/57 +f 55/91/58 61/81/58 56/89/58 +f 54/92/59 60/80/59 55/91/59 +f 79/93/60 58/84/60 80/86/60 +f 52/94/61 58/88/61 53/95/61 +f 76/96/62 36/90/62 41/97/62 +f 75/98/63 56/89/63 76/96/63 +f 75/98/64 54/92/64 55/91/64 +f 73/99/65 79/93/65 83/100/65 +f 73/101/66 52/94/66 53/95/66 +f 71/102/67 41/97/67 40/103/67 +f 70/104/68 76/96/68 71/102/68 +f 70/104/69 74/105/69 75/98/69 +f 68/106/70 83/100/70 82/107/70 +f 67/108/71 73/101/71 68/109/71 +f 51/110/72 40/103/72 35/111/72 +f 50/112/73 71/102/73 51/110/73 +f 49/113/74 70/104/74 50/112/74 +f 78/114/75 68/106/75 82/107/75 +f 47/115/76 68/109/76 48/116/76 +f 42/65/77 35/111/77 33/66/77 +f 43/70/78 51/110/78 42/65/78 +f 44/69/79 50/112/79 43/70/79 +f 45/72/80 78/114/80 77/73/80 +f 46/117/81 48/116/81 45/75/81 +f 44/69/82 78/114/82 49/113/82 +f 49/113/83 82/107/83 69/118/83 +f 82/107/84 74/105/84 69/118/84 +f 83/100/85 54/92/85 74/105/85 +f 79/93/86 59/119/86 54/92/86 +f 80/86/87 64/82/87 59/119/87 +f 64/120/88 77/73/88 44/69/88 +f 35/12/89 40/62/89 25/13/89 +f 7/2/90 36/32/90 37/15/90 +f 35/12/91 26/14/91 17/19/91 +f 25/13/92 40/62/92 39/29/92 +f 38/30/93 16/23/93 12/10/93 +f 8/5/94 41/63/94 36/32/94 +f 38/30/95 33/20/95 17/19/95 +f 26/34/31 25/38/31 13/37/31 +f 22/40/33 32/52/33 31/41/33 +f 6/43/34 11/47/34 28/44/34 +f 15/46/34 29/50/34 28/44/34 +f 21/42/35 31/41/35 30/48/35 +f 20/49/36 30/48/36 29/50/36 +f 39/29/96 41/63/96 8/5/96 +f 38/64/47 66/68/47 42/65/47 +f 65/67/48 43/70/48 42/65/48 +f 65/67/49 64/120/49 44/69/49 +f 81/71/50 63/121/50 45/72/50 +f 62/74/51 46/117/51 45/75/51 +f 37/77/52 61/81/52 66/78/52 +f 60/80/53 65/83/53 66/78/53 +f 60/80/54 59/119/54 64/82/54 +f 58/84/55 63/122/55 81/85/55 +f 57/87/56 62/74/56 63/76/56 +f 56/89/57 61/81/57 37/77/57 +f 55/91/58 60/80/58 61/81/58 +f 54/92/59 59/119/59 60/80/59 +f 79/93/60 53/123/60 58/84/60 +f 52/94/61 57/87/61 58/88/61 +f 76/96/62 56/89/62 36/90/62 +f 75/98/63 55/91/63 56/89/63 +f 75/98/64 74/105/64 54/92/64 +f 73/99/65 53/123/65 79/93/65 +f 73/101/66 72/124/66 52/94/66 +f 71/102/67 76/96/67 41/97/67 +f 70/104/68 75/98/68 76/96/68 +f 70/104/69 69/118/69 74/105/69 +f 68/106/70 73/99/70 83/100/70 +f 67/108/71 72/124/71 73/101/71 +f 51/110/72 71/102/72 40/103/72 +f 50/112/73 70/104/73 71/102/73 +f 49/113/74 69/118/74 70/104/74 +f 78/114/75 48/125/75 68/106/75 +f 47/115/76 67/108/76 68/109/76 +f 42/65/77 51/110/77 35/111/77 +f 43/70/78 50/112/78 51/110/78 +f 44/69/79 49/113/79 50/112/79 +f 45/72/80 48/125/80 78/114/80 +f 46/117/81 47/115/81 48/116/81 +f 44/69/82 77/73/82 78/114/82 +f 49/113/83 78/114/83 82/107/83 +f 82/107/84 83/100/84 74/105/84 +f 83/100/85 79/93/85 54/92/85 +f 79/93/86 80/86/86 59/119/86 +f 80/86/87 81/85/87 64/82/87 +f 64/120/88 81/71/88 77/73/88 diff --git a/examples/resources/model/lowpoly-tower.png b/examples/resources/model/lowpoly-tower.png new file mode 100644 index 00000000..7c9239e2 Binary files /dev/null and b/examples/resources/model/lowpoly-tower.png differ diff --git a/src/models.c b/src/models.c index a2043913..41e527dc 100644 --- a/src/models.c +++ b/src/models.c @@ -1918,3 +1918,41 @@ static Material LoadMTL(const char *fileName) return material; } + +RayHitInfo RaycastMesh( Ray ray, Mesh *mesh ) +{ + RayHitInfo result = {0}; + + // If mesh doesn't have vertex data on CPU, can't test it. + if (!mesh->vertices) { + return result; + } + + // mesh->triangleCount may not be set, vertexCount is more reliable + int triangleCount = mesh->vertexCount / 3; + + // Test against all triangles in mesh + for (int i=0; i < triangleCount; i++) { + Vector3 a, b, c; + Vector3 *vertdata = (Vector3*)mesh->vertices; + if (mesh->indices) { + a = vertdata[ mesh->indices[i*3+0] ]; + b = vertdata[ mesh->indices[i*3+1] ]; + c = vertdata[ mesh->indices[i*3+2] ]; + } else { + a = vertdata[i*3+0]; + b = vertdata[i*3+1]; + c = vertdata[i*3+2]; + } + + RayHitInfo triHitInfo = RaycastTriangle( ray, a, b, c ); + if (triHitInfo.hit) { + // Save the closest hit triangle + if ((!result.hit)||(result.distance > triHitInfo.distance)) { + result = triHitInfo; + } + } + } + + return result; +} diff --git a/src/raylib.h b/src/raylib.h index f291ce85..7252ba4e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -497,6 +497,7 @@ typedef struct Ray { // Information returned from a raycast typedef struct RayHitInfo { bool hit; // Did the ray hit something? + float distance; // Distance to nearest hit Vector3 hitPosition; // Position of nearest hit Vector3 hitNormal; // Surface normal of hit } RayHitInfo; @@ -924,6 +925,8 @@ RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Ray Casts //------------------------------------------------------------------------------------ RLAPI RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ); +RLAPI RayHitInfo RaycastTriangle( Ray ray, Vector3 a, Vector3 b, Vector3 c ); +RLAPI RayHitInfo RaycastMesh( Ray ray, Mesh *mesh ); //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) diff --git a/src/raymath.h b/src/raymath.h index 3cd1394e..5871e350 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -130,6 +130,7 @@ RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Ve RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components +RMDEF Vector3 Barycentric(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycentric coords for p in triangle abc //------------------------------------------------------------------------------------ // Functions Declaration to work with Matrix @@ -382,6 +383,31 @@ RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2) return result; } +// Compute barycentric coordinates (u, v, w) for +// point p with respect to triangle (a, b, c) +// Assumes P is on the plane of the triangle +RMDEF Vector3 Barycentric(Vector3 p, Vector3 a, Vector3 b, Vector3 c) +{ + + //Vector v0 = b - a, v1 = c - a, v2 = p - a; + Vector3 v0 = VectorSubtract( b, a ); + Vector3 v1 = VectorSubtract( c, a ); + Vector3 v2 = VectorSubtract( p, a ); + float d00 = VectorDotProduct(v0, v0); + float d01 = VectorDotProduct(v0, v1); + float d11 = VectorDotProduct(v1, v1); + float d20 = VectorDotProduct(v2, v0); + float d21 = VectorDotProduct(v2, v1); + float denom = d00 * d11 - d01 * d01; + + Vector3 result; + result.y = (d11 * d20 - d01 * d21) / denom; + result.z = (d00 * d21 - d01 * d20) / denom; + result.x = 1.0f - (result.z + result.y); + + return result; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Matrix math //---------------------------------------------------------------------------------- diff --git a/src/shapes.c b/src/shapes.c index 4b2de4f2..74480c83 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -544,13 +544,74 @@ RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ) { float t = (ray.position.y - groundHeight) / -ray.direction.y; if (t >= 0.0) { - Vector3 camDir = ray.direction; - VectorScale( &camDir, t ); - result.hit = true; - result.hitNormal = (Vector3){ 0.0, 1.0, 0.0}; - result.hitPosition = VectorAdd( ray.position, camDir ); + Vector3 rayDir = ray.direction; + VectorScale( &rayDir, t ); + result.hit = true; + result.distance = t; + result.hitNormal = (Vector3){ 0.0, 1.0, 0.0}; + result.hitPosition = VectorAdd( ray.position, rayDir ); } } + return result; +} +// Adapted from: +// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm +RayHitInfo RaycastTriangle( Ray ray, Vector3 a, Vector3 b, Vector3 c ) +{ + Vector3 e1, e2; //Edge1, Edge2 + Vector3 p, q, tv; + float det, inv_det, u, v; + float t; + RayHitInfo result = {0}; + + //Find vectors for two edges sharing V1 + e1 = VectorSubtract( b, a); + e2 = VectorSubtract( c, a); + + //Begin calculating determinant - also used to calculate u parameter + p = VectorCrossProduct( ray.direction, e2); + + //if determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle + det = VectorDotProduct(e1, p); + + //NOT CULLING + if(det > -EPSILON && det < EPSILON) return result; + inv_det = 1.f / det; + + //calculate distance from V1 to ray origin + tv = VectorSubtract( ray.position, a ); + + //Calculate u parameter and test bound + u = VectorDotProduct(tv, p) * inv_det; + + //The intersection lies outside of the triangle + if(u < 0.f || u > 1.f) return result; + + //Prepare to test v parameter + q = VectorCrossProduct( tv, e1 ); + + //Calculate V parameter and test bound + v = VectorDotProduct( ray.direction, q) * inv_det; + + //The intersection lies outside of the triangle + if(v < 0.f || (u + v) > 1.f) return result; + + t = VectorDotProduct(e2, q) * inv_det; + + + if(t > EPSILON) { + // ray hit, get hit point and normal + result.hit = true; + result.distance = t; + result.hit = true; + result.hitNormal = VectorCrossProduct( e1, e2 ); + VectorNormalize( &result.hitNormal ); + Vector3 rayDir = ray.direction; + VectorScale( &rayDir, t ); + result.hitPosition = VectorAdd( ray.position, rayDir ); + } + return result; -} \ No newline at end of file +} + -- cgit v1.2.3 From 658c2806690ace34a0dae6b6ed12d0ea52d2d6e4 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 5 Jan 2017 19:33:05 +0100 Subject: Lattest PR review Function names, code formatting... --- examples/Makefile | 11 ++- examples/core_3d_raypick.c | 195 ----------------------------------------- examples/models_ray_picking.c | 197 ++++++++++++++++++++++++++++++++++++++++++ src/models.c | 167 +++++++++++++++++++++++++++-------- src/raylib.h | 21 ++--- src/raymath.h | 25 +++--- src/shapes.c | 81 ----------------- 7 files changed, 351 insertions(+), 346 deletions(-) delete mode 100644 examples/core_3d_raypick.c create mode 100644 examples/models_ray_picking.c (limited to 'src/raylib.h') diff --git a/examples/Makefile b/examples/Makefile index 676529c7..80437590 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -203,7 +203,6 @@ EXAMPLES = \ core_gestures_detection \ core_3d_mode \ core_3d_picking \ - core_3d_raypick \ core_3d_camera_free \ core_3d_camera_first_person \ core_2d_camera \ @@ -237,6 +236,7 @@ EXAMPLES = \ models_obj_loading \ models_heightmap \ models_cubicmap \ + models_ray_picking \ shaders_model_shader \ shaders_shapes_textures \ shaders_custom_uniform \ @@ -321,11 +321,6 @@ core_3d_mode: core_3d_mode.c core_3d_picking: core_3d_picking.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) -# compile [core] example - 3d ray picking -core_3d_raypick: core_3d_raypick.c - $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) - - # compile [core] example - 3d camera free core_3d_camera_free: core_3d_camera_free.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) @@ -462,6 +457,10 @@ models_heightmap: models_heightmap.c models_cubicmap: models_cubicmap.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) +# compile [models] example - model ray picking +models_ray_picking: models_ray_picking.c + $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + # compile [shaders] example - model shader shaders_model_shader: shaders_model_shader.c $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) diff --git a/examples/core_3d_raypick.c b/examples/core_3d_raypick.c deleted file mode 100644 index cf56b277..00000000 --- a/examples/core_3d_raypick.c +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************************* -* -* raylib [core] example - Ray-Picking in 3d mode, ground plane, triangle, mesh -* -* 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) 2015 Ramon Santamaria (@raysan5) -* Example contributed by Joel Davis (@joeld42) -* -********************************************************************************************/ - -#include "raylib.h" -#include "raymath.h" - -#include -#include - - -int main() -{ - // Initialization - //-------------------------------------------------------------------------------------- - int screenWidth = 800; - int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [core] example - 3d ray picking"); - - // Define the camera to look into our 3d world - Camera camera; - camera.position = (Vector3){ 10.0f, 8.0f, 10.0f }; // Camera position - camera.target = (Vector3){ 0.0f, 2.3f, 0.0f }; // Camera looking at point - camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target) - camera.fovy = 45.0f; // Camera field-of-view Y - - Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; - Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; - - Ray ray; // Picking line ray - - Model tower = LoadModel("resources/model/lowpoly-tower.obj"); // Load OBJ model - Texture2D texture = LoadTexture("resources/model/lowpoly-tower.png"); // Load model texture - tower.material.texDiffuse = texture; // Set model diffuse texture - Vector3 towerPos = { 0.0f, 0.0f, 0.0f }; // Set model position - BoundingBox towerBBox = CalculateBoundingBox( tower.mesh ); - bool hitMeshBBox; - bool hitTriangle; - - // Test triangle - Vector3 ta = (Vector3){ -25.0, 0.5, 0.0 }; - Vector3 tb = (Vector3){ -4.0, 2.5, 1.0 }; - Vector3 tc = (Vector3){ -8.0, 6.5, 0.0 }; - - Vector3 bary = {0}; - - SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode - - 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 camera - - - // Display information about closest hit - RayHitInfo nearestHit; - char *hitObjectName = "None"; - nearestHit.distance = FLT_MAX; - nearestHit.hit = false; - Color cursorColor = WHITE; - - // Get ray and test against ground, triangle, and mesh - ray = GetMouseRay(GetMousePosition(), camera); - - RayHitInfo groundHitInfo = RaycastGroundPlane( ray, 0.0 ); - if ((groundHitInfo.hit) && (groundHitInfo.distance < nearestHit.distance)) { - nearestHit = groundHitInfo; - cursorColor = GREEN; - hitObjectName = "Ground"; - } - - RayHitInfo triHitInfo = RaycastTriangle( ray, ta, tb, tc ); - if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance)) { - nearestHit = triHitInfo; - cursorColor = PURPLE; - hitObjectName = "Triangle"; - - bary = Barycentric( nearestHit.hitPosition, ta, tb, tc ); - hitTriangle = true; - } else { - hitTriangle = false; - } - - RayHitInfo meshHitInfo; - - // check the bounding box first, before trying the full ray/mesh test - if (CheckCollisionRayBox( ray, towerBBox )) { - hitMeshBBox = true; - meshHitInfo = RaycastMesh( ray, &tower.mesh ); - if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance)) { - nearestHit = meshHitInfo; - cursorColor = ORANGE; - hitObjectName = "Mesh"; - } - } else { - hitMeshBBox = false; - } - - //---------------------------------------------------------------------------------- - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - Begin3dMode(camera); - - // Draw the tower - DrawModel( tower, towerPos, 1.0, WHITE ); - - // Draw the test triangle - DrawLine3D( ta, tb, PURPLE ); - DrawLine3D( tb, tc, PURPLE ); - DrawLine3D( tc, ta, PURPLE ); - - // Draw the mesh bbox if we hit it - if (hitMeshBBox) { - DrawBoundingBox( towerBBox, LIME ); - } - - // If we hit something, draw the cursor at the hit point - if (nearestHit.hit) { - DrawCube( nearestHit.hitPosition, 0.5, 0.5, 0.5, cursorColor ); - DrawCubeWires( nearestHit.hitPosition, 0.5, 0.5, 0.5, YELLOW ); - - Vector3 normalEnd; - normalEnd.x = nearestHit.hitPosition.x + nearestHit.hitNormal.x; - normalEnd.y = nearestHit.hitPosition.y + nearestHit.hitNormal.y; - normalEnd.z = nearestHit.hitPosition.z + nearestHit.hitNormal.z; - DrawLine3D( nearestHit.hitPosition, normalEnd, YELLOW ); - } - - DrawRay(ray, MAROON); - - DrawGrid(10, 1.0f); - - End3dMode(); - - // Show some debug text - char line[1024]; - sprintf( line, "Hit Object: %s\n", hitObjectName ); - DrawText( line, 10, 30, 15, BLACK ); - - if (nearestHit.hit) { - int ypos = 45; - sprintf( line, "Distance: %3.2f", nearestHit.distance ); - DrawText( line, 10, ypos, 15, BLACK ); - ypos += 15; - - sprintf( line, "Hit Pos: %3.2f %3.2f %3.2f", - nearestHit.hitPosition.x, nearestHit.hitPosition.y, nearestHit.hitPosition.z ); - DrawText( line, 10, ypos, 15, BLACK ); - ypos += 15; - - sprintf( line, "Hit Norm: %3.2f %3.2f %3.2f", - nearestHit.hitNormal.x, nearestHit.hitNormal.y, nearestHit.hitNormal.z ); - DrawText( line, 10, ypos, 15, BLACK ); - ypos += 15; - - if (hitTriangle) { - sprintf( line, "Barycentric: %3.2f %3.2f %3.2f", - bary.x, bary.y, bary.z ); - DrawText( line, 10, ypos, 15, BLACK ); - } - } - - DrawText( "Use Mouse to Move Camera", 10, 420, 15, LIGHTGRAY ); - - DrawFPS(10, 10); - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} \ No newline at end of file diff --git a/examples/models_ray_picking.c b/examples/models_ray_picking.c new file mode 100644 index 00000000..c578a185 --- /dev/null +++ b/examples/models_ray_picking.c @@ -0,0 +1,197 @@ +/******************************************************************************************* +* +* raylib [models] example - Ray picking in 3d mode, ground plane, triangle, mesh +* +* This example has been created using raylib 1.7 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* Example contributed by Joel Davis (@joeld42) +* +********************************************************************************************/ + +#include "raylib.h" +#include "../src/raymath.h" + +#include +#include + + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [models] example - 3d ray picking"); + + // Define the camera to look into our 3d world + Camera camera; + camera.position = (Vector3){ 10.0f, 8.0f, 10.0f }; // Camera position + camera.target = (Vector3){ 0.0f, 2.3f, 0.0f }; // Camera looking at point + camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target) + camera.fovy = 45.0f; // Camera field-of-view Y + + Vector3 cubePosition = { 0.0f, 1.0f, 0.0f }; + Vector3 cubeSize = { 2.0f, 2.0f, 2.0f }; + + Ray ray; // Picking line ray + + Model tower = LoadModel("resources/model/lowpoly-tower.obj"); // Load OBJ model + Texture2D texture = LoadTexture("resources/model/lowpoly-tower.png"); // Load model texture + tower.material.texDiffuse = texture; // Set model diffuse texture + + Vector3 towerPos = { 0.0f, 0.0f, 0.0f }; // Set model position + BoundingBox towerBBox = CalculateBoundingBox( tower.mesh ); + bool hitMeshBBox = false; + bool hitTriangle = false; + + // Test triangle + Vector3 ta = (Vector3){ -25.0, 0.5, 0.0 }; + Vector3 tb = (Vector3){ -4.0, 2.5, 1.0 }; + Vector3 tc = (Vector3){ -8.0, 6.5, 0.0 }; + + Vector3 bary = { 0.0f, 0.0f, 0.0f }; + + SetCameraMode(camera, CAMERA_FREE); // Set a free camera mode + + 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 camera + + // Display information about closest hit + RayHitInfo nearestHit; + char *hitObjectName = "None"; + nearestHit.distance = FLT_MAX; + nearestHit.hit = false; + Color cursorColor = WHITE; + + // Get ray and test against ground, triangle, and mesh + ray = GetMouseRay(GetMousePosition(), camera); + + // Check ray collision aginst ground plane + RayHitInfo groundHitInfo = GetCollisionRayGround(ray, 0.0f); + + if ((groundHitInfo.hit) && (groundHitInfo.distance < nearestHit.distance)) + { + nearestHit = groundHitInfo; + cursorColor = GREEN; + hitObjectName = "Ground"; + } + + // Check ray collision against test triangle + RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, ta, tb, tc); + + if ((triHitInfo.hit) && (triHitInfo.distance < nearestHit.distance)) + { + nearestHit = triHitInfo; + cursorColor = PURPLE; + hitObjectName = "Triangle"; + + bary = Barycenter(nearestHit.hitPosition, ta, tb, tc); + hitTriangle = true; + } + else hitTriangle = false; + + RayHitInfo meshHitInfo; + + // Check ray collision against bounding box first, before trying the full ray-mesh test + if (CheckCollisionRayBox(ray, towerBBox)) + { + hitMeshBBox = true; + + // Check ray collision against mesh + meshHitInfo = GetCollisionRayMesh(ray, &tower.mesh); + + if ((meshHitInfo.hit) && (meshHitInfo.distance < nearestHit.distance)) + { + nearestHit = meshHitInfo; + cursorColor = ORANGE; + hitObjectName = "Mesh"; + } + + } hitMeshBBox = false; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + Begin3dMode(camera); + + // Draw the tower + DrawModel(tower, towerPos, 1.0, WHITE); + + // Draw the test triangle + DrawLine3D(ta, tb, PURPLE); + DrawLine3D(tb, tc, PURPLE); + DrawLine3D(tc, ta, PURPLE); + + // Draw the mesh bbox if we hit it + if (hitMeshBBox) DrawBoundingBox(towerBBox, LIME); + + // If we hit something, draw the cursor at the hit point + if (nearestHit.hit) + { + DrawCube(nearestHit.hitPosition, 0.5, 0.5, 0.5, cursorColor); + DrawCubeWires(nearestHit.hitPosition, 0.5, 0.5, 0.5, YELLOW); + + Vector3 normalEnd; + normalEnd.x = nearestHit.hitPosition.x + nearestHit.hitNormal.x; + normalEnd.y = nearestHit.hitPosition.y + nearestHit.hitNormal.y; + normalEnd.z = nearestHit.hitPosition.z + nearestHit.hitNormal.z; + + DrawLine3D(nearestHit.hitPosition, normalEnd, YELLOW); + } + + DrawRay(ray, MAROON); + + DrawGrid(100, 1.0f); + + End3dMode(); + + // Draw some debug GUI text + DrawText(FormatText("Hit Object: %s", hitObjectName), 10, 50, 10, BLACK); + + if (nearestHit.hit) + { + int ypos = 70; + + DrawText(FormatText("Distance: %3.2f", nearestHit.distance), 10, ypos, 10, BLACK); + + DrawText(FormatText("Hit Pos: %3.2f %3.2f %3.2f", + nearestHit.hitPosition.x, + nearestHit.hitPosition.y, + nearestHit.hitPosition.z), 10, ypos + 15, 10, BLACK); + + DrawText(FormatText("Hit Norm: %3.2f %3.2f %3.2f", + nearestHit.hitNormal.x, + nearestHit.hitNormal.y, + nearestHit.hitNormal.z), 10, ypos + 30, 10, BLACK); + + if (hitTriangle) DrawText(FormatText("Barycenter: %3.2f %3.2f %3.2f", bary.x, bary.y, bary.z), 10, ypos + 45, 10, BLACK); + } + + DrawText("Use Mouse to Move Camera", 10, 430, 10, GRAY); + + DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/src/models.c b/src/models.c index 41e527dc..0673874b 100644 --- a/src/models.c +++ b/src/models.c @@ -1474,6 +1474,135 @@ bool CheckCollisionRayBox(Ray ray, BoundingBox box) return collision; } +// Get collision info between ray and mesh +RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh) +{ + RayHitInfo result = { 0 }; + + // If mesh doesn't have vertex data on CPU, can't test it. + if (!mesh->vertices) return result; + + // mesh->triangleCount may not be set, vertexCount is more reliable + int triangleCount = mesh->vertexCount/3; + + // Test against all triangles in mesh + for (int i = 0; i < triangleCount; i++) + { + Vector3 a, b, c; + Vector3 *vertdata = (Vector3 *)mesh->vertices; + + if (mesh->indices) + { + a = vertdata[mesh->indices[i*3 + 0]]; + b = vertdata[mesh->indices[i*3 + 1]]; + c = vertdata[mesh->indices[i*3 + 2]]; + } + else + { + a = vertdata[i*3 + 0]; + b = vertdata[i*3 + 1]; + c = vertdata[i*3 + 2]; + } + + RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); + + if (triHitInfo.hit) + { + // Save the closest hit triangle + if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; + } + } + + return result; +} + +// Get collision info between ray and triangle +// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm +RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) +{ + #define EPSILON 0.000001 // A small number + + Vector3 edge1, edge2; + Vector3 p, q, tv; + float det, invDet, u, v, t; + RayHitInfo result = {0}; + + // Find vectors for two edges sharing V1 + edge1 = VectorSubtract(p2, p1); + edge2 = VectorSubtract(p3, p1); + + // Begin calculating determinant - also used to calculate u parameter + p = VectorCrossProduct(ray.direction, edge2); + + // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle + det = VectorDotProduct(edge1, p); + + // Avoid culling! + if ((det > -EPSILON) && (det < EPSILON)) return result; + + invDet = 1.0f/det; + + // Calculate distance from V1 to ray origin + tv = VectorSubtract(ray.position, p1); + + // Calculate u parameter and test bound + u = VectorDotProduct(tv, p)*invDet; + + // The intersection lies outside of the triangle + if ((u < 0.0f) || (u > 1.0f)) return result; + + // Prepare to test v parameter + q = VectorCrossProduct(tv, edge1); + + // Calculate V parameter and test bound + v = VectorDotProduct(ray.direction, q)*invDet; + + // The intersection lies outside of the triangle + if ((v < 0.0f) || ((u + v) > 1.0f)) return result; + + t = VectorDotProduct(edge2, q)*invDet; + + if (t > EPSILON) + { + // Ray hit, get hit point and normal + result.hit = true; + result.distance = t; + result.hit = true; + result.hitNormal = VectorCrossProduct(edge1, edge2); + VectorNormalize(&result.hitNormal); + Vector3 rayDir = ray.direction; + VectorScale(&rayDir, t); + result.hitPosition = VectorAdd(ray.position, rayDir); + } + + return result; +} + +// Get collision info between ray and ground plane (Y-normal plane) +RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) +{ + #define EPSILON 0.000001 // A small number + + RayHitInfo result = { 0 }; + + if (fabsf(ray.direction.y) > EPSILON) + { + float t = (ray.position.y - groundHeight)/-ray.direction.y; + + if (t >= 0.0) + { + Vector3 rayDir = ray.direction; + VectorScale(&rayDir, t); + result.hit = true; + result.distance = t; + result.hitNormal = (Vector3){ 0.0, 1.0, 0.0 }; + result.hitPosition = VectorAdd(ray.position, rayDir); + } + } + + return result; +} + // Calculate mesh bounding box limits // NOTE: minVertex and maxVertex should be transformed by model transform matrix (position, scale, rotate) BoundingBox CalculateBoundingBox(Mesh mesh) @@ -1918,41 +2047,3 @@ static Material LoadMTL(const char *fileName) return material; } - -RayHitInfo RaycastMesh( Ray ray, Mesh *mesh ) -{ - RayHitInfo result = {0}; - - // If mesh doesn't have vertex data on CPU, can't test it. - if (!mesh->vertices) { - return result; - } - - // mesh->triangleCount may not be set, vertexCount is more reliable - int triangleCount = mesh->vertexCount / 3; - - // Test against all triangles in mesh - for (int i=0; i < triangleCount; i++) { - Vector3 a, b, c; - Vector3 *vertdata = (Vector3*)mesh->vertices; - if (mesh->indices) { - a = vertdata[ mesh->indices[i*3+0] ]; - b = vertdata[ mesh->indices[i*3+1] ]; - c = vertdata[ mesh->indices[i*3+2] ]; - } else { - a = vertdata[i*3+0]; - b = vertdata[i*3+1]; - c = vertdata[i*3+2]; - } - - RayHitInfo triHitInfo = RaycastTriangle( ray, a, b, c ); - if (triHitInfo.hit) { - // Save the closest hit triangle - if ((!result.hit)||(result.distance > triHitInfo.distance)) { - result = triHitInfo; - } - } - } - - return result; -} diff --git a/src/raylib.h b/src/raylib.h index 7252ba4e..fa4f44e6 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -97,9 +97,6 @@ #define DEG2RAD (PI/180.0f) #define RAD2DEG (180.0f/PI) -// A small number -#define EPSILON 0.000001 - // raylib Config Flags #define FLAG_FULLSCREEN_MODE 1 #define FLAG_RESIZABLE_WINDOW 2 @@ -496,10 +493,10 @@ typedef struct Ray { // Information returned from a raycast typedef struct RayHitInfo { - bool hit; // Did the ray hit something? - float distance; // Distance to nearest hit - Vector3 hitPosition; // Position of nearest hit - Vector3 hitNormal; // Surface normal of hit + bool hit; // Did the ray hit something? + float distance; // Distance to nearest hit + Vector3 hitPosition; // Position of nearest hit + Vector3 hitNormal; // Surface normal of hit } RayHitInfo; // Wave type, defines audio wave data @@ -920,13 +917,9 @@ RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphere RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box - -//------------------------------------------------------------------------------------ -// Ray Casts -//------------------------------------------------------------------------------------ -RLAPI RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ); -RLAPI RayHitInfo RaycastTriangle( Ray ray, Vector3 a, Vector3 b, Vector3 c ); -RLAPI RayHitInfo RaycastMesh( Ray ray, Mesh *mesh ); +RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh); // Get collision info between ray and mesh +RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle +RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane) //------------------------------------------------------------------------------------ // Shaders System Functions (Module: rlgl) diff --git a/src/raymath.h b/src/raymath.h index 5871e350..c073b72d 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -130,7 +130,7 @@ RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Ve RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components -RMDEF Vector3 Barycentric(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycentric coords for p in triangle abc +RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc //------------------------------------------------------------------------------------ // Functions Declaration to work with Matrix @@ -383,26 +383,27 @@ RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2) return result; } -// Compute barycentric coordinates (u, v, w) for -// point p with respect to triangle (a, b, c) -// Assumes P is on the plane of the triangle -RMDEF Vector3 Barycentric(Vector3 p, Vector3 a, Vector3 b, Vector3 c) +// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c) +// NOTE: Assumes P is on the plane of the triangle +RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { - //Vector v0 = b - a, v1 = c - a, v2 = p - a; - Vector3 v0 = VectorSubtract( b, a ); - Vector3 v1 = VectorSubtract( c, a ); - Vector3 v2 = VectorSubtract( p, a ); + + Vector3 v0 = VectorSubtract(b, a); + Vector3 v1 = VectorSubtract(c, a); + Vector3 v2 = VectorSubtract(p, a); float d00 = VectorDotProduct(v0, v0); float d01 = VectorDotProduct(v0, v1); float d11 = VectorDotProduct(v1, v1); float d20 = VectorDotProduct(v2, v0); float d21 = VectorDotProduct(v2, v1); - float denom = d00 * d11 - d01 * d01; + + float denom = d00*d11 - d01*d01; Vector3 result; - result.y = (d11 * d20 - d01 * d21) / denom; - result.z = (d00 * d21 - d01 * d20) / denom; + + result.y = (d11*d20 - d01*d21)/denom; + result.z = (d00*d21 - d01*d20)/denom; result.x = 1.0f - (result.z + result.y); return result; diff --git a/src/shapes.c b/src/shapes.c index 74480c83..8c6c4be0 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -534,84 +534,3 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) return retRec; } - - -RayHitInfo RaycastGroundPlane( Ray ray, float groundHeight ) -{ - RayHitInfo result = {0}; - - if (fabs(ray.direction.y) > EPSILON) - { - float t = (ray.position.y - groundHeight) / -ray.direction.y; - if (t >= 0.0) { - Vector3 rayDir = ray.direction; - VectorScale( &rayDir, t ); - result.hit = true; - result.distance = t; - result.hitNormal = (Vector3){ 0.0, 1.0, 0.0}; - result.hitPosition = VectorAdd( ray.position, rayDir ); - } - } - return result; -} -// Adapted from: -// https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm -RayHitInfo RaycastTriangle( Ray ray, Vector3 a, Vector3 b, Vector3 c ) -{ - Vector3 e1, e2; //Edge1, Edge2 - Vector3 p, q, tv; - float det, inv_det, u, v; - float t; - RayHitInfo result = {0}; - - //Find vectors for two edges sharing V1 - e1 = VectorSubtract( b, a); - e2 = VectorSubtract( c, a); - - //Begin calculating determinant - also used to calculate u parameter - p = VectorCrossProduct( ray.direction, e2); - - //if determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle - det = VectorDotProduct(e1, p); - - //NOT CULLING - if(det > -EPSILON && det < EPSILON) return result; - inv_det = 1.f / det; - - //calculate distance from V1 to ray origin - tv = VectorSubtract( ray.position, a ); - - //Calculate u parameter and test bound - u = VectorDotProduct(tv, p) * inv_det; - - //The intersection lies outside of the triangle - if(u < 0.f || u > 1.f) return result; - - //Prepare to test v parameter - q = VectorCrossProduct( tv, e1 ); - - //Calculate V parameter and test bound - v = VectorDotProduct( ray.direction, q) * inv_det; - - //The intersection lies outside of the triangle - if(v < 0.f || (u + v) > 1.f) return result; - - t = VectorDotProduct(e2, q) * inv_det; - - - if(t > EPSILON) { - // ray hit, get hit point and normal - result.hit = true; - result.distance = t; - - result.hit = true; - result.hitNormal = VectorCrossProduct( e1, e2 ); - VectorNormalize( &result.hitNormal ); - Vector3 rayDir = ray.direction; - VectorScale( &rayDir, t ); - result.hitPosition = VectorAdd( ray.position, rayDir ); - } - - return result; -} - -- cgit v1.2.3 From 4a158d972d9d110fcb581bc9f6583d05a2dc2544 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 15 Jan 2017 01:09:15 +0100 Subject: Added LoadText() function Actually, renamed ReadTextFile() from rlgl and make it public --- src/raylib.h | 1 + src/rlgl.c | 76 +++++++++++++++++++++++++++++------------------------------- 2 files changed, 38 insertions(+), 39 deletions(-) (limited to 'src/raylib.h') diff --git a/src/raylib.h b/src/raylib.h index fa4f44e6..a47d3c59 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -925,6 +925,7 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Shaders System Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ +RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) diff --git a/src/rlgl.c b/src/rlgl.c index 9770b647..bcbca227 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -48,7 +48,7 @@ #include "rlgl.h" -#include // Required for: fopen(), fclose(), fread()... [Used only on ReadTextFile()] +#include // Required for: fopen(), fclose(), fread()... [Used only on LoadText()] #include // Required for: malloc(), free(), rand() #include // Required for: strcmp(), strlen(), strtok() #include // Required for: atan2() @@ -400,8 +400,6 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS) static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights - -static char *ReadTextFile(const char *fileName); // Read chars array from text file #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -2423,6 +2421,40 @@ Texture2D GetDefaultTexture(void) return texture; } +// Load text data from file +// NOTE: text chars array should be freed manually +char *LoadText(const char *fileName) +{ + FILE *textFile; + char *text = NULL; + + int count = 0; + + if (fileName != NULL) + { + textFile = fopen(fileName,"rt"); + + if (textFile != NULL) + { + fseek(textFile, 0, SEEK_END); + count = ftell(textFile); + rewind(textFile); + + if (count > 0) + { + text = (char *)malloc(sizeof(char)*(count + 1)); + count = fread(text, sizeof(char), count, textFile); + text[count] = '\0'; + } + + fclose(textFile); + } + else TraceLog(WARNING, "[%s] Text file could not be opened", fileName); + } + + return text; +} + // Load shader from files and bind default locations Shader LoadShader(char *vsFileName, char *fsFileName) { @@ -2430,8 +2462,8 @@ Shader LoadShader(char *vsFileName, char *fsFileName) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Shaders loading from external text file - char *vShaderStr = ReadTextFile(vsFileName); - char *fShaderStr = ReadTextFile(fsFileName); + char *vShaderStr = LoadText(vsFileName); + char *fShaderStr = LoadText(fsFileName); if ((vShaderStr != NULL) && (fShaderStr != NULL)) { @@ -3829,40 +3861,6 @@ static void SetShaderLightsValues(Shader shader) } } -// Read text data from file -// NOTE: text chars array should be freed manually -static char *ReadTextFile(const char *fileName) -{ - FILE *textFile; - char *text = NULL; - - int count = 0; - - if (fileName != NULL) - { - textFile = fopen(fileName,"rt"); - - if (textFile != NULL) - { - fseek(textFile, 0, SEEK_END); - count = ftell(textFile); - rewind(textFile); - - if (count > 0) - { - text = (char *)malloc(sizeof(char)*(count + 1)); - count = fread(text, sizeof(char), count, textFile); - text[count] = '\0'; - } - - fclose(textFile); - } - else TraceLog(WARNING, "[%s] Text file could not be opened", fileName); - } - - return text; -} - // Configure stereo rendering (including distortion shader) with HMD device parameters static void SetStereoConfig(VrDeviceInfo hmd) { -- cgit v1.2.3 From 37a64df7b9944d1d24872f07a7e713884b33432e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 27 Jan 2017 23:03:08 +0100 Subject: Move lighting system out of raylib Lighting is implemented as a raylib example now --- examples/shaders_standard_lighting.c | 366 ++++++++++++++++++++++++++++++++++- src/models.c | 48 ----- src/raylib.h | 26 --- src/rlgl.c | 275 +------------------------- src/shader_standard.h | 173 ----------------- 5 files changed, 366 insertions(+), 522 deletions(-) delete mode 100644 src/shader_standard.h (limited to 'src/raylib.h') diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c index 728bdae0..16cd7ff6 100644 --- a/examples/shaders_standard_lighting.c +++ b/examples/shaders_standard_lighting.c @@ -9,15 +9,79 @@ * 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) +* This example has been created using raylib 1.7 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * -* Copyright (c) 2016 Ramon Santamaria (@raysan5) +* Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) * ********************************************************************************************/ #include "raylib.h" +#include // Required for: NULL +#include // Required for: strcpy() +#include // Required for: vector math + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define MAX_LIGHTS 8 // Max lights supported by standard shader + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Light type +typedef struct LightData { + unsigned int id; // Light unique id + bool enabled; // Light enabled + int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT + + Vector3 position; // Light position + Vector3 target; // Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) + float radius; // Light attenuation radius light intensity reduced with distance (world distance) + + Color diffuse; // Light diffuse color + float intensity; // Light intensity level + + float coneAngle; // Light cone max angle: LIGHT_SPOT +} LightData, *Light; + +// Light types +typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static Light lights[MAX_LIGHTS]; // Lights pool +static int lightsCount = 0; // Enabled lights counter +static int lightsLocs[MAX_LIGHTS][8]; // Lights location points in shader: 8 possible points per light: + // enabled, type, position, target, radius, diffuse, intensity, coneAngle + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool +static void DestroyLight(Light light); // Destroy a light and take it out of the list +static void DrawLight(Light light); // Draw light in 3D world + +static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS) +static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights + +// Vector3 math functions +static float VectorLength(const Vector3 v); // Calculate vector lenght +static void VectorNormalize(Vector3 *v); // Normalize provided vector +static Vector3 VectorSubtract(Vector3 v1, Vector3 v2); // Substract two vectors + + +//https://www.gamedev.net/topic/655969-speed-gluniform-vs-uniform-buffer-objects/ +//https://www.reddit.com/r/opengl/comments/4ri20g/is_gluniform_more_expensive_than_glprogramuniform/ +//http://cg.alexandra.dk/?p=3778 - AZDO +//https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/BestPracticesforShaders/BestPracticesforShaders.html + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ int main() { // Initialization @@ -39,6 +103,9 @@ int main() material.shader = LoadShader("resources/shaders/glsl330/standard.vs", "resources/shaders/glsl330/standard.fs"); + // Try to get lights location points (if available) + GetShaderLightsLocations(material.shader); + material.texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png"); // Load model diffuse texture material.texNormal = LoadTexture("resources/model/dwarf_normal.png"); // Load model normal texture material.texSpecular = LoadTexture("resources/model/dwarf_specular.png"); // Load model specular texture @@ -64,6 +131,12 @@ int main() pointLight->intensity = 2.0f; pointLight->diffuse = (Color){100, 100, 255, 255}; pointLight->radius = 3.0f; + + // Set shader lights values for enabled lights + // NOTE: If values are not changed in real time, they can be set at initialization!!! + SetShaderLightsValues(material.shader); + + //SetShaderActive(0); // Setup orbital camera SetCameraMode(camera, CAMERA_ORBITAL); // Set an orbital camera mode @@ -115,8 +188,295 @@ int main() DestroyLight(dirLight); DestroyLight(spotLight); + // Unload lights + if (lightsCount > 0) + { + for (int i = 0; i < lightsCount; i++) free(lights[i]); + lightsCount = 0; + } + CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} + +//-------------------------------------------------------------------------------------------- +// Module Functions Definitions +//-------------------------------------------------------------------------------------------- + +// Create a new light, initialize it and add to pool +Light CreateLight(int type, Vector3 position, Color diffuse) +{ + Light light = NULL; + + if (lightsCount < MAX_LIGHTS) + { + // Allocate dynamic memory + 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++; + } + else + { + // NOTE: Returning latest created light to avoid crashes + light = lights[lightsCount]; + } + + return light; +} + +// Destroy a light and take it out of the list +void DestroyLight(Light light) +{ + if (light != NULL) + { + int lightId = light->id; + + // Free dynamic memory allocation + free(lights[lightId]); + + // Remove *obj from the pointers array + for (int i = lightId; 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; + } + } + + // Decrease enabled physic objects count + lightsCount--; + } +} + +// Draw light in 3D world +void DrawLight(Light light) +{ + switch (light->type) + { + case LIGHT_POINT: + { + DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY)); + + DrawCircle3D(light->position, light->radius, (Vector3){ 0, 0, 0 }, 0.0f, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, light->radius, (Vector3){ 1, 0, 0 }, 90.0f, (light->enabled ? light->diffuse : GRAY)); + DrawCircle3D(light->position, light->radius, (Vector3){ 0, 1, 0 },90.0f, (light->enabled ? light->diffuse : GRAY)); + } break; + case LIGHT_DIRECTIONAL: + { + DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY)); + + DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY)); + DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY)); + } break; + case LIGHT_SPOT: + { + DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY)); + + Vector3 dir = VectorSubtract(light->target, light->position); + VectorNormalize(&dir); + + DrawCircle3D(light->position, 0.5f, dir, 0.0f, (light->enabled ? light->diffuse : GRAY)); + + //DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : GRAY)); + DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY)); + } break; + default: break; + } +} + +// Get shader locations for lights (up to MAX_LIGHTS) +static void GetShaderLightsLocations(Shader shader) +{ + char locName[32] = "lights[x].\0"; + char locNameUpdated[64]; + + for (int i = 0; i < MAX_LIGHTS; i++) + { + locName[7] = '0' + i; + + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "enabled\0"); + lightsLocs[i][0] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "type\0"); + lightsLocs[i][1] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "position\0"); + lightsLocs[i][2] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "direction\0"); + lightsLocs[i][3] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "radius\0"); + lightsLocs[i][4] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "diffuse\0"); + lightsLocs[i][5] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "intensity\0"); + lightsLocs[i][6] = GetShaderLocation(shader, locNameUpdated); + + locNameUpdated[0] = '\0'; + strcpy(locNameUpdated, locName); + strcat(locNameUpdated, "coneAngle\0"); + lightsLocs[i][7] = GetShaderLocation(shader, locNameUpdated); + } +} + +// Set shader uniform values for lights +// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0 +// TODO: Replace glUniform1i(), glUniform1f(), glUniform3f(), glUniform4f(): +//SetShaderValue(Shader shader, int uniformLoc, float *value, int size) +//SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) +static void SetShaderLightsValues(Shader shader) +{ + int tempInt[8] = { 0 }; + float tempFloat[8] = { 0.0f }; + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (i < lightsCount) + { + tempInt[0] = lights[i]->enabled; + SetShaderValuei(shader, lightsLocs[i][0], tempInt, 1); //glUniform1i(lightsLocs[i][0], lights[i]->enabled); + + tempInt[0] = lights[i]->type; + SetShaderValuei(shader, lightsLocs[i][1], tempInt, 1); //glUniform1i(lightsLocs[i][1], lights[i]->type); + + tempFloat[0] = (float)lights[i]->diffuse.r/255.0f; + tempFloat[1] = (float)lights[i]->diffuse.g/255.0f; + tempFloat[2] = (float)lights[i]->diffuse.b/255.0f; + tempFloat[3] = (float)lights[i]->diffuse.a/255.0f; + SetShaderValue(shader, lightsLocs[i][5], tempFloat, 4); + //glUniform4f(lightsLocs[i][5], (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); + + tempFloat[0] = lights[i]->intensity; + SetShaderValue(shader, lightsLocs[i][6], tempFloat, 1); + + switch (lights[i]->type) + { + case LIGHT_POINT: + { + tempFloat[0] = lights[i]->position.x; + tempFloat[1] = lights[i]->position.y; + tempFloat[2] = lights[i]->position.z; + SetShaderValue(shader, lightsLocs[i][2], tempFloat, 3); + + tempFloat[0] = lights[i]->radius; + SetShaderValue(shader, lightsLocs[i][4], tempFloat, 1); + + //glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + //glUniform1f(lightsLocs[i][4], lights[i]->radius); + } break; + case LIGHT_DIRECTIONAL: + { + Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position); + VectorNormalize(&direction); + + tempFloat[0] = direction.x; + tempFloat[1] = direction.y; + tempFloat[2] = direction.z; + SetShaderValue(shader, lightsLocs[i][3], tempFloat, 3); + + //glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); + } break; + case LIGHT_SPOT: + { + tempFloat[0] = lights[i]->position.x; + tempFloat[1] = lights[i]->position.y; + tempFloat[2] = lights[i]->position.z; + SetShaderValue(shader, lightsLocs[i][2], tempFloat, 3); + + //glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); + + Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position); + VectorNormalize(&direction); + + tempFloat[0] = direction.x; + tempFloat[1] = direction.y; + tempFloat[2] = direction.z; + SetShaderValue(shader, lightsLocs[i][3], tempFloat, 3); + //glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); + + tempFloat[0] = lights[i]->coneAngle; + SetShaderValue(shader, lightsLocs[i][7], tempFloat, 1); + //glUniform1f(lightsLocs[i][7], lights[i]->coneAngle); + } break; + default: break; + } + } + else + { + tempInt[0] = 0; + SetShaderValuei(shader, lightsLocs[i][0], tempInt, 1); //glUniform1i(lightsLocs[i][0], 0); // Light disabled + } + } +} + +// Calculate vector lenght +float VectorLength(const Vector3 v) +{ + float length; + + length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + + return length; +} + +// Normalize provided vector +void VectorNormalize(Vector3 *v) +{ + float length, ilength; + + length = VectorLength(*v); + + if (length == 0.0f) length = 1.0f; + + ilength = 1.0f/length; + + v->x *= ilength; + v->y *= ilength; + v->z *= ilength; +} + +// Substract two vectors +Vector3 VectorSubtract(Vector3 v1, Vector3 v2) +{ + Vector3 result; + + result.x = v1.x - v2.x; + result.y = v1.y - v2.y; + result.z = v1.z - v2.z; + + return result; +} diff --git a/src/models.c b/src/models.c index 0673874b..23c2e6fd 100644 --- a/src/models.c +++ b/src/models.c @@ -574,43 +574,6 @@ void DrawGizmo(Vector3 position) rlPopMatrix(); } - -// Draw light in 3D world -void DrawLight(Light light) -{ - switch (light->type) - { - case LIGHT_POINT: - { - DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY)); - - DrawCircle3D(light->position, light->radius, (Vector3){ 0, 0, 0 }, 0.0f, (light->enabled ? light->diffuse : GRAY)); - DrawCircle3D(light->position, light->radius, (Vector3){ 1, 0, 0 }, 90.0f, (light->enabled ? light->diffuse : GRAY)); - DrawCircle3D(light->position, light->radius, (Vector3){ 0, 1, 0 },90.0f, (light->enabled ? light->diffuse : GRAY)); - } break; - case LIGHT_DIRECTIONAL: - { - DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY)); - - DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY)); - DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY)); - } break; - case LIGHT_SPOT: - { - DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY)); - - Vector3 dir = VectorSubtract(light->target, light->position); - VectorNormalize(&dir); - - DrawCircle3D(light->position, 0.5f, dir, 0.0f, (light->enabled ? light->diffuse : GRAY)); - - //DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : GRAY)); - DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY)); - } break; - default: break; - } -} - // Load mesh from file Mesh LoadMesh(const char *fileName) { @@ -751,17 +714,6 @@ 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) { diff --git a/src/raylib.h b/src/raylib.h index a47d3c59..f8f17eec 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -12,7 +12,6 @@ * Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF) * Multiple textures support, including compressed formats and mipmaps generation * Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps -* Materials (diffuse, normal, specular) and Lighting (point, directional, spot) support * Powerful math module for Vector, Matrix and Quaternion operations: [raymath] * Audio loading and playing with streaming support and mixing channels [audio] * VR stereo rendering support with configurable HMD device parameters @@ -466,25 +465,6 @@ typedef struct Model { Material material; // Shader and textures data } Model; -// Light type -typedef struct LightData { - unsigned int id; // Light unique id - bool enabled; // Light enabled - int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT - - Vector3 position; // Light position - Vector3 target; // Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target) - float radius; // Light attenuation radius light intensity reduced with distance (world distance) - - Color diffuse; // Light diffuse color - float intensity; // Light intensity level - - float coneAngle; // Light cone max angle: LIGHT_SPOT -} LightData, *Light; - -// Light types -typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType; - // Ray type (useful for raycast) typedef struct Ray { Vector3 position; // Ray position (origin) @@ -876,7 +856,6 @@ RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo -RLAPI void DrawLight(Light light); // Draw light in 3D world //DrawTorus(), DrawTeapot() could be useful? //------------------------------------------------------------------------------------ @@ -894,7 +873,6 @@ RLAPI void UnloadModel(Model model); RLAPI Material LoadMaterial(const char *fileName); // Load material from file RLAPI Material LoadMaterialEx(Shader shader, Texture2D diffuse, Color color); // Load material from basic shading data RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader) -RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader) RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) @@ -930,7 +908,6 @@ RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Loa RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetDefaultShader(void); // Get default shader -RLAPI Shader GetStandardShader(void); // Get standard shader RLAPI Texture2D GetDefaultTexture(void); // Get default texture RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location @@ -946,9 +923,6 @@ RLAPI void EndShaderMode(void); // End RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied) RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) -RLAPI Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool -RLAPI void DestroyLight(Light light); // Destroy a light and take it out of the list - //------------------------------------------------------------------------------------ // VR experience Functions (Module: rlgl) // NOTE: This functions are useless when using OpenGL 1.1 diff --git a/src/rlgl.c b/src/rlgl.c index bcbca227..8ec867eb 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -22,7 +22,6 @@ * GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend * * RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency) -* RLGL_NO_STANDARD_SHADER - Avoid standard shader (shader_standard.h) inclusion * RLGL_NO_DISTORTION_SHADER - Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion * RLGL_OCULUS_SUPPORT - Enable Oculus Rift CV1 functionality * @@ -92,10 +91,6 @@ #include // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()] #endif -#if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_STANDARD_SHADER) - #include "shader_standard.h" // Standard shader to be embedded -#endif - #if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_DISTORTION_SHADER) #include "shader_distortion.h" // Distortion shader to be embedded #endif @@ -118,8 +113,6 @@ #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 @@ -305,10 +298,7 @@ static bool useTempBuffer = false; // Shader Programs static Shader defaultShader; // Basic shader, support vertex color and diffuse texture -static Shader standardShader; // Shader with support for lighting and materials - // NOTE: Lazy initialization when GetStandardShader() static Shader currentShader; // Shader to be used on rendering (by default, defaultShader) -static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded // Extension supported flag: VAO static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension) @@ -368,12 +358,6 @@ static unsigned int whiteTexture; static int screenWidth; // Default framebuffer width static int screenHeight; // Default framebuffer height -// Lighting data -static Light lights[MAX_LIGHTS]; // Lights pool -static int lightsCount = 0; // Enabled lights counter -static int lightsLocs[MAX_LIGHTS][8]; // Lights location points in shader: 8 possible points per light: - // enabled, type, position, target, radius, diffuse, intensity, coneAngle - //---------------------------------------------------------------------------------- // Module specific Functions Declaration //---------------------------------------------------------------------------------- @@ -382,10 +366,8 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in static unsigned int LoadShaderProgram(const char *vShaderStr, const 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 @@ -397,9 +379,6 @@ static void SetStereoConfig(VrDeviceInfo info); // Set internal projection and modelview matrix depending on eyes tracking data static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView); - -static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS) -static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights #endif #if defined(RLGL_OCULUS_SUPPORT) @@ -1328,19 +1307,11 @@ void rlglClose(void) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UnloadDefaultShader(); - UnloadStandardShader(); UnloadDefaultBuffers(); // Delete default white texture glDeleteTextures(1, &whiteTexture); TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); - - // Unload lights - if (lightsCount > 0) - { - for (int i = 0; i < lightsCount; i++) free(lights[i]); - lightsCount = 0; - } free(draws); #endif @@ -2003,8 +1974,6 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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 - // TODO: Support OpenGL 1.1 lighting system - rlPushMatrix(); rlMultMatrixf(MatrixToFloat(transform)); rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a); @@ -2070,10 +2039,6 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Check if glossiness is located in shader and upload value int glossinessLoc = glGetUniformLocation(material.shader.id, "glossiness"); if (glossinessLoc != -1) glUniform1f(glossinessLoc, material.glossiness); - - // Set shader lights values for enabled lights - // NOTE: Lights array location points are obtained on shader loading (if available) - if (lightsCount > 0) SetShaderLightsValues(material.shader); } // Set shader textures (diffuse, normal, specular) @@ -2528,25 +2493,6 @@ Shader GetDefaultShader(void) #endif } -// Get default shader -// NOTE: Inits global variable standardShader -Shader GetStandardShader(void) -{ - Shader shader = { 0 }; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (standardShaderLoaded) shader = standardShader; - else - { - // Lazy initialization of standard shader - standardShader = LoadStandardShader(); - shader = standardShader; - } -#endif - - return shader; -} - // Get shader uniform location int GetShaderLocation(Shader shader, const char *uniformName) { @@ -2571,7 +2517,7 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size) else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4 else TraceLog(WARNING, "Shader value float array size not supported"); - glUseProgram(0); + //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set #endif } @@ -2587,7 +2533,7 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4 else TraceLog(WARNING, "Shader value int array size not supported"); - glUseProgram(0); + //glUseProgram(0); #endif } @@ -2599,7 +2545,7 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); - glUseProgram(0); + //glUseProgram(0); #endif } @@ -2645,73 +2591,6 @@ void EndBlendMode(void) BeginBlendMode(BLEND_ALPHA); } -// Create a new light, initialize it and add to pool -Light CreateLight(int type, Vector3 position, Color diffuse) -{ - Light light = NULL; - - if (lightsCount < MAX_LIGHTS) - { - // Allocate dynamic memory - 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++; - } - else - { - TraceLog(WARNING, "Too many lights, only supported up to %i lights", MAX_LIGHTS); - - // NOTE: Returning latest created light to avoid crashes - light = lights[lightsCount]; - } - -#if defined(GRAPHICS_API_OPENGL_11) - TraceLog(WARNING, "Lighting currently not supported on OpenGL 1.1"); -#endif - - return light; -} - -// Destroy a light and take it out of the list -void DestroyLight(Light light) -{ - if (light != NULL) - { - int lightId = light->id; - - // Free dynamic memory allocation - free(lights[lightId]); - - // Remove *obj from the pointers array - for (int i = lightId; 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; - } - } - - // Decrease enabled physic objects count - lightsCount--; - } -} - // Init VR device (or simulator) // NOTE: If device is not available, it fallbacks to default device (simulator) // NOTE: It modifies the global variable: VrDeviceInfo hmd @@ -3209,39 +3088,6 @@ 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 -// - Up to 8 lights: Point, Directional or Spot -static Shader LoadStandardShader(void) -{ - Shader shader; - -#if !defined(RLGL_NO_STANDARD_SHADER) - // Load standard shader (embeded in standard_shader.h) - shader.id = LoadShaderProgram(vStandardShaderStr, fStandardShaderStr); - - if (shader.id != 0) - { - LoadDefaultShaderLocations(&shader); - TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id); - - standardShaderLoaded = true; - } - else - { - TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded, using default shader", shader.id); - shader = GetDefaultShader(); - } -#else - shader = GetDefaultShader(); - TraceLog(WARNING, "[SHDR ID %i] Standard shader not available, using default shader", shader.id); -#endif - - 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) @@ -3275,9 +3121,6 @@ static void LoadDefaultShaderLocations(Shader *shader) shader->mapTexture2Loc = glGetUniformLocation(shader->id, "texture2"); // TODO: Try to find all expected/recognized shader locations (predefined names, must be documented) - - // Try to get lights location points (if available) - GetShaderLightsLocations(*shader); } // Unload default shader @@ -3292,20 +3135,6 @@ static void UnloadDefaultShader(void) glDeleteProgram(defaultShader.id); } -// Unload standard shader -static void UnloadStandardShader(void) -{ - glUseProgram(0); -#if !defined(RLGL_NO_STANDARD_SHADER) - //glDetachShader(defaultShader, vertexShader); - //glDetachShader(defaultShader, fragmentShader); - //glDeleteShader(vertexShader); // Already deleted on shader compilation - //glDeleteShader(fragmentShader); // Already deleted on shader compilation - glDeleteProgram(standardShader.id); -#endif -} - - // Load default internal buffers (lines, triangles, quads) static void LoadDefaultBuffers(void) { @@ -3763,104 +3592,6 @@ static void UnloadDefaultBuffers(void) free(quads.indices); } -// Get shader locations for lights (up to MAX_LIGHTS) -static void GetShaderLightsLocations(Shader shader) -{ - char locName[32] = "lights[x].\0"; - char locNameUpdated[64]; - - for (int i = 0; i < MAX_LIGHTS; i++) - { - locName[7] = '0' + i; - - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "enabled\0"); - lightsLocs[i][0] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "type\0"); - lightsLocs[i][1] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "position\0"); - lightsLocs[i][2] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "direction\0"); - lightsLocs[i][3] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "radius\0"); - lightsLocs[i][4] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "diffuse\0"); - lightsLocs[i][5] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "intensity\0"); - lightsLocs[i][6] = glGetUniformLocation(shader.id, locNameUpdated); - - locNameUpdated[0] = '\0'; - strcpy(locNameUpdated, locName); - strcat(locNameUpdated, "coneAngle\0"); - lightsLocs[i][7] = glGetUniformLocation(shader.id, locNameUpdated); - } -} - -// Set shader uniform values for lights -// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0 -static void SetShaderLightsValues(Shader shader) -{ - for (int i = 0; i < MAX_LIGHTS; i++) - { - if (i < lightsCount) - { - glUniform1i(lightsLocs[i][0], lights[i]->enabled); - - glUniform1i(lightsLocs[i][1], lights[i]->type); - glUniform4f(lightsLocs[i][5], (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255); - glUniform1f(lightsLocs[i][6], lights[i]->intensity); - - switch (lights[i]->type) - { - case LIGHT_POINT: - { - glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); - glUniform1f(lightsLocs[i][4], lights[i]->radius); - } break; - case LIGHT_DIRECTIONAL: - { - Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position); - VectorNormalize(&direction); - glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); - } break; - case LIGHT_SPOT: - { - glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z); - - Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position); - VectorNormalize(&direction); - glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z); - - glUniform1f(lightsLocs[i][7], lights[i]->coneAngle); - } break; - default: break; - } - } - else - { - glUniform1i(lightsLocs[i][0], 0); // Light disabled - } - } -} - // Configure stereo rendering (including distortion shader) with HMD device parameters static void SetStereoConfig(VrDeviceInfo hmd) { diff --git a/src/shader_standard.h b/src/shader_standard.h deleted file mode 100644 index 995c62ea..00000000 --- a/src/shader_standard.h +++ /dev/null @@ -1,173 +0,0 @@ - -// Vertex shader definition to embed, no external file required -static const char vStandardShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) -"#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) -"#version 100 \n" -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -"attribute vec3 vertexPosition; \n" -"attribute vec3 vertexNormal; \n" -"attribute vec2 vertexTexCoord; \n" -"attribute vec4 vertexColor; \n" -"varying vec3 fragPosition; \n" -"varying vec3 fragNormal; \n" -"varying vec2 fragTexCoord; \n" -"varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -"#version 330 \n" -"in vec3 vertexPosition; \n" -"in vec3 vertexNormal; \n" -"in vec2 vertexTexCoord; \n" -"in vec4 vertexColor; \n" -"out vec3 fragPosition; \n" -"out vec3 fragNormal; \n" -"out vec2 fragTexCoord; \n" -"out vec4 fragColor; \n" -#endif -"uniform mat4 mvpMatrix; \n" -"void main() \n" -"{ \n" -" fragPosition = vertexPosition; \n" -" fragNormal = vertexNormal; \n" -" fragTexCoord = vertexTexCoord; \n" -" fragColor = vertexColor; \n" -" gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n" -"} \n"; - -// Fragment shader definition to embed, no external file required -static const char fStandardShaderStr[] = -#if defined(GRAPHICS_API_OPENGL_21) -"#version 120 \n" -#elif defined(GRAPHICS_API_OPENGL_ES2) -"#version 100 \n" -"precision mediump float; \n" // precision required for OpenGL ES2 (WebGL) -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -"varying vec3 fragPosition; \n" -"varying vec3 fragNormal; \n" -"varying vec2 fragTexCoord; \n" -"varying vec4 fragColor; \n" -#elif defined(GRAPHICS_API_OPENGL_33) -"#version 330 \n" -"in vec3 fragPosition; \n" -"in vec3 fragNormal; \n" -"in vec2 fragTexCoord; \n" -"in vec4 fragColor; \n" -"out vec4 finalColor; \n" -#endif -"uniform sampler2D texture0; \n" -"uniform sampler2D texture1; \n" -"uniform sampler2D texture2; \n" -"uniform vec4 colAmbient; \n" -"uniform vec4 colDiffuse; \n" -"uniform vec4 colSpecular; \n" -"uniform float glossiness; \n" -"uniform int useNormal; \n" -"uniform int useSpecular; \n" -"uniform mat4 modelMatrix; \n" -"uniform vec3 viewDir; \n" -"struct Light { \n" -" int enabled; \n" -" int type; \n" -" vec3 position; \n" -" vec3 direction; \n" -" vec4 diffuse; \n" -" float intensity; \n" -" float radius; \n" -" float coneAngle; }; \n" -"const int maxLights = 8; \n" -"uniform Light lights[maxLights]; \n" -"\n" -"vec3 CalcPointLight(Light l, vec3 n, vec3 v, float s) \n" -"{\n" -" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));\n" -" vec3 surfaceToLight = l.position - surfacePos;\n" -" float brightness = clamp(float(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n))), 0.0, 1.0);\n" -" float diff = 1.0/dot(surfaceToLight/l.radius, surfaceToLight/l.radius)*brightness*l.intensity;\n" -" float spec = 0.0;\n" -" if (diff > 0.0)\n" -" {\n" -" vec3 h = normalize(-l.direction + v);\n" -" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n" -" }\n" -" return (diff*l.diffuse.rgb + spec*colSpecular.rgb);\n" -"}\n" -"\n" -"vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v, float s)\n" -"{\n" -" vec3 lightDir = normalize(-l.direction);\n" -" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n" -" float spec = 0.0;\n" -" if (diff > 0.0)\n" -" {\n" -" vec3 h = normalize(lightDir + v);\n" -" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n" -" }\n" -" return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb);\n" -"}\n" -"\n" -"vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s)\n" -"{\n" -" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1.0));\n" -" vec3 lightToSurface = normalize(surfacePos - l.position);\n" -" vec3 lightDir = normalize(-l.direction);\n" -" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n" -" float attenuation = clamp(float(dot(n, lightToSurface)), 0.0, 1.0);\n" -" attenuation = dot(lightToSurface, -lightDir);\n" -" float lightToSurfaceAngle = degrees(acos(attenuation));\n" -" if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;\n" -" float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;\n" -" float diffAttenuation = diff*attenuation;\n" -" float spec = 0.0;\n" -" if (diffAttenuation > 0.0)\n" -" {\n" -" vec3 h = normalize(lightDir + v);\n" -" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n" -" }\n" -" return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb));\n" -"}\n" -"\n" -"void main()\n" -"{\n" -" mat3 normalMatrix = mat3(modelMatrix);\n" -" vec3 normal = normalize(normalMatrix*fragNormal);\n" -" vec3 n = normalize(normal);\n" -" vec3 v = normalize(viewDir);\n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" vec4 texelColor = texture2D(texture0, fragTexCoord);\n" -#elif defined(GRAPHICS_API_OPENGL_33) -" vec4 texelColor = texture(texture0, fragTexCoord);\n" -#endif -" vec3 lighting = colAmbient.rgb;\n" -" if (useNormal == 1)\n" -" {\n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" n *= texture2D(texture1, fragTexCoord).rgb;\n" -#elif defined(GRAPHICS_API_OPENGL_33) -" n *= texture(texture1, fragTexCoord).rgb;\n" -#endif -" n = normalize(n);\n" -" }\n" -" float spec = 1.0;\n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" if (useSpecular == 1) spec = texture2D(texture2, fragTexCoord).r;\n" -#elif defined(GRAPHICS_API_OPENGL_33) -" if (useSpecular == 1) spec = texture(texture2, fragTexCoord).r;\n" -#endif -" for (int i = 0; i < maxLights; i++)\n" -" {\n" -" if (lights[i].enabled == 1)\n" -" {\n" -" if(lights[i].type == 0) lighting += CalcPointLight(lights[i], n, v, spec);\n" -" else if(lights[i].type == 1) lighting += CalcDirectionalLight(lights[i], n, v, spec);\n" -" else if(lights[i].type == 2) lighting += CalcSpotLight(lights[i], n, v, spec);\n" -" }\n" -" }\n" -#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21) -" gl_FragColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); \n" -#elif defined(GRAPHICS_API_OPENGL_33) -" finalColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); \n" -#endif -"}\n"; -- cgit v1.2.3 From b681e8c2775bbb467c0f0607afd9840fda25c563 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 28 Jan 2017 00:56:45 +0100 Subject: Implemented Wait() Now program is halted (OS signal call) for required amount of time every frame, so CPU usage drops to zero, instead of using a busy wait loop. --- src/core.c | 66 ++++++++++++++++++++++++++++++++++++++++++++---------------- src/raylib.h | 4 ++-- src/text.c | 21 ++----------------- 3 files changed, 53 insertions(+), 38 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 2917d839..8b97314d 100644 --- a/src/core.c +++ b/src/core.c @@ -67,9 +67,13 @@ #include // Required for: strcmp() //#include // Macros for reporting and retrieving error conditions through error codes +#if defined __linux || defined(PLATFORM_WEB) + #include // Required for: timespec, nanosleep(), select() - POSIX +#endif + #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 - #include // GLFW3 library: Windows, OpenGL context and Input management + //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3 + #include // GLFW3 library: Windows, OpenGL context and Input management #ifdef __linux #define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting @@ -243,7 +247,7 @@ static int dropFilesCount = 0; // Count stored strings static double currentTime, previousTime; // Used to track timmings static double updateTime, drawTime; // Time measures for update and draw -static double frameTime; // Time measure for one frame +static double frameTime = 0.0; // Time measure for one frame static double targetTime = 0.0; // Desired time for one frame, if 0 not applied static char configFlags = 0; // Configuration flags (bit based) @@ -264,6 +268,7 @@ static void InitGraphicsDevice(int width, int height); // Initialize graphics d static void SetupFramebufferSize(int displayWidth, int displayHeight); static void InitTimer(void); // Initialize timer static double GetTime(void); // Returns time since InitTimer() was run +static void Wait(int ms); // Wait for some milliseconds (stop program execution) static bool GetKeyStatus(int key); // Returns if a key has been pressed static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed static void PollInputEvents(void); // Register user events @@ -313,6 +318,11 @@ static void InitGamepad(void); // Init raw gamepad inpu static void *GamepadThread(void *arg); // Mouse reading thread #endif +#if defined(_WIN32) + // NOTE: We include Sleep() function signature here to avoid windows.h inclusion + void __stdcall Sleep(unsigned long msTimeout); // Required for Delay() +#endif + //---------------------------------------------------------------------------------- // Module Functions Definition - Window and OpenGL Context Functions //---------------------------------------------------------------------------------- @@ -638,15 +648,16 @@ void EndDrawing(void) frameTime = updateTime + drawTime; - double extraTime = 0.0; - - while (frameTime < targetTime) + // Wait for some milliseconds... + if (frameTime < targetTime) { - // Implement a delay + Wait((int)((targetTime - frameTime)*1000)); + currentTime = GetTime(); - extraTime = currentTime - previousTime; + double extraTime = currentTime - previousTime; previousTime = currentTime; - frameTime += extraTime; + + frameTime = updateTime + drawTime + extraTime; } } @@ -780,20 +791,16 @@ void SetTargetFPS(int fps) } // Returns current FPS -float GetFPS(void) +int GetFPS(void) { - return (float)(1.0/frameTime); + return (int)floorf(1.0f/GetFrameTime()); } // Returns time in seconds for one frame float GetFrameTime(void) { - // As we are operate quite a lot with frameTime, - // it could be no stable, so we round it before passing it around - // NOTE: There are still problems with high framerates (>500fps) - double roundedFrameTime = round(frameTime*10000)/10000.0; - - return (float)roundedFrameTime; // Time in seconds to run a frame + // NOTE: We round value to milliseconds + return (roundf(frameTime*1000.0)/1000.0f); } // Converts Color to float array and normalizes @@ -1931,6 +1938,31 @@ static double GetTime(void) #endif } +// Wait for some milliseconds (stop program execution) +static void Wait(int ms) +{ +#if defined _WIN32 + Sleep(ms); +#elif defined __linux || defined(PLATFORM_WEB) + struct timespec req = { 0 }; + time_t sec = (int)(ms/1000); + ms -= (sec*1000); + req.tv_sec=sec; + req.tv_nsec=ms*1000000L; + + // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated. + while (nanosleep(&req,&req) == -1) continue; +//#elif defined __APPLE__ + // TODO: +#else + double prevTime = GetTime(); + double nextTime = 0.0; + + // Busy wait loop + while ((nextTime - prevTime) < (double)ms/1000.0) nextTime = GetTime(); +#endif +} + // Get one key state static bool GetKeyStatus(int key) { diff --git a/src/raylib.h b/src/raylib.h index f8f17eec..97130253 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -659,8 +659,8 @@ RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI float GetFPS(void); // Returns current FPS -RLAPI float GetFrameTime(void); // Returns time in seconds for one frame +RLAPI int GetFPS(void); // Returns current FPS (rounded value) +RLAPI float GetFrameTime(void); // Returns time in seconds for one frame (rounded value) RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color diff --git a/src/text.c b/src/text.c index 4510b3af..4e163668 100644 --- a/src/text.c +++ b/src/text.c @@ -504,25 +504,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i // NOTE: Uses default font void DrawFPS(int posX, int posY) { - // NOTE: We are rendering fps every second for better viewing on high framerates - // TODO: Not working properly on ANDROID and RPI (for high framerates) - - static float fps = 0.0f; - static int counter = 0; - static int refreshRate = 20; - - if (counter < refreshRate) - { - counter++; - } - else - { - fps = GetFPS(); - refreshRate = (int)fps; - counter = 0; - } - - DrawText(FormatText("%2.0f FPS", fps), posX, posY, 20, LIME); + // NOTE: We have rounding errors every frame, so it oscillates a lot + DrawText(FormatText("%2i FPS", GetFPS()), posX, posY, 20, LIME); } //---------------------------------------------------------------------------------- -- cgit v1.2.3 From c85dfd4bc65099924b3ffa4402c24b73b40d35f6 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 28 Jan 2017 23:02:30 +0100 Subject: Remove unecessary spaces... --- src/audio.c | 98 ++++++------ src/core.c | 100 ++++++------ src/models.c | 66 ++++---- src/raylib.h | 26 +-- src/rlgl.c | 488 ++++++++++++++++++++++++++++----------------------------- src/text.c | 60 +++---- src/textures.c | 52 +++--- 7 files changed, 445 insertions(+), 445 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 74a54b04..22da74be 100644 --- a/src/audio.c +++ b/src/audio.c @@ -231,9 +231,9 @@ Wave LoadWave(const char *fileName) else if (strcmp(GetExtension(fileName),"rres") == 0) { RRESData rres = LoadResource(fileName); - + // NOTE: Parameters for RRES_WAVE type are: sampleCount, sampleRate, sampleSize, channels - + if (rres.type == RRES_WAVE) wave = LoadWaveEx(rres.data, rres.param1, rres.param2, rres.param3, rres.param4); else TraceLog(WARNING, "[%s] Resource file does not contain wave data", fileName); @@ -248,18 +248,18 @@ Wave LoadWave(const char *fileName) Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels) { Wave wave; - + wave.data = data; wave.sampleCount = sampleCount; wave.sampleRate = sampleRate; wave.sampleSize = sampleSize; wave.channels = channels; - + // NOTE: Copy wave data to work with, user is responsible of input data to free Wave cwave = WaveCopy(wave); - + WaveFormat(&cwave, sampleRate, sampleSize, channels); - + return cwave; } @@ -268,9 +268,9 @@ Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int Sound LoadSound(const char *fileName) { Wave wave = LoadWave(fileName); - + Sound sound = LoadSoundFromWave(wave); - + UnloadWave(wave); // Sound is loaded, we can unload wave return sound; @@ -354,7 +354,7 @@ void UnloadWave(Wave wave) void UnloadSound(Sound sound) { alSourceStop(sound.source); - + alDeleteSources(1, &sound.source); alDeleteBuffers(1, &sound.buffer); @@ -369,13 +369,13 @@ void UpdateSound(Sound sound, const void *data, int numSamples) alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format - + TraceLog(DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate); TraceLog(DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize); TraceLog(DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels); unsigned int dataSize = numSamples*channels*sampleSize/8; // Size of data in bytes - + alSourceStop(sound.source); // Stop sound alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update //alDeleteBuffers(1, &sound.buffer); // Delete current buffer data @@ -463,18 +463,18 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) if (wave->sampleRate != sampleRate) { // TODO: Resample wave data (upsampling or downsampling) - // NOTE 1: To downsample, you have to drop samples or average them. + // NOTE 1: To downsample, you have to drop samples or average them. // NOTE 2: To upsample, you have to interpolate new samples. - + wave->sampleRate = sampleRate; } - + // Format sample size // NOTE: Only supported 8 bit <--> 16 bit <--> 32 bit if (wave->sampleSize != sampleSize) { void *data = malloc(wave->sampleCount*wave->channels*sampleSize/8); - + for (int i = 0; i < wave->sampleCount; i++) { for (int j = 0; j < wave->channels; j++) @@ -484,30 +484,30 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) if (wave->sampleSize == 16) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float)(((short *)wave->data)[wave->channels*i + j])/32767.0f)*256); else if (wave->sampleSize == 32) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float *)wave->data)[wave->channels*i + j]*127.0f + 127); } - else if (sampleSize == 16) + else if (sampleSize == 16) { if (wave->sampleSize == 8) ((short *)data)[wave->channels*i + j] = (short)(((float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f)*32767); else if (wave->sampleSize == 32) ((short *)data)[wave->channels*i + j] = (short)((((float *)wave->data)[wave->channels*i + j])*32767); } - else if (sampleSize == 32) + else if (sampleSize == 32) { if (wave->sampleSize == 8) ((float *)data)[wave->channels*i + j] = (float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f; else if (wave->sampleSize == 16) ((float *)data)[wave->channels*i + j] = (float)(((short *)wave->data)[wave->channels*i + j])/32767.0f; } } } - + wave->sampleSize = sampleSize; free(wave->data); wave->data = data; } - + // Format channels (interlaced mode) // NOTE: Only supported mono <--> stereo if (wave->channels != channels) { void *data = malloc(wave->sampleCount*channels*wave->sampleSize/8); - + if ((wave->channels == 1) && (channels == 2)) // mono ---> stereo (duplicate mono information) { for (int i = 0; i < wave->sampleCount; i++) @@ -529,7 +529,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) else if (wave->sampleSize == 32) ((float *)data)[i] = (((float *)wave->data)[j] + ((float *)wave->data)[j + 1])/2.0f; } } - + // TODO: Add/remove additional interlaced channels wave->channels = channels; @@ -563,15 +563,15 @@ Wave WaveCopy(Wave wave) // NOTE: Security check in case of out-of-range void WaveCrop(Wave *wave, int initSample, int finalSample) { - if ((initSample >= 0) && (initSample < finalSample) && + if ((initSample >= 0) && (initSample < finalSample) && (finalSample > 0) && (finalSample < wave->sampleCount)) { int sampleCount = finalSample - initSample; - + void *data = malloc(sampleCount*wave->channels*wave->sampleSize/8); - + memcpy(data, wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8); - + free(wave->data); wave->data = data; } @@ -583,7 +583,7 @@ void WaveCrop(Wave *wave, int initSample, int finalSample) float *GetWaveData(Wave wave) { float *samples = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float)); - + for (int i = 0; i < wave.sampleCount; i++) { for (int j = 0; j < wave.channels; j++) @@ -593,7 +593,7 @@ float *GetWaveData(Wave wave) else if (wave.sampleSize == 32) samples[wave.channels*i + j] = ((float *)wave.data)[wave.channels*i + j]; } } - + return samples; } @@ -632,7 +632,7 @@ Music LoadMusicStream(const char *fileName) else if (strcmp(GetExtension(fileName), "flac") == 0) { music->ctxFlac = drflac_open_file(fileName); - + if (music->ctxFlac == NULL) TraceLog(WARNING, "[%s] FLAC audio file could not be opened", fileName); else { @@ -641,7 +641,7 @@ Music LoadMusicStream(const char *fileName) music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; music->loop = true; // We loop by default - + TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate); TraceLog(DEBUG, "[%s] FLAC bits per sample: %i", fileName, music->ctxFlac->bitsPerSample); @@ -728,7 +728,7 @@ void ResumeMusicStream(Music music) void StopMusicStream(Music music) { alSourceStop(music->stream.source); - + switch (music->ctxType) { case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break; @@ -736,7 +736,7 @@ void StopMusicStream(Music music) case MUSIC_MODULE_MOD: jar_mod_seek_start(&music->ctxMod); break; default: break; } - + music->samplesLeft = music->totalSamples; } @@ -745,14 +745,14 @@ void UpdateMusicStream(Music music) { ALenum state; ALint processed = 0; - + alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); // Get music stream state alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); // Get processed buffers if (processed > 0) { bool active = true; - + // NOTE: Using dynamic allocation because it could require more than 16KB void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.channels*music->stream.sampleSize/8, 1); @@ -764,7 +764,7 @@ void UpdateMusicStream(Music music) { if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE; else numSamples = music->samplesLeft; - + // TODO: Really don't like ctxType thingy... switch (music->ctxType) { @@ -784,7 +784,7 @@ void UpdateMusicStream(Music music) case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); break; default: break; } - + UpdateAudioStream(music->stream, pcm, numSamples); music->samplesLeft -= numSamples; @@ -794,12 +794,12 @@ void UpdateMusicStream(Music music) break; } } - + // This error is registered when UpdateAudioStream() fails if (alGetError() == AL_INVALID_VALUE) TraceLog(WARNING, "OpenAL: Error buffering data..."); // Reset audio stream for looping - if (!active) + if (!active) { StopMusicStream(music); // Stop music (and reset) if (music->loop) PlayMusicStream(music); // Play again @@ -810,7 +810,7 @@ void UpdateMusicStream(Music music) // just make sure to play again on window restore if (state != AL_PLAYING) PlayMusicStream(music); } - + free(pcm); } } @@ -866,7 +866,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un stream.sampleRate = sampleRate; stream.sampleSize = sampleSize; - + // Only mono and stereo channels are supported, more channels require AL_EXT_MCFORMATS extension if ((channels > 0) && (channels < 3)) stream.channels = channels; else @@ -910,12 +910,12 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Initialize buffer with zeros by default // NOTE: Using dynamic allocation because it requires more than 16KB void *pcm = calloc(AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, 1); - + for (int i = 0; i < MAX_STREAM_BUFFERS; i++) { alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, stream.sampleRate); } - + free(pcm); alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers); @@ -1095,7 +1095,7 @@ static Wave LoadWAV(const char *fileName) wave.sampleRate = wavFormat.sampleRate; wave.sampleSize = wavFormat.bitsPerSample; wave.channels = wavFormat.numChannels; - + // NOTE: Only support 8 bit, 16 bit and 32 bit sample sizes if ((wave.sampleSize != 8) && (wave.sampleSize != 16) && (wave.sampleSize != 32)) { @@ -1104,16 +1104,16 @@ static Wave LoadWAV(const char *fileName) } // NOTE: Only support up to 2 channels (mono, stereo) - if (wave.channels > 2) + if (wave.channels > 2) { WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2); TraceLog(WARNING, "[%s] WAV channels number (%i) not supported, converted to 2 channels", fileName, wave.channels); } - + // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels; - TraceLog(INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); + TraceLog(INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); } } } @@ -1145,7 +1145,7 @@ static Wave LoadOGG(const char *fileName) wave.sampleSize = 16; // 16 bit per sample (short) wave.channels = info.channels; wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile); - + float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); @@ -1173,16 +1173,16 @@ static Wave LoadFLAC(const char *fileName) // Decode an entire FLAC file in one go uint64_t totalSampleCount; wave.data = drflac_open_and_decode_file_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount); - + wave.sampleCount = (int)totalSampleCount/wave.channels; wave.sampleSize = 16; - + // NOTE: Only support up to 2 channels (mono, stereo) if (wave.channels > 2) TraceLog(WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels); if (wave.data == NULL) TraceLog(WARNING, "[%s] FLAC data could not be loaded", fileName); else TraceLog(INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); - + return wave; } diff --git a/src/core.c b/src/core.c index 8b97314d..ea363fce 100644 --- a/src/core.c +++ b/src/core.c @@ -9,7 +9,7 @@ * External libs: * GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX) * raymath - 3D math functionality (Vector3, Matrix, Quaternion) -* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) +* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) * gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) * * Module Configuration Flags: @@ -103,7 +103,7 @@ #include // Linux: KDSKBMODE, K_MEDIUMRAM constants definition #include // Linux: Keycodes constants definition (KEY_A, ...) #include // Linux: Joystick support library - + #include "bcm_host.h" // Raspberry Pi VideoCore IV access functions #include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions @@ -488,9 +488,9 @@ void CloseWindow(void) // Wait for mouse and gamepad threads to finish before closing // NOTE: Those threads should already have finished at this point // because they are controlled by windowShouldClose variable - + windowShouldClose = true; // Added to force threads to exit when the close window is called - + pthread_join(mouseThreadId, NULL); pthread_join(touchThreadId, NULL); pthread_join(gamepadThreadId, NULL); @@ -649,14 +649,14 @@ void EndDrawing(void) frameTime = updateTime + drawTime; // Wait for some milliseconds... - if (frameTime < targetTime) + if (frameTime < targetTime) { Wait((int)((targetTime - frameTime)*1000)); - + currentTime = GetTime(); double extraTime = currentTime - previousTime; previousTime = currentTime; - + frameTime = updateTime + drawTime + extraTime; } } @@ -1147,7 +1147,7 @@ bool IsKeyDown(int key) bool IsKeyReleased(int key) { bool released = false; - + if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true; else released = false; @@ -1182,7 +1182,7 @@ void SetExitKey(int key) bool IsGamepadAvailable(int gamepad) { bool result = false; - + #if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true; #endif @@ -1196,7 +1196,7 @@ bool IsGamepadName(int gamepad, const char *name) bool result = false; #if !defined(PLATFORM_ANDROID) - const char *gamepadName = NULL; + const char *gamepadName = NULL; if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad); if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0); @@ -1235,7 +1235,7 @@ int GetGamepadAxisCount(int gamepad) float GetGamepadAxisMovement(int gamepad, int axis) { float value = 0; - + #if !defined(PLATFORM_ANDROID) if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = gamepadAxisState[gamepad][axis]; #endif @@ -1249,8 +1249,8 @@ bool IsGamepadButtonPressed(int gamepad, int button) bool pressed = false; #if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 1)) pressed = true; #endif @@ -1274,10 +1274,10 @@ bool IsGamepadButtonDown(int gamepad, int button) bool IsGamepadButtonReleased(int gamepad, int button) { bool released = false; - + #if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && - (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) && (currentGamepadState[gamepad][button] == 0)) released = true; #endif @@ -1290,7 +1290,7 @@ bool IsGamepadButtonUp(int gamepad, int button) bool result = false; #if !defined(PLATFORM_ANDROID) - if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && + if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) && (currentGamepadState[gamepad][button] == 0)) result = true; #endif @@ -1503,7 +1503,7 @@ static void InitGraphicsDevice(int width, int height) glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window } else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable - + //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default) @@ -1941,7 +1941,7 @@ static double GetTime(void) // Wait for some milliseconds (stop program execution) static void Wait(int ms) { -#if defined _WIN32 +#if defined _WIN32 Sleep(ms); #elif defined __linux || defined(PLATFORM_WEB) struct timespec req = { 0 }; @@ -1949,7 +1949,7 @@ static void Wait(int ms) ms -= (sec*1000); req.tv_sec=sec; req.tv_nsec=ms*1000000L; - + // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated. while (nanosleep(&req,&req) == -1) continue; //#elif defined __APPLE__ @@ -1999,10 +1999,10 @@ static void PollInputEvents(void) // NOTE: Gestures update must be called every frame to reset gestures correctly // because ProcessGestureEvent() is just called on an event, not every frame UpdateGestures(); - + // Reset last key pressed registered lastKeyPressed = -1; - + #if !defined(PLATFORM_RPI) // Reset last gamepad button/axis registered state lastGamepadButtonPressed = -1; @@ -2018,7 +2018,7 @@ static void PollInputEvents(void) mousePosition.x = (float)mouseX; mousePosition.y = (float)mouseY; - + // Keyboard input polling (automatically managed by GLFW3 through callback) // Register previous keys states @@ -2039,7 +2039,7 @@ static void PollInputEvents(void) if (glfwJoystickPresent(i)) gamepadReady[i] = true; else gamepadReady[i] = false; } - + // Register gamepads buttons events for (int i = 0; i < MAX_GAMEPADS; i++) { @@ -2047,14 +2047,14 @@ static void PollInputEvents(void) { // Register previous gamepad states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; - + // Get current gamepad state // NOTE: There is no callback available, so we get it manually const unsigned char *buttons; int buttonsCount; buttons = glfwGetJoystickButtons(i, &buttonsCount); - + for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++) { if (buttons[k] == GLFW_PRESS) @@ -2064,18 +2064,18 @@ static void PollInputEvents(void) } else currentGamepadState[i][k] = 0; } - + // Get current axis state const float *axes; int axisCount = 0; axes = glfwGetJoystickAxes(i, &axisCount); - + for (int k = 0; (axes != NULL) && (k < axisCount) && (k < MAX_GAMEPAD_AXIS); k++) { gamepadAxisState[i][k] = axes[k]; } - + gamepadAxisCount = axisCount; } } @@ -2088,16 +2088,16 @@ static void PollInputEvents(void) #if defined(PLATFORM_WEB) // Get number of gamepads connected int numGamepads = emscripten_get_num_gamepads(); - + for (int i = 0; (i < numGamepads) && (i < MAX_GAMEPADS); i++) { // Register previous gamepad button states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k]; - + EmscriptenGamepadEvent gamepadState; - + int result = emscripten_get_gamepad_status(i, &gamepadState); - + if (result == EMSCRIPTEN_RESULT_SUCCESS) { // Register buttons data for every connected gamepad @@ -2109,16 +2109,16 @@ static void PollInputEvents(void) lastGamepadButtonPressed = j; } else currentGamepadState[i][j] = 0; - + //printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]); } - + // Register axis data for every connected gamepad for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++) { gamepadAxisState[i][j] = gamepadState.axis[j]; } - + gamepadAxisCount = gamepadState.numAxes; } } @@ -2665,16 +2665,16 @@ static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadE { /* printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n", - eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", + eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state", gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping); - + for(int i = 0; i < gamepadEvent->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]); for(int i = 0; i < gamepadEvent->numButtons; ++i) printf("Button %d: Digital: %d, Analog: %g\n", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]); */ - + if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true; else gamepadReady[gamepadEvent->index] = false; - + // TODO: Test gamepadEvent->index return 0; @@ -2935,7 +2935,7 @@ static void InitTouch(void) } // Touch reading thread. -// This reads from a Virtual Input Event /dev/input/event4 which is +// This reads from a Virtual Input Event /dev/input/event4 which is // created by the ts_uinput daemon. This takes, filters and scales // raw input from the Touchscreen (which appears in /dev/input/event3) // based on the Calibration data referenced by tslib. @@ -2949,7 +2949,7 @@ static void *TouchThread(void *arg) if (read(touchStream, &ev, sizeof(ev)) == (int)sizeof(ev)) { // if pressure > 0 then simulate left mouse button click - if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1) + if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1) { currentMouseState[0] = 0; gestureEvent.touchAction = TOUCH_UP; @@ -2963,10 +2963,10 @@ static void *TouchThread(void *arg) gestureEvent.position[1].x /= (float)GetScreenWidth(); gestureEvent.position[1].y /= (float)GetScreenHeight(); ProcessGestureEvent(gestureEvent); - } - if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0) + } + if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0) { - currentMouseState[0] = 1; + currentMouseState[0] = 1; gestureEvent.touchAction = TOUCH_DOWN; gestureEvent.pointCount = 1; gestureEvent.pointerId[0] = 0; @@ -2978,9 +2978,9 @@ static void *TouchThread(void *arg) gestureEvent.position[1].x /= (float)GetScreenWidth(); gestureEvent.position[1].y /= (float)GetScreenHeight(); ProcessGestureEvent(gestureEvent); - } + } // x & y values supplied by event4 have been scaled & de-jittered using tslib calibration data - if (ev.type == EV_ABS && ev.code == 0) + if (ev.type == EV_ABS && ev.code == 0) { mousePosition.x = ev.value; if (mousePosition.x < 0) mousePosition.x = 0; @@ -2997,7 +2997,7 @@ static void *TouchThread(void *arg) gestureEvent.position[1].y /= (float)GetScreenHeight(); ProcessGestureEvent(gestureEvent); } - if (ev.type == EV_ABS && ev.code == 1) + if (ev.type == EV_ABS && ev.code == 1) { mousePosition.y = ev.value; if (mousePosition.y < 0) mousePosition.y = 0; @@ -3014,7 +3014,7 @@ static void *TouchThread(void *arg) gestureEvent.position[1].y /= (float)GetScreenHeight(); ProcessGestureEvent(gestureEvent); } - + } } return NULL; @@ -3084,7 +3084,7 @@ static void *GamepadThread(void *arg) { // 1 - button pressed, 0 - button released currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value; - + if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number; else lastGamepadButtonPressed = -1; } diff --git a/src/models.c b/src/models.c index 23c2e6fd..43821691 100644 --- a/src/models.c +++ b/src/models.c @@ -584,7 +584,7 @@ Mesh LoadMesh(const char *fileName) if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded"); else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) - + // TODO: Initialize default mesh data in case loading fails, maybe a cube? return mesh; @@ -607,7 +607,7 @@ Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color mesh.indices = NULL; rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) - + return mesh; } @@ -668,7 +668,7 @@ Model LoadCubicmap(Image cubicmap) return model; } - + // Unload mesh from memory (RAM and/or VRAM) void UnloadMesh(Mesh *mesh) { @@ -1438,34 +1438,34 @@ RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh) int triangleCount = mesh->vertexCount/3; // Test against all triangles in mesh - for (int i = 0; i < triangleCount; i++) + for (int i = 0; i < triangleCount; i++) { Vector3 a, b, c; Vector3 *vertdata = (Vector3 *)mesh->vertices; - - if (mesh->indices) + + if (mesh->indices) { a = vertdata[mesh->indices[i*3 + 0]]; b = vertdata[mesh->indices[i*3 + 1]]; - c = vertdata[mesh->indices[i*3 + 2]]; - } - else - { + c = vertdata[mesh->indices[i*3 + 2]]; + } + else + { a = vertdata[i*3 + 0]; b = vertdata[i*3 + 1]; c = vertdata[i*3 + 2]; } RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c); - - if (triHitInfo.hit) + + if (triHitInfo.hit) { // Save the closest hit triangle if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo; } } - return result; + return result; } // Get collision info between ray and triangle @@ -1478,44 +1478,44 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) Vector3 p, q, tv; float det, invDet, u, v, t; RayHitInfo result = {0}; - + // Find vectors for two edges sharing V1 edge1 = VectorSubtract(p2, p1); edge2 = VectorSubtract(p3, p1); - + // Begin calculating determinant - also used to calculate u parameter p = VectorCrossProduct(ray.direction, edge2); - + // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle det = VectorDotProduct(edge1, p); - + // Avoid culling! if ((det > -EPSILON) && (det < EPSILON)) return result; - + invDet = 1.0f/det; - + // Calculate distance from V1 to ray origin tv = VectorSubtract(ray.position, p1); - + // Calculate u parameter and test bound u = VectorDotProduct(tv, p)*invDet; - + // The intersection lies outside of the triangle if ((u < 0.0f) || (u > 1.0f)) return result; - + // Prepare to test v parameter q = VectorCrossProduct(tv, edge1); - + // Calculate V parameter and test bound v = VectorDotProduct(ray.direction, q)*invDet; - + // The intersection lies outside of the triangle if ((v < 0.0f) || ((u + v) > 1.0f)) return result; - + t = VectorDotProduct(edge2, q)*invDet; - - if (t > EPSILON) - { + + if (t > EPSILON) + { // Ray hit, get hit point and normal result.hit = true; result.distance = t; @@ -1523,10 +1523,10 @@ RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3) result.hitNormal = VectorCrossProduct(edge1, edge2); VectorNormalize(&result.hitNormal); Vector3 rayDir = ray.direction; - VectorScale(&rayDir, t); + VectorScale(&rayDir, t); result.hitPosition = VectorAdd(ray.position, rayDir); } - + return result; } @@ -1540,8 +1540,8 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) if (fabsf(ray.direction.y) > EPSILON) { float t = (ray.position.y - groundHeight)/-ray.direction.y; - - if (t >= 0.0) + + if (t >= 0.0) { Vector3 rayDir = ray.direction; VectorScale(&rayDir, t); @@ -1551,7 +1551,7 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight) result.hitPosition = VectorAdd(ray.position, rayDir); } } - + return result; } diff --git a/src/raylib.h b/src/raylib.h index 97130253..c1c9ebae 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -593,21 +593,21 @@ typedef enum { // rRES data returned when reading a resource, it contains all required data for user (24 byte) typedef struct { unsigned int type; // Resource type (4 byte) - + unsigned int param1; // Resouce parameter 1 (4 byte) unsigned int param2; // Resouce parameter 2 (4 byte) unsigned int param3; // Resouce parameter 3 (4 byte) unsigned int param4; // Resouce parameter 4 (4 byte) - + void *data; // Resource data pointer (4 byte) } RRESData; -typedef enum { - RRES_RAW = 0, - RRES_IMAGE, - RRES_WAVE, - RRES_VERTEX, - RRES_TEXT +typedef enum { + RRES_RAW = 0, + RRES_IMAGE, + RRES_WAVE, + RRES_VERTEX, + RRES_TEXT } RRESDataType; #ifdef __cplusplus @@ -800,7 +800,7 @@ RLAPI Image ImageText(const char *text, int fontSize, Color color); RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) -RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, +RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text, float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally @@ -876,15 +876,15 @@ RLAPI Material LoadDefaultMaterial(void); RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) -RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) -RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture -RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits @@ -892,7 +892,7 @@ RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere -RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, +RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius, Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh); // Get collision info between ray and mesh diff --git a/src/rlgl.c b/src/rlgl.c index 8ec867eb..6c4e5927 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2,10 +2,10 @@ * * rlgl - raylib OpenGL abstraction layer * -* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to -* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). +* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to +* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). * -* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal +* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal * VBO buffers (and VAOs if available). It requires calling 3 functions: * rlglInit() - Initialize internal buffers and auxiliar resources * rlglDraw() - Process internal buffers and send required draw calls @@ -57,7 +57,7 @@ #endif #if defined(GRAPHICS_API_OPENGL_11) - #ifdef __APPLE__ + #ifdef __APPLE__ #include // OpenGL 1.1 library for OSX #else #include // OpenGL 1.1 library @@ -69,7 +69,7 @@ #endif #if defined(GRAPHICS_API_OPENGL_33) - #ifdef __APPLE__ + #ifdef __APPLE__ #include // OpenGL 3 library for OSX #else #define GLAD_IMPLEMENTATION @@ -168,7 +168,7 @@ #if defined(GRAPHICS_API_OPENGL_ES2) #define glClearDepth glClearDepthf - #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER + #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER #endif @@ -695,7 +695,7 @@ void rlEnd(void) } break; default: break; } - + // NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values, // as well as depth buffer bit-depth (16bit or 24bit or 32bit) // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) @@ -880,7 +880,7 @@ void rlDisableTexture(void) glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); #else - // NOTE: If quads batch limit is reached, + // NOTE: If quads batch limit is reached, // we force a draw call and next batch starts if (quads.vCounter/4 >= MAX_QUADS_BATCH) rlglDraw(); #endif @@ -982,7 +982,7 @@ void rlDeleteRenderTextures(RenderTexture2D target) if (target.id != 0) glDeleteFramebuffers(1, &target.id); if (target.texture.id != 0) glDeleteTextures(1, &target.texture.id); if (target.depth.id != 0) glDeleteTextures(1, &target.depth.id); - + TraceLog(INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id); #endif } @@ -999,7 +999,7 @@ void rlDeleteShader(unsigned int id) void rlDeleteVertexArrays(unsigned int id) { #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if (vaoSupported) + if (vaoSupported) { if (id != 0) glDeleteVertexArrays(1, &id); TraceLog(INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", id); @@ -1061,7 +1061,7 @@ void rlglInit(int width, int height) { // Check OpenGL information and capabilities //------------------------------------------------------------------------------ - + // Print current OpenGL and GLSL version TraceLog(INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR)); TraceLog(INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER)); @@ -1072,14 +1072,14 @@ void rlglInit(int width, int height) //int maxTexSize; //glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); //TraceLog(INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize); - + //GL_MAX_TEXTURE_IMAGE_UNITS //GL_MAX_VIEWPORT_DIMS //int numAuxBuffers; //glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers); //TraceLog(INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers); - + //GLint numComp = 0; //GLint format[32] = { 0 }; //glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp); @@ -1087,7 +1087,7 @@ void rlglInit(int width, int height) //for (int i = 0; i < numComp; i++) TraceLog(INFO, "Supported compressed format: 0x%x", format[i]); // NOTE: We don't need that much data on screen... right now... - + #if defined(GRAPHICS_API_OPENGL_11) //TraceLog(INFO, "OpenGL 1.1 (or driver default) profile initialized"); #endif @@ -1095,7 +1095,7 @@ void rlglInit(int width, int height) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Get supported extensions list GLint numExt = 0; - + #if defined(GRAPHICS_API_OPENGL_33) // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default @@ -1105,18 +1105,18 @@ void rlglInit(int width, int height) // We get a list of available extensions and we check for some of them (compressed textures) // NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that) glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); - + #ifdef _MSC_VER const char **extList = malloc(sizeof(const char *)*numExt); #else const char *extList[numExt]; #endif - + for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i); - + #elif defined(GRAPHICS_API_OPENGL_ES2) char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string - + // NOTE: We have to duplicate string because glGetString() returns a const value // If not duplicated, it fails in some systems (Raspberry Pi) // Equivalent to function: char *strdup(const char *str) @@ -1125,12 +1125,12 @@ void rlglInit(int width, int height) void *newstr = malloc(len); if (newstr == NULL) extensionsDup = NULL; extensionsDup = (char *)memcpy(newstr, extensions, len); - + // NOTE: String could be splitted using strtok() function (string.h) // NOTE: strtok() modifies the received string, it can not be const - + char *extList[512]; // Allocate 512 strings pointers (2 KB) - + extList[numExt] = strtok(extensionsDup, " "); while (extList[numExt] != NULL) @@ -1138,9 +1138,9 @@ void rlglInit(int width, int height) numExt++; extList[numExt] = strtok(NULL, " "); } - + free(extensionsDup); // Duplicated string must be deallocated - + numExt -= 1; #endif @@ -1158,25 +1158,25 @@ void rlglInit(int width, int height) if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0) { vaoSupported = true; - - // The extension is supported by our hardware and driver, try to get related functions pointers + + // The extension is supported by our hardware and driver, try to get related functions pointers // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES"); glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES"); glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES"); //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted } - + // Check NPOT textures support // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true; #endif - + // DDS texture compression support if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true; - + (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true; + // ETC1 texture compression support if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) || (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) texCompETC1Supported = true; @@ -1189,26 +1189,26 @@ void rlglInit(int width, int height) // ASTC texture compression support if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true; - + // Anisotropic texture filter support if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) { texAnisotropicFilterSupported = true; - glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT } - + // Clamp mirror wrap mode supported if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true; } - + #ifdef _MSC_VER free(extList); #endif - + #if defined(GRAPHICS_API_OPENGL_ES2) if (vaoSupported) TraceLog(INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully"); else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported"); - + if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported"); else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); #endif @@ -1218,13 +1218,13 @@ void rlglInit(int width, int height) if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported"); if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported"); if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported"); - + if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel); if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported"); // Initialize buffers, default shaders and default textures //---------------------------------------------------------- - + // Init default white texture unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) @@ -1238,7 +1238,7 @@ void rlglInit(int width, int height) currentShader = defaultShader; // Init default vertex arrays buffers (lines, triangles, quads) - LoadDefaultBuffers(); + LoadDefaultBuffers(); // Init temp vertex buffer, used when transformation required (translate, rotate, scale) tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE); @@ -1257,7 +1257,7 @@ void rlglInit(int width, int height) drawsCounter = 1; draws[drawsCounter - 1].textureId = whiteTexture; currentDrawMode = RL_TRIANGLES; // Set default draw mode - + // Init internal matrix stack (emulating OpenGL 1.1) for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity(); @@ -1286,7 +1286,7 @@ void rlglInit(int width, int height) #if defined(GRAPHICS_API_OPENGL_11) // Init state: Color hints (deprecated in OpenGL 3.0+) - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) #endif @@ -1294,7 +1294,7 @@ void rlglInit(int width, int height) glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) glClearDepth(1.0f); // Set clear depth value (default) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) - + // Store screen size into global variables screenWidth = width; screenHeight = height; @@ -1308,7 +1308,7 @@ void rlglClose(void) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) UnloadDefaultShader(); UnloadDefaultBuffers(); - + // Delete default white texture glDeleteTextures(1, &whiteTexture); TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture); @@ -1326,7 +1326,7 @@ void rlglDraw(void) // NOTE: Default buffers upload and draw UpdateDefaultBuffers(); - + if (vrEnabled && vrRendering) DrawDefaultBuffers(2); else DrawDefaultBuffers(1); #endif @@ -1342,7 +1342,7 @@ void rlglLoadExtensions(void *loader) if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions"); else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully"); #endif - + #if defined(GRAPHICS_API_OPENGL_21) #ifndef __APPLE__ if (GLAD_GL_VERSION_2_1) TraceLog(INFO, "OpenGL 2.1 profile supported"); @@ -1363,17 +1363,17 @@ void rlglLoadExtensions(void *loader) Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view) { Vector3 result = { 0.0f, 0.0f, 0.0f }; - + // Calculate unproject matrix (multiply projection matrix and view matrix) and invert it Matrix matProjView = MatrixMultiply(proj, view); MatrixInvert(&matProjView); - + // Create quaternion from source point Quaternion quat = { source.x, source.y, source.z, 1.0f }; - + // Multiply quat point by unproject matrix QuaternionTransform(&quat, matProjView); - + // Normalized world points in vectors result.x = quat.x/quat.w; result.y = quat.y/quat.w; @@ -1388,41 +1388,41 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding GLuint id = 0; - + // Check texture format support by OpenGL 1.1 (compressed textures not supported) -#if defined(GRAPHICS_API_OPENGL_11) +#if defined(GRAPHICS_API_OPENGL_11) if (textureFormat >= 8) { TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats"); return id; } #endif - + if ((!texCompDXTSupported) && ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT1_RGBA) || (textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA))) { TraceLog(WARNING, "DXT compressed texture format not supported"); return id; } -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if ((!texCompETC1Supported) && (textureFormat == COMPRESSED_ETC1_RGB)) { TraceLog(WARNING, "ETC1 compressed texture format not supported"); return id; } - + if ((!texCompETC2Supported) && ((textureFormat == COMPRESSED_ETC2_RGB) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA))) { TraceLog(WARNING, "ETC2 compressed texture format not supported"); return id; } - + if ((!texCompPVRTSupported) && ((textureFormat == COMPRESSED_PVRT_RGB) || (textureFormat == COMPRESSED_PVRT_RGBA))) { TraceLog(WARNING, "PVRT compressed texture format not supported"); return id; } - + if ((!texCompASTCSupported) && ((textureFormat == COMPRESSED_ASTC_4x4_RGBA) || (textureFormat == COMPRESSED_ASTC_8x8_RGBA))) { TraceLog(WARNING, "ASTC compressed texture format not supported"); @@ -1450,24 +1450,24 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma // GL_RGBA4 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4 // GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE // GL_RGB8 GL_RGB GL_UNSIGNED_BYTE - + switch (textureFormat) { case UNCOMPRESSED_GRAYSCALE: { glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data); - + // With swizzleMask we define how a one channel texture will be mapped to RGBA // Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - + TraceLog(INFO, "[TEX ID %i] Grayscale texture loaded and swizzled", id); } break; case UNCOMPRESSED_GRAY_ALPHA: { glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width, height, 0, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data); - + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); } break; @@ -1541,7 +1541,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma // Magnification and minification filters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR - + #if defined(GRAPHICS_API_OPENGL_33) if (mipmapCount > 1) { @@ -1551,7 +1551,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma #endif // At this point we have the texture loaded in GPU and texture parameters configured - + // NOTE: If mipmaps were not in data, they are not generated automatically // Unbind current texture @@ -1567,15 +1567,15 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma RenderTexture2D rlglLoadRenderTexture(int width, int height) { RenderTexture2D target; - + target.id = 0; - + target.texture.id = 0; target.texture.width = width; target.texture.height = height; target.texture.format = UNCOMPRESSED_R8G8B8A8; target.texture.mipmaps = 1; - + target.depth.id = 0; target.depth.width = width; target.depth.height = height; @@ -1592,13 +1592,13 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); - + #if defined(GRAPHICS_API_OPENGL_33) #define USE_DEPTH_TEXTURE #else #define USE_DEPTH_RENDERBUFFER #endif - + #if defined(USE_DEPTH_RENDERBUFFER) // Create the renderbuffer that will serve as the depth attachment for the framebuffer. glGenRenderbuffers(1, &target.depth.id); @@ -1634,7 +1634,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) if (status != GL_FRAMEBUFFER_COMPLETE) { TraceLog(WARNING, "Framebuffer object could not be created..."); - + switch (status) { case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break; @@ -1645,17 +1645,17 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height) case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break; default: break; } - + glDeleteTextures(1, &target.texture.id); glDeleteTextures(1, &target.depth.id); glDeleteFramebuffers(1, &target.id); } else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", target.id); - + glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif - return target; + return target; } // Update already loaded texture in GPU with new data @@ -1695,11 +1695,11 @@ void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void rlglGenerateMipmaps(Texture2D *texture) { glBindTexture(GL_TEXTURE_2D, texture->id); - + // Check if texture is power-of-two (POT) bool texIsPOT = false; - - if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) && + + if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) && ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true; if ((texIsPOT) || (npotSupported)) @@ -1707,7 +1707,7 @@ void rlglGenerateMipmaps(Texture2D *texture) #if defined(GRAPHICS_API_OPENGL_11) // Compute required mipmaps void *data = rlglReadTexturePixels(*texture); - + // NOTE: data size is reallocated to fit mipmaps data // NOTE: CPU mipmap generation only supports RGBA 32bit data int mipmapCount = GenerateMipmaps(data, texture->width, texture->height); @@ -1729,12 +1729,12 @@ void rlglGenerateMipmaps(Texture2D *texture) mipWidth /= 2; mipHeight /= 2; } - + TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture->id); - + // NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data free(data); - + texture->mipmaps = mipmapCount + 1; #endif @@ -1745,10 +1745,10 @@ void rlglGenerateMipmaps(Texture2D *texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps - + #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) - + texture->mipmaps = 1 + (int)floor(log(MAX(texture->width, texture->height))/log(2)); #endif } @@ -1768,7 +1768,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) mesh->vboId[4] = 0; // Vertex tangents VBO mesh->vboId[5] = 0; // Vertex texcoords2 VBO mesh->vboId[6] = 0; // Vertex indices VBO - + #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) int drawHint = GL_STATIC_DRAW; if (dynamic) drawHint = GL_DYNAMIC_DRAW; @@ -1783,8 +1783,8 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glBindVertexArray(vaoId); } - // NOTE: Attributes must be uploaded considering default locations points - + // NOTE: Attributes must be uploaded considering default locations points + // Enable vertex attributes: position (shader-location = 0) glGenBuffers(1, &vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); @@ -1814,7 +1814,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f); glDisableVertexAttribArray(2); } - + // Default color vertex attribute (shader-location = 3) if (mesh->colors != NULL) { @@ -1830,7 +1830,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f); glDisableVertexAttribArray(3); } - + // Default tangent vertex attribute (shader-location = 4) if (mesh->tangents != NULL) { @@ -1846,7 +1846,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glVertexAttrib3f(4, 0.0f, 0.0f, 0.0f); glDisableVertexAttribArray(4); } - + // Default texcoord2 vertex attribute (shader-location = 5) if (mesh->texcoords2 != NULL) { @@ -1862,7 +1862,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic) glVertexAttrib2f(5, 0.0f, 0.0f); glDisableVertexAttribArray(5); } - + if (mesh->indices != NULL) { glGenBuffers(1, &vboId[6]); @@ -1900,7 +1900,7 @@ void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) // Activate mesh VAO if (vaoSupported) glBindVertexArray(mesh.vaoId); - + switch (buffer) { case 0: // Update vertices (vertex position) @@ -1908,28 +1908,28 @@ void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex) 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[2]); 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[3]); 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) { @@ -1945,7 +1945,7 @@ void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex) } break; default: break; } - + // Unbind the current VAO if (vaoSupported) glBindVertexArray(0); @@ -1973,11 +1973,11 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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(); @@ -1996,13 +1996,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) if (vrEnabled) eyesCount = 2; glUseProgram(material.shader.id); - + // Upload to shader material.colDiffuse glUniform4f(material.shader.colDiffuseLoc, (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255); - + // Upload to shader material.colAmbient (if available) if (material.shader.colAmbientLoc != -1) glUniform4f(material.shader.colAmbientLoc, (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 (if available) if (material.shader.colSpecularLoc != -1) glUniform4f(material.shader.colSpecularLoc, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255); @@ -2010,7 +2010,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // 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 @@ -2026,7 +2026,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) Matrix transInvTransform = transform; MatrixTranspose(&transInvTransform); MatrixInvert(&transInvTransform); - + // Send model transformations matrix to shader glUniformMatrix4fv(modelMatrixLoc, 1, false, MatrixToFloat(transInvTransform)); } @@ -2039,7 +2039,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) // Check if glossiness is located in shader and upload value int glossinessLoc = glGetUniformLocation(material.shader.id, "glossiness"); if (glossinessLoc != -1) glUniform1f(glossinessLoc, material.glossiness); - } + } // Set shader textures (diffuse, normal, specular) glActiveTexture(GL_TEXTURE0); @@ -2050,22 +2050,22 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) { // Upload to shader specular map flag glUniform1i(glGetUniformLocation(material.shader.id, "useNormal"), 1); - + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, material.texNormal.id); glUniform1i(material.shader.mapTexture1Loc, 1); // Normal texture fits in active texture unit 1 } - + if ((material.texSpecular.id != 0) && (material.shader.mapTexture2Loc != -1)) { // Upload to shader specular map flag glUniform1i(glGetUniformLocation(material.shader.id, "useSpecular"), 1); - + glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, material.texSpecular.id); glUniform1i(material.shader.mapTexture2Loc, 2); // Specular texture fits in active texture unit 2 } - + if (vaoSupported) { glBindVertexArray(mesh.vaoId); @@ -2089,7 +2089,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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) if (material.shader.colorLoc != -1) { @@ -2107,7 +2107,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) glDisableVertexAttribArray(material.shader.colorLoc); } } - + // Bind mesh VBO data: vertex tangents (shader-location = 4, if available) if (material.shader.tangentLoc != -1) { @@ -2115,7 +2115,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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) { @@ -2123,7 +2123,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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]); } @@ -2142,13 +2142,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) 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); @@ -2166,7 +2166,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform) } glUseProgram(0); // Unbind shader program - + // Restore projection/modelview matrices projection = matProjection; modelview = matView; @@ -2212,7 +2212,7 @@ unsigned char *rlglReadScreenPixels(int width, int height) { // Flip line imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; - + // Set alpha component value to 255 (no trasparent image retrieval) // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255; @@ -2230,10 +2230,10 @@ unsigned char *rlglReadScreenPixels(int width, int height) void *rlglReadTexturePixels(Texture2D texture) { void *pixels = NULL; - + #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) glBindTexture(GL_TEXTURE_2D, texture.id); - + // NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0) /* int width, height, format; @@ -2242,11 +2242,11 @@ void *rlglReadTexturePixels(Texture2D texture) glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); // Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE */ - + int glFormat = 0, glType = 0; unsigned int size = texture.width*texture.height; - + // NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1 // Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3 @@ -2255,8 +2255,8 @@ void *rlglReadTexturePixels(Texture2D texture) #if defined(GRAPHICS_API_OPENGL_11) case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break; // 8 bit per pixel (no alpha) case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_LUMINANCE_ALPHA; glType = GL_UNSIGNED_BYTE; break; // 16 bpp (2 channels) -#elif defined(GRAPHICS_API_OPENGL_33) - case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break; +#elif defined(GRAPHICS_API_OPENGL_33) + case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break; case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE; break; #endif case UNCOMPRESSED_R5G6B5: pixels = (unsigned short *)malloc(size); glFormat = GL_RGB; glType = GL_UNSIGNED_SHORT_5_6_5; break; // 16 bpp @@ -2266,15 +2266,15 @@ void *rlglReadTexturePixels(Texture2D texture) case UNCOMPRESSED_R8G8B8A8: pixels = (unsigned char *)malloc(size*4); glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; // 32 bpp default: TraceLog(WARNING, "Texture data retrieval, format not suported"); break; } - + // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding. - // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting. - // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) + // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting. + // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) glPixelStorei(GL_PACK_ALIGNMENT, 1); glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); - + glBindTexture(GL_TEXTURE_2D, 0); #endif @@ -2285,7 +2285,7 @@ void *rlglReadTexturePixels(Texture2D texture) // NOTE: Two possible Options: // 1 - Bind texture to color fbo attachment and glReadPixels() // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() - + #define GET_TEXTURE_FBO_OPTION_1 // It works #if defined(GET_TEXTURE_FBO_OPTION_1) @@ -2295,48 +2295,48 @@ void *rlglReadTexturePixels(Texture2D texture) // Attach our texture to FBO -> Texture must be RGB // NOTE: Previoust attached texture is automatically detached glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0); - + pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char)); - + // NOTE: Despite FBO color texture is RGB, we read data as RGBA... reading as RGB doesn't work... o__O glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - + // Re-attach internal FBO color texture before deleting it glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.texture.id, 0); - + glBindFramebuffer(GL_FRAMEBUFFER, 0); - + #elif defined(GET_TEXTURE_FBO_OPTION_2) // Render texture to fbo glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); - + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepthf(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, width, height); //glMatrixMode(GL_PROJECTION); //glLoadIdentity(); - rlOrtho(0.0, width, height, 0.0, 0.0, 1.0); + rlOrtho(0.0, width, height, 0.0, 0.0, 1.0); //glMatrixMode(GL_MODELVIEW); //glLoadIdentity(); //glDisable(GL_TEXTURE_2D); //glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); - + Model quad; //quad.mesh = GenMeshQuad(width, height); quad.transform = MatrixIdentity(); quad.shader = defaultShader; - + DrawModel(quad, (Vector3){ 0.0f, 0.0f, 0.0f }, 1.0f, WHITE); - + pixels = (unsigned char *)malloc(texture.width*texture.height*3*sizeof(unsigned char)); - + glReadPixels(0, 0, texture.width, texture.height, GL_RGB, GL_UNSIGNED_BYTE, pixels); // Bind framebuffer 0, which means render to back buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); - + UnloadModel(quad); #endif // GET_TEXTURE_FBO_OPTION @@ -2361,7 +2361,7 @@ void rlglRecordDraw(void) draws[drawsCounter].projection = projection; draws[drawsCounter].modelview = modelview; draws[drawsCounter].vertexCount = currentState.vertexCount; - + drawsCounter++; #endif } @@ -2376,13 +2376,13 @@ void rlglRecordDraw(void) Texture2D GetDefaultTexture(void) { Texture2D texture; - + texture.id = whiteTexture; texture.width = 1; texture.height = 1; texture.mipmaps = 1; texture.format = UNCOMPRESSED_R8G8B8A8; - + return texture; } @@ -2429,24 +2429,24 @@ Shader LoadShader(char *vsFileName, char *fsFileName) // Shaders loading from external text file char *vShaderStr = LoadText(vsFileName); char *fShaderStr = LoadText(fsFileName); - + if ((vShaderStr != NULL) && (fShaderStr != NULL)) { shader.id = LoadShaderProgram(vShaderStr, fShaderStr); // After shader loading, we try to load default location names if (shader.id != 0) LoadDefaultShaderLocations(&shader); - + // Shader strings must be freed free(vShaderStr); free(fShaderStr); } - + if (shader.id == 0) { TraceLog(WARNING, "Custom shader could not be loaded"); shader = defaultShader; - } + } #endif return shader; @@ -2497,9 +2497,9 @@ Shader GetDefaultShader(void) int GetShaderLocation(Shader shader, const char *uniformName) { int location = -1; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) location = glGetUniformLocation(shader.id, uniformName); - + if (location == -1) TraceLog(DEBUG, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName); #endif return location; @@ -2516,7 +2516,7 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size) else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3 else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4 else TraceLog(WARNING, "Shader value float array size not supported"); - + //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set #endif } @@ -2532,7 +2532,7 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size) else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3 else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4 else TraceLog(WARNING, "Shader value int array size not supported"); - + //glUseProgram(0); #endif } @@ -2544,7 +2544,7 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat) glUseProgram(shader.id); glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat)); - + //glUseProgram(0); #endif } @@ -2572,7 +2572,7 @@ void BeginBlendMode(int mode) if ((blendMode != mode) && (mode < 3)) { rlglDraw(); - + switch (mode) { case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; @@ -2580,7 +2580,7 @@ void BeginBlendMode(int mode) case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break; default: break; } - + blendMode = mode; } } @@ -2646,9 +2646,9 @@ void InitVrDevice(int vrDevice) { // Oculus Rift CV1 parameters // NOTE: CV1 represents a complete HMD redesign compared to previous versions, - // new Fresnel-hybrid-asymmetric lenses have been added and, consequently, - // previous parameters (DK2) and distortion shader (DK2) doesn't work any more. - // I just defined a set of parameters for simulator that approximate to CV1 stereo rendering + // new Fresnel-hybrid-asymmetric lenses have been added and, consequently, + // previous parameters (DK2) and distortion shader (DK2) doesn't work any more. + // I just defined a set of parameters for simulator that approximate to CV1 stereo rendering // but result is not the same obtained with Oculus PC SDK. hmd.hResolution = 2160; // HMD horizontal resolution in pixels hmd.vResolution = 1200; // HMD vertical resolution in pixels @@ -2667,17 +2667,17 @@ void InitVrDevice(int vrDevice) hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2 hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3 } - + // Initialize framebuffer and textures for stereo rendering // NOTE: screen size should match HMD aspect ratio vrConfig.stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight); - + // Load distortion shader (initialized by default with Oculus Rift CV1 parameters) vrConfig.distortionShader.id = LoadShaderProgram(vDistortionShaderStr, fDistortionShaderStr); if (vrConfig.distortionShader.id != 0) LoadDefaultShaderLocations(&vrConfig.distortionShader); SetStereoConfig(hmd); - + vrSimulator = true; vrEnabled = true; } @@ -2722,9 +2722,9 @@ void ToggleVrMode(void) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) if (vrDeviceReady || vrSimulator) vrEnabled = !vrEnabled; else vrEnabled = false; - + if (!vrEnabled) - { + { // Reset viewport and default projection-modelview matrices rlViewport(0, 0, screenWidth, screenHeight); projection = MatrixOrtho(0, screenWidth, screenHeight, 0, 0.0f, 1.0f); @@ -2759,15 +2759,15 @@ void BeginVrDrawing(void) rlEnableRenderTexture(vrConfig.stereoFbo.id); } - // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) + // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA) // and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then: // - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB // - Do NOT enable GL_FRAMEBUFFER_SRGB //glEnable(GL_FRAMEBUFFER_SRGB); - + //glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye) rlClearScreenBuffers(); // Clear current framebuffer(s) - + vrRendering = true; #endif } @@ -2786,12 +2786,12 @@ void EndVrDrawing(void) { // Unbind current framebuffer rlDisableRenderTexture(); - + rlClearScreenBuffers(); // Clear current framebuffer // Set viewport to default framebuffer size (screen size) rlViewport(0, 0, screenWidth, screenHeight); - + // Let rlgl reconfigure internal matrices rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix rlLoadIdentity(); // Reset internal projection matrix @@ -2799,7 +2799,7 @@ void EndVrDrawing(void) rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix rlLoadIdentity(); // Reset internal modelview matrix - // Draw RenderTexture (stereoFbo) using distortion shader + // Draw RenderTexture (stereoFbo) using distortion shader currentShader = vrConfig.distortionShader; rlEnableTexture(vrConfig.stereoFbo.texture.id); @@ -2836,7 +2836,7 @@ void EndVrDrawing(void) } rlDisableDepthTest(); - + vrRendering = false; #endif } @@ -2867,7 +2867,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in for (int level = 0; level < mipmapCount && (width || height); level++) { unsigned int size = 0; - + size = ((width + 3)/4)*((height + 3)/4)*blockSize; glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset); @@ -2923,7 +2923,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade glGetShaderInfoLog(vertexShader, maxLength, &length, log); TraceLog(INFO, "%s", log); - + #ifdef _MSC_VER free(log); #endif @@ -2962,7 +2962,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); - + // NOTE: Default attribute shader locations must be binded before linking glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME); glBindAttribLocation(program, 1, DEFAULT_ATTRIB_TEXCOORD_NAME); @@ -2970,11 +2970,11 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade glBindAttribLocation(program, 3, DEFAULT_ATTRIB_COLOR_NAME); glBindAttribLocation(program, 4, DEFAULT_ATTRIB_TANGENT_NAME); glBindAttribLocation(program, 5, DEFAULT_ATTRIB_TEXCOORD2_NAME); - + // NOTE: If some attrib name is no found on the shader, it locations becomes -1 - + glLinkProgram(program); - + // NOTE: All uniform variables are intitialised to 0 when a program links glGetProgramiv(program, GL_LINK_STATUS, &success); @@ -2996,7 +2996,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade glGetProgramInfoLog(program, maxLength, &length, log); TraceLog(INFO, "%s", log); - + #ifdef _MSC_VER free(log); #endif @@ -3099,7 +3099,7 @@ static void LoadDefaultShaderLocations(Shader *shader) // vertex color location = 3 // vertex tangent location = 4 // vertex texcoord2 location = 5 - + // Get handles to GLSL input attibute locations shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME); shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME); @@ -3115,15 +3115,15 @@ static void LoadDefaultShaderLocations(Shader *shader) shader->colDiffuseLoc = glGetUniformLocation(shader->id, "colDiffuse"); shader->colAmbientLoc = glGetUniformLocation(shader->id, "colAmbient"); shader->colSpecularLoc = glGetUniformLocation(shader->id, "colSpecular"); - + shader->mapTexture0Loc = glGetUniformLocation(shader->id, "texture0"); shader->mapTexture1Loc = glGetUniformLocation(shader->id, "texture1"); shader->mapTexture2Loc = glGetUniformLocation(shader->id, "texture2"); - + // TODO: Try to find all expected/recognized shader locations (predefined names, must be documented) } -// Unload default shader +// Unload default shader static void UnloadDefaultShader(void) { glUseProgram(0); @@ -3140,7 +3140,7 @@ static void LoadDefaultBuffers(void) { // [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads) //-------------------------------------------------------------------------------------------- - + // Lines - Initialize arrays (vertex position and color data) lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line @@ -3202,11 +3202,11 @@ static void LoadDefaultBuffers(void) TraceLog(INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)"); //-------------------------------------------------------------------------------------------- - + // [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads) // NOTE: Default buffers are linked to use currentShader (defaultShader) //-------------------------------------------------------------------------------------------- - + // Upload and link lines vertex buffers if (vaoSupported) { @@ -3215,7 +3215,7 @@ static void LoadDefaultBuffers(void) glBindVertexArray(lines.vaoId); } - // Lines - Vertex buffers binding and attributes enable + // Lines - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) glGenBuffers(2, &lines.vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]); @@ -3241,7 +3241,7 @@ static void LoadDefaultBuffers(void) glBindVertexArray(triangles.vaoId); } - // Triangles - Vertex buffers binding and attributes enable + // Triangles - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) glGenBuffers(1, &triangles.vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]); @@ -3267,7 +3267,7 @@ static void LoadDefaultBuffers(void) glBindVertexArray(quads.vaoId); } - // Quads - Vertex buffers binding and attributes enable + // Quads - Vertex buffers binding and attributes enable // Vertex position buffer (shader-location = 0) glGenBuffers(1, &quads.vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]); @@ -3383,7 +3383,7 @@ static void DrawDefaultBuffers(int eyesCount) { Matrix matProjection = projection; Matrix matModelView = modelview; - + for (int eye = 0; eye < eyesCount; eye++) { if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView); @@ -3392,17 +3392,17 @@ static void DrawDefaultBuffers(int eyesCount) if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0)) { glUseProgram(currentShader.id); - + // Create modelview-projection matrix Matrix matMVP = MatrixMultiply(modelview, projection); glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP)); glUniform4f(currentShader.colDiffuseLoc, 1.0f, 1.0f, 1.0f, 1.0f); glUniform1i(currentShader.mapTexture0Loc, 0); - + // NOTE: Additional map textures not considered for default buffers drawing } - + // Draw lines buffers if (lines.vCounter > 0) { @@ -3486,7 +3486,7 @@ static void DrawDefaultBuffers(int eyesCount) glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]); glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); glEnableVertexAttribArray(currentShader.colorLoc); - + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]); } @@ -3526,7 +3526,7 @@ static void DrawDefaultBuffers(int eyesCount) glUseProgram(0); // Unbind shader program } - + // Reset draws counter drawsCounter = 1; draws[0].textureId = whiteTexture; @@ -3540,10 +3540,10 @@ static void DrawDefaultBuffers(int eyesCount) quads.vCounter = 0; quads.tcCounter = 0; quads.cCounter = 0; - + // Reset depth for next draw currentDepth = -1.0f; - + // Restore projection/modelview matrices projection = matProjection; modelview = matModelView; @@ -3604,34 +3604,34 @@ static void SetStereoConfig(VrDeviceInfo hmd) float rightLensCenter[2] = { 0.75f - lensShift, 0.5f }; float leftScreenCenter[2] = { 0.25f, 0.5f }; float rightScreenCenter[2] = { 0.75f, 0.5f }; - + // Compute distortion scale parameters // NOTE: To get lens max radius, lensShift must be normalized to [-1..1] float lensRadius = fabsf(-1.0f - 4.0f*lensShift); float lensRadiusSq = lensRadius*lensRadius; - float distortionScale = hmd.distortionK[0] + - hmd.distortionK[1]*lensRadiusSq + - hmd.distortionK[2]*lensRadiusSq*lensRadiusSq + + float distortionScale = hmd.distortionK[0] + + hmd.distortionK[1]*lensRadiusSq + + hmd.distortionK[2]*lensRadiusSq*lensRadiusSq + hmd.distortionK[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq; - + TraceLog(DEBUG, "VR: Distortion Scale: %f", distortionScale); - + float normScreenWidth = 0.5f; float normScreenHeight = 1.0f; float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect }; float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale }; - + TraceLog(DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]); TraceLog(DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]); TraceLog(DEBUG, "VR: Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]); TraceLog(DEBUG, "VR: Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]); - + // Update distortion shader with lens and distortion-scale parameters SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftScreenCenter"), leftScreenCenter, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightScreenCenter"), rightScreenCenter, 2); - + SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scale"), scale, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2); SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.distortionK, 4); @@ -3641,24 +3641,24 @@ static void SetStereoConfig(VrDeviceInfo hmd) // ...but with lens distortion it is increased (see Oculus SDK Documentation) //float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance)*RAD2DEG; // Really need distortionScale? float fovy = 2.0f*(float)atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG; - + // Compute camera projection matrices float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1] Matrix proj = MatrixPerspective(fovy, aspect, 0.01, 1000.0); vrConfig.eyesProjection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f)); vrConfig.eyesProjection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f)); - + // NOTE: Projection matrices must be transposed due to raymath convention MatrixTranspose(&vrConfig.eyesProjection[0]); MatrixTranspose(&vrConfig.eyesProjection[1]); - + // Compute camera transformation matrices - // NOTE: Camera movement might seem more natural if we model the head. - // Our axis of rotation is the base of our head, so we might want to add + // NOTE: Camera movement might seem more natural if we model the head. + // Our axis of rotation is the base of our head, so we might want to add // some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions. vrConfig.eyesViewOffset[0] = MatrixTranslate(-hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f); - + // Compute eyes Viewports //vrConfig.eyesViewport[0] = (Rectangle){ 0, 0, hmd.hResolution/2, hmd.vResolution }; //vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution }; @@ -3675,17 +3675,17 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) #if defined(RLGL_OCULUS_SUPPORT) if (vrDeviceReady) { - rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, + rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y, layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h); - Quaternion eyeRenderPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, - layer.eyeLayer.RenderPose[eye].Orientation.y, - layer.eyeLayer.RenderPose[eye].Orientation.z, + Quaternion eyeRenderPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x, + layer.eyeLayer.RenderPose[eye].Orientation.y, + layer.eyeLayer.RenderPose[eye].Orientation.z, layer.eyeLayer.RenderPose[eye].Orientation.w }; QuaternionInvert(&eyeRenderPose); Matrix eyeOrientation = QuaternionToMatrix(eyeRenderPose); - Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, - -layer.eyeLayer.RenderPose[eye].Position.y, + Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x, + -layer.eyeLayer.RenderPose[eye].Position.y, -layer.eyeLayer.RenderPose[eye].Position.z); Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); // Matrix containing eye-head movement @@ -3701,7 +3701,7 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView) // Apply view offset to modelview matrix eyeModelView = MatrixMultiply(matModelView, vrConfig.eyesViewOffset[eye]); - + eyeProjection = vrConfig.eyesProjection[eye]; } @@ -3845,7 +3845,7 @@ OCULUSAPI bool InitOculusDevice(void) bool oculusReady = false; ovrResult result = ovr_Initialize(NULL); - + if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device"); else { @@ -3865,24 +3865,24 @@ OCULUSAPI bool InitOculusDevice(void) TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type); //TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber); TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h); - + // NOTE: Oculus mirror is set to defined screenWidth and screenHeight... // ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2) - + // Initialize Oculus Buffers - layer = InitOculusLayer(session); + layer = InitOculusLayer(session); buffer = LoadOculusBuffer(session, layer.width, layer.height); mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); // NOTE: hardcoded... layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain); - + // Recenter OVR tracking origin ovr_RecenterTrackingOrigin(session); - + oculusReady = true; vrEnabled = true; } } - + return oculusReady; } @@ -3903,18 +3903,18 @@ OCULUSAPI void UpdateOculusTracking(Camera *camera) ovrPosef eyePoses[2]; ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime); - + layer.eyeLayer.RenderPose[0] = eyePoses[0]; layer.eyeLayer.RenderPose[1] = eyePoses[1]; - + // TODO: Update external camera with eyePoses data (position, orientation) // NOTE: We can simplify to simple camera if we consider IPD and HMD device configuration again later // it will be useful for the user to draw, lets say, billboards oriented to camera - + // Get session status information ovrSessionStatus sessionStatus; ovr_GetSessionStatus(session, &sessionStatus); - + if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit..."); if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session); //if (sessionStatus.HmdPresent) // HMD is present. @@ -3928,7 +3928,7 @@ OCULUSAPI void BeginOculusDrawing(void) { GLuint currentTexId; int currentIndex; - + ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, ¤tIndex); ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, ¤tTexId); @@ -3943,9 +3943,9 @@ OCULUSAPI void EndOculusDrawing(void) // Unbind current framebuffer (Oculus buffer) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - + ovr_CommitTextureSwapChain(session, buffer.textureChain); - + ovrLayerHeader *layers = &layer.eyeLayer.Header; ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1); @@ -3959,7 +3959,7 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) OculusBuffer buffer; buffer.width = width; buffer.height = height; - + // Create OVR texture chain ovrTextureSwapChainDesc desc = {}; desc.Type = ovrTexture_2D; @@ -3972,12 +3972,12 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) desc.StaticImage = ovrFalse; ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain); - + if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer"); int textureCount = 0; ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount); - + if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures"); for (int i = 0; i < textureCount; ++i) @@ -3990,9 +3990,9 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - + glBindTexture(GL_TEXTURE_2D, 0); - + /* // Setup framebuffer object (using depth texture) glGenFramebuffers(1, &buffer.fboId); @@ -4004,7 +4004,7 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); */ - + // Setup framebuffer object (using depth renderbuffer) glGenFramebuffers(1, &buffer.fboId); glGenRenderbuffers(1, &buffer.depthId); @@ -4037,13 +4037,13 @@ static OculusMirror LoadOculusMirror(ovrSession session, int width, int height) OculusMirror mirror; mirror.width = width; mirror.height = height; - + ovrMirrorTextureDesc mirrorDesc; memset(&mirrorDesc, 0, sizeof(mirrorDesc)); mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB; mirrorDesc.Width = mirror.width; mirrorDesc.Height = mirror.height; - + if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture"); glGenFramebuffers(1, &mirror.fboId); @@ -4062,9 +4062,9 @@ static void UnloadOculusMirror(ovrSession session, OculusMirror mirror) static void BlitOculusMirror(ovrSession session, OculusMirror mirror) { GLuint mirrorTextureId; - + ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId); - + glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0); #if defined(GRAPHICS_API_OPENGL_33) @@ -4078,7 +4078,7 @@ static void BlitOculusMirror(ovrSession session, OculusMirror mirror) static OculusLayer InitOculusLayer(ovrSession session) { OculusLayer layer = { 0 }; - + layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov)); @@ -4086,7 +4086,7 @@ static OculusLayer InitOculusLayer(ovrSession session) layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft; ovrEyeRenderDesc eyeRenderDescs[2]; - + for (int eye = 0; eye < 2; eye++) { eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]); @@ -4095,7 +4095,7 @@ static OculusLayer InitOculusLayer(ovrSession session) layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset; layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov; - + ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f); layer.eyeLayer.Viewport[eye].Size = eyeSize; layer.eyeLayer.Viewport[eye].Pos.x = layer.width; @@ -4104,7 +4104,7 @@ static OculusLayer InitOculusLayer(ovrSession session) layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h); layer.width += eyeSize.w; } - + return layer; } @@ -4112,7 +4112,7 @@ static OculusLayer InitOculusLayer(ovrSession session) static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) { Matrix rmat; - + rmat.m0 = ovrmat.M[0][0]; rmat.m1 = ovrmat.M[1][0]; rmat.m2 = ovrmat.M[2][0]; @@ -4129,9 +4129,9 @@ static Matrix FromOvrMatrix(ovrMatrix4f ovrmat) rmat.m13 = ovrmat.M[1][3]; rmat.m14 = ovrmat.M[2][3]; rmat.m15 = ovrmat.M[3][3]; - + MatrixTranspose(&rmat); - + return rmat; } #endif @@ -4162,7 +4162,7 @@ void TraceLog(int msgType, const char *text, ...) } // Converts Matrix to float array -// NOTE: Returned vector is a transposed version of the Matrix struct, +// NOTE: Returned vector is a transposed version of the Matrix struct, // it should be this way because, despite raymath use OpenGL column-major convention, // Matrix struct memory alignment and variables naming are not coherent float *MatrixToFloat(Matrix mat) diff --git a/src/text.c b/src/text.c index 4e163668..e3d22fbd 100644 --- a/src/text.c +++ b/src/text.c @@ -286,17 +286,17 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) { SpriteFont spriteFont = { 0 }; - - if (strcmp(GetExtension(fileName),"ttf") == 0) + + if (strcmp(GetExtension(fileName),"ttf") == 0) { if ((fontChars == NULL) || (numChars == 0)) { int totalChars = 95; // Default charset [32..126] - + int *defaultFontChars = (int *)malloc(totalChars*sizeof(int)); - + for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32] - + spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); } else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars); @@ -353,10 +353,10 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float int textOffsetX = 0; // Offset between characters int textOffsetY = 0; // Required for line break! float scaleFactor; - + unsigned char letter; // Current character int index; // Index position in sprite font - + scaleFactor = fontSize/spriteFont.size; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly @@ -388,10 +388,10 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float } else index = GetCharIndex(spriteFont, (int)text[i]); - DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], + DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, - spriteFont.charRecs[index].width*scaleFactor, + spriteFont.charRecs[index].width*scaleFactor, spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (int)(spriteFont.charRecs[index].width*scaleFactor + spacing); @@ -476,7 +476,7 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i if (text[i] != '\n') { int index = GetCharIndex(spriteFont, (int)text[i]); - + if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); } @@ -517,7 +517,7 @@ static int GetCharIndex(SpriteFont font, int letter) #define UNORDERED_CHARSET #if defined(UNORDERED_CHARSET) int index = 0; - + for (int i = 0; i < font.numChars; i++) { if (font.charValues[i] == letter) @@ -526,7 +526,7 @@ static int GetCharIndex(SpriteFont font, int letter) break; } } - + return index; #else return (letter - 32); @@ -607,14 +607,14 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) } TraceLog(DEBUG, "SpriteFont data parsed correctly from image"); - - // NOTE: We need to remove key color borders from image to avoid weird + + // NOTE: We need to remove key color borders from image to avoid weird // artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; // Create a new image with the processed color data (key color replaced by BLANK) Image fontClear = LoadImageEx(pixels, image.width, image.height); - + free(pixels); // Free pixels array memory // Create spritefont with all data parsed from image @@ -622,7 +622,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture spriteFont.numChars = index; - + UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data @@ -643,7 +643,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) } spriteFont.size = spriteFont.charRecs[0].height; - + TraceLog(INFO, "Image file loaded correctly as SpriteFont"); return spriteFont; @@ -853,13 +853,13 @@ static SpriteFont LoadBMFont(const char *fileName) strncat(texPath, texFileName, strlen(texFileName)); TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath); - + Image imFont = LoadImage(texPath); - - if (imFont.format == UNCOMPRESSED_GRAYSCALE) + + if (imFont.format == UNCOMPRESSED_GRAYSCALE) { Image imCopy = ImageCopy(imFont); - + for (int i = 0; i < imCopy.width*imCopy.height; i++) ((unsigned char *)imCopy.data)[i] = 0xff; // WHITE pixel ImageAlphaMask(&imCopy, imFont); @@ -867,7 +867,7 @@ static SpriteFont LoadBMFont(const char *fileName) UnloadImage(imCopy); } else font.texture = LoadTextureFromImage(imFont); - + font.size = fontSize; font.numChars = numChars; font.charValues = (int *)malloc(numChars*sizeof(int)); @@ -876,7 +876,7 @@ static SpriteFont LoadBMFont(const char *fileName) font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); UnloadImage(imFont); - + free(texPath); int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; @@ -913,11 +913,11 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int // NOTE: Font texture size is predicted (being as much conservative as possible) // Predictive method consist of supposing same number of chars by line-column (sqrtf) // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... - + // Calculate next power-of-two value float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)numChars)); int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT - + TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); @@ -935,7 +935,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int } fread(ttfBuffer, 1, 1 << 25, ttfFile); - + if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character"); // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... @@ -945,7 +945,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); - + free(ttfBuffer); // Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA @@ -966,11 +966,11 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int image.mipmaps = 1; image.format = UNCOMPRESSED_GRAY_ALPHA; image.data = dataGrayAlpha; - + font.texture = LoadTextureFromImage(image); - + //SavePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2); - + UnloadImage(image); // Unloads dataGrayAlpha font.size = fontSize; diff --git a/src/textures.c b/src/textures.c index 3fa250c2..9d865aa1 100644 --- a/src/textures.c +++ b/src/textures.c @@ -144,9 +144,9 @@ Image LoadImage(const char *fileName) else if (strcmp(GetExtension(fileName),"rres") == 0) { RRESData rres = LoadResource(fileName); - + // NOTE: Parameters for RRES_IMAGE type are: width, height, format, mipmaps - + if (rres.type == RRES_IMAGE) image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); else TraceLog(WARNING, "[%s] Resource file does not contain image data", fileName); @@ -197,9 +197,9 @@ Image LoadImagePro(void *data, int width, int height, int format) srcImage.height = height; srcImage.mipmaps = 1; srcImage.format = format; - + Image dstImage = ImageCopy(srcImage); - + return dstImage; } @@ -244,7 +244,7 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int if (bytes < size) { TraceLog(WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName); - + if (image.data != NULL) free(image.data); } else @@ -615,12 +615,12 @@ void ImageAlphaMask(Image *image, Image alphaMask) // Force mask to be Grayscale Image mask = ImageCopy(alphaMask); if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE); - + // In case image is only grayscale, we just add alpha channel if (image->format == UNCOMPRESSED_GRAYSCALE) { ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA); - + // Apply alpha mask to alpha channel for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2) { @@ -955,7 +955,7 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight) void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) { bool cropRequired = false; - + // Security checks to avoid size and rectangle issues (out of bounds) // Check that srcRec is inside src image if (srcRec.x < 0) srcRec.x = 0; @@ -973,15 +973,15 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) TraceLog(WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height); cropRequired = true; } - + Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle - + // Check that dstRec is inside dst image // TODO: Allow negative position within destination with cropping if (dstRec.x < 0) dstRec.x = 0; if (dstRec.y < 0) dstRec.y = 0; - + // Scale source image in case destination rec size is different than source rec size if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height)) { @@ -1001,20 +1001,20 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) TraceLog(WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height); cropRequired = true; } - + if (cropRequired) { // Crop destination rectangle if out of bounds Rectangle crop = { 0, 0, dstRec.width, dstRec.height }; ImageCrop(&srcCopy, crop); } - + // Get image data as Color pixels array to work with it Color *dstPixels = GetImageData(*dst); Color *srcPixels = GetImageData(srcCopy); UnloadImage(srcCopy); // Source copy not required any more... - + Color srcCol, dstCol; // Blit pixels, copy source image into destination @@ -1026,13 +1026,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec) // Alpha blending implementation dstCol = dstPixels[j*dst->width + i]; srcCol = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)]; - + dstCol.r = ((srcCol.a*(srcCol.r - dstCol.r)) >> 8) + dstCol.r; dstCol.g = ((srcCol.a*(srcCol.g - dstCol.g)) >> 8) + dstCol.g; dstCol.b = ((srcCol.a*(srcCol.b - dstCol.b)) >> 8) + dstCol.b; - + dstPixels[j*dst->width + i] = dstCol; - + // TODO: Support other blending options } } @@ -1369,7 +1369,7 @@ void SetTextureFilter(Texture2D texture, int filterMode) { // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps) rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST); - + // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST); } @@ -1387,7 +1387,7 @@ void SetTextureFilter(Texture2D texture, int filterMode) // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps) // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps) rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST); - + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); } @@ -1404,14 +1404,14 @@ void SetTextureFilter(Texture2D texture, int filterMode) { // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps) rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR); - + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); } else { TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id); - + // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR); rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR); @@ -2007,19 +2007,19 @@ static Image LoadPVR(const char *fileName) image.mipmaps = pvrHeader.numMipmaps; // Check data format - if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 0)) && (pvrHeader.channelDepth[0] == 8)) + if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 0)) && (pvrHeader.channelDepth[0] == 8)) image.format = UNCOMPRESSED_GRAYSCALE; - else if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8))) + else if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8))) image.format = UNCOMPRESSED_GRAY_ALPHA; else if ((pvrHeader.channels[0] == 'r') && (pvrHeader.channels[1] == 'g') && (pvrHeader.channels[2] == 'b')) { if (pvrHeader.channels[3] == 'a') { - if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 5) && (pvrHeader.channelDepth[2] == 5) && (pvrHeader.channelDepth[3] == 1)) + if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 5) && (pvrHeader.channelDepth[2] == 5) && (pvrHeader.channelDepth[3] == 1)) image.format = UNCOMPRESSED_R5G5B5A1; - else if ((pvrHeader.channelDepth[0] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4)) + else if ((pvrHeader.channelDepth[0] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4)) image.format = UNCOMPRESSED_R4G4B4A4; - else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8) && (pvrHeader.channelDepth[3] == 8)) + else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8) && (pvrHeader.channelDepth[3] == 8)) image.format = UNCOMPRESSED_R8G8B8A8; } else if (pvrHeader.channels[3] == 0) -- cgit v1.2.3 From 495108a2e9a911c88c090f2ddd82391130701031 Mon Sep 17 00:00:00 2001 From: Ray Date: Sun, 29 Jan 2017 23:08:19 +0100 Subject: Updated raylib version to 1.7 Preparing for next version... still some work left... :P --- src/core.c | 4 ++-- src/raylib.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index ea363fce..4ce32a05 100644 --- a/src/core.c +++ b/src/core.c @@ -330,7 +330,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread // Initialize Window and Graphics Context (OpenGL) void InitWindow(int width, int height, const char *title) { - TraceLog(INFO, "Initializing raylib (v1.6.0)"); + TraceLog(INFO, "Initializing raylib (v1.7.0)"); // Store window title (could be useful...) windowTitle = title; @@ -387,7 +387,7 @@ void InitWindow(int width, int height, const char *title) // Android activity initialization void InitWindow(int width, int height, void *state) { - TraceLog(INFO, "Initializing raylib (v1.6.0)"); + TraceLog(INFO, "Initializing raylib (v1.7.0)"); app_dummy(); diff --git a/src/raylib.h b/src/raylib.h index c1c9ebae..3c84ee72 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,6 +1,6 @@ /********************************************************************************************** * -* raylib 1.6.0 (www.raylib.com) +* raylib 1.7.0 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * -- cgit v1.2.3 From 1a879ba08efe1877c26a76bfabd43f282d2b2a97 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 5 Feb 2017 02:59:39 +0100 Subject: Refactor SpriteFont struct Now it uses CharInfo data, this way, it's better aligned with the future RRES file format data layout for sprite font characters. --- examples/text_bmfont_ttf.c | 8 +- examples/text_bmfont_unordered.c | 6 +- examples/text_font_select.c | 6 +- examples/text_rbmf_fonts.c | 6 +- examples/text_sprite_fonts.c | 18 +-- examples/text_ttf_loading.c | 2 +- src/raylib.h | 20 ++-- src/rlua.h | 8 +- src/text.c | 230 +++++++++++++++++++++------------------ src/textures.c | 4 +- 10 files changed, 164 insertions(+), 144 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/text_bmfont_ttf.c b/examples/text_bmfont_ttf.c index caece548..4d060915 100644 --- a/examples/text_bmfont_ttf.c +++ b/examples/text_bmfont_ttf.c @@ -29,8 +29,8 @@ int main() Vector2 fontPosition; - fontPosition.x = screenWidth/2 - MeasureTextEx(fontBm, msgBm, fontBm.size, 0).x/2; - fontPosition.y = screenHeight/2 - fontBm.size/2 - 80; + fontPosition.x = screenWidth/2 - MeasureTextEx(fontBm, msgBm, fontBm.baseSize, 0).x/2; + fontPosition.y = screenHeight/2 - fontBm.baseSize/2 - 80; SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -49,8 +49,8 @@ int main() ClearBackground(RAYWHITE); - DrawTextEx(fontBm, msgBm, fontPosition, fontBm.size, 0, MAROON); - DrawTextEx(fontTtf, msgTtf, (Vector2){ 75.0f, 240.0f }, fontTtf.size*0.8f, 2, LIME); + DrawTextEx(fontBm, msgBm, fontPosition, fontBm.baseSize, 0, MAROON); + DrawTextEx(fontTtf, msgTtf, (Vector2){ 75.0f, 240.0f }, fontTtf.baseSize*0.8f, 2, LIME); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/text_bmfont_unordered.c b/examples/text_bmfont_unordered.c index b29c5f8b..6fec3256 100644 --- a/examples/text_bmfont_unordered.c +++ b/examples/text_bmfont_unordered.c @@ -45,10 +45,10 @@ int main() ClearBackground(RAYWHITE); DrawText("Font name: PixAntiqua", 40, 50, 20, GRAY); - DrawText(FormatText("Font base size: %i", font.size), 40, 80, 20, GRAY); - DrawText(FormatText("Font chars number: %i", font.numChars), 40, 110, 20, GRAY); + DrawText(FormatText("Font base size: %i", font.baseSize), 40, 80, 20, GRAY); + DrawText(FormatText("Font chars number: %i", font.charsCount), 40, 110, 20, GRAY); - DrawTextEx(font, msg, (Vector2){ 40, 180 }, font.size, 0, MAROON); + DrawTextEx(font, msg, (Vector2){ 40, 180 }, font.baseSize, 0, MAROON); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/text_font_select.c b/examples/text_font_select.c index fe586db8..5891bef7 100644 --- a/examples/text_font_select.c +++ b/examples/text_font_select.c @@ -41,7 +41,7 @@ int main() const char text[50] = "THIS is THE FONT you SELECTED!"; // Main text - Vector2 textSize = MeasureTextEx(fonts[currentFont], text, fonts[currentFont].size*3, 1); + Vector2 textSize = MeasureTextEx(fonts[currentFont], text, fonts[currentFont].baseSize*3, 1); Vector2 mousePoint; @@ -118,7 +118,7 @@ int main() } // Text measurement for better positioning on screen - textSize = MeasureTextEx(fonts[currentFont], text, fonts[currentFont].size*3, 1); + textSize = MeasureTextEx(fonts[currentFont], text, fonts[currentFont].baseSize*3, 1); //---------------------------------------------------------------------------------- // Draw @@ -140,7 +140,7 @@ int main() DrawText("NEXT", 700, positionY + 13, 20, btnNextOutColor); DrawTextEx(fonts[currentFont], text, (Vector2){ screenWidth/2 - textSize.x/2, - 260 + (70 - textSize.y)/2 }, fonts[currentFont].size*3, + 260 + (70 - textSize.y)/2 }, fonts[currentFont].baseSize*3, 1, colors[currentFont]); EndDrawing(); diff --git a/examples/text_rbmf_fonts.c b/examples/text_rbmf_fonts.c index b4bd851b..cd5da1fe 100644 --- a/examples/text_rbmf_fonts.c +++ b/examples/text_rbmf_fonts.c @@ -50,8 +50,8 @@ int main() for (int i = 0; i < 8; i++) { - positions[i].x = screenWidth/2 - MeasureTextEx(fonts[i], messages[i], fonts[i].size*2, spacings[i]).x/2; - positions[i].y = 60 + fonts[i].size + 50*i; + positions[i].x = screenWidth/2 - MeasureTextEx(fonts[i], messages[i], fonts[i].baseSize*2, spacings[i]).x/2; + positions[i].y = 60 + fonts[i].baseSize + 50*i; } Color colors[8] = { MAROON, ORANGE, DARKGREEN, DARKBLUE, DARKPURPLE, LIME, GOLD }; @@ -76,7 +76,7 @@ int main() for (int i = 0; i < 8; i++) { - DrawTextEx(fonts[i], messages[i], positions[i], fonts[i].size*2, spacings[i], colors[i]); + DrawTextEx(fonts[i], messages[i], positions[i], fonts[i].baseSize*2, spacings[i], colors[i]); } EndDrawing(); diff --git a/examples/text_sprite_fonts.c b/examples/text_sprite_fonts.c index c73eda85..bded266e 100644 --- a/examples/text_sprite_fonts.c +++ b/examples/text_sprite_fonts.c @@ -31,14 +31,14 @@ int main() Vector2 fontPosition1, fontPosition2, fontPosition3; - fontPosition1.x = screenWidth/2 - MeasureTextEx(font1, msg1, font1.size, -3).x/2; - fontPosition1.y = screenHeight/2 - font1.size/2 - 80; + fontPosition1.x = screenWidth/2 - MeasureTextEx(font1, msg1, font1.baseSize, -3).x/2; + fontPosition1.y = screenHeight/2 - font1.baseSize/2 - 80; - fontPosition2.x = screenWidth/2 - MeasureTextEx(font2, msg2, font2.size, -2).x/2; - fontPosition2.y = screenHeight/2 - font2.size/2 - 10; + fontPosition2.x = screenWidth/2 - MeasureTextEx(font2, msg2, font2.baseSize, -2).x/2; + fontPosition2.y = screenHeight/2 - font2.baseSize/2 - 10; - fontPosition3.x = screenWidth/2 - MeasureTextEx(font3, msg3, font3.size, 2).x/2; - fontPosition3.y = screenHeight/2 - font3.size/2 + 50; + fontPosition3.x = screenWidth/2 - MeasureTextEx(font3, msg3, font3.baseSize, 2).x/2; + fontPosition3.y = screenHeight/2 - font3.baseSize/2 + 50; //-------------------------------------------------------------------------------------- @@ -56,9 +56,9 @@ int main() ClearBackground(RAYWHITE); - DrawTextEx(font1, msg1, fontPosition1, font1.size, -3, WHITE); - DrawTextEx(font2, msg2, fontPosition2, font2.size, -2, WHITE); - DrawTextEx(font3, msg3, fontPosition3, font3.size, 2, WHITE); + DrawTextEx(font1, msg1, fontPosition1, font1.baseSize, -3, WHITE); + DrawTextEx(font2, msg2, fontPosition2, font2.baseSize, -2, WHITE); + DrawTextEx(font3, msg3, fontPosition3, font3.baseSize, 2, WHITE); EndDrawing(); //---------------------------------------------------------------------------------- diff --git a/examples/text_ttf_loading.c b/examples/text_ttf_loading.c index 918209dd..10025c2f 100644 --- a/examples/text_ttf_loading.c +++ b/examples/text_ttf_loading.c @@ -31,7 +31,7 @@ int main() // NOTE: On 2D drawing it won't be noticeable, it looks like FILTER_BILINEAR GenTextureMipmaps(&font.texture); - float fontSize = font.size; + float fontSize = font.baseSize; Vector2 fontPosition = { 40, screenHeight/2 + 50 }; Vector2 textSize; diff --git a/src/raylib.h b/src/raylib.h index 3c84ee72..f5b908db 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -370,15 +370,21 @@ typedef struct RenderTexture2D { Texture2D depth; // Depth buffer attachment texture } RenderTexture2D; +// SpriteFont character info +typedef struct CharInfo { + int value; // Character value (Unicode) + Rectangle rec; // Character rectangle in sprite font + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X +} CharInfo; + // SpriteFont type, includes texture and charSet array data typedef struct SpriteFont { Texture2D texture; // Font texture - int size; // Base size (default chars height) - int numChars; // Number of characters - int *charValues; // Characters values array - Rectangle *charRecs; // Characters rectangles within the texture - Vector2 *charOffsets; // Characters offsets (on drawing) - int *charAdvanceX; // Characters x advance (on drawing) + int baseSize; // Base size (default chars height) + int charsCount; // Number of characters + CharInfo *chars; // Characters info data } SpriteFont; // Camera type, defines a camera position/orientation in 3d space @@ -825,7 +831,7 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest //------------------------------------------------------------------------------------ RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM) -RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load SpriteFont from TTF font file with generation parameters +RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from TTF font file with generation parameters RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM) RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) diff --git a/src/rlua.h b/src/rlua.h index e9ed2c3c..80dede41 100644 --- a/src/rlua.h +++ b/src/rlua.h @@ -16,7 +16,7 @@ * * The following types: * Image, Texture2D, RenderTexture2D, SpriteFont -* are immutable, and you can only read their non-pointer arguments (e.g. sprfnt.size). +* are immutable, and you can only read their non-pointer arguments (e.g. sprfnt.baseSize). * * All other object types are opaque, that is, you cannot access or * change their fields directly. @@ -293,8 +293,8 @@ static int LuaIndexSpriteFont(lua_State* L) lua_pushinteger(L, img.size); else if (!strcmp(key, "texture")) LuaPush_Texture2D(L, img.texture); - else if (!strcmp(key, "numChars")) - lua_pushinteger(L, img.numChars); + else if (!strcmp(key, "charsCount")) + lua_pushinteger(L, img.charsCount); else return 0; return 1; @@ -2203,7 +2203,7 @@ int lua_LoadSpriteFontTTF(lua_State* L) int arg2 = LuaGetArgument_int(L, 2); int arg3 = LuaGetArgument_int(L, 3); int arg4 = LuaGetArgument_int(L, 4); - //LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); + //LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); SpriteFont result = LoadSpriteFontTTF(arg1, arg2, arg3, &arg4); LuaPush_SpriteFont(L, result); return 1; diff --git a/src/text.c b/src/text.c index e3d22fbd..af07bb69 100644 --- a/src/text.c +++ b/src/text.c @@ -79,7 +79,7 @@ static int GetCharIndex(SpriteFont font, int letter); static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style) static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font) static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data +static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data extern void LoadDefaultFont(void); extern void UnloadDefaultFont(void); @@ -92,7 +92,7 @@ extern void LoadDefaultFont(void) // NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement // http://www.utf8-chartable.de/unicode-utf8-table.pl - defaultFont.numChars = 224; // Number of chars included in our default font + defaultFont.charsCount = 224; // Number of chars included in our default font // Default font is directly defined here (data generated from a sprite font image) // This way, we reconstruct SpriteFont without creating large global variables @@ -189,29 +189,27 @@ extern void LoadDefaultFont(void) defaultFont.texture = LoadTextureFromImage(image); UnloadImage(image); - // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars + // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount //------------------------------------------------------------------------------ - defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int)); - defaultFont.charRecs = (Rectangle *)malloc(defaultFont.numChars*sizeof(Rectangle)); // Allocate space for our character rectangle data - // This memory should be freed at end! --> Done on CloseWindow() - - defaultFont.charOffsets = (Vector2 *)malloc(defaultFont.numChars*sizeof(Vector2)); - defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int)); + + // Allocate space for our characters info data + // NOTE: This memory should be freed at end! --> CloseWindow() + defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; int testPosX = charsDivisor; - for (int i = 0; i < defaultFont.numChars; i++) + for (int i = 0; i < defaultFont.charsCount; i++) { - defaultFont.charValues[i] = 32 + i; // First char is 32 + defaultFont.chars[i].value = 32 + i; // First char is 32 - defaultFont.charRecs[i].x = currentPosX; - defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); - defaultFont.charRecs[i].width = charsWidth[i]; - defaultFont.charRecs[i].height = charsHeight; + defaultFont.chars[i].rec.x = currentPosX; + defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor); + defaultFont.chars[i].rec.width = charsWidth[i]; + defaultFont.chars[i].rec.height = charsHeight; - testPosX += (defaultFont.charRecs[i].width + charsDivisor); + testPosX += (defaultFont.chars[i].rec.width + charsDivisor); if (testPosX >= defaultFont.texture.width) { @@ -219,17 +217,18 @@ extern void LoadDefaultFont(void) currentPosX = 2*charsDivisor + charsWidth[i]; testPosX = currentPosX; - defaultFont.charRecs[i].x = charsDivisor; - defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor); + defaultFont.chars[i].rec.x = charsDivisor; + defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor); } else currentPosX = testPosX; // NOTE: On default font character offsets and xAdvance are not required - defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - defaultFont.charAdvanceX[i] = 0; + defaultFont.chars[i].offsetX = 0; + defaultFont.chars[i].offsetY = 0; + defaultFont.chars[i].advanceX = 0; } - defaultFont.size = defaultFont.charRecs[0].height; + defaultFont.baseSize = defaultFont.chars[0].rec.height; TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id); } @@ -237,10 +236,7 @@ extern void LoadDefaultFont(void) extern void UnloadDefaultFont(void) { UnloadTexture(defaultFont.texture); - free(defaultFont.charValues); - free(defaultFont.charRecs); - free(defaultFont.charOffsets); - free(defaultFont.charAdvanceX); + free(defaultFont.chars); } // Get the default font, useful to be used with extended parameters @@ -260,9 +256,35 @@ SpriteFont LoadSpriteFont(const char *fileName) SpriteFont spriteFont = { 0 }; // Check file extension - if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); + if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); // TODO: DELETE... SOON... else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL); else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName); + else if (strcmp(GetExtension(fileName),"rres") == 0) + { + // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) + RRESData rres = LoadResource(fileName); + + // Load sprite font texture + if (rres.type == RRES_FONT_IMAGE) + { + // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps + Image image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); + spriteFont.texture = LoadTextureFromImage(image); + UnloadImage(image); + } + + // Load sprite characters data + if (rres.type == RRES_FONT_CHARDATA) + { + // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount + spriteFont.baseSize = rres.param1; + spriteFont.charsCount = rres.param2; + spriteFont.chars = rres.data; + } + + // TODO: Do not free rres.data memory (chars info data!) + UnloadResource(rres); + } else { Image image = LoadImage(fileName); @@ -283,13 +305,13 @@ SpriteFont LoadSpriteFont(const char *fileName) // Load SpriteFont from TTF font file with generation parameters // NOTE: You can pass an array with desired characters, those characters should be available in the font // if array is NULL, default char set is selected 32..126 -SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars) +SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) { SpriteFont spriteFont = { 0 }; if (strcmp(GetExtension(fileName),"ttf") == 0) { - if ((fontChars == NULL) || (numChars == 0)) + if ((fontChars == NULL) || (charsCount == 0)) { int totalChars = 95; // Default charset [32..126] @@ -299,7 +321,7 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars); } - else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars); + else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars); } if (spriteFont.texture.id == 0) @@ -318,10 +340,7 @@ void UnloadSpriteFont(SpriteFont spriteFont) if (spriteFont.texture.id != defaultFont.texture.id) { UnloadTexture(spriteFont.texture); - free(spriteFont.charValues); - free(spriteFont.charRecs); - free(spriteFont.charOffsets); - free(spriteFont.charAdvanceX); + free(spriteFont.chars); TraceLog(DEBUG, "Unloaded sprite font data"); } @@ -357,7 +376,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float unsigned char letter; // Current character int index; // Index position in sprite font - scaleFactor = fontSize/spriteFont.size; + scaleFactor = fontSize/spriteFont.baseSize; // NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly // written in C code files (codified by default as UTF-8) @@ -367,7 +386,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float if ((unsigned char)text[i] == '\n') { // NOTE: Fixed line spacing of 1.5 lines - textOffsetY += (int)((spriteFont.size + spriteFont.size/2)*scaleFactor); + textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor); textOffsetX = 0; } else @@ -388,14 +407,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float } else index = GetCharIndex(spriteFont, (int)text[i]); - DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index], - (Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor, - position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor, - spriteFont.charRecs[index].width*scaleFactor, - spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); + DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec, + (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor, + position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor, + spriteFont.chars[index].rec.width*scaleFactor, + spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint); - if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (int)(spriteFont.charRecs[index].width*scaleFactor + spacing); - else textOffsetX += (int)(spriteFont.charAdvanceX[index]*scaleFactor + spacing); + if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing); + else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing); } } } @@ -466,8 +485,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i float textWidth = 0; float tempTextWidth = 0; // Used to count longer text line width - float textHeight = (float)spriteFont.size; - float scaleFactor = fontSize/(float)spriteFont.size; + float textHeight = (float)spriteFont.baseSize; + float scaleFactor = fontSize/(float)spriteFont.baseSize; for (int i = 0; i < len; i++) { @@ -477,15 +496,15 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i { int index = GetCharIndex(spriteFont, (int)text[i]); - if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index]; - else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x); + if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX; + else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX); } else { if (tempTextWidth < textWidth) tempTextWidth = textWidth; lenCounter = 0; textWidth = 0; - textHeight += ((float)spriteFont.size*1.5f); // NOTE: Fixed line spacing of 1.5 lines + textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines } if (tempLen < lenCounter) tempLen = lenCounter; @@ -518,9 +537,9 @@ static int GetCharIndex(SpriteFont font, int letter) #if defined(UNORDERED_CHARSET) int index = 0; - for (int i = 0; i < font.numChars; i++) + for (int i = 0; i < font.charsCount; i++) { - if (font.charValues[i] == letter) + if (font.chars[i].value == letter) { index = i; break; @@ -621,28 +640,26 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar) SpriteFont spriteFont = { 0 }; spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture - spriteFont.numChars = index; + spriteFont.charsCount = index; UnloadImage(fontClear); // Unload processed image once converted to texture // We got tempCharValues and tempCharsRecs populated with chars data // Now we move temp data to sized charValues and charRecs arrays - spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); - spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); - spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2)); - spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int)); + spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); - for (int i = 0; i < spriteFont.numChars; i++) + for (int i = 0; i < spriteFont.charsCount; i++) { - spriteFont.charValues[i] = tempCharValues[i]; - spriteFont.charRecs[i] = tempCharRecs[i]; + spriteFont.chars[i].value = tempCharValues[i]; + spriteFont.chars[i].rec = tempCharRecs[i]; // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - spriteFont.charAdvanceX[i] = 0; + spriteFont.chars[i].offsetX = 0; + spriteFont.chars[i].offsetY = 0; + spriteFont.chars[i].advanceX = 0; } - spriteFont.size = spriteFont.charRecs[0].height; + spriteFont.baseSize = spriteFont.chars[0].rec.height; TraceLog(INFO, "Image file loaded correctly as SpriteFont"); @@ -672,6 +689,8 @@ static SpriteFont LoadRBMF(const char *fileName) SpriteFont spriteFont = { 0 }; + // REMOVE SOON!!! +/* rbmfInfoHeader rbmfHeader; unsigned int *rbmfFileData = NULL; unsigned char *rbmfCharWidthData = NULL; @@ -737,29 +756,27 @@ static SpriteFont LoadRBMF(const char *fileName) //TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName); // Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars - spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int)); - spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle)); - spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2)); - spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int)); + spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo)); int currentLine = 0; int currentPosX = charsDivisor; int testPosX = charsDivisor; - for (int i = 0; i < spriteFont.numChars; i++) + for (int i = 0; i < spriteFont.charsCount; i++) { - spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i; + spriteFont.chars[i].value = (int)rbmfHeader.firstChar + i; - spriteFont.charRecs[i].x = currentPosX; - spriteFont.charRecs[i].y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor); - spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i]; - spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight; + spriteFont.chars[i].rec.x = currentPosX; + spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor); + spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i]; + spriteFont.chars[i].rec.height = (int)rbmfHeader.charHeight; // NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0) - spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f }; - spriteFont.charAdvanceX[i] = 0; + spriteFont.chars[i].offsetX = 0; + spriteFont.chars[i].offsetY = 0; + spriteFont.chars[i].advanceX = 0; - testPosX += (spriteFont.charRecs[i].width + charsDivisor); + testPosX += (spriteFont.chars[i].rec.width + charsDivisor); if (testPosX > spriteFont.texture.width) { @@ -767,13 +784,13 @@ static SpriteFont LoadRBMF(const char *fileName) currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i]; testPosX = currentPosX; - spriteFont.charRecs[i].x = charsDivisor; - spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor); + spriteFont.chars[i].rec.x = charsDivisor; + spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor); } else currentPosX = testPosX; } - spriteFont.size = spriteFont.charRecs[0].height; + spriteFont.baseSize = spriteFont.charRecs[0].height; TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName); } @@ -782,6 +799,7 @@ static SpriteFont LoadRBMF(const char *fileName) free(rbmfFileData); // Now we can free loaded data from RAM memory free(rbmfCharWidthData); +*/ return spriteFont; } @@ -800,7 +818,7 @@ static SpriteFont LoadBMFont(const char *fileName) int fontSize = 0; int texWidth, texHeight; char texFileName[128]; - int numChars = 0; + int charsCount = 0; int base; // Useless data @@ -834,9 +852,9 @@ static SpriteFont LoadBMFont(const char *fileName) fgets(buffer, MAX_BUFFER_SIZE, fntFile); searchPoint = strstr(buffer, "count"); - sscanf(searchPoint, "count=%i", &numChars); + sscanf(searchPoint, "count=%i", &charsCount); - TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars); + TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, charsCount); // Compose correct path using route of .fnt file (fileName) and texFileName char *texPath = NULL; @@ -868,12 +886,9 @@ static SpriteFont LoadBMFont(const char *fileName) } else font.texture = LoadTextureFromImage(imFont); - font.size = fontSize; - font.numChars = numChars; - font.charValues = (int *)malloc(numChars*sizeof(int)); - font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle)); - font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2)); - font.charAdvanceX = (int *)malloc(numChars*sizeof(int)); + font.baseSize = fontSize; + font.charsCount = charsCount; + font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo)); UnloadImage(imFont); @@ -881,17 +896,18 @@ static SpriteFont LoadBMFont(const char *fileName) int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX; - for (int i = 0; i < numChars; i++) + for (int i = 0; i < charsCount; i++) { fgets(buffer, MAX_BUFFER_SIZE, fntFile); sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); // Save data properly in sprite font - font.charValues[i] = charId; - font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight }; - font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY }; - font.charAdvanceX[i] = charAdvanceX; + font.chars[i].value = charId; + font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight }; + font.chars[i].offsetX = charOffsetX; + font.chars[i].offsetY = charOffsetY; + font.chars[i].advanceX = charAdvanceX; } fclose(fntFile); @@ -908,21 +924,21 @@ static SpriteFont LoadBMFont(const char *fileName) // Generate a sprite font from TTF file data (font size required) // TODO: Review texture packing method and generation (use oversampling) -static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars) +static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars) { // NOTE: Font texture size is predicted (being as much conservative as possible) // Predictive method consist of supposing same number of chars by line-column (sqrtf) // and a maximum character width of 3/4 of fontSize... it worked ok with all my tests... // Calculate next power-of-two value - float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)numChars)); + float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount)); int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize); unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25); unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned! - stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars); + stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount); SpriteFont font = { 0 }; @@ -941,7 +957,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int // NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image... // TODO: Replace this function by a proper packing method and support random chars order, // we already receive a list (fontChars) with the ordered expected characters - int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData); + int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, charData); //if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result); if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font"); @@ -973,24 +989,22 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int UnloadImage(image); // Unloads dataGrayAlpha - font.size = fontSize; - font.numChars = numChars; - font.charValues = (int *)malloc(font.numChars*sizeof(int)); - font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle)); - font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2)); - font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int)); + font.baseSize = fontSize; + font.charsCount = charsCount; + font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo)); - for (int i = 0; i < font.numChars; i++) + for (int i = 0; i < font.charsCount; i++) { - font.charValues[i] = fontChars[i]; + font.chars[i].value = fontChars[i]; - font.charRecs[i].x = (int)charData[i].x0; - font.charRecs[i].y = (int)charData[i].y0; - font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0; - font.charRecs[i].height = (int)charData[i].y1 - (int)charData[i].y0; + font.chars[i].rec.x = (int)charData[i].x0; + font.chars[i].rec.y = (int)charData[i].y0; + font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0; + font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0; - font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff }; - font.charAdvanceX[i] = (int)charData[i].xadvance; + font.chars[i].offsetX = charData[i].xoff; + font.chars[i].offsetY = charData[i].yoff; + font.chars[i].advanceX = (int)charData[i].xadvance; } free(charData); diff --git a/src/textures.c b/src/textures.c index 9d865aa1..ce978b6c 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1064,7 +1064,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing int length = strlen(text); int posX = 0; - Vector2 imSize = MeasureTextEx(font, text, font.size, spacing); + Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing); // NOTE: GetTextureData() not available in OpenGL ES Image imFont = GetTextureData(font.texture); @@ -1080,7 +1080,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing for (int i = 0; i < length; i++) { - Rectangle letterRec = font.charRecs[(int)text[i] - 32]; + Rectangle letterRec = font.chars[(int)text[i] - 32].rec; for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++) { -- cgit v1.2.3 From c4bd214cf07c68476c4ce972766c24ee54a982f6 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 5 Feb 2017 03:00:35 +0100 Subject: Added function SetWindowIcon() Only DESKTOP platforms (Windows, Linus, OSX) --- src/core.c | 21 ++++++++++++++++++++- src/raylib.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 4ce32a05..04dd0540 100644 --- a/src/core.c +++ b/src/core.c @@ -524,7 +524,7 @@ bool IsWindowMinimized(void) #endif } -// Fullscreen toggle +// Fullscreen toggle (only PLATFORM_DESKTOP) void ToggleFullscreen(void) { #if defined(PLATFORM_DESKTOP) @@ -540,6 +540,25 @@ void ToggleFullscreen(void) #endif } +// Set icon for window (only PLATFORM_DESKTOP) +void SetWindowIcon(Image image) +{ +#if defined(PLATFORM_DESKTOP) + ImageFormat(&image, UNCOMPRESSED_R8G8B8A8); + + GLFWimage icon[1]; + + icon[0].width = image.width; + icon[0].height = image.height; + icon[0].pixels = (unsigned char *)image.data; + + // NOTE: We only support one image icon + glfwSetWindowIcon(window, 1, icon); + + // TODO: Support multi-image icons --> image.mipmaps +#endif +} + // Get current screen width int GetScreenWidth(void) { diff --git a/src/raylib.h b/src/raylib.h index f5b908db..5a1304fc 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -638,6 +638,7 @@ RLAPI void CloseWindow(void); // Close Windo RLAPI bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) +RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -- cgit v1.2.3 From ac6b4d3830b1ed1a1446ecb57009456306ef008d Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Feb 2017 00:44:54 +0100 Subject: Added audio function: SetMasterVolume() --- src/audio.c | 33 ++++++++++++++++++++++----------- src/raylib.h | 1 + 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 22da74be..e669eceb 100644 --- a/src/audio.c +++ b/src/audio.c @@ -177,9 +177,11 @@ void InitAudioDevice(void) TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER)); // Listener definition (just for 2D) - alListener3f(AL_POSITION, 0, 0, 0); - alListener3f(AL_VELOCITY, 0, 0, 0); - alListener3f(AL_ORIENTATION, 0, 0, -1); + alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f); + alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f); + + alListenerf(AL_GAIN, 1.0f); } } } @@ -216,6 +218,15 @@ bool IsAudioDeviceReady(void) } } +// Set master volume (listener) +void SetMasterVolume(float volume) +{ + if (volume < 0.0f) volume = 0.0f; + else if (volume > 1.0f) volume = 1.0f; + + alListenerf(AL_GAIN, volume); +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Sounds loading and playing (.WAV) //---------------------------------------------------------------------------------- @@ -313,10 +324,10 @@ Sound LoadSoundFromWave(Wave wave) ALuint source; alGenSources(1, &source); // Generate pointer to audio source - alSourcef(source, AL_PITCH, 1); - alSourcef(source, AL_GAIN, 1); - alSource3f(source, AL_POSITION, 0, 0, 0); - alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcef(source, AL_PITCH, 1.0f); + alSourcef(source, AL_GAIN, 1.0f); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); alSourcei(source, AL_LOOPING, AL_FALSE); // Convert loaded data to OpenAL buffer @@ -899,10 +910,10 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un // Create an audio source alGenSources(1, &stream.source); - alSourcef(stream.source, AL_PITCH, 1); - alSourcef(stream.source, AL_GAIN, 1); - alSource3f(stream.source, AL_POSITION, 0, 0, 0); - alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); + alSourcef(stream.source, AL_PITCH, 1.0f); + alSourcef(stream.source, AL_GAIN, 1.0f); + alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); // Create Buffers (double buffering) alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); diff --git a/src/raylib.h b/src/raylib.h index 5a1304fc..85cad6c3 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -947,6 +947,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR experienc RLAPI void InitAudioDevice(void); // Initialize audio device and context RLAPI void CloseAudioDevice(void); // Close the audio device and context RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully +RLAPI void SetMasterVolume(float volume); // Set master volume (listener) RLAPI Wave LoadWave(const char *fileName); // Load wave data from file RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data -- cgit v1.2.3 From f2f05a734d4999ffdc19629c838f46914650bbd0 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Feb 2017 01:03:58 +0100 Subject: Added audio function: SetMusicLoopCount() Useful to set number of repeats for a music, needs to be tested... --- src/audio.c | 27 ++++++++++++++++++++------- src/raylib.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index e669eceb..5a5b008f 100644 --- a/src/audio.c +++ b/src/audio.c @@ -123,7 +123,7 @@ typedef struct MusicData { AudioStream stream; // Audio stream (double buffering) - bool loop; // Repeat music after finish (loop) + int loopCount; // Loops count (times music repeats), -1 means infinite loop unsigned int totalSamples; // Total number of samples unsigned int samplesLeft; // Number of samples left to end } MusicData; @@ -632,7 +632,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg); // Independent by channel music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_OGG; - music->loop = true; // We loop by default + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate); @@ -651,7 +651,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels; music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_AUDIO_FLAC; - music->loop = true; // We loop by default + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate); @@ -665,14 +665,14 @@ Music LoadMusicStream(const char *fileName) if (!result) // XM context created successfully { - jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops + jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops // NOTE: Only stereo is supported for XM music->stream = InitAudioStream(48000, 16, 2); music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm); music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_XM; - music->loop = true; + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples); TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); @@ -689,7 +689,7 @@ Music LoadMusicStream(const char *fileName) music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod); music->samplesLeft = music->totalSamples; music->ctxType = MUSIC_MODULE_MOD; - music->loop = true; + music->loopCount = -1; // Infinite loop by default TraceLog(DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft); TraceLog(DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f); @@ -813,7 +813,13 @@ void UpdateMusicStream(Music music) if (!active) { StopMusicStream(music); // Stop music (and reset) - if (music->loop) PlayMusicStream(music); // Play again + + // Decrease loopCount to stop when required + if (music->loopCount > 0) + { + music->loopCount--; // Decrease loop count + PlayMusicStream(music); // Play again + } } else { @@ -851,6 +857,13 @@ void SetMusicPitch(Music music, float pitch) alSourcef(music->stream.source, AL_PITCH, pitch); } +// Set music loop count (loop repeats) +// NOTE: If set to -1, means infinite loop +void SetMusicLoopCount(Music music, float count); +{ + music->loopCount = count; +} + // Get music time length (in seconds) float GetMusicTimeLength(Music music) { diff --git a/src/raylib.h b/src/raylib.h index 85cad6c3..907ef1e9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -977,6 +977,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume RLAPI bool IsMusicPlaying(Music music); // Check if music is playing RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +RLAPI void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) -- cgit v1.2.3 From b4988777ef60b312632602d7591ab508f0c90ab2 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 9 Feb 2017 22:19:48 +0100 Subject: [audio] Renamed variable --- src/audio.c | 29 +++++++++++++++-------------- src/audio.h | 4 ++-- src/raylib.h | 4 ++-- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index adbe4f4f..720233e0 100644 --- a/src/audio.c +++ b/src/audio.c @@ -374,7 +374,7 @@ void UnloadSound(Sound sound) // Update sound buffer with new data // NOTE: data must match sound.format -void UpdateSound(Sound sound, const void *data, int numSamples) +void UpdateSound(Sound sound, const void *data, int samplesCount) { ALint sampleRate, sampleSize, channels; alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); @@ -385,7 +385,7 @@ void UpdateSound(Sound sound, const void *data, int numSamples) TraceLog(DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize); TraceLog(DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels); - unsigned int dataSize = numSamples*channels*sampleSize/8; // Size of data in bytes + unsigned int dataSize = samplesCount*channels*sampleSize/8; // Size of data in bytes alSourceStop(sound.source); // Stop sound alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update @@ -752,6 +752,7 @@ void StopMusicStream(Music music) } // Update (re-fill) music buffers if data already processed +// TODO: Make sure buffers are ready for update... check music state void UpdateMusicStream(Music music) { ALenum state; @@ -768,13 +769,13 @@ void UpdateMusicStream(Music music) void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.channels*music->stream.sampleSize/8, 1); int numBuffersToProcess = processed; - int numSamples = 0; // Total size of data steamed in L+R samples for xm floats, - // individual L or R for ogg shorts + int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats, + //individual L or R for ogg shorts for (int i = 0; i < numBuffersToProcess; i++) { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE; - else numSamples = music->samplesLeft; + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE; + else samplesCount = music->samplesLeft; // TODO: Really don't like ctxType thingy... switch (music->ctxType) @@ -782,22 +783,22 @@ void UpdateMusicStream(Music music) case MUSIC_AUDIO_OGG: { // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) - int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, numSamples*music->stream.channels); + int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels); } break; case MUSIC_AUDIO_FLAC: { // NOTE: Returns the number of samples to process - unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, numSamples*music->stream.channels, (short *)pcm); + unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm); } break; - case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, numSamples); break; - case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); break; + case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break; + case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break; default: break; } - UpdateAudioStream(music->stream, pcm, numSamples); - music->samplesLeft -= numSamples; + UpdateAudioStream(music->stream, pcm, samplesCount); + music->samplesLeft -= samplesCount; if (music->samplesLeft <= 0) { @@ -976,7 +977,7 @@ void CloseAudioStream(AudioStream stream) // Update audio stream buffers with data // NOTE: Only updates one buffer per call -void UpdateAudioStream(AudioStream stream, const void *data, int numSamples) +void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount) { ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); @@ -984,7 +985,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int numSamples) // Check if any buffer was available for unqueue if (alGetError() != AL_INVALID_VALUE) { - alBufferData(buffer, stream.format, data, numSamples*stream.channels*stream.sampleSize/8, stream.sampleRate); + alBufferData(buffer, stream.format, data, samplesCount*stream.channels*stream.sampleSize/8, stream.sampleRate); alSourceQueueBuffers(stream.source, 1, &buffer); } } diff --git a/src/audio.h b/src/audio.h index 05ba1a1d..99b58e15 100644 --- a/src/audio.h +++ b/src/audio.h @@ -115,7 +115,7 @@ Wave LoadWave(const char *fileName); // Load wave dat Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data Sound LoadSound(const char *fileName); // Load sound from file Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data +void UpdateSound(Sound sound, const void *data, int samplesCount); // Update sound buffer with new data void UnloadWave(Wave wave); // Unload wave data void UnloadSound(Sound sound); // Unload sound void PlaySound(Sound sound); // Play a sound @@ -146,7 +146,7 @@ float GetMusicTimePlayed(Music music); // Get current m AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) -void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +void UpdateAudioStream(AudioStream stream, void *data, int samplesCount); // Update audio stream buffers with data void CloseAudioStream(AudioStream stream); // Close audio stream and free memory bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill void PlayAudioStream(AudioStream stream); // Play audio stream diff --git a/src/raylib.h b/src/raylib.h index 907ef1e9..a5849180 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -953,7 +953,7 @@ RLAPI Wave LoadWave(const char *fileName); // Load wa RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data RLAPI Sound LoadSound(const char *fileName); // Load sound from file RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -RLAPI void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data +RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound RLAPI void PlaySound(Sound sound); // Play a sound @@ -984,7 +984,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Init audio stream (to stream raw audio pcm data) -RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int numSamples); // Update audio stream buffers with data +RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream -- cgit v1.2.3 From 05f039f85fb43f9ae4598747a4d9c6770ec5774b Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sat, 11 Feb 2017 23:34:41 +0100 Subject: Corrected issue with OpenAL being 'keg only' on OSX Also reviewed issue with stdbool when compiling with clang --- examples/Makefile | 2 +- src/audio.c | 13 +++++++++---- src/external/jar_mod.h | 3 +-- src/raylib.h | 10 +++------- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/raylib.h') diff --git a/examples/Makefile b/examples/Makefile index 80437590..bef0fa11 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -153,7 +153,7 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP) # libraries for OS X 10.9 desktop compiling # requires the following packages: # libglfw3-dev libopenal-dev libegl1-mesa-dev - LIBS = -lraylib -lglfw3 -framework OpenGL -framework OpenAl -framework Cocoa + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAL -framework Cocoa else # libraries for Windows desktop compiling # NOTE: GLFW3 and OpenAL Soft libraries should be installed diff --git a/src/audio.c b/src/audio.c index eb5e65d6..58699035 100644 --- a/src/audio.c +++ b/src/audio.c @@ -59,9 +59,14 @@ #include "utils.h" // Required for: fopen() Android mapping, TraceLog() #endif -#include "AL/al.h" // OpenAL basic header -#include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) -//#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS +#ifdef __APPLE__ + #include "OpenAL/al.h" // OpenAL basic header + #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) +#else + #include "AL/al.h" // OpenAL basic header + #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work) + //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS +#endif // OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples // OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1) @@ -1252,4 +1257,4 @@ void TraceLog(int msgType, const char *text, ...) if (msgType == ERROR) exit(1); // If ERROR message, exit program } -#endif \ No newline at end of file +#endif diff --git a/src/external/jar_mod.h b/src/external/jar_mod.h index bee9f6ee..c17130a6 100644 --- a/src/external/jar_mod.h +++ b/src/external/jar_mod.h @@ -83,8 +83,7 @@ #include #include -#include - +//#include #ifdef __cplusplus diff --git a/src/raylib.h b/src/raylib.h index a5849180..800ab2be 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -296,13 +296,9 @@ //---------------------------------------------------------------------------------- #ifndef __cplusplus // Boolean type - #ifndef __APPLE__ - #if !defined(_STDBOOL_H) - typedef enum { false, true } bool; - #define _STDBOOL_H - #endif - #else - #include + #if !defined(_STDBOOL_H) + typedef enum { false, true } bool; + #define _STDBOOL_H #endif #endif -- cgit v1.2.3 From 05cff44d0a9af5bcb41ddd0baa6b7693f6ac116b Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Feb 2017 00:50:02 +0100 Subject: Improved modules description -IN PROGRESS- Working in modules configuration flags... --- src/audio.c | 56 +++++++++++++++++++++++++++++++++++++------------------- src/audio.h | 4 +++- src/camera.h | 14 +++++++++++--- src/core.c | 55 +++++++++++++++++++++++++++++++++++++------------------ src/gestures.h | 17 +++++++++++++---- src/models.c | 13 +++++++------ src/physac.h | 15 +++++++++------ src/raylib.h | 44 +++++++++++++++++++++++++++----------------- src/raymath.h | 25 +++++++++++++------------ src/rlgl.c | 46 ++++++++++++++++++++++++++++++++++++---------- src/rres.h | 18 +++++++++++------- src/shapes.c | 11 ++++------- src/text.c | 36 +++++++++++++++++++++--------------- src/textures.c | 35 +++++++++++++++++++++++++++-------- src/utils.c | 19 +++++++++++++------ 15 files changed, 269 insertions(+), 139 deletions(-) (limited to 'src/raylib.h') diff --git a/src/audio.c b/src/audio.c index 58699035..690a41eb 100644 --- a/src/audio.c +++ b/src/audio.c @@ -3,32 +3,50 @@ * raylib.audio * * This module provides basic functionality to work with audio: -* Manage audio device (init/close) -* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) -* Play/Stop/Pause/Resume loaded audio -* Manage mixing channels -* Manage raw audio context +* Manage audio device (init/close) +* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD) +* Play/Stop/Pause/Resume loaded audio +* Manage mixing channels +* Manage raw audio context * -* External libs: +* NOTES: +* +* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS) +* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) +* +* CONFIGURATION: +* +* #define AUDIO_STANDALONE +* If defined, the module can be used as standalone library (independently of raylib). +* Required types and functions are defined in the same module. +* +* #define SUPPORT_FILEFORMAT_WAV / SUPPORT_LOAD_WAV / ENABLE_LOAD_WAV +* #define SUPPORT_FILEFORMAT_OGG +* #define SUPPORT_FILEFORMAT_XM +* #define SUPPORT_FILEFORMAT_MOD +* #define SUPPORT_FILEFORMAT_FLAC +* Selected desired fileformats to be supported for loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module +* +* #define SUPPORT_RAW_AUDIO_BUFFERS +* +* DEPENDENCIES: * OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) * jar_xm - XM module file loading * jar_mod - MOD audio file loading * dr_flac - FLAC audio file loading * -* Module Configuration Flags: -* AUDIO_STANDALONE - Use this module as standalone library (independently of raylib) -* -* Some design decisions: -* Support only up to two channels: MONO and STEREO (for additional channels, AL_EXT_MCFORMATS) -* Support only the following sample sizes: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32) +* CONTRIBUTORS: * * Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions: -* XM audio module support (jar_xm) -* MOD audio module support (jar_mod) -* Mixing channels support -* Raw audio context support +* XM audio module support (jar_xm) +* MOD audio module support (jar_mod) +* Mixing channels support +* Raw audio context support +* * +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * @@ -246,11 +264,11 @@ Wave LoadWave(const char *fileName) else if (strcmp(GetExtension(fileName), "flac") == 0) wave = LoadFLAC(fileName); else if (strcmp(GetExtension(fileName),"rres") == 0) { - RRESData rres = LoadResource(fileName); + RRES rres = LoadResource(fileName, 0); - // NOTE: Parameters for RRES_WAVE type are: sampleCount, sampleRate, sampleSize, channels + // NOTE: Parameters for RRES_TYPE_WAVE are: sampleCount, sampleRate, sampleSize, channels - if (rres.type == RRES_WAVE) wave = LoadWaveEx(rres.data, rres.param1, rres.param2, rres.param3, rres.param4); + if (rres[0].type == RRES_TYPE_WAVE) wave = LoadWaveEx(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3, rres[0].param4); else TraceLog(WARNING, "[%s] Resource file does not contain wave data", fileName); UnloadResource(rres); diff --git a/src/audio.h b/src/audio.h index 99b58e15..01ed9f72 100644 --- a/src/audio.h +++ b/src/audio.h @@ -9,7 +9,7 @@ * Manage mixing channels * Manage raw audio context * -* External libs: +* DEPENDENCIES: * OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html) * stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/) * jar_xm - XM module file loading @@ -23,6 +23,8 @@ * Raw audio context support * * +* LICENSE: zlib/libpng +* * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event diff --git a/src/camera.h b/src/camera.h index cf542288..87ba1942 100644 --- a/src/camera.h +++ b/src/camera.h @@ -2,6 +2,10 @@ * * raylib Camera System - Camera Modes Setup and Control Functions * +* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) +* +* CONFIGURATION: +* * #define CAMERA_IMPLEMENTATION * Generates the implementation of the library into the included file. * If not defined, the library is in header only mode and can be included in other headers @@ -11,10 +15,14 @@ * If defined, the library can be used as standalone as a camera system but some * functions must be redefined to manage inputs accordingly. * -* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) +* CONTRIBUTORS: +* Marc Palau: Initial implementation (2014) +* Ramon Santamaria: Supervision, review, update and maintenance +* +* +* LICENSE: zlib/libpng * -* Initial design by Marc Palau (2014) -* Reviewed by Ramon Santamaria (2015-2016) +* Copyright (c) 2015-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/core.c b/src/core.c index 28f73345..9d40edcc 100644 --- a/src/core.c +++ b/src/core.c @@ -1,27 +1,46 @@ /********************************************************************************************** * -* raylib.core -* -* Basic functions to manage windows, OpenGL context and input on multiple platforms +* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms * * The following platforms are supported: Windows, Linux, Mac (OSX), Android, Raspberry Pi, HTML5, Oculus Rift CV1 * -* External libs: +* CONFIGURATION: +* +* #define PLATFORM_DESKTOP +* Windowing and input system configured for desktop platforms: Windows, Linux, OSX (managed by GLFW3 library) +* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [rlgl] module to enable it +* +* #define PLATFORM_ANDROID +* Windowing and input system configured for Android device, app activity managed internally in this module. +* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL +* +* #define PLATFORM_RPI +* Windowing and input system configured for Raspberry Pi (tested on Raspbian), graphic device is managed by EGL +* and inputs are processed is raw mode, reading from /dev/input/ +* +* #define PLATFORM_WEB +* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js +* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code. +* +* #define LOAD_DEFAULT_FONT (defined by default) +* Default font is loaded on window initialization to be available for the user to render simple text. +* NOTE: If enabled, uses external module functions to load default raylib font (module: text) +* +* #define INCLUDE_CAMERA_SYSTEM / SUPPORT_CAMERA_SYSTEM +* +* #define INCLUDE_GESTURES_SYSTEM / SUPPORT_GESTURES_SYSTEM +* +* #define SUPPORT_MOUSE_GESTURES +* Mouse gestures are directly mapped like touches and processed by gestures system. +* +* DEPENDENCIES: * GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX) * raymath - 3D math functionality (Vector3, Matrix, Quaternion) * camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person) * gestures - Gestures system for touch-ready devices (or simulated from mouse inputs) * -* Module Configuration Flags: -* PLATFORM_DESKTOP - Windows, Linux, Mac (OSX) -* PLATFORM_ANDROID - Android (only OpenGL ES 2.0 devices), graphic device is managed by EGL and input system by Android activity. -* PLATFORM_RPI - Rapsberry Pi (tested on Raspbian), graphic device is managed by EGL and input system is coded in raw mode. -* PLATFORM_WEB - HTML5 (using emscripten compiler) -* -* RL_LOAD_DEFAULT_FONT - Use external module functions to load default raylib font (module: text) -* -* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for render mirror - View [rlgl] module to enable it * +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * @@ -140,7 +159,7 @@ #define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) #define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) -#define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) +#define LOAD_DEFAULT_FONT // Load default font on window initialization (module: text) //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -256,7 +275,7 @@ static bool showLogo = false; // Track if showing logo at init is //---------------------------------------------------------------------------------- // Other Modules Functions Declaration (required by core) //---------------------------------------------------------------------------------- -#if defined(RL_LOAD_DEFAULT_FONT) +#if defined(LOAD_DEFAULT_FONT) extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow() extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory #endif @@ -338,7 +357,7 @@ void InitWindow(int width, int height, const char *title) // Init graphics device (display device and OpenGL context) InitGraphicsDevice(width, height); -#if defined(RL_LOAD_DEFAULT_FONT) +#if defined(LOAD_DEFAULT_FONT) // Load default font // NOTE: External function (defined in module: text) LoadDefaultFont(); @@ -450,7 +469,7 @@ void InitWindow(int width, int height, void *state) // Close Window and Terminate Context void CloseWindow(void) { -#if defined(RL_LOAD_DEFAULT_FONT) +#if defined(LOAD_DEFAULT_FONT) UnloadDefaultFont(); #endif @@ -2410,7 +2429,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd) // Init graphics device (display device and OpenGL context) InitGraphicsDevice(screenWidth, screenHeight); - #if defined(RL_LOAD_DEFAULT_FONT) + #if defined(LOAD_DEFAULT_FONT) // Load default font // NOTE: External function (defined in module: text) LoadDefaultFont(); diff --git a/src/gestures.h b/src/gestures.h index f4dcb133..99f49d2a 100644 --- a/src/gestures.h +++ b/src/gestures.h @@ -2,6 +2,10 @@ * * raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse) * +* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables) +* +* CONFIGURATION: +* * #define GESTURES_IMPLEMENTATION * Generates the implementation of the library into the included file. * If not defined, the library is in header only mode and can be included in other headers @@ -11,11 +15,16 @@ * If defined, the library can be used as standalone to process gesture events with * no external dependencies. * -* NOTE: Memory footprint of this library is aproximately 128 bytes +* CONTRIBUTORS: +* Marc Palau: Initial implementation (2014) +* Albert Martos: Complete redesign and testing (2015) +* Ian Eito: Complete redesign and testing (2015) +* Ramon Santamaria: Supervision, review, update and maintenance +* +* +* LICENSE: zlib/libpng * -* Initial design by Marc Palau (2014) -* Redesigned by Albert Martos and Ian Eito (2015) -* Reviewed by Ramon Santamaria (2015-2016) +* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. diff --git a/src/models.c b/src/models.c index 43821691..bef19e10 100644 --- a/src/models.c +++ b/src/models.c @@ -1,14 +1,15 @@ /********************************************************************************************** * -* raylib.models +* raylib.models - Basic functions to draw 3d shapes and 3d models * -* Basic functions to draw 3d shapes and load/draw 3d models (.OBJ) +* CONFIGURATION: * -* External libs: -* rlgl - raylib OpenGL abstraction layer +* #define SUPPORT_FILEFORMAT_OBJ / SUPPORT_LOAD_OBJ * -* Module Configuration Flags: -* ... +* #define SUPPORT_FILEFORMAT_MTL +* +* +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * diff --git a/src/physac.h b/src/physac.h index d958c701..cb0e3f3c 100644 --- a/src/physac.h +++ b/src/physac.h @@ -1,11 +1,13 @@ /********************************************************************************************** * -* Physac - 2D Physics library for videogames +* Physac v1.0 - 2D Physics library for videogames * -* Description: Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop -* to simluate physics. A physics step contains the following phases: get collision information, apply dynamics, -* collision solving and position correction. It uses a very simple struct for physic bodies with a position vector -* to be used in any 3D rendering API. +* DESCRIPTION: +* +* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop +* to simluate physics. A physics step contains the following phases: get collision information, +* apply dynamics, collision solving and position correction. It uses a very simple struct for physic +* bodies with a position vector to be used in any 3D rendering API. * * CONFIGURATION: * @@ -37,7 +39,8 @@ * Otherwise it will include stdlib.h and use the C standard library malloc()/free() function. * * VERY THANKS TO: -* - Ramón Santamaria (@raysan5) +* Ramón Santamaria (@raysan5) +* * * LICENSE: zlib/libpng * diff --git a/src/raylib.h b/src/raylib.h index 800ab2be..3ff0d28f 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,10 +1,10 @@ /********************************************************************************************** * -* raylib 1.7.0 (www.raylib.com) +* raylib v1.7.0 (www.raylib.com) * * A simple and easy-to-use library to learn videogames programming * -* Features: +* FEATURES: * Library written in plain C code (C99) * Uses PascalCase/camelCase notation * Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0) @@ -20,7 +20,13 @@ * Minimal external dependencies (GLFW3, OpenGL, OpenAL) * Complete binding for Lua [rlua] * -* External libs: +* NOTES: +* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) +* One custom default font could be loaded automatically when InitWindow() [core] +* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads +* If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined) +* +* DEPENDENCIES: * GLFW3 (www.glfw.org) for window/context management and input [core] * GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl] * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures] @@ -33,13 +39,8 @@ * OpenAL Soft for audio device/context management [audio] * tinfl for data decompression (DEFLATE algorithm) [utils] * -* Some design decisions: -* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte) -* One custom default font could be loaded automatically when InitWindow() [core] -* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads -* If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined) * -* -- LICENSE -- +* LICENSE: zlib/libpng * * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * BSD-like license that allows static linking with closed source software: @@ -592,8 +593,9 @@ typedef enum { HMD_FOVE_VR, } VrDevice; -// rRES data returned when reading a resource, it contains all required data for user (24 byte) -typedef struct { +// rRES data returned when reading a resource, +// it contains all required data for user (24 byte) +typedef struct RRESData { unsigned int type; // Resource type (4 byte) unsigned int param1; // Resouce parameter 1 (4 byte) @@ -604,14 +606,21 @@ typedef struct { void *data; // Resource data pointer (4 byte) } RRESData; -typedef enum { - RRES_RAW = 0, - RRES_IMAGE, - RRES_WAVE, - RRES_VERTEX, - RRES_TEXT +// RRESData type +typedef enum { + RRES_TYPE_RAW = 0, + RRES_TYPE_IMAGE, + RRES_TYPE_WAVE, + RRES_TYPE_VERTEX, + RRES_TYPE_TEXT, + RRES_TYPE_FONT_IMAGE, + RRES_TYPE_FONT_CHARDATA, // CharInfo data array + RRES_TYPE_DIRECTORY } RRESDataType; +// RRES type (pointer to RRESData array) +typedef struct RRESData *RRES; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -758,6 +767,7 @@ RLAPI void DrawCircleV(Vector2 center, float radius, Color color); RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters RLAPI void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2); // Draw a gradient-filled rectangle RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline diff --git a/src/raymath.h b/src/raymath.h index c073b72d..a2263f19 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -1,22 +1,23 @@ /********************************************************************************************** * -* raymath (header only file) +* raymath v1.0 - Some useful functions to work with Vector3, Matrix and Quaternions * -* Some useful functions to work with Vector3, Matrix and Quaternions +* CONFIGURATION: * -* You must: -* #define RAYMATH_IMPLEMENTATION -* before you include this file in *only one* C or C++ file to create the implementation. +* #define RAYMATH_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. * -* Example: -* #define RAYMATH_IMPLEMENTATION -* #include "raymath.h" +* #define RAYMATH_EXTERN_INLINE +* Inlines all functions code, so it runs faster. This requires lots of memory on system. +* +* #define RAYMATH_STANDALONE +* Avoid raylib.h header inclusion in this file. +* Vector3 and Matrix data types are defined internally in raymath module. * -* You can also use: -* #define RAYMATH_EXTERN_INLINE // Inlines all functions code, so it runs faster. -* // This requires lots of memory on system. -* #define RAYMATH_STANDALONE // Not dependent on raylib.h structs: Vector3, Matrix. * +* LICENSE: zlib/libpng * * Copyright (c) 2015 Ramon Santamaria (@raysan5) * diff --git a/src/rlgl.c b/src/rlgl.c index ce17adc3..ffc9d741 100644 --- a/src/rlgl.c +++ b/src/rlgl.c @@ -2,6 +2,8 @@ * * rlgl - raylib OpenGL abstraction layer * +* DESCRIPTION: +* * rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to * selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0). * @@ -11,20 +13,44 @@ * rlglDraw() - Process internal buffers and send required draw calls * rlglClose() - De-initialize internal buffers data and other auxiliar resources * -* External libs: +* CONFIGURATION: +* +* #define GRAPHICS_API_OPENGL_11 +* Use OpenGL 1.1 backend +* +* #define GRAPHICS_API_OPENGL_21 +* Use OpenGL 2.1 backend +* +* #define GRAPHICS_API_OPENGL_33 +* Use OpenGL 3.3 Core profile backend +* +* #define GRAPHICS_API_OPENGL_ES2 +* Use OpenGL ES 2.0 backend +* +* #define RLGL_STANDALONE +* Use rlgl as standalone library (no raylib dependency) +* +* #define RLGL_NO_DISTORTION_SHADER +* Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion +* +* #define SUPPORT_SHADER_DEFAULT / ENABLE_SHADER_DEFAULT +* +* #define SUPPORT_SHADER_DISTORTION +* +* +* #define SUPPORT_OCULUS_RIFT_CV1 / RLGL_OCULUS_SUPPORT +* Enable Oculus Rift CV1 functionality +* +* #define SUPPORT_STEREO_RENDERING +* +* #define RLGL_NO_DEFAULT_SHADER +* +* DEPENDENCIES: * raymath - 3D math functionality (Vector3, Matrix, Quaternion) * GLAD - OpenGL extensions loading (OpenGL 3.3 Core only) * -* Module Configuration Flags: -* GRAPHICS_API_OPENGL_11 - Use OpenGL 1.1 backend -* GRAPHICS_API_OPENGL_21 - Use OpenGL 2.1 backend -* GRAPHICS_API_OPENGL_33 - Use OpenGL 3.3 Core profile backend -* GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend -* -* RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency) -* RLGL_NO_DISTORTION_SHADER - Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion -* RLGL_OCULUS_SUPPORT - Enable Oculus Rift CV1 functionality * +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * diff --git a/src/rres.h b/src/rres.h index bed28723..362da10d 100644 --- a/src/rres.h +++ b/src/rres.h @@ -4,14 +4,18 @@ * * Basic functions to load/save rRES resource files * -* External libs: -* tinfl - DEFLATE decompression functions +* CONFIGURATION: +* +* #define RREM_IMPLEMENTATION +* Generates the implementation of the library into the included file. +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation. * -* Module Configuration Flags: +* DEPENDENCIES: +* tinfl - DEFLATE decompression functions * -* #define RREM_IMPLEMENTATION -* Generates the implementation of the library into the included file. * +* LICENSE: zlib/libpng * * Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) * @@ -81,7 +85,7 @@ RRES_TYPE_VERTEX, RRES_TYPE_TEXT, RRES_TYPE_FONT_IMAGE, - RRES_TYPE_FONT_DATA, // Character { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance } + RRES_TYPE_FONT_CHARDATA, // Character { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance } RRES_TYPE_DIRECTORY } RRESDataType; @@ -243,7 +247,7 @@ static void *DecompressData(const unsigned char *data, unsigned long compSize, i // NOTE: Returns uncompressed data with parameters, search resource by id RRESDEF RRES LoadResource(const char *fileName, int rresId) { - RRES rres; + RRES rres = { 0 }; RRESFileHeader fileHeader; RRESInfoHeader infoHeader; diff --git a/src/shapes.c b/src/shapes.c index 83b80182..a42b0551 100644 --- a/src/shapes.c +++ b/src/shapes.c @@ -1,17 +1,14 @@ /********************************************************************************************** * -* raylib.shapes -* -* Basic functions to draw 2d Shapes and check collisions -* -* DEPENDENCIES: -* rlgl - raylib OpenGL abstraction layer +* raylib.shapes - Basic functions to draw 2d Shapes and check collisions * * CONFIGURATION: * * #define SUPPORT_QUADS_ONLY +* Draw shapes using only QUADS, vertex are accumulated in QUADS arrays (like textures) * - #define SUPPORT_TRIANGLES_ONLY +* #define SUPPORT_TRIANGLES_ONLY +* Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays * * * LICENSE: zlib/libpng diff --git a/src/text.c b/src/text.c index 4deae25c..6f18b391 100644 --- a/src/text.c +++ b/src/text.c @@ -1,14 +1,22 @@ /********************************************************************************************** * -* raylib.text +* raylib.text - Basic functions to load SpriteFonts and draw Text * -* Basic functions to load SpriteFonts and draw Text +* CONFIGURATION: * -* External libs: +* #define SUPPORT_FILEFORMAT_FNT +* #define SUPPORT_FILEFORMAT_TTF / INCLUDE_STB_TRUETYPE +* #define SUPPORT_FILEFORMAT_IMAGE_FONT +* Selected desired fileformats to be supported for loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module +* +* #define INCLUDE_DEFAULT_FONT / SUPPORT_DEFAULT_FONT +* +* DEPENDENCIES: * stb_truetype - Load TTF file and rasterize characters data * -* Module Configuration Flags: -* ... +* +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * @@ -262,30 +270,28 @@ SpriteFont LoadSpriteFont(const char *fileName) else if (strcmp(GetExtension(fileName),"rres") == 0) { // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA) - RRESData rres = LoadResource(fileName); + RRES rres = LoadResource(fileName, 0); // Load sprite font texture - /* - if (rres.type == RRES_FONT_IMAGE) + if (rres[0].type == RRES_TYPE_FONT_IMAGE) { // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps - Image image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); + Image image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3); spriteFont.texture = LoadTextureFromImage(image); UnloadImage(image); } // Load sprite characters data - if (rres.type == RRES_FONT_CHARDATA) + if (rres[1].type == RRES_TYPE_FONT_CHARDATA) { // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount - spriteFont.baseSize = rres.param1; - spriteFont.charsCount = rres.param2; - spriteFont.chars = rres.data; + spriteFont.baseSize = rres[1].param1; + spriteFont.charsCount = rres[1].param2; + spriteFont.chars = rres[1].data; } - */ // TODO: Do not free rres.data memory (chars info data!) - UnloadResource(rres); + //UnloadResource(rres[0]); } else { diff --git a/src/textures.c b/src/textures.c index 5b2e4775..7db3bf56 100644 --- a/src/textures.c +++ b/src/textures.c @@ -1,16 +1,35 @@ /********************************************************************************************** * -* raylib.textures +* raylib.textures - Basic functions to load and draw Textures (2d) * -* Basic functions to load and draw Textures (2d) +* CONFIGURATION: * -* External libs: +* #define SUPPORT_STB_IMAGE / INCLUDE_STB_IMAGE +* +* #define SUPPORT_FILEFORMAT_BMP / SUPPORT_LOAD_BMP +* #define SUPPORT_FILEFORMAT_PNG / SUPPORT_LOAD_PNG +* #define SUPPORT_FILEFORMAT_TGA +* #define SUPPORT_FILEFORMAT_JPG / ENABLE_LOAD_JPG +* #define SUPPORT_FILEFORMAT_GIF +* #define SUPPORT_FILEFORMAT_HDR +* #define SUPPORT_FILEFORMAT_DDS / ENABLE_LOAD_DDS +* #define SUPPORT_FILEFORMAT_PKM +* #define SUPPORT_FILEFORMAT_KTX +* #define SUPPORT_FILEFORMAT_PVR +* #define SUPPORT_FILEFORMAT_ASTC +* Selected desired fileformats to be supported for loading. Some of those formats are +* supported by default, to remove support, just comment unrequired #define in this module +* +* #define SUPPORT_IMAGE_RESIZE / INCLUDE_STB_IMAGE_RESIZE +* #define SUPPORT_IMAGE_MANIPULATION +* +* DEPENDENCIES: * stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * NOTE: stb_image has been slightly modified to support Android platform. * stb_image_resize - Multiple image resize algorythms * -* Module Configuration Flags: -* ... +* +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * @@ -143,11 +162,11 @@ Image LoadImage(const char *fileName) else if (strcmp(GetExtension(fileName),"astc") == 0) image = LoadASTC(fileName); else if (strcmp(GetExtension(fileName),"rres") == 0) { - RRESData rres = LoadResource(fileName); + RRES rres = LoadResource(fileName, 0); - // NOTE: Parameters for RRES_IMAGE type are: width, height, format, mipmaps + // NOTE: Parameters for RRES_TYPE_IMAGE are: width, height, format, mipmaps - if (rres.type == RRES_IMAGE) image = LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); + if (rres[0].type == RRES_TYPE_IMAGE) image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3); else TraceLog(WARNING, "[%s] Resource file does not contain image data", fileName); UnloadResource(rres); diff --git a/src/utils.c b/src/utils.c index e5e05955..9a2a723a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,16 +1,23 @@ /********************************************************************************************** * -* raylib.utils +* raylib.utils - Some common utility functions * -* Some utility functions +* CONFIGURATION: * -* External libs: -* tinfl - zlib DEFLATE algorithm decompression +* #define SUPPORT_SAVE_PNG +* Enable saving PNG fileformat +* NOTE: Requires stb_image_write library +* +* #define SUPPORT_SAVE_BMP +* +* #define DO_NOT_TRACE_DEBUG_MSGS +* Avoid showing DEBUG TraceLog() messages +* +* DEPENDENCIES: * stb_image_write - PNG writting functions * -* Module Configuration Flags: -* DO_NOT_TRACE_DEBUG_MSGS - Avoid showing DEBUG TraceLog() messages * +* LICENSE: zlib/libpng * * Copyright (c) 2014-2016 Ramon Santamaria (@raysan5) * -- cgit v1.2.3 From 9cfaa81a7e7741f03db1f9579aa0b49bee42cdd7 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 5 Mar 2017 10:55:29 +0100 Subject: Added some flags and functions to manage window - SetWindowPosition(int x, int y); - SetWindowMonitor(int monitor); --- src/core.c | 46 +++++++++++++++++++++++++++++++++++----------- src/raylib.h | 17 ++++++++++------- 2 files changed, 45 insertions(+), 18 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 9d40edcc..6ea54862 100644 --- a/src/core.c +++ b/src/core.c @@ -578,6 +578,26 @@ void SetWindowIcon(Image image) #endif } +// Set window position on screen (windowed mode) +void SetWindowPosition(int x, int y) +{ + glfwSetWindowPos(window, x, y); +} + +// Set monitor for the current window (fullscreen mode) +void SetWindowMonitor(int monitor) +{ + int monitorCount; + GLFWmonitor** monitors = glfwGetMonitors(&monitorCount); + + if ((monitor >= 0) && (monitor < monitorCount)) + { + glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE); + TraceLog(INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor])); + } + else TraceLog(WARNING, "Selected monitor not found"); +} + // Get current screen width int GetScreenWidth(void) { @@ -1536,13 +1556,23 @@ static void InitGraphicsDevice(int width, int height) glfwDefaultWindowHints(); // Set default windows hints - if (configFlags & FLAG_RESIZABLE_WINDOW) + // Check some Window creation flags + if (configFlags & FLAG_WINDOW_RESIZABLE) glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window + else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable + + if (configFlags & FLAG_WINDOW_DECORATED) glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window + + if (configFlags & FLAG_WINDOW_TRANSPARENT) { - glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window + // TODO: Enable transparent window (not ready yet on GLFW 3.2) } - else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable - //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window + if (configFlags & FLAG_MSAA_4X_HINT) + { + glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 + TraceLog(INFO, "Trying to enable MSAA x4"); + } + //glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits //glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default) //glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window @@ -1551,13 +1581,7 @@ static void InitGraphicsDevice(int width, int height) // NOTE: When asking for an OpenGL context version, most drivers provide highest supported version // with forward compatibility to older OpenGL versions. - // For example, if using OpenGL 1.1, driver can provide a 3.3 context fordward compatible. - - if (configFlags & FLAG_MSAA_4X_HINT) - { - glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0 - TraceLog(INFO, "Trying to enable MSAA x4"); - } + // For example, if using OpenGL 1.1, driver can provide a 4.3 context forward compatible. // Check selection OpenGL version if (rlGetVersion() == OPENGL_21) diff --git a/src/raylib.h b/src/raylib.h index 3ff0d28f..ab7d7027 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -98,13 +98,14 @@ #define RAD2DEG (180.0f/PI) // raylib Config Flags -#define FLAG_FULLSCREEN_MODE 1 -#define FLAG_RESIZABLE_WINDOW 2 -#define FLAG_SHOW_LOGO 4 -#define FLAG_SHOW_MOUSE_CURSOR 8 -#define FLAG_CENTERED_MODE 16 -#define FLAG_MSAA_4X_HINT 32 -#define FLAG_VSYNC_HINT 64 +#define FLAG_SHOW_LOGO 1 +#define FLAG_SHOW_MOUSE_CURSOR 2 +#define FLAG_FULLSCREEN_MODE 4 +#define FLAG_WINDOW_RESIZABLE 8 +#define FLAG_WINDOW_DECORATED 16 +#define FLAG_WINDOW_TRANSPARENT 32 +#define FLAG_MSAA_4X_HINT 64 +#define FLAG_VSYNC_HINT 128 // Keyboard Function Keys #define KEY_SPACE 32 @@ -644,6 +645,8 @@ RLAPI bool WindowShouldClose(void); // Detect if K RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus) RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP) RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) +RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) +RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) RLAPI int GetScreenWidth(void); // Get current screen width RLAPI int GetScreenHeight(void); // Get current screen height -- cgit v1.2.3 From d1c9afd1d8ae4ae3e075b117fff7a5a77f3c4d60 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 5 Mar 2017 19:17:00 +0100 Subject: Work on timming functions... It seems Sleep() behaves weird on my computer, disabled by default returning to the busy wait loop... also re-implemented DrawFPS() to avoid frame blitting... --- src/core.c | 63 +++++++++++++++++++++++++++++++++--------------------------- src/raylib.h | 19 +++++++++--------- src/text.c | 16 ++++++++++++++- 3 files changed, 59 insertions(+), 39 deletions(-) (limited to 'src/raylib.h') diff --git a/src/core.c b/src/core.c index 6ea54862..a3b5f486 100644 --- a/src/core.c +++ b/src/core.c @@ -88,6 +88,8 @@ #if defined __linux || defined(PLATFORM_WEB) #include // Required for: timespec, nanosleep(), select() - POSIX +#elif defined __APPLE__ + #include // Required for: usleep() #endif #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) @@ -287,7 +289,7 @@ static void InitGraphicsDevice(int width, int height); // Initialize graphics d static void SetupFramebufferSize(int displayWidth, int displayHeight); static void InitTimer(void); // Initialize timer static double GetTime(void); // Returns time since InitTimer() was run -static void Wait(int ms); // Wait for some milliseconds (stop program execution) +static void Wait(float ms); // Wait for some milliseconds (stop program execution) static bool GetKeyStatus(int key); // Returns if a key has been pressed static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed static void PollInputEvents(void); // Register user events @@ -339,7 +341,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread #if defined(_WIN32) // NOTE: We include Sleep() function signature here to avoid windows.h inclusion - void __stdcall Sleep(unsigned long msTimeout); // Required for Delay() + void __stdcall Sleep(unsigned long msTimeout); // Required for Wait() #endif //---------------------------------------------------------------------------------- @@ -703,19 +705,19 @@ void EndDrawing(void) currentTime = GetTime(); drawTime = currentTime - previousTime; previousTime = currentTime; - + frameTime = updateTime + drawTime; // Wait for some milliseconds... if (frameTime < targetTime) { - Wait((int)((targetTime - frameTime)*1000)); + Wait((targetTime - frameTime)*1000.0f); currentTime = GetTime(); double extraTime = currentTime - previousTime; previousTime = currentTime; - frameTime = updateTime + drawTime + extraTime; + frameTime += extraTime; } } @@ -851,14 +853,14 @@ void SetTargetFPS(int fps) // Returns current FPS int GetFPS(void) { - return (int)floorf(1.0f/GetFrameTime()); + return (int)(1.0f/GetFrameTime()); } // Returns time in seconds for one frame float GetFrameTime(void) { // NOTE: We round value to milliseconds - return (roundf(frameTime*1000.0)/1000.0f); + return (float)frameTime; } // Converts Color to float array and normalizes @@ -1688,7 +1690,10 @@ static void InitGraphicsDevice(int width, int height) #endif glfwMakeContextCurrent(window); - glfwSwapInterval(0); // Disable VSync by default + + // Try to disable GPU V-Sync by default, set framerate using SetTargetFPS() + // NOTE: V-Sync can be enabled by graphic driver configuration + glfwSwapInterval(0); #if defined(PLATFORM_DESKTOP) // Load OpenGL 3.3 extensions @@ -1696,9 +1701,8 @@ static void InitGraphicsDevice(int width, int height) rlglLoadExtensions(glfwGetProcAddress); #endif - // Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS) - // If not set, swap interval uses GPU v-sync configuration - // Framerate can be setup using SetTargetFPS() + // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS) + // NOTE: V-Sync can be enabled by graphic driver configuration if (configFlags & FLAG_VSYNC_HINT) { glfwSwapInterval(1); @@ -2001,27 +2005,30 @@ static double GetTime(void) } // Wait for some milliseconds (stop program execution) -static void Wait(int ms) -{ -#if defined _WIN32 - Sleep(ms); -#elif defined __linux || defined(PLATFORM_WEB) - struct timespec req = { 0 }; - time_t sec = (int)(ms/1000); - ms -= (sec*1000); - req.tv_sec=sec; - req.tv_nsec=ms*1000000L; - - // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated. - while (nanosleep(&req,&req) == -1) continue; -//#elif defined __APPLE__ - // TODO: -#else +static void Wait(float ms) +{ +#define SUPPORT_BUSY_WAIT_LOOP +#if defined(SUPPORT_BUSY_WAIT_LOOP) double prevTime = GetTime(); double nextTime = 0.0; // Busy wait loop - while ((nextTime - prevTime) < (double)ms/1000.0) nextTime = GetTime(); + while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime(); +#else + #if defined _WIN32 + Sleep(ms); + #elif defined __linux || defined(PLATFORM_WEB) + struct timespec req = { 0 }; + time_t sec = (int)(ms/1000.0f); + ms -= (sec*1000); + req.tv_sec = sec; + req.tv_nsec = ms*1000000L; + + // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated. + while (nanosleep(&req, &req) == -1) continue; + #elif defined __APPLE__ + usleep(ms*1000.0f); + #endif #endif } diff --git a/src/raylib.h b/src/raylib.h index ab7d7027..beda833c 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -98,14 +98,13 @@ #define RAD2DEG (180.0f/PI) // raylib Config Flags -#define FLAG_SHOW_LOGO 1 -#define FLAG_SHOW_MOUSE_CURSOR 2 -#define FLAG_FULLSCREEN_MODE 4 -#define FLAG_WINDOW_RESIZABLE 8 -#define FLAG_WINDOW_DECORATED 16 -#define FLAG_WINDOW_TRANSPARENT 32 -#define FLAG_MSAA_4X_HINT 64 -#define FLAG_VSYNC_HINT 128 +#define FLAG_SHOW_LOGO 1 // Set this flag to show raylib logo at startup +#define FLAG_FULLSCREEN_MODE 2 // Set this flag to run program in fullscreen +#define FLAG_WINDOW_RESIZABLE 4 // Set this flag to allow resizable window +#define FLAG_WINDOW_DECORATED 8 // Set this flag to show window decoration (frame and buttons) +#define FLAG_WINDOW_TRANSPARENT 16 // Set this flag to allow transparent window +#define FLAG_MSAA_4X_HINT 32 // Set this flag to try enabling MSAA 4X +#define FLAG_VSYNC_HINT 64 // Set this flag to try enabling V-Sync on GPU // Keyboard Function Keys #define KEY_SPACE 32 @@ -674,8 +673,8 @@ RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix) RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) -RLAPI int GetFPS(void); // Returns current FPS (rounded value) -RLAPI float GetFrameTime(void); // Returns time in seconds for one frame (rounded value) +RLAPI int GetFPS(void); // Returns current FPS +RLAPI float GetFrameTime(void); // Returns time in seconds for one frame RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color diff --git a/src/text.c b/src/text.c index 6f18b391..18ebf482 100644 --- a/src/text.c +++ b/src/text.c @@ -531,8 +531,22 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i // NOTE: Uses default font void DrawFPS(int posX, int posY) { + // NOTE: We are rendering fps every second for better viewing on high framerates + + static int fps = 0; + static int counter = 0; + static int refreshRate = 20; + + if (counter < refreshRate) counter++; + else + { + fps = GetFPS(); + refreshRate = fps; + counter = 0; + } + // NOTE: We have rounding errors every frame, so it oscillates a lot - DrawText(FormatText("%2i FPS", GetFPS()), posX, posY, 20, LIME); + DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME); } //---------------------------------------------------------------------------------- -- cgit v1.2.3