Merge pull request #2 from raysan5/master

merged raylib-master
This commit is contained in:
Jak 2019-02-24 21:57:31 +00:00 committed by GitHub
commit 44c2df3c12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 545 additions and 422 deletions

1
.gitignore vendored
View File

@ -49,6 +49,7 @@ ipch/
# Ignore compiled binaries # Ignore compiled binaries
*.o *.o
*.exe *.exe
*.a
!raylib.rc.o !raylib.rc.o
# Ignore all examples files # Ignore all examples files

View File

@ -707,7 +707,7 @@ bool WindowShouldClose(void)
{ {
#if defined(PLATFORM_WEB) #if defined(PLATFORM_WEB)
// Emterpreter-Async required to run sync code // Emterpreter-Async required to run sync code
// https://github.com/kripken/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code // https://github.com/emscripten-core/emscripten/wiki/Emterpreter#emterpreter-async-run-synchronous-code
// By default, this function is never called on a web-ready raylib example because we encapsulate // By default, this function is never called on a web-ready raylib example because we encapsulate
// frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously // frame code in a UpdateDrawFrame() function, to allow browser manage execution asynchronously
// but now emscripten allows sync code to be executed in an interpreted way, using emterpreter! // but now emscripten allows sync code to be executed in an interpreted way, using emterpreter!
@ -871,7 +871,7 @@ void *GetWindowHandle(void)
{ {
#if defined(_WIN32) #if defined(_WIN32)
// NOTE: Returned handle is: void *HWND (windows.h) // NOTE: Returned handle is: void *HWND (windows.h)
return glfwGetWin32Window(window); return glfwGetWin32Window(window);
#elif defined(__linux__) #elif defined(__linux__)
// NOTE: Returned handle is: unsigned long Window (X.h) // NOTE: Returned handle is: unsigned long Window (X.h)
// typedef unsigned long XID; // typedef unsigned long XID;
@ -1228,7 +1228,7 @@ void BeginTextureMode(RenderTexture2D target)
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
//rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?) //rlScalef(0.0f, -1.0f, 0.0f); // Flip Y-drawing (?)
// Setup current width/height for proper aspect ratio // Setup current width/height for proper aspect ratio
// calculation when using BeginMode3D() // calculation when using BeginMode3D()
currentWidth = target.texture.width; currentWidth = target.texture.width;
@ -1254,6 +1254,10 @@ void EndTextureMode(void)
rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
// Reset current screen size
currentWidth = GetScreenWidth();
currentHeight = GetScreenHeight();
} }
// Returns a ray trace from mouse position // Returns a ray trace from mouse position
@ -1426,11 +1430,11 @@ Vector3 ColorToHSV(Color color)
Vector3 hsv = { 0.0f, 0.0f, 0.0f }; Vector3 hsv = { 0.0f, 0.0f, 0.0f };
float min, max, delta; float min, max, delta;
min = rgb.x < rgb.y ? rgb.x : rgb.y; min = rgb.x < rgb.y? rgb.x : rgb.y;
min = min < rgb.z ? min : rgb.z; min = min < rgb.z? min : rgb.z;
max = rgb.x > rgb.y ? rgb.x : rgb.y; max = rgb.x > rgb.y? rgb.x : rgb.y;
max = max > rgb.z ? max : rgb.z; max = max > rgb.z? max : rgb.z;
hsv.z = max; // Value hsv.z = max; // Value
delta = max - min; delta = max - min;
@ -1481,25 +1485,25 @@ Color ColorFromHSV(Vector3 hsv)
// Red channel // Red channel
float k = fmod((5.0f + h/60.0f), 6); float k = fmod((5.0f + h/60.0f), 6);
float t = 4.0f - k; float t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.r = (v - v*s*k)*255; color.r = (v - v*s*k)*255;
// Green channel // Green channel
k = fmod((3.0f + h/60.0f), 6); k = fmod((3.0f + h/60.0f), 6);
t = 4.0f - k; t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.g = (v - v*s*k)*255; color.g = (v - v*s*k)*255;
// Blue channel // Blue channel
k = fmod((1.0f + h/60.0f), 6); k = fmod((1.0f + h/60.0f), 6);
t = 4.0f - k; t = 4.0f - k;
k = (t < k) ? t : k; k = (t < k)? t : k;
k = (k < 1) ? k : 1; k = (k < 1)? k : 1;
k = (k > 0) ? k : 0; k = (k > 0)? k : 0;
color.b = (v - v*s*k)*255; color.b = (v - v*s*k)*255;
return color; return color;
@ -1673,7 +1677,7 @@ const char *GetFileNameWithoutExt(const char *filePath)
// NOTE: strrchr() returns a pointer to the last occurrence of character // NOTE: strrchr() returns a pointer to the last occurrence of character
lastDot = strrchr(result, nameDot); lastDot = strrchr(result, nameDot);
lastSep = (pathSep == 0) ? NULL : strrchr(result, pathSep); lastSep = (pathSep == 0)? NULL : strrchr(result, pathSep);
if (lastDot != NULL) // Check if it has an extension separator... if (lastDot != NULL) // Check if it has an extension separator...
{ {
@ -1913,14 +1917,13 @@ void OpenURL(const char *url)
char *cmd = (char *)calloc(strlen(url) + 10, sizeof(char)); char *cmd = (char *)calloc(strlen(url) + 10, sizeof(char));
#if defined(_WIN32) #if defined(_WIN32)
sprintf(cmd, "explorer '%s'", url); sprintf(cmd, "explorer %s", url);
#elif defined(__linux__) #elif defined(__linux__)
sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser sprintf(cmd, "xdg-open '%s'", url); // Alternatives: firefox, x-www-browser
#elif defined(__APPLE__) #elif defined(__APPLE__)
sprintf(cmd, "open '%s'", url); sprintf(cmd, "open '%s'", url);
#endif #endif
system(cmd); system(cmd);
free(cmd); free(cmd);
} }
} }
@ -2210,7 +2213,7 @@ void SetMouseOffset(int offsetX, int offsetY)
// NOTE: Useful when rendering to different size targets // NOTE: Useful when rendering to different size targets
void SetMouseScale(float scaleX, float scaleY) void SetMouseScale(float scaleX, float scaleY)
{ {
mouseScale = (Vector2){ scaleX, scaleY }; mouseScale = (Vector2){ scaleX, scaleY };
} }
// Returns mouse wheel movement Y // Returns mouse wheel movement Y
@ -3188,7 +3191,7 @@ static void PollInputEvents(void)
// Poll Events (registered events) // Poll Events (registered events)
// NOTE: Activity is paused if not enabled (appEnabled) // NOTE: Activity is paused if not enabled (appEnabled)
while ((ident = ALooper_pollAll(appEnabled ? 0 : -1, NULL, &events,(void**)&source)) >= 0) while ((ident = ALooper_pollAll(appEnabled? 0 : -1, NULL, &events,(void**)&source)) >= 0)
{ {
// Process this event // Process this event
if (source != NULL) source->process(androidApp, source); if (source != NULL) source->process(androidApp, source);
@ -3274,9 +3277,9 @@ static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, i
char path[512] = { 0 }; char path[512] = { 0 };
#if defined(PLATFORM_ANDROID) #if defined(PLATFORM_ANDROID)
strcpy(path, internalDataPath); strcpy(path, internalDataPath);
strcat(path, TextFormat("/screenrec%03i.gif", screenshotCounter)); strcat(path, TextFormat("./screenrec%03i.gif", screenshotCounter));
#else #else
strcpy(path, TextFormat("/screenrec%03i.gif", screenshotCounter)); strcpy(path, TextFormat("./screenrec%03i.gif", screenshotCounter));
#endif #endif
// NOTE: delay represents the time between frames in the gif, if we capture a gif frame every // NOTE: delay represents the time between frames in the gif, if we capture a gif frame every
@ -3768,7 +3771,7 @@ static EM_BOOL EmscriptenTouchCallback(int eventType, const EmscriptenTouchEvent
} }
printf("%s, numTouches: %d %s%s%s%s\n", emscripten_event_type_to_string(eventType), event->numTouches, 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" : ""); event->ctrlKey? " CTRL" : "", event->shiftKey? " SHIFT" : "", event->altKey? " ALT" : "", event->metaKey? " META" : "");
for (int i = 0; i < event->numTouches; ++i) for (int i = 0; i < event->numTouches; ++i)
{ {
@ -3822,7 +3825,7 @@ 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", 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); 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->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]);
@ -4186,11 +4189,11 @@ static void EventThreadSpawn(char *device)
{ {
// Looks like a interesting device // Looks like a interesting device
TraceLog(LOG_INFO, "Opening input device [%s] (%s%s%s%s%s)", device, TraceLog(LOG_INFO, "Opening input device [%s] (%s%s%s%s%s)", device,
worker->isMouse ? "mouse " : "", worker->isMouse? "mouse " : "",
worker->isMultitouch ? "multitouch " : "", worker->isMultitouch? "multitouch " : "",
worker->isTouch ? "touchscreen " : "", worker->isTouch? "touchscreen " : "",
worker->isGamepad ? "gamepad " : "", worker->isGamepad? "gamepad " : "",
worker->isKeyboard ? "keyboard " : ""); worker->isKeyboard? "keyboard " : "");
// Create a thread for this device // Create a thread for this device
int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker); int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);

51
src/external/cgltf.h vendored
View File

@ -1,6 +1,49 @@
/** /**
* cgltf - a single-file glTF 2.0 parser written in C99. * cgltf - a single-file glTF 2.0 parser written in C99.
*
* Version: 1.0
*
* Website: https://github.com/jkuhlmann/cgltf
*
* Distributed under the MIT License, see notice at the end of this file. * Distributed under the MIT License, see notice at the end of this file.
*
* Building:
* Include this file where you need the struct and function
* declarations. Have exactly one source file where you define
* `CGLTF_IMPLEMENTATION` before including this file to get the
* function definitions.
*
* Reference:
* `cgltf_result cgltf_parse(const cgltf_options*, const void*,
* cgltf_size, cgltf_data**)` parses both glTF and GLB data. If
* this function returns `cgltf_result_success`, you have to call
* `cgltf_free()` on the created `cgltf_data*` variable.
* Note that contents of external files for buffers and images are not
* automatically loaded. You'll need to read these files yourself using
* URIs in the `cgltf_data` structure.
*
* `cgltf_options` is the struct passed to `cgltf_parse()` to control
* parts of the parsing process. You can use it to force the file type
* and provide memory allocation callbacks. Should be zero-initialized
* to trigger default behavior.
*
* `cgltf_data` is the struct allocated and filled by `cgltf_parse()`.
* It generally mirrors the glTF format as described by the spec (see
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0).
*
* `void cgltf_free(cgltf_data*)` frees the allocated `cgltf_data`
* variable.
*
* `cgltf_result cgltf_load_buffers(const cgltf_options*, cgltf_data*,
* const char*)` can be optionally called to open and read buffer
* files using the `FILE*` APIs.
*
* `cgltf_result cgltf_parse_file(const cgltf_options* options, const
* char* path, cgltf_data** out_data)` can be used to open the given
* file using `FILE*` APIs and parse the data using `cgltf_parse()`.
*
* `cgltf_result cgltf_validate(cgltf_data*)` can be used to do additional
* checks to make sure the parsed glTF data is valid.
*/ */
#ifndef CGLTF_H_INCLUDED__ #ifndef CGLTF_H_INCLUDED__
#define CGLTF_H_INCLUDED__ #define CGLTF_H_INCLUDED__
@ -462,6 +505,10 @@ void cgltf_free(cgltf_data* data);
void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix); void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef CGLTF_H_INCLUDED__ */ #endif /* #ifndef CGLTF_H_INCLUDED__ */
/* /*
@ -4266,10 +4313,6 @@ static void jsmn_init(jsmn_parser *parser) {
#endif /* #ifdef CGLTF_IMPLEMENTATION */ #endif /* #ifdef CGLTF_IMPLEMENTATION */
#ifdef __cplusplus
}
#endif
/* cgltf is distributed under MIT license: /* cgltf is distributed under MIT license:
* *
* Copyright (c) 2018 Johannes Kuhlmann * Copyright (c) 2018 Johannes Kuhlmann

Binary file not shown.

View File

@ -116,7 +116,7 @@ void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color)
void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color) void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color)
{ {
if (rlCheckBufferLimit(2*36)) rlglDraw(); if (rlCheckBufferLimit(2*36)) rlglDraw();
rlPushMatrix(); rlPushMatrix();
rlTranslatef(center.x, center.y, center.z); rlTranslatef(center.x, center.y, center.z);
rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z); rlRotatef(rotationAngle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
@ -140,7 +140,7 @@ void DrawCube(Vector3 position, float width, float height, float length, Color c
float x = 0.0f; float x = 0.0f;
float y = 0.0f; float y = 0.0f;
float z = 0.0f; float z = 0.0f;
if (rlCheckBufferLimit(36)) rlglDraw(); if (rlCheckBufferLimit(36)) rlglDraw();
rlPushMatrix(); rlPushMatrix();
@ -221,7 +221,7 @@ void DrawCubeWires(Vector3 position, float width, float height, float length, Co
float x = 0.0f; float x = 0.0f;
float y = 0.0f; float y = 0.0f;
float z = 0.0f; float z = 0.0f;
if (rlCheckBufferLimit(36)) rlglDraw(); if (rlCheckBufferLimit(36)) rlglDraw();
rlPushMatrix(); rlPushMatrix();
@ -626,7 +626,7 @@ Model LoadModel(const char *fileName)
Model LoadModelFromMesh(Mesh mesh) Model LoadModelFromMesh(Mesh mesh)
{ {
Model model = { 0 }; Model model = { 0 };
model.mesh = mesh; model.mesh = mesh;
model.transform = MatrixIdentity(); model.transform = MatrixIdentity();
model.material = LoadMaterialDefault(); model.material = LoadMaterialDefault();
@ -655,12 +655,16 @@ Mesh LoadMesh(const char *fileName)
TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName); TraceLog(LOG_WARNING, "[%s] Mesh fileformat not supported, it can't be loaded", fileName);
#endif #endif
#if defined(SUPPORT_MESH_GENERATION)
if (mesh.vertexCount == 0) if (mesh.vertexCount == 0)
{ {
TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!"); TraceLog(LOG_WARNING, "Mesh could not be loaded! Let's load a cube to replace it!");
mesh = GenMeshCube(1.0f, 1.0f, 1.0f); mesh = GenMeshCube(1.0f, 1.0f, 1.0f);
} }
else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh) else rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
#else
rlLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
#endif
return mesh; return mesh;
} }
@ -675,11 +679,11 @@ void UnloadMesh(Mesh *mesh)
void ExportMesh(Mesh mesh, const char *fileName) void ExportMesh(Mesh mesh, const char *fileName)
{ {
bool success = false; bool success = false;
if (IsFileExtension(fileName, ".obj")) if (IsFileExtension(fileName, ".obj"))
{ {
FILE *objFile = fopen(fileName, "wt"); FILE *objFile = fopen(fileName, "wt");
fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n"); fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n");
fprintf(objFile, "# // //\n"); fprintf(objFile, "# // //\n");
fprintf(objFile, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n"); fprintf(objFile, "# // rMeshOBJ exporter v1.0 - Mesh exported as triangle faces and not optimized //\n");
@ -692,33 +696,33 @@ void ExportMesh(Mesh mesh, const char *fileName)
fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n\n"); fprintf(objFile, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount); fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount);
fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount); fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount);
fprintf(objFile, "g mesh\n"); fprintf(objFile, "g mesh\n");
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{ {
fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]);
} }
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2)
{ {
fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]);
} }
for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3)
{ {
fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
} }
for (int i = 0; i < mesh.triangleCount; i += 3) for (int i = 0; i < mesh.triangleCount; i += 3)
{ {
fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2); fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
} }
fprintf(objFile, "\n"); fprintf(objFile, "\n");
fclose(objFile); fclose(objFile);
success = true; success = true;
} }
else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data
@ -733,7 +737,7 @@ Mesh GenMeshPoly(int sides, float radius)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
int vertexCount = sides*3; int vertexCount = sides*3;
// Vertices definition // Vertices definition
Vector3 *vertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); Vector3 *vertices = (Vector3 *)malloc(vertexCount*sizeof(Vector3));
for (int i = 0, v = 0; i < 360; i += 360/sides, v += 3) for (int i = 0, v = 0; i < 360; i += 360/sides, v += 3)
@ -741,13 +745,13 @@ Mesh GenMeshPoly(int sides, float radius)
vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f }; vertices[v] = (Vector3){ 0.0f, 0.0f, 0.0f };
vertices[v + 1] = (Vector3){ sinf(DEG2RAD*i)*radius, 0.0f, cosf(DEG2RAD*i)*radius }; vertices[v + 1] = (Vector3){ sinf(DEG2RAD*i)*radius, 0.0f, cosf(DEG2RAD*i)*radius };
vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(i + 360/sides))*radius, 0.0f, cosf(DEG2RAD*(i + 360/sides))*radius }; vertices[v + 2] = (Vector3){ sinf(DEG2RAD*(i + 360/sides))*radius, 0.0f, cosf(DEG2RAD*(i + 360/sides))*radius };
} }
// Normals definition // Normals definition
Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3));
for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
// TexCoords definition // TexCoords definition
Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2));
for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f }; for (int n = 0; n < vertexCount; n++) texcoords[n] = (Vector2){ 0.0f, 0.0f };
@ -756,7 +760,7 @@ Mesh GenMeshPoly(int sides, float radius)
mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.vertices = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
// Mesh vertices position array // Mesh vertices position array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
@ -764,14 +768,14 @@ Mesh GenMeshPoly(int sides, float radius)
mesh.vertices[3*i + 1] = vertices[i].y; mesh.vertices[3*i + 1] = vertices[i].y;
mesh.vertices[3*i + 2] = vertices[i].z; mesh.vertices[3*i + 2] = vertices[i].z;
} }
// Mesh texcoords array // Mesh texcoords array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
mesh.texcoords[2*i] = texcoords[i].x; mesh.texcoords[2*i] = texcoords[i].x;
mesh.texcoords[2*i + 1] = texcoords[i].y; mesh.texcoords[2*i + 1] = texcoords[i].y;
} }
// Mesh normals array // Mesh normals array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
@ -779,14 +783,14 @@ Mesh GenMeshPoly(int sides, float radius)
mesh.normals[3*i + 1] = normals[i].y; mesh.normals[3*i + 1] = normals[i].y;
mesh.normals[3*i + 2] = normals[i].z; mesh.normals[3*i + 2] = normals[i].z;
} }
free(vertices); free(vertices);
free(normals); free(normals);
free(texcoords); free(texcoords);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -799,7 +803,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
#if defined(CUSTOM_MESH_GEN_PLANE) #if defined(CUSTOM_MESH_GEN_PLANE)
resX++; resX++;
resZ++; resZ++;
// Vertices definition // Vertices definition
int vertexCount = resX*resZ; // vertices get reused for the faces int vertexCount = resX*resZ; // vertices get reused for the faces
@ -820,7 +824,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3)); Vector3 *normals = (Vector3 *)malloc(vertexCount*sizeof(Vector3));
for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up; for (int n = 0; n < vertexCount; n++) normals[n] = (Vector3){ 0.0f, 1.0f, 0.0f }; // Vector3.up;
// TexCoords definition // TexCoords definition
Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2)); Vector2 *texcoords = (Vector2 *)malloc(vertexCount*sizeof(Vector2));
for (int v = 0; v < resZ; v++) for (int v = 0; v < resZ; v++)
{ {
@ -843,7 +847,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
triangles[t++] = i + 1; triangles[t++] = i + 1;
triangles[t++] = i; triangles[t++] = i;
triangles[t++] = i + resX; triangles[t++] = i + resX;
triangles[t++] = i + resX + 1; triangles[t++] = i + resX + 1;
triangles[t++] = i + 1; triangles[t++] = i + 1;
} }
@ -854,7 +858,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float)); mesh.texcoords = (float *)malloc(mesh.vertexCount*2*sizeof(float));
mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float)); mesh.normals = (float *)malloc(mesh.vertexCount*3*sizeof(float));
mesh.indices = (unsigned short *)malloc(mesh.triangleCount*3*sizeof(unsigned short)); mesh.indices = (unsigned short *)malloc(mesh.triangleCount*3*sizeof(unsigned short));
// Mesh vertices position array // Mesh vertices position array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
@ -862,14 +866,14 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
mesh.vertices[3*i + 1] = vertices[i].y; mesh.vertices[3*i + 1] = vertices[i].y;
mesh.vertices[3*i + 2] = vertices[i].z; mesh.vertices[3*i + 2] = vertices[i].z;
} }
// Mesh texcoords array // Mesh texcoords array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
mesh.texcoords[2*i] = texcoords[i].x; mesh.texcoords[2*i] = texcoords[i].x;
mesh.texcoords[2*i + 1] = texcoords[i].y; mesh.texcoords[2*i + 1] = texcoords[i].y;
} }
// Mesh normals array // Mesh normals array
for (int i = 0; i < mesh.vertexCount; i++) for (int i = 0; i < mesh.vertexCount; i++)
{ {
@ -877,22 +881,22 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
mesh.normals[3*i + 1] = normals[i].y; mesh.normals[3*i + 1] = normals[i].y;
mesh.normals[3*i + 2] = normals[i].z; mesh.normals[3*i + 2] = normals[i].z;
} }
// Mesh indices array initialization // Mesh indices array initialization
for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i]; for (int i = 0; i < mesh.triangleCount*3; i++) mesh.indices[i] = triangles[i];
free(vertices); free(vertices);
free(normals); free(normals);
free(texcoords); free(texcoords);
free(triangles); free(triangles);
#else // Use par_shapes library to generate plane mesh #else // Use par_shapes library to generate plane mesh
par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!! par_shapes_mesh *plane = par_shapes_create_plane(resX, resZ); // No normals/texcoords generated!!!
par_shapes_scale(plane, width, length, 1.0f); par_shapes_scale(plane, width, length, 1.0f);
par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_rotate(plane, -PI/2.0f, (float[]){ 1, 0, 0 });
par_shapes_translate(plane, -width/2, 0.0f, length/2); par_shapes_translate(plane, -width/2, 0.0f, length/2);
mesh.vertices = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); mesh.vertices = (float *)malloc(plane->ntriangles*3*3*sizeof(float));
mesh.texcoords = (float *)malloc(plane->ntriangles*3*2*sizeof(float)); mesh.texcoords = (float *)malloc(plane->ntriangles*3*2*sizeof(float));
mesh.normals = (float *)malloc(plane->ntriangles*3*3*sizeof(float)); mesh.normals = (float *)malloc(plane->ntriangles*3*3*sizeof(float));
@ -905,11 +909,11 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
mesh.vertices[k*3] = plane->points[plane->triangles[k]*3]; mesh.vertices[k*3] = plane->points[plane->triangles[k]*3];
mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = plane->points[plane->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = plane->points[plane->triangles[k]*3 + 2];
mesh.normals[k*3] = plane->normals[plane->triangles[k]*3]; mesh.normals[k*3] = plane->normals[plane->triangles[k]*3];
mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = plane->normals[plane->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = plane->normals[plane->triangles[k]*3 + 2];
mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2]; mesh.texcoords[k*2] = plane->tcoords[plane->triangles[k]*2];
mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = plane->tcoords[plane->triangles[k]*2 + 1];
} }
@ -918,7 +922,7 @@ Mesh GenMeshPlane(float width, float length, int resX, int resZ)
#endif #endif
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -956,7 +960,7 @@ Mesh GenMeshCube(float width, float height, float length)
-width/2, height/2, length/2, -width/2, height/2, length/2,
-width/2, height/2, -length/2 -width/2, height/2, -length/2
}; };
float texcoords[] = { float texcoords[] = {
0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f, 0.0f,
@ -983,7 +987,7 @@ Mesh GenMeshCube(float width, float height, float length)
1.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f 0.0f, 1.0f
}; };
float normals[] = { float normals[] = {
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
@ -1013,15 +1017,15 @@ Mesh GenMeshCube(float width, float height, float length)
mesh.vertices = (float *)malloc(24*3*sizeof(float)); mesh.vertices = (float *)malloc(24*3*sizeof(float));
memcpy(mesh.vertices, vertices, 24*3*sizeof(float)); memcpy(mesh.vertices, vertices, 24*3*sizeof(float));
mesh.texcoords = (float *)malloc(24*2*sizeof(float)); mesh.texcoords = (float *)malloc(24*2*sizeof(float));
memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float)); memcpy(mesh.texcoords, texcoords, 24*2*sizeof(float));
mesh.normals = (float *)malloc(24*3*sizeof(float)); mesh.normals = (float *)malloc(24*3*sizeof(float));
memcpy(mesh.normals, normals, 24*3*sizeof(float)); memcpy(mesh.normals, normals, 24*3*sizeof(float));
mesh.indices = (unsigned short *)malloc(36*sizeof(unsigned short)); mesh.indices = (unsigned short *)malloc(36*sizeof(unsigned short));
int k = 0; int k = 0;
// Indices can be initialized right now // Indices can be initialized right now
@ -1036,10 +1040,10 @@ Mesh GenMeshCube(float width, float height, float length)
k++; k++;
} }
mesh.vertexCount = 24; mesh.vertexCount = 24;
mesh.triangleCount = 12; mesh.triangleCount = 12;
#else // Use par_shapes library to generate cube mesh #else // Use par_shapes library to generate cube mesh
/* /*
// Platonic solids: // Platonic solids:
@ -1053,11 +1057,11 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron
// NOTE: No normals/texcoords generated by default // NOTE: No normals/texcoords generated by default
par_shapes_mesh *cube = par_shapes_create_cube(); par_shapes_mesh *cube = par_shapes_create_cube();
cube->tcoords = PAR_MALLOC(float, 2*cube->npoints); cube->tcoords = PAR_MALLOC(float, 2*cube->npoints);
for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f; for (int i = 0; i < 2*cube->npoints; i++) cube->tcoords[i] = 0.0f;
par_shapes_scale(cube, width, height, length); par_shapes_scale(cube, width, height, length);
par_shapes_translate(cube, -width/2, 0.0f, -length/2); par_shapes_translate(cube, -width/2, 0.0f, -length/2);
par_shapes_compute_normals(cube); par_shapes_compute_normals(cube);
mesh.vertices = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); mesh.vertices = (float *)malloc(cube->ntriangles*3*3*sizeof(float));
mesh.texcoords = (float *)malloc(cube->ntriangles*3*2*sizeof(float)); mesh.texcoords = (float *)malloc(cube->ntriangles*3*2*sizeof(float));
mesh.normals = (float *)malloc(cube->ntriangles*3*3*sizeof(float)); mesh.normals = (float *)malloc(cube->ntriangles*3*3*sizeof(float));
@ -1070,11 +1074,11 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron
mesh.vertices[k*3] = cube->points[cube->triangles[k]*3]; mesh.vertices[k*3] = cube->points[cube->triangles[k]*3];
mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = cube->points[cube->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = cube->points[cube->triangles[k]*3 + 2];
mesh.normals[k*3] = cube->normals[cube->triangles[k]*3]; mesh.normals[k*3] = cube->normals[cube->triangles[k]*3];
mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = cube->normals[cube->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = cube->normals[cube->triangles[k]*3 + 2];
mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2]; mesh.texcoords[k*2] = cube->tcoords[cube->triangles[k]*2];
mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = cube->tcoords[cube->triangles[k]*2 + 1];
} }
@ -1083,7 +1087,7 @@ par_shapes_mesh* par_shapes_create_icosahedron(); // 20 sides polyhedron
#endif #endif
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1095,8 +1099,8 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices)
par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings); par_shapes_mesh *sphere = par_shapes_create_parametric_sphere(slices, rings);
par_shapes_scale(sphere, radius, radius, radius); par_shapes_scale(sphere, radius, radius, radius);
// NOTE: Soft normals are computed internally // NOTE: Soft normals are computed internally
mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float));
mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float));
mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float));
@ -1109,19 +1113,19 @@ RLAPI Mesh GenMeshSphere(float radius, int rings, int slices)
mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
} }
par_shapes_free_mesh(sphere); par_shapes_free_mesh(sphere);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1133,8 +1137,8 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices)
par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings); par_shapes_mesh *sphere = par_shapes_create_hemisphere(slices, rings);
par_shapes_scale(sphere, radius, radius, radius); par_shapes_scale(sphere, radius, radius, radius);
// NOTE: Soft normals are computed internally // NOTE: Soft normals are computed internally
mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.vertices = (float *)malloc(sphere->ntriangles*3*3*sizeof(float));
mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float)); mesh.texcoords = (float *)malloc(sphere->ntriangles*3*2*sizeof(float));
mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float)); mesh.normals = (float *)malloc(sphere->ntriangles*3*3*sizeof(float));
@ -1147,19 +1151,19 @@ RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices)
mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3]; mesh.vertices[k*3] = sphere->points[sphere->triangles[k]*3];
mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = sphere->points[sphere->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = sphere->points[sphere->triangles[k]*3 + 2];
mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3]; mesh.normals[k*3] = sphere->normals[sphere->triangles[k]*3];
mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = sphere->normals[sphere->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = sphere->normals[sphere->triangles[k]*3 + 2];
mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2]; mesh.texcoords[k*2] = sphere->tcoords[sphere->triangles[k]*2];
mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = sphere->tcoords[sphere->triangles[k]*2 + 1];
} }
par_shapes_free_mesh(sphere); par_shapes_free_mesh(sphere);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1171,7 +1175,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
// Instance a cylinder that sits on the Z=0 plane using the given tessellation // Instance a cylinder that sits on the Z=0 plane using the given tessellation
// levels across the UV domain. Think of "slices" like a number of pizza // levels across the UV domain. Think of "slices" like a number of pizza
// slices, and "stacks" like a number of stacked rings. // slices, and "stacks" like a number of stacked rings.
// Height and radius are both 1.0, but they can easily be changed with par_shapes_scale // Height and radius are both 1.0, but they can easily be changed with par_shapes_scale
par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8); par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
par_shapes_scale(cylinder, radius, radius, height); par_shapes_scale(cylinder, radius, radius, height);
@ -1183,16 +1187,16 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f; for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
par_shapes_translate(capTop, 0, height, 0); par_shapes_translate(capTop, 0, height, 0);
// Generate an orientable disk shape (bottom cap) // Generate an orientable disk shape (bottom cap)
par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 }); par_shapes_mesh *capBottom = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, -1 });
capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints); capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f; for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 }); par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
par_shapes_merge_and_free(cylinder, capTop); par_shapes_merge_and_free(cylinder, capTop);
par_shapes_merge_and_free(cylinder, capBottom); par_shapes_merge_and_free(cylinder, capBottom);
mesh.vertices = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); mesh.vertices = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float));
mesh.texcoords = (float *)malloc(cylinder->ntriangles*3*2*sizeof(float)); mesh.texcoords = (float *)malloc(cylinder->ntriangles*3*2*sizeof(float));
mesh.normals = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float)); mesh.normals = (float *)malloc(cylinder->ntriangles*3*3*sizeof(float));
@ -1205,19 +1209,19 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3]; mesh.vertices[k*3] = cylinder->points[cylinder->triangles[k]*3];
mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = cylinder->points[cylinder->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = cylinder->points[cylinder->triangles[k]*3 + 2];
mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3]; mesh.normals[k*3] = cylinder->normals[cylinder->triangles[k]*3];
mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = cylinder->normals[cylinder->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = cylinder->normals[cylinder->triangles[k]*3 + 2];
mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2]; mesh.texcoords[k*2] = cylinder->tcoords[cylinder->triangles[k]*2];
mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = cylinder->tcoords[cylinder->triangles[k]*2 + 1];
} }
par_shapes_free_mesh(cylinder); par_shapes_free_mesh(cylinder);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1229,7 +1233,7 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
if (radius > 1.0f) radius = 1.0f; if (radius > 1.0f) radius = 1.0f;
else if (radius < 0.1f) radius = 0.1f; else if (radius < 0.1f) radius = 0.1f;
// Create a donut that sits on the Z=0 plane with the specified inner radius // Create a donut that sits on the Z=0 plane with the specified inner radius
// The outer radius can be controlled with par_shapes_scale // The outer radius can be controlled with par_shapes_scale
par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius); par_shapes_mesh *torus = par_shapes_create_torus(radSeg, sides, radius);
@ -1247,19 +1251,19 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
mesh.vertices[k*3] = torus->points[torus->triangles[k]*3]; mesh.vertices[k*3] = torus->points[torus->triangles[k]*3];
mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = torus->points[torus->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = torus->points[torus->triangles[k]*3 + 2];
mesh.normals[k*3] = torus->normals[torus->triangles[k]*3]; mesh.normals[k*3] = torus->normals[torus->triangles[k]*3];
mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = torus->normals[torus->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = torus->normals[torus->triangles[k]*3 + 2];
mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2]; mesh.texcoords[k*2] = torus->tcoords[torus->triangles[k]*2];
mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = torus->tcoords[torus->triangles[k]*2 + 1];
} }
par_shapes_free_mesh(torus); par_shapes_free_mesh(torus);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1268,7 +1272,7 @@ Mesh GenMeshTorus(float radius, float size, int radSeg, int sides)
Mesh GenMeshKnot(float radius, float size, int radSeg, int sides) Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
if (radius > 3.0f) radius = 3.0f; if (radius > 3.0f) radius = 3.0f;
else if (radius < 0.5f) radius = 0.5f; else if (radius < 0.5f) radius = 0.5f;
@ -1287,19 +1291,19 @@ Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
mesh.vertices[k*3] = knot->points[knot->triangles[k]*3]; mesh.vertices[k*3] = knot->points[knot->triangles[k]*3];
mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1]; mesh.vertices[k*3 + 1] = knot->points[knot->triangles[k]*3 + 1];
mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2]; mesh.vertices[k*3 + 2] = knot->points[knot->triangles[k]*3 + 2];
mesh.normals[k*3] = knot->normals[knot->triangles[k]*3]; mesh.normals[k*3] = knot->normals[knot->triangles[k]*3];
mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1]; mesh.normals[k*3 + 1] = knot->normals[knot->triangles[k]*3 + 1];
mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2]; mesh.normals[k*3 + 2] = knot->normals[knot->triangles[k]*3 + 2];
mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2]; mesh.texcoords[k*2] = knot->tcoords[knot->triangles[k]*2];
mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1]; mesh.texcoords[k*2 + 1] = knot->tcoords[knot->triangles[k]*2 + 1];
} }
par_shapes_free_mesh(knot); par_shapes_free_mesh(knot);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1407,7 +1411,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
} }
free(pixels); free(pixels);
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
@ -1767,9 +1771,9 @@ Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize)
free(mapTexcoords); free(mapTexcoords);
free(cubicmapPixels); // Free image pixel data free(cubicmapPixels); // Free image pixel data
// Upload vertex data to GPU (static mesh) // Upload vertex data to GPU (static mesh)
rlLoadMesh(&mesh, false); rlLoadMesh(&mesh, false);
return mesh; return mesh;
} }
@ -1817,7 +1821,7 @@ void UnloadMaterial(Material material)
// Unload loaded texture maps (avoid unloading default texture, managed by raylib) // Unload loaded texture maps (avoid unloading default texture, managed by raylib)
for (int i = 0; i < MAX_MATERIAL_MAPS; i++) for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
{ {
if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id); if (material.maps[i].texture.id != GetTextureDefault().id) rlDeleteTextures(material.maps[i].texture.id);
} }
} }
@ -1838,7 +1842,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
Matrix matScale = MatrixScale(scale.x, scale.y, scale.z); Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD); Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z); Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation); Matrix matTransform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
// Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform) // Combine model transformation matrix (model.transform) with matrix generated by function parameters (matTransform)
@ -2033,7 +2037,7 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
if (distance < sphereRadius) collisionDistance = vector + sqrtf(d); if (distance < sphereRadius) collisionDistance = vector + sqrtf(d);
else collisionDistance = vector - sqrtf(d); else collisionDistance = vector - sqrtf(d);
// Calculate collision point // Calculate collision point
Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance)); Vector3 cPoint = Vector3Add(ray.position, Vector3Scale(ray.direction, collisionDistance));
@ -2093,7 +2097,7 @@ RayHitInfo GetCollisionRayModel(Ray ray, Model *model)
b = vertdata[i*3 + 1]; b = vertdata[i*3 + 1];
c = vertdata[i*3 + 2]; c = vertdata[i*3 + 2];
} }
a = Vector3Transform(a, model->transform); a = Vector3Transform(a, model->transform);
b = Vector3Transform(b, model->transform); b = Vector3Transform(b, model->transform);
c = Vector3Transform(c, model->transform); c = Vector3Transform(c, model->transform);
@ -2227,7 +2231,7 @@ void MeshTangents(Mesh *mesh)
{ {
if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float)); if (mesh->tangents == NULL) mesh->tangents = (float *)malloc(mesh->vertexCount*4*sizeof(float));
else TraceLog(LOG_WARNING, "Mesh tangents already exist"); else TraceLog(LOG_WARNING, "Mesh tangents already exist");
Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); Vector3 *tan1 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3));
Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3)); Vector3 *tan2 = (Vector3 *)malloc(mesh->vertexCount*sizeof(Vector3));
@ -2256,11 +2260,11 @@ void MeshTangents(Mesh *mesh)
float t2 = uv3.y - uv1.y; float t2 = uv3.y - uv1.y;
float div = s1*t2 - s2*t1; float div = s1*t2 - s2*t1;
float r = (div == 0.0f) ? 0.0f : 1.0f/div; float r = (div == 0.0f)? 0.0f : 1.0f/div;
Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r }; Vector3 sdir = { (t2*x1 - t1*x2)*r, (t2*y1 - t1*y2)*r, (t2*z1 - t1*z2)*r };
Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r }; Vector3 tdir = { (s1*x2 - s2*x1)*r, (s1*y2 - s2*y1)*r, (s1*z2 - s2*z1)*r };
tan1[i + 0] = sdir; tan1[i + 0] = sdir;
tan1[i + 1] = sdir; tan1[i + 1] = sdir;
tan1[i + 2] = sdir; tan1[i + 2] = sdir;
@ -2289,13 +2293,13 @@ void MeshTangents(Mesh *mesh)
mesh->tangents[i*4 + 0] = tangent.x; mesh->tangents[i*4 + 0] = tangent.x;
mesh->tangents[i*4 + 1] = tangent.y; mesh->tangents[i*4 + 1] = tangent.y;
mesh->tangents[i*4 + 2] = tangent.z; mesh->tangents[i*4 + 2] = tangent.z;
mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f) ? -1.0f : 1.0f; mesh->tangents[i*4 + 3] = (Vector3DotProduct(Vector3CrossProduct(normal, tangent), tan2[i]) < 0.0f)? -1.0f : 1.0f;
#endif #endif
} }
free(tan1); free(tan1);
free(tan2); free(tan2);
TraceLog(LOG_INFO, "Tangents computed for mesh"); TraceLog(LOG_INFO, "Tangents computed for mesh");
} }
@ -2307,8 +2311,8 @@ void MeshBinormals(Mesh *mesh)
Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] }; Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] }; Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
float tangentW = mesh->tangents[i*4 + 3]; float tangentW = mesh->tangents[i*4 + 3];
// TODO: Register computed binormal in mesh->binormal ? // TODO: Register computed binormal in mesh->binormal?
// Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW); // Vector3 binormal = Vector3Multiply(Vector3CrossProduct(normal, tangent), tangentW);
} }
} }
@ -2635,7 +2639,7 @@ static Material LoadMTL(const char *fileName)
} break; } break;
case 'e': // Ke float float float Emmisive color (RGB) case 'e': // Ke float float float Emmisive color (RGB)
{ {
// TODO: Support Ke ? // TODO: Support Ke?
} break; } break;
default: break; default: break;
} }
@ -2736,25 +2740,25 @@ static Material LoadMTL(const char *fileName)
static Mesh LoadIQM(const char *fileName) static Mesh LoadIQM(const char *fileName)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
// TODO: Load IQM file // TODO: Load IQM file
return mesh; return mesh;
} }
#endif #endif
#if defined(SUPPORT_FILEFORMAT_GLTF) #if defined(SUPPORT_FILEFORMAT_GLTF)
// Load GLTF mesh data // Load glTF mesh data
static Mesh LoadGLTF(const char *fileName) static Mesh LoadGLTF(const char *fileName)
{ {
Mesh mesh = { 0 }; Mesh mesh = { 0 };
// GLTF file loading // glTF file loading
FILE *gltfFile = fopen(fileName, "rb"); FILE *gltfFile = fopen(fileName, "rb");
if (gltfFile == NULL) if (gltfFile == NULL)
{ {
TraceLog(LOG_WARNING, "[%s] GLTF file could not be opened", fileName); TraceLog(LOG_WARNING, "[%s] glTF file could not be opened", fileName);
return mesh; return mesh;
} }
@ -2764,25 +2768,31 @@ static Mesh LoadGLTF(const char *fileName)
void *buffer = malloc(size); void *buffer = malloc(size);
fread(buffer, size, 1, gltfFile); fread(buffer, size, 1, gltfFile);
fclose(gltfFile); fclose(gltfFile);
// GLTF data loading // glTF data loading
cgltf_options options = {0}; cgltf_options options = {0};
cgltf_data data; cgltf_data data;
cgltf_result result = cgltf_parse(&options, buffer, size, &data); cgltf_result result = cgltf_parse(&options, buffer, size, &data);
free(buffer);
if (result == cgltf_result_success) if (result == cgltf_result_success)
{ {
printf("Type: %u\n", data.file_type); printf("Type: %u\n", data.file_type);
printf("Version: %d\n", data.version); printf("Version: %d\n", data.version);
printf("Meshes: %lu\n", data.meshes_count); printf("Meshes: %lu\n", data.meshes_count);
}
else TraceLog(LOG_WARNING, "[%s] GLTF data could not be loaded", fileName);
free(buffer); // TODO: Process glTF data and map to mesh
cgltf_free(&data);
// NOTE: data.buffers[] and data.images[] should be loaded
return mesh; // using buffers[n].uri and images[n].uri... or use cgltf_load_buffers(&options, data, fileName);
cgltf_free(&data);
}
else TraceLog(LOG_WARNING, "[%s] glTF data could not be loaded", fileName);
return mesh;
} }
#endif #endif

View File

@ -712,11 +712,13 @@ void SetAudioBufferPitch(AudioBuffer *audioBuffer, float pitch)
return; return;
} }
audioBuffer->pitch = pitch; float pitchMul = pitch / audioBuffer->pitch;
// Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches // Pitching is just an adjustment of the sample rate. Note that this changes the duration of the sound - higher pitches
// will make the sound faster; lower pitches make it slower. // will make the sound faster; lower pitches make it slower.
mal_uint32 newOutputSampleRate = (mal_uint32)((((float)audioBuffer->dsp.src.config.sampleRateOut / (float)audioBuffer->dsp.src.config.sampleRateIn) / pitch) * audioBuffer->dsp.src.config.sampleRateIn); mal_uint32 newOutputSampleRate = (mal_uint32)((float)audioBuffer->dsp.src.config.sampleRateOut / pitchMul);
audioBuffer->pitch *= (float)audioBuffer->dsp.src.config.sampleRateOut / newOutputSampleRate;
mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate); mal_dsp_set_output_sample_rate(&audioBuffer->dsp, newOutputSampleRate);
} }
@ -767,7 +769,11 @@ Wave LoadWave(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName); if (IsFileExtension(fileName, ".wav")) wave = LoadWAV(fileName);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName); else if (IsFileExtension(fileName, ".ogg")) wave = LoadOGG(fileName);
#endif #endif
@ -830,7 +836,7 @@ Sound LoadSoundFromWave(Wave wave)
// //
// I have decided on the first option because it offloads work required for the format conversion to the to the loading stage. // I have decided on the first option because it offloads work required for the format conversion to the to the loading stage.
// The downside to this is that it uses more memory if the original sound is u8 or s16. // The downside to this is that it uses more memory if the original sound is u8 or s16.
mal_format formatIn = ((wave.sampleSize == 8) ? mal_format_u8 : ((wave.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((wave.sampleSize == 8)? mal_format_u8 : ((wave.sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_uint32 frameCountIn = wave.sampleCount/wave.channels; mal_uint32 frameCountIn = wave.sampleCount/wave.channels;
mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn); mal_uint32 frameCount = (mal_uint32)mal_convert_frames(NULL, DEVICE_FORMAT, DEVICE_CHANNELS, DEVICE_SAMPLE_RATE, NULL, formatIn, wave.channels, wave.sampleRate, frameCountIn);
@ -887,7 +893,11 @@ void ExportWave(Wave wave, const char *fileName)
{ {
bool success = false; bool success = false;
#if defined(SUPPORT_FILEFORMAT_WAV)
if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName); if (IsFileExtension(fileName, ".wav")) success = SaveWAV(wave, fileName);
#else
if (false) {}
#endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
// Export raw sample data (without header) // Export raw sample data (without header)
@ -938,7 +948,7 @@ void ExportWaveAsCode(Wave wave, const char *fileName)
// Write byte data as hexadecimal text // Write byte data as hexadecimal text
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
fclose(txtFile); fclose(txtFile);
@ -989,8 +999,8 @@ void SetSoundPitch(Sound sound, float pitch)
// Convert wave data to desired format // Convert wave data to desired format
void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
{ {
mal_format formatIn = ((wave->sampleSize == 8) ? mal_format_u8 : ((wave->sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((wave->sampleSize == 8)? mal_format_u8 : ((wave->sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_format formatOut = (( sampleSize == 8) ? mal_format_u8 : (( sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatOut = (( sampleSize == 8)? mal_format_u8 : (( sampleSize == 16)? mal_format_s16 : mal_format_f32));
mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so. mal_uint32 frameCountIn = wave->sampleCount; // Is wave->sampleCount actually the frame count? That terminology needs to change, if so.
@ -1087,6 +1097,7 @@ Music LoadMusicStream(const char *fileName)
Music music = (MusicData *)malloc(sizeof(MusicData)); Music music = (MusicData *)malloc(sizeof(MusicData));
bool musicLoaded = true; bool musicLoaded = true;
#if defined(SUPPORT_FILEFORMAT_OGG)
if (IsFileExtension(fileName, ".ogg")) if (IsFileExtension(fileName, ".ogg"))
{ {
// Open ogg audio stream // Open ogg audio stream
@ -1110,6 +1121,9 @@ Music LoadMusicStream(const char *fileName)
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required); TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
} }
} }
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (IsFileExtension(fileName, ".flac")) else if (IsFileExtension(fileName, ".flac"))
{ {
@ -1202,7 +1216,11 @@ Music LoadMusicStream(const char *fileName)
if (!musicLoaded) if (!musicLoaded)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
#endif #endif
@ -1229,10 +1247,14 @@ Music LoadMusicStream(const char *fileName)
void UnloadMusicStream(Music music) void UnloadMusicStream(Music music)
{ {
if (music == NULL) return; if (music == NULL) return;
CloseAudioStream(music->stream); CloseAudioStream(music->stream);
#if defined(SUPPORT_FILEFORMAT_OGG)
if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg); if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close(music->ctxOgg);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac); else if (music->ctxType == MUSIC_AUDIO_FLAC) drflac_free(music->ctxFlac);
#endif #endif
@ -1291,13 +1313,15 @@ void ResumeMusicStream(Music music)
void StopMusicStream(Music music) void StopMusicStream(Music music)
{ {
if (music == NULL) return; if (music == NULL) return;
StopAudioStream(music->stream); StopAudioStream(music->stream);
// Restart music context // Restart music context
switch (music->ctxType) switch (music->ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break; case MUSIC_AUDIO_FLAC: /* TODO: Restart FLAC context */ break;
#endif #endif
@ -1321,7 +1345,7 @@ void StopMusicStream(Music music)
void UpdateMusicStream(Music music) void UpdateMusicStream(Music music)
{ {
if (music == NULL) return; if (music == NULL) return;
bool streamEnding = false; bool streamEnding = false;
unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2; unsigned int subBufferSizeInFrames = ((AudioBuffer *)music->stream.audioBuffer)->bufferSizeInFrames/2;
@ -1339,12 +1363,14 @@ void UpdateMusicStream(Music music)
// TODO: Really don't like ctxType thingy... // TODO: Really don't like ctxType thingy...
switch (music->ctxType) switch (music->ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: case MUSIC_AUDIO_OGG:
{ {
// NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!) // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount); stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount);
} break; } break;
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_FLAC)
case MUSIC_AUDIO_FLAC: case MUSIC_AUDIO_FLAC:
{ {
@ -1369,21 +1395,21 @@ void UpdateMusicStream(Music music)
} break; } break;
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MOD) #if defined(SUPPORT_FILEFORMAT_MOD)
case MUSIC_MODULE_MOD: case MUSIC_MODULE_MOD:
{ {
// NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2 // NOTE: 3rd parameter (nbsample) specify the number of stereo 16bits samples you want, so sampleCount/2
jar_mod_fillbuffer(&music->ctxMod, (short *)pcm, samplesCount/2, 0); jar_mod_fillbuffer(&music->ctxMod, (short *)pcm, samplesCount/2, 0);
} break; } break;
#endif #endif
default: break; default: break;
} }
UpdateAudioStream(music->stream, pcm, samplesCount); UpdateAudioStream(music->stream, pcm, samplesCount);
if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD)) if ((music->ctxType == MUSIC_MODULE_XM) || (music->ctxType == MUSIC_MODULE_MOD))
{ {
if (samplesCount > 1) music->samplesLeft -= samplesCount/2; if (samplesCount > 1) music->samplesLeft -= samplesCount/2;
else music->samplesLeft -= samplesCount; else music->samplesLeft -= samplesCount;
} }
else music->samplesLeft -= samplesCount; else music->samplesLeft -= samplesCount;
@ -1451,7 +1477,7 @@ void SetMusicLoopCount(Music music, int count)
float GetMusicTimeLength(Music music) float GetMusicTimeLength(Music music)
{ {
float totalSeconds = 0.0f; float totalSeconds = 0.0f;
if (music != NULL) totalSeconds = (float)music->totalSamples/(music->stream.sampleRate*music->stream.channels); if (music != NULL) totalSeconds = (float)music->totalSamples/(music->stream.sampleRate*music->stream.channels);
return totalSeconds; return totalSeconds;
@ -1487,7 +1513,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
stream.channels = 1; // Fallback to mono channel stream.channels = 1; // Fallback to mono channel
} }
mal_format formatIn = ((stream.sampleSize == 8) ? mal_format_u8 : ((stream.sampleSize == 16) ? mal_format_s16 : mal_format_f32)); mal_format formatIn = ((stream.sampleSize == 8)? mal_format_u8 : ((stream.sampleSize == 16)? mal_format_s16 : mal_format_f32));
// The size of a streaming buffer must be at least double the size of a period. // The size of a streaming buffer must be at least double the size of a period.
unsigned int periodSize = device.bufferSizeInFrames/device.periods; unsigned int periodSize = device.bufferSizeInFrames/device.periods;
@ -1504,7 +1530,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
audioBuffer->looping = true; // Always loop for streaming buffers. audioBuffer->looping = true; // Always loop for streaming buffers.
stream.audioBuffer = audioBuffer; stream.audioBuffer = audioBuffer;
TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1)? "Mono" : "Stereo");
return stream; return stream;
} }
@ -1542,7 +1568,7 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
else else
{ {
// Just update whichever sub-buffer is processed. // Just update whichever sub-buffer is processed.
subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0]) ? 0 : 1; subBufferToUpdate = (audioBuffer->isSubBufferProcessed[0])? 0 : 1;
} }
mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2; mal_uint32 subBufferSizeInFrames = audioBuffer->bufferSizeInFrames/2;
@ -1745,7 +1771,7 @@ static Wave LoadWAV(const char *fileName)
// NOTE: subChunkSize comes in bytes, we need to translate it to number of samples // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels; wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
} }
} }
} }
@ -1866,7 +1892,7 @@ static Wave LoadOGG(const char *fileName)
TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg); TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg);
TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); TraceLog(LOG_INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
stb_vorbis_close(oggFile); stb_vorbis_close(oggFile);
} }
@ -1893,7 +1919,7 @@ static Wave LoadFLAC(const char *fileName)
if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels); if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels);
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
return wave; return wave;
} }
@ -1920,7 +1946,7 @@ static Wave LoadMP3(const char *fileName)
if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels); if (wave.channels > 2) TraceLog(LOG_WARNING, "[%s] MP3 channels number (%i) not supported", fileName, wave.channels);
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName); if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] MP3 data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo"); else TraceLog(LOG_INFO, "[%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
return wave; return wave;
} }

View File

@ -356,7 +356,7 @@ typedef unsigned char byte;
LOC_MAP_PREFILTER, LOC_MAP_PREFILTER,
LOC_MAP_BRDF LOC_MAP_BRDF
} ShaderLocationIndex; } ShaderLocationIndex;
// Shader uniform data types // Shader uniform data types
typedef enum { typedef enum {
UNIFORM_FLOAT = 0, UNIFORM_FLOAT = 0,
@ -775,8 +775,8 @@ typedef struct DrawCall {
#endif #endif
"void main() \n" "void main() \n"
"{ \n" "{ \n"
" vec2 lensCenter = fragTexCoord.x < 0.5 ? leftLensCenter : rightLensCenter; \n" " vec2 lensCenter = fragTexCoord.x < 0.5? leftLensCenter : rightLensCenter; \n"
" vec2 screenCenter = fragTexCoord.x < 0.5 ? leftScreenCenter : rightScreenCenter; \n" " vec2 screenCenter = fragTexCoord.x < 0.5? leftScreenCenter : rightScreenCenter; \n"
" vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n" " vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n"
" float rSq = theta.x*theta.x + theta.y*theta.y; \n" " float rSq = theta.x*theta.x + theta.y*theta.y; \n"
" vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n" " vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n"
@ -993,14 +993,14 @@ void rlPushMatrix(void)
// Pop lattest inserted matrix from stack // Pop lattest inserted matrix from stack
void rlPopMatrix(void) void rlPopMatrix(void)
{ {
if (stackCounter > 0) if (stackCounter > 0)
{ {
Matrix mat = stack[stackCounter - 1]; Matrix mat = stack[stackCounter - 1];
*currentMatrix = mat; *currentMatrix = mat;
stackCounter--; stackCounter--;
} }
if ((stackCounter == 0) && (currentMatrixMode == RL_MODELVIEW)) if ((stackCounter == 0) && (currentMatrixMode == RL_MODELVIEW))
{ {
currentMatrix = &modelview; currentMatrix = &modelview;
@ -1136,12 +1136,12 @@ void rlEnd(void)
// TODO: System could be improved (a bit) just storing every draw alignment value // TODO: System could be improved (a bit) just storing every draw alignment value
// and adding it to vertexOffset on drawing... maybe in a future... // and adding it to vertexOffset on drawing... maybe in a future...
int vertexCount = draws[drawsCounter - 1].vertexCount; int vertexCount = draws[drawsCounter - 1].vertexCount;
int vertexToAlign = (vertexCount >= 4) ? vertexCount%4 : (4 - vertexCount%4); int vertexToAlign = (vertexCount >= 4)? vertexCount%4 : (4 - vertexCount%4);
for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1); for (int i = 0; i < vertexToAlign; i++) rlVertex3f(-1, -1, -1);
// Make sure vertexCount is the same for vertices, texcoords, colors and normals // Make sure vertexCount is the same for vertices, texcoords, colors and normals
// NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls
// Make sure colors count match vertex count // Make sure colors count match vertex count
if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].cCounter) if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].cCounter)
{ {
@ -1156,7 +1156,7 @@ void rlEnd(void)
vertexData[currentBuffer].cCounter++; vertexData[currentBuffer].cCounter++;
} }
} }
// Make sure texcoords count match vertex count // Make sure texcoords count match vertex count
if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].tcCounter) if (vertexData[currentBuffer].vCounter != vertexData[currentBuffer].tcCounter)
{ {
@ -1194,10 +1194,10 @@ void rlEnd(void)
void rlVertex3f(float x, float y, float z) void rlVertex3f(float x, float y, float z)
{ {
Vector3 vec = { x, y, z }; Vector3 vec = { x, y, z };
// Transform provided vector if required // Transform provided vector if required
if (useTransformMatrix) vec = Vector3Transform(vec, transformMatrix); if (useTransformMatrix) vec = Vector3Transform(vec, transformMatrix);
// Verify that MAX_BATCH_ELEMENTS limit not reached // Verify that MAX_BATCH_ELEMENTS limit not reached
if (vertexData[currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4)) if (vertexData[currentBuffer].vCounter < (MAX_BATCH_ELEMENTS*4))
{ {
@ -1233,7 +1233,7 @@ void rlTexCoord2f(float x, float y)
} }
// Define one vertex (normal) // Define one vertex (normal)
// NOTE: Normals limited to TRIANGLES only ? // NOTE: Normals limited to TRIANGLES only?
void rlNormal3f(float x, float y, float z) void rlNormal3f(float x, float y, float z)
{ {
// TODO: Normals usage... // TODO: Normals usage...
@ -1499,7 +1499,7 @@ void rlglInit(int width, int height)
//for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]); //for (int i = 0; i < numComp; i++) TraceLog(LOG_INFO, "Supported compressed format: 0x%x", format[i]);
// NOTE: We don't need that much data on screen... right now... // NOTE: We don't need that much data on screen... right now...
// TODO: Automatize extensions loading using rlLoadExtensions() and GLAD // TODO: Automatize extensions loading using rlLoadExtensions() and GLAD
// Actually, when rlglInit() is called in InitWindow() in core.c, // Actually, when rlglInit() is called in InitWindow() in core.c,
// OpenGL required extensions have already been loaded (PLATFORM_DESKTOP) // OpenGL required extensions have already been loaded (PLATFORM_DESKTOP)
@ -1512,7 +1512,7 @@ void rlglInit(int width, int height)
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default // NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
vaoSupported = true; vaoSupported = true;
// Multiple texture extensions supported by default // Multiple texture extensions supported by default
texNPOTSupported = true; texNPOTSupported = true;
texFloatSupported = true; texFloatSupported = true;
@ -1585,11 +1585,11 @@ void rlglInit(int width, int height)
// Check texture float support // Check texture float support
if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true; if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) texFloatSupported = true;
// Check depth texture support // Check depth texture support
if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) || if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) texDepthSupported = true; (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) texDepthSupported = true;
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) maxDepthBits = 24; if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) maxDepthBits = 24;
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) maxDepthBits = 32; if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) maxDepthBits = 32;
#endif #endif
@ -1648,8 +1648,8 @@ void rlglInit(int width, int height)
if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported"); if (debugMarkerSupported) TraceLog(LOG_INFO, "[EXTENSION] Debug Marker supported");
// Initialize buffers, default shaders and default textures // Initialize buffers, default shaders and default textures
//---------------------------------------------------------- //----------------------------------------------------------
@ -1666,7 +1666,7 @@ void rlglInit(int width, int height)
// Init default vertex arrays buffers // Init default vertex arrays buffers
LoadBuffersDefault(); LoadBuffersDefault();
// Init transformations matrix accumulator // Init transformations matrix accumulator
transformMatrix = MatrixIdentity(); transformMatrix = MatrixIdentity();
@ -1995,9 +1995,9 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB
{ {
unsigned int id = 0; unsigned int id = 0;
unsigned int glInternalFormat = GL_DEPTH_COMPONENT16; unsigned int glInternalFormat = GL_DEPTH_COMPONENT16;
if ((bits != 16) && (bits != 24) && (bits != 32)) bits = 16; if ((bits != 16) && (bits != 24) && (bits != 32)) bits = 16;
if (bits == 24) if (bits == 24)
{ {
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
@ -2006,7 +2006,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB
if (maxDepthBits >= 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; if (maxDepthBits >= 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES;
#endif #endif
} }
if (bits == 32) if (bits == 32)
{ {
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
@ -2021,7 +2021,7 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -2036,10 +2036,10 @@ unsigned int rlLoadTextureDepth(int width, int height, int bits, bool useRenderB
glGenRenderbuffers(1, &id); glGenRenderbuffers(1, &id);
glBindRenderbuffer(GL_RENDERBUFFER, id); glBindRenderbuffer(GL_RENDERBUFFER, id);
glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height); glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
return id; return id;
} }
@ -2053,7 +2053,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
glGenTextures(1, &cubemapId); glGenTextures(1, &cubemapId);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapId);
unsigned int glInternalFormat, glFormat, glType; unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
@ -2084,7 +2084,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
#endif #endif
} }
} }
// Set cubemap texture sampling parameters // Set cubemap texture sampling parameters
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -2178,14 +2178,14 @@ void rlUnloadTexture(unsigned int id)
RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depthBits, bool useDepthTexture) RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depthBits, bool useDepthTexture)
{ {
RenderTexture2D target = { 0 }; RenderTexture2D target = { 0 };
if (useDepthTexture && texDepthSupported) target.depthTexture = true; if (useDepthTexture && texDepthSupported) target.depthTexture = true;
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Create the framebuffer object // Create the framebuffer object
glGenFramebuffers(1, &target.id); glGenFramebuffers(1, &target.id);
glBindFramebuffer(GL_FRAMEBUFFER, target.id); glBindFramebuffer(GL_FRAMEBUFFER, target.id);
// Create fbo color texture attachment // Create fbo color texture attachment
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
if ((format != -1) && (format < COMPRESSED_DXT1_RGB)) if ((format != -1) && (format < COMPRESSED_DXT1_RGB))
@ -2198,7 +2198,7 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth
target.texture.mipmaps = 1; target.texture.mipmaps = 1;
} }
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
// Create fbo depth renderbuffer/texture // Create fbo depth renderbuffer/texture
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
if (depthBits > 0) if (depthBits > 0)
@ -2206,11 +2206,11 @@ RenderTexture2D rlLoadRenderTexture(int width, int height, int format, int depth
target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture); target.depth.id = rlLoadTextureDepth(width, height, depthBits, !useDepthTexture);
target.depth.width = width; target.depth.width = width;
target.depth.height = height; target.depth.height = height;
target.depth.format = 19; //DEPTH_COMPONENT_24BIT ? target.depth.format = 19; //DEPTH_COMPONENT_24BIT?
target.depth.mipmaps = 1; target.depth.mipmaps = 1;
} }
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
// Attach color texture and depth renderbuffer to FBO // Attach color texture and depth renderbuffer to FBO
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
rlRenderTextureAttach(target, target.texture.id, 0); // COLOR attachment rlRenderTextureAttach(target, target.texture.id, 0); // COLOR attachment
@ -2235,12 +2235,12 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy
glBindFramebuffer(GL_FRAMEBUFFER, target.id); glBindFramebuffer(GL_FRAMEBUFFER, target.id);
if (attachType == 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); if (attachType == 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0);
else if (attachType == 1) else if (attachType == 1)
{ {
if (target.depthTexture) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, id, 0); if (target.depthTexture) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, id, 0);
else glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, id); else glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, id);
} }
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
@ -2248,7 +2248,7 @@ void rlRenderTextureAttach(RenderTexture2D target, unsigned int id, int attachTy
bool rlRenderTextureComplete(RenderTexture target) bool rlRenderTextureComplete(RenderTexture target)
{ {
glBindFramebuffer(GL_FRAMEBUFFER, target.id); glBindFramebuffer(GL_FRAMEBUFFER, target.id);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) if (status != GL_FRAMEBUFFER_COMPLETE)
@ -2264,9 +2264,9 @@ bool rlRenderTextureComplete(RenderTexture target)
default: break; default: break;
} }
} }
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
return (status == GL_FRAMEBUFFER_COMPLETE); return (status == GL_FRAMEBUFFER_COMPLETE);
} }
@ -2349,7 +2349,7 @@ void rlLoadMesh(Mesh *mesh, bool dynamic)
TraceLog(LOG_WARNING, "Trying to re-load an already loaded mesh"); TraceLog(LOG_WARNING, "Trying to re-load an already loaded mesh");
return; return;
} }
mesh->vaoId = 0; // Vertex Array Object mesh->vaoId = 0; // Vertex Array Object
mesh->vboId[0] = 0; // Vertex positions VBO mesh->vboId[0] = 0; // Vertex positions VBO
mesh->vboId[1] = 0; // Vertex texcoords VBO mesh->vboId[1] = 0; // Vertex texcoords VBO
@ -2766,7 +2766,7 @@ unsigned char *rlReadScreenPixels(int width, int height)
for (int x = 0; x < (width*4); x++) for (int x = 0; x < (width*4); x++)
{ {
imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line
// Set alpha component value to 255 (no trasparent image retrieval) // 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! // 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; if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255;
@ -2822,7 +2822,7 @@ void *rlReadTexturePixels(Texture2D texture)
// We are using Option 1, just need to care for texture format on retrieval // We are using Option 1, just need to care for texture format on retrieval
// NOTE: This behaviour could be conditioned by graphic driver... // NOTE: This behaviour could be conditioned by graphic driver...
RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height, UNCOMPRESSED_R8G8B8A8, 16, false); RenderTexture2D fbo = rlLoadRenderTexture(texture.width, texture.height, UNCOMPRESSED_R8G8B8A8, 16, false);
glBindFramebuffer(GL_FRAMEBUFFER, fbo.id); glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
@ -2836,7 +2836,7 @@ void *rlReadTexturePixels(Texture2D texture)
// Get OpenGL internal formats and data type from our texture format // Get OpenGL internal formats and data type from our texture format
unsigned int glInternalFormat, glFormat, glType; unsigned int glInternalFormat, glFormat, glType;
rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType);
// NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture... // NOTE: We read data as RGBA because FBO texture is configured as RGBA, despite binding a RGB texture...
glReadPixels(0, 0, texture.width, texture.height, glFormat, glType, pixels); glReadPixels(0, 0, texture.width, texture.height, glFormat, glType, pixels);
@ -3064,7 +3064,7 @@ void SetShaderValueV(Shader shader, int uniformLoc, const void *value, int unifo
case UNIFORM_SAMPLER2D: glUniform1iv(uniformLoc, count, (int *)value); break; case UNIFORM_SAMPLER2D: glUniform1iv(uniformLoc, count, (int *)value); break;
default: TraceLog(LOG_WARNING, "Shader uniform could not be set data type not recognized"); default: TraceLog(LOG_WARNING, "Shader uniform could not be set data type not recognized");
} }
//glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set
#endif #endif
} }
@ -3143,7 +3143,7 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
// NOTE: Faces are stored as 32 bit floating point values // NOTE: Faces are stored as 32 bit floating point values
glGenTextures(1, &cubemap.id); glGenTextures(1, &cubemap.id);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id); glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
for (unsigned int i = 0; i < 6; i++) for (unsigned int i = 0; i < 6; i++)
{ {
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
@ -3151,7 +3151,7 @@ Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
if (texFloatSupported) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL); if (texFloatSupported) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL);
#endif #endif
} }
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
@ -3231,7 +3231,7 @@ Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
{ {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
} }
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
@ -3309,7 +3309,7 @@ Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
{ {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, size, size, 0, GL_RGB, GL_FLOAT, NULL);
} }
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
@ -3417,7 +3417,7 @@ Texture2D GenTextureBRDF(Shader shader, int size)
// Unbind framebuffer and textures // Unbind framebuffer and textures
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Unload framebuffer but keep color texture // Unload framebuffer but keep color texture
glDeleteRenderbuffers(1, &rbo); glDeleteRenderbuffers(1, &rbo);
glDeleteFramebuffers(1, &fbo); glDeleteFramebuffers(1, &fbo);
@ -3464,7 +3464,7 @@ void EndBlendMode(void)
void BeginScissorMode(int x, int y, int width, int height) void BeginScissorMode(int x, int y, int width, int height)
{ {
rlglDraw(); // Force drawing elements rlglDraw(); // Force drawing elements
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
glScissor(x, screenHeight - (y + height), width, height); glScissor(x, screenHeight - (y + height), width, height);
} }
@ -3473,7 +3473,7 @@ void BeginScissorMode(int x, int y, int width, int height)
void EndScissorMode(void) void EndScissorMode(void)
{ {
rlglDraw(); // Force drawing elements rlglDraw(); // Force drawing elements
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
@ -4050,7 +4050,7 @@ static void LoadBuffersDefault(void)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, vertexData[i].indices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*6*MAX_BATCH_ELEMENTS, vertexData[i].indices, GL_STATIC_DRAW);
#endif #endif
} }
TraceLog(LOG_INFO, "Internal buffers uploaded successfully (GPU)"); TraceLog(LOG_INFO, "Internal buffers uploaded successfully (GPU)");
// Unbind the current VAO // Unbind the current VAO
@ -4073,7 +4073,7 @@ static void UpdateBuffersDefault(void)
glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[0]); glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].vertices); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].vertices);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer
// Texture coordinates buffer // Texture coordinates buffer
glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[1]); glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[1]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].texcoords); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].texcoords);
@ -4083,13 +4083,13 @@ static void UpdateBuffersDefault(void)
glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[2]); glBindBuffer(GL_ARRAY_BUFFER, vertexData[currentBuffer].vboId[2]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].colors); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*vertexData[currentBuffer].vCounter, vertexData[currentBuffer].colors);
//glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_BATCH_ELEMENTS, vertexData[currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer
// NOTE: glMapBuffer() causes sync issue. // NOTE: glMapBuffer() causes sync issue.
// If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job. // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job.
// To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer(). // To avoid waiting (idle), you can call first glBufferData() with NULL pointer before glMapBuffer().
// If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new // If you do that, the previous data in PBO will be discarded and glMapBuffer() returns a new
// allocated pointer immediately even if GPU is still working with the previous data. // allocated pointer immediately even if GPU is still working with the previous data.
// Another option: map the buffer object into client's memory // Another option: map the buffer object into client's memory
// Probably this code could be moved somewhere else... // Probably this code could be moved somewhere else...
// vertexData[currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); // vertexData[currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
@ -4135,7 +4135,7 @@ static void DrawBuffersDefault(void)
glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0); glUniform1i(currentShader.locs[LOC_MAP_DIFFUSE], 0);
// NOTE: Additional map textures not considered for default buffers drawing // NOTE: Additional map textures not considered for default buffers drawing
int vertexOffset = 0; int vertexOffset = 0;
if (vaoSupported) glBindVertexArray(vertexData[currentBuffer].vaoId); if (vaoSupported) glBindVertexArray(vertexData[currentBuffer].vaoId);
@ -4160,7 +4160,7 @@ static void DrawBuffersDefault(void)
} }
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
for (int i = 0; i < drawsCounter; i++) for (int i = 0; i < drawsCounter; i++)
{ {
glBindTexture(GL_TEXTURE_2D, draws[i].textureId); glBindTexture(GL_TEXTURE_2D, draws[i].textureId);
@ -4170,7 +4170,7 @@ static void DrawBuffersDefault(void)
{ {
#if defined(GRAPHICS_API_OPENGL_33) #if defined(GRAPHICS_API_OPENGL_33)
// We need to define the number of indices to be processed: quadsCount*6 // We need to define the number of indices to be processed: quadsCount*6
// NOTE: The final parameter tells the GPU the offset in bytes from the // 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 // start of the index buffer to the location of the first index to process
glDrawElements(GL_TRIANGLES, draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6)); glDrawElements(GL_TRIANGLES, draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(sizeof(GLuint)*vertexOffset/4*6));
#elif defined(GRAPHICS_API_OPENGL_ES2) #elif defined(GRAPHICS_API_OPENGL_ES2)
@ -4216,7 +4216,7 @@ static void DrawBuffersDefault(void)
} }
drawsCounter = 1; drawsCounter = 1;
// Change to next buffer in the list // Change to next buffer in the list
currentBuffer++; currentBuffer++;
if (currentBuffer >= MAX_BATCH_BUFFERING) currentBuffer = 0; if (currentBuffer >= MAX_BATCH_BUFFERING) currentBuffer = 0;
@ -4369,14 +4369,14 @@ static void GenDrawCube(void)
static VrStereoConfig SetStereoConfig(VrDeviceInfo hmd, Shader distortion) static VrStereoConfig SetStereoConfig(VrDeviceInfo hmd, Shader distortion)
{ {
VrStereoConfig config = { 0 }; VrStereoConfig config = { 0 };
// Initialize framebuffer and textures for stereo rendering // Initialize framebuffer and textures for stereo rendering
// NOTE: Screen size should match HMD aspect ratio // NOTE: Screen size should match HMD aspect ratio
config.stereoFbo = rlLoadRenderTexture(screenWidth, screenHeight, UNCOMPRESSED_R8G8B8A8, 24, false); config.stereoFbo = rlLoadRenderTexture(screenWidth, screenHeight, UNCOMPRESSED_R8G8B8A8, 24, false);
// Assign distortion shader // Assign distortion shader
config.distortionShader = distortion; config.distortionShader = distortion;
// Compute aspect ratio // Compute aspect ratio
float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution; float aspect = ((float)hmd.hResolution*0.5f)/(float)hmd.vResolution;
@ -4442,7 +4442,7 @@ static VrStereoConfig SetStereoConfig(VrDeviceInfo hmd, Shader distortion)
SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, UNIFORM_VEC4); SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "hmdWarpParam"), hmd.lensDistortionValues, UNIFORM_VEC4);
SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, UNIFORM_VEC4); SetShaderValue(config.distortionShader, GetShaderLocation(config.distortionShader, "chromaAbParam"), hmd.chromaAbCorrection, UNIFORM_VEC4);
#endif #endif
return config; return config;
} }

View File

@ -132,7 +132,7 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
rlPushMatrix(); rlPushMatrix();
rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f); rlTranslatef((float)startPos.x, (float)startPos.y, 0.0f);
rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f); rlRotatef(RAD2DEG*angle, 0.0f, 0.0f, 1.0f);
rlTranslatef(0, (thick > 1.0f) ? -thick/2.0f : -1.0f, 0.0f); rlTranslatef(0, (thick > 1.0f)? -thick/2.0f : -1.0f, 0.0f);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
@ -143,7 +143,7 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(0.0f, thick); rlVertex2f(0.0f, thick);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(d, thick); rlVertex2f(d, thick);
@ -187,7 +187,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle, Color color) void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle, Color color)
{ {
#define CIRCLE_SECTOR_LENGTH 10 #define CIRCLE_SECTOR_LENGTH 10
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(4*((360/CIRCLE_SECTOR_LENGTH)/2))) rlglDraw(); if (rlCheckBufferLimit(4*((360/CIRCLE_SECTOR_LENGTH)/2))) rlglDraw();
@ -307,10 +307,10 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height); rlTexCoord2f(recTexShapes.x/texShapes.width, recTexShapes.y/texShapes.height);
rlVertex2f(0.0f, 0.0f); rlVertex2f(0.0f, 0.0f);
rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlTexCoord2f(recTexShapes.x/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(0.0f, rec.height); rlVertex2f(0.0f, rec.height);
rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height); rlTexCoord2f((recTexShapes.x + recTexShapes.width)/texShapes.width, (recTexShapes.y + recTexShapes.height)/texShapes.height);
rlVertex2f(rec.width, rec.height); rlVertex2f(rec.width, rec.height);
@ -644,7 +644,7 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
if (dy <= (rec.height/2.0f)) { return true; } if (dy <= (rec.height/2.0f)) { return true; }
float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) + float cornerDistanceSq = (dx - rec.width/2.0f)*(dx - rec.width/2.0f) +
(dy - rec.height/2.0f)*(dy - rec.height/2.0f); (dy - rec.height/2.0f)*(dy - rec.height/2.0f);
return (cornerDistanceSq <= (radius*radius)); return (cornerDistanceSq <= (radius*radius));
} }
@ -742,7 +742,7 @@ static Texture2D GetShapesTexture(void)
recTexShapes = (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }; recTexShapes = (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 };
#else #else
texShapes = GetTextureDefault(); // Use default white texture texShapes = GetTextureDefault(); // Use default white texture
recTexShapes = { 0.0f, 0.0f, 1.0f, 1.0f }; recTexShapes = (Rectangle){ 0.0f, 0.0f, 1.0f, 1.0f };
#endif #endif
} }

View File

@ -306,9 +306,10 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
Font font = { 0 }; Font font = { 0 };
font.baseSize = fontSize; font.baseSize = fontSize;
font.charsCount = (charsCount > 0) ? charsCount : 95; font.charsCount = (charsCount > 0)? charsCount : 95;
font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT); font.chars = LoadFontData(fileName, font.baseSize, fontChars, font.charsCount, FONT_DEFAULT);
#if defined(SUPPORT_FILEFORMAT_TTF)
if (font.chars != NULL) if (font.chars != NULL)
{ {
Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0); Image atlas = GenImageFontAtlas(font.chars, font.charsCount, font.baseSize, 2, 0);
@ -316,6 +317,9 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
UnloadImage(atlas); UnloadImage(atlas);
} }
else font = GetFontDefault(); else font = GetFontDefault();
#else
font = GetFontDefault();
#endif
return font; return font;
} }
@ -426,6 +430,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
spriteFont.chars[i].offsetX = 0; spriteFont.chars[i].offsetX = 0;
spriteFont.chars[i].offsetY = 0; spriteFont.chars[i].offsetY = 0;
spriteFont.chars[i].advanceX = 0; spriteFont.chars[i].advanceX = 0;
spriteFont.chars[i].data = NULL;
} }
spriteFont.baseSize = (int)spriteFont.chars[0].rec.height; spriteFont.baseSize = (int)spriteFont.chars[0].rec.height;
@ -449,6 +454,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
CharInfo *chars = NULL; CharInfo *chars = NULL;
#if defined(SUPPORT_FILEFORMAT_TTF)
// Load font data (including pixel data) from TTF file // Load font data (including pixel data) from TTF file
// NOTE: Loaded information should be enough to generate font image atlas, // NOTE: Loaded information should be enough to generate font image atlas,
// using any packaging method // using any packaging method
@ -478,7 +484,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(&fontInfo, &ascent, &descent, &lineGap);
// In case no chars count provided, default to 95 // In case no chars count provided, default to 95
charsCount = (charsCount > 0) ? charsCount : 95; charsCount = (charsCount > 0)? charsCount : 95;
// Fill fontChars in case not provided externally // Fill fontChars in case not provided externally
// NOTE: By default we fill charsCount consecutevely, starting at 32 (Space) // NOTE: By default we fill charsCount consecutevely, starting at 32 (Space)
@ -506,6 +512,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); if (type != FONT_SDF) chars[i].data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); else if (ch != 32) chars[i].data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else chars[i].data = NULL;
if (type == FONT_BITMAP) if (type == FONT_BITMAP)
{ {
@ -537,18 +544,22 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
if (genFontChars) free(fontChars); if (genFontChars) free(fontChars);
} }
else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName); else TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
#else
TraceLog(LOG_WARNING, "[%s] TTF support is disabled", fileName);
#endif
return chars; return chars;
} }
// Generate image font atlas using chars info // Generate image font atlas using chars info
// NOTE: Packing method: 0-Default, 1-Skyline // NOTE: Packing method: 0-Default, 1-Skyline
#if defined(SUPPORT_FILEFORMAT_TTF)
Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod) Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int padding, int packMethod)
{ {
Image atlas = { 0 }; Image atlas = { 0 };
// In case no chars count provided we suppose default of 95 // In case no chars count provided we suppose default of 95
charsCount = (charsCount > 0) ? charsCount : 95; charsCount = (charsCount > 0)? charsCount : 95;
// Calculate image size based on required pixel area // Calculate image size based on required pixel area
// NOTE 1: Image is forced to be squared and POT... very conservative! // NOTE 1: Image is forced to be squared and POT... very conservative!
@ -667,6 +678,7 @@ Image GenImageFontAtlas(CharInfo *chars, int charsCount, int fontSize, int paddi
return atlas; return atlas;
} }
#endif
// Unload Font from GPU memory (VRAM) // Unload Font from GPU memory (VRAM)
void UnloadFont(Font font) void UnloadFont(Font font)
@ -674,6 +686,11 @@ void UnloadFont(Font font)
// NOTE: Make sure spriteFont is not default font (fallback) // NOTE: Make sure spriteFont is not default font (fallback)
if (font.texture.id != GetFontDefault().texture.id) if (font.texture.id != GetFontDefault().texture.id)
{ {
for (int i = 0; i < font.charsCount; i++)
{
if(font.chars[i].data != NULL)
free(font.chars[i].data);
}
UnloadTexture(font.texture); UnloadTexture(font.texture);
free(font.chars); free(font.chars);
@ -780,14 +797,14 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
} }
// Draw text using font inside rectangle limits // Draw text using font inside rectangle limits
void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint) void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
{ {
DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE); DrawTextRecEx(font, text, rec, fontSize, spacing, wordWrap, tint, 0, 0, WHITE, WHITE);
} }
// Draw text using font inside rectangle limits with support for text selection // Draw text using font inside rectangle limits with support for text selection
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
int selectStart, int selectLength, Color selectText, Color selectBack) int selectStart, int selectLength, Color selectText, Color selectBack)
{ {
int length = strlen(text); int length = strlen(text);
int textOffsetX = 0; // Offset between characters int textOffsetX = 0; // Offset between characters
@ -803,12 +820,12 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
int state = wordWrap? MEASURE_STATE : DRAW_STATE; int state = wordWrap? MEASURE_STATE : DRAW_STATE;
int startLine = -1; // Index where to begin drawing (where a line begins) int startLine = -1; // Index where to begin drawing (where a line begins)
int endLine = -1; // Index where to stop drawing (where a line ends) int endLine = -1; // Index where to stop drawing (where a line ends)
for (int i = 0; i < length; i++) for (int i = 0; i < length; i++)
{ {
int glyphWidth = 0; int glyphWidth = 0;
letter = (unsigned char)text[i]; letter = (unsigned char)text[i];
if (letter != '\n') if (letter != '\n')
{ {
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK! if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK!
@ -826,41 +843,41 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
i++; i++;
} }
else index = GetGlyphIndex(font, (unsigned char)text[i]); else index = GetGlyphIndex(font, (unsigned char)text[i]);
glyphWidth = (font.chars[index].advanceX == 0)? glyphWidth = (font.chars[index].advanceX == 0)?
(int)(font.chars[index].rec.width*scaleFactor + spacing): (int)(font.chars[index].rec.width*scaleFactor + spacing):
(int)(font.chars[index].advanceX*scaleFactor + spacing); (int)(font.chars[index].advanceX*scaleFactor + spacing);
} }
// NOTE: When wordWrap is ON we first measure how much of the text we can draw // NOTE: When wordWrap is ON we first measure how much of the text we can draw
// before going outside of the `rec` container. We store this info inside // before going outside of the `rec` container. We store this info inside
// `startLine` and `endLine` then we change states, draw the text between those two // `startLine` and `endLine` then we change states, draw the text between those two
// variables then change states again and again recursively until the end of the text // variables then change states again and again recursively until the end of the text
// (or until we get outside of the container). // (or until we get outside of the container).
// When wordWrap is OFF we don't need the measure state so we go to the drawing // When wordWrap is OFF we don't need the measure state so we go to the drawing
// state immediately and begin drawing on the next line before we can get outside // state immediately and begin drawing on the next line before we can get outside
// the container. // the container.
if (state == MEASURE_STATE) if (state == MEASURE_STATE)
{ {
if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i; if ((letter == ' ') || (letter == '\t') || (letter == '\n')) endLine = i;
if ((textOffsetX + glyphWidth + 1) >= rec.width) if ((textOffsetX + glyphWidth + 1) >= rec.width)
{ {
endLine = (endLine < 1) ? i : endLine; endLine = (endLine < 1)? i : endLine;
if (i == endLine) endLine -= 1; if (i == endLine) endLine -= 1;
if ((startLine + 1) == endLine) endLine = i - 1; if ((startLine + 1) == endLine) endLine = i - 1;
state = !state; state = !state;
} }
else if ((i + 1) == length) else if ((i + 1) == length)
{ {
endLine = i; endLine = i;
state = !state; state = !state;
} }
else if (letter == '\n') else if (letter == '\n')
{ {
state = !state; state = !state;
} }
if (state == DRAW_STATE) if (state == DRAW_STATE)
{ {
textOffsetX = 0; textOffsetX = 0;
@ -868,8 +885,8 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
glyphWidth = 0; glyphWidth = 0;
} }
} }
else else
{ {
if (letter == '\n') if (letter == '\n')
{ {
@ -878,17 +895,17 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0; textOffsetX = 0;
} }
} }
else else
{ {
if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width)) if (!wordWrap && ((textOffsetX + glyphWidth + 1) >= rec.width))
{ {
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0; textOffsetX = 0;
} }
if ((textOffsetY + (int)((font.baseSize + font.baseSize/2)*scaleFactor)) > rec.height) break; if ((textOffsetY + (int)(font.baseSize*scaleFactor)) > rec.height) break;
//draw selected //draw selected
bool isGlyphSelected = false; bool isGlyphSelected = false;
if ((selectStart >= 0) && (i >= selectStart) && (i < (selectStart + selectLength))) if ((selectStart >= 0) && (i >= selectStart) && (i < (selectStart + selectLength)))
@ -897,7 +914,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
DrawRectangleRec(strec, selectBack); DrawRectangleRec(strec, selectBack);
isGlyphSelected = true; isGlyphSelected = true;
} }
//draw glyph //draw glyph
if ((letter != ' ') && (letter != '\t')) if ((letter != ' ') && (letter != '\t'))
{ {
@ -905,12 +922,12 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
(Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor, (Rectangle){ rec.x + textOffsetX + font.chars[index].offsetX*scaleFactor,
rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor, rec.y + textOffsetY + font.chars[index].offsetY*scaleFactor,
font.chars[index].rec.width*scaleFactor, font.chars[index].rec.width*scaleFactor,
font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, font.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f,
(!isGlyphSelected) ? tint : selectText); (!isGlyphSelected)? tint : selectText);
} }
} }
if (wordWrap && (i == endLine)) if (wordWrap && (i == endLine))
{ {
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor); textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
textOffsetX = 0; textOffsetX = 0;
@ -920,7 +937,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
state = !state; state = !state;
} }
} }
textOffsetX += glyphWidth; textOffsetX += glyphWidth;
} }
} }
@ -958,11 +975,11 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
unsigned char letter = 0; // Current character unsigned char letter = 0; // Current character
int index = 0; // Index position in sprite font int index = 0; // Index position in sprite font
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
lenCounter++; lenCounter++;
if (text[i] != '\n') if (text[i] != '\n')
{ {
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification
@ -1095,7 +1112,7 @@ const char *TextSubtext(const char *text, int position, int length)
const char *TextReplace(char *text, const char *replace, const char *by) const char *TextReplace(char *text, const char *replace, const char *by)
{ {
char *result; char *result;
char *insertPoint; // Next insert point char *insertPoint; // Next insert point
char *temp; // Temp pointer char *temp; // Temp pointer
int replaceLen; // Replace string length of (the string to remove) int replaceLen; // Replace string length of (the string to remove)
@ -1153,7 +1170,7 @@ const char *TextInsert(const char *text, const char *insert, int position)
for (int i = 0; i < position; i++) result[i] = text[i]; for (int i = 0; i < position; i++) result[i] = text[i];
for (int i = position; i < insertLen + position; i++) result[i] = insert[i]; for (int i = position; i < insertLen + position; i++) result[i] = insert[i];
for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i];
result[textLen + insertLen] = '\0'; // Make sure text string is valid! result[textLen + insertLen] = '\0'; // Make sure text string is valid!
return result; return result;
@ -1164,7 +1181,7 @@ const char *TextInsert(const char *text, const char *insert, int position)
const char *TextJoin(const char **textList, int count, const char *delimiter) const char *TextJoin(const char **textList, int count, const char *delimiter)
{ {
// TODO: Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH // TODO: Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(text, 0, MAX_TEXT_BUFFER_LENGTH); memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1187,9 +1204,9 @@ const char **TextSplit(const char *text, char delimiter, int *count)
// all used memory is static... it has some limitations: // all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT // 1. Maximum number of possible split strings is set by MAX_SUBSTRINGS_COUNT
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
#define MAX_SUBSTRINGS_COUNT 64 #define MAX_SUBSTRINGS_COUNT 64
static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL }; static const char *result[MAX_SUBSTRINGS_COUNT] = { NULL };
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
@ -1198,7 +1215,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
int counter = 1; int counter = 1;
// Count how many substrings we have on text and point to every one // Count how many substrings we have on text and point to every one
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++) for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
{ {
buffer[i] = text[i]; buffer[i] = text[i];
if (buffer[i] == '\0') break; if (buffer[i] == '\0') break;
@ -1207,7 +1224,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
buffer[i] = '\0'; // Set an end of string at this point buffer[i] = '\0'; // Set an end of string at this point
result[counter] = buffer + i + 1; result[counter] = buffer + i + 1;
counter++; counter++;
if (counter == MAX_SUBSTRINGS_COUNT) break; if (counter == MAX_SUBSTRINGS_COUNT) break;
} }
} }
@ -1229,11 +1246,11 @@ void TextAppend(char *text, const char *append, int *position)
int TextFindIndex(const char *text, const char *find) int TextFindIndex(const char *text, const char *find)
{ {
int position = -1; int position = -1;
char *ptr = strstr(text, find); char *ptr = strstr(text, find);
if (ptr != NULL) position = ptr - text; if (ptr != NULL) position = ptr - text;
return position; return position;
} }
@ -1304,10 +1321,10 @@ int TextToInteger(const char *text)
{ {
if ((text[i] > 47) && (text[i] < 58)) result += ((int)text[i] - 48)*units; if ((text[i] > 47) && (text[i] < 58)) result += ((int)text[i] - 48)*units;
else { result = -1; break; } else { result = -1; break; }
units *= 10; units *= 10;
} }
return result; return result;
} }
@ -1376,10 +1393,10 @@ static Font LoadBMFont(const char *fileName)
char *lastSlash = NULL; char *lastSlash = NULL;
lastSlash = strrchr(fileName, '/'); lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL) if (lastSlash == NULL)
{ {
lastSlash = strrchr(fileName, '\\'); lastSlash = strrchr(fileName, '\\');
} }
// NOTE: We need some extra space to avoid memory corruption on next allocations! // NOTE: We need some extra space to avoid memory corruption on next allocations!
texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4); texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4);
@ -1428,6 +1445,7 @@ static Font LoadBMFont(const char *fileName)
font.chars[i].offsetX = charOffsetX; font.chars[i].offsetX = charOffsetX;
font.chars[i].offsetY = charOffsetY; font.chars[i].offsetY = charOffsetY;
font.chars[i].advanceX = charAdvanceX; font.chars[i].advanceX = charAdvanceX;
font.chars[i].data = NULL;
} }
fclose(fntFile); fclose(fntFile);

View File

@ -182,7 +182,11 @@ Image LoadImage(const char *fileName)
{ {
Image image = { 0 }; Image image = { 0 };
#if defined(SUPPORT_FILEFORMAT_PNG)
if ((IsFileExtension(fileName, ".png")) if ((IsFileExtension(fileName, ".png"))
#else
if ((false)
#endif
#if defined(SUPPORT_FILEFORMAT_BMP) #if defined(SUPPORT_FILEFORMAT_BMP)
|| (IsFileExtension(fileName, ".bmp")) || (IsFileExtension(fileName, ".bmp"))
#endif #endif
@ -398,90 +402,6 @@ Texture2D LoadTextureFromImage(Image image)
return texture; return texture;
} }
// Load cubemap from image, multiple image cubemap layouts supported
TextureCubemap LoadTextureCubemap(Image image, int layoutType)
{
TextureCubemap cubemap = { 0 };
if (layoutType == CUBEMAP_AUTO_DETECT) // Try to automatically guess layout type
{
// Check image width/height to determine the type of cubemap provided
if (image.width > image.height)
{
if ((image.width/6) == image.height) { layoutType = CUBEMAP_LINE_HORIZONTAL; cubemap.width = image.width/6; }
else if ((image.width/4) == (image.height/3)) { layoutType = CUBEMAP_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
else if (image.width >= (int)((float)image.height*1.85f)) { layoutType = CUBEMAP_PANORAMA; cubemap.width = image.width/4; }
}
else if (image.height > image.width)
{
if ((image.height/6) == image.width) { layoutType = CUBEMAP_LINE_VERTICAL; cubemap.width = image.height/6; }
else if ((image.width/3) == (image.height/4)) { layoutType = CUBEMAP_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
}
cubemap.height = cubemap.width;
}
int size = cubemap.width;
if (layoutType != CUBEMAP_AUTO_DETECT)
{
//unsigned int dataSize = GetPixelDataSize(size, size, format);
//void *facesData = malloc(size*size*dataSize*6); // Get memory for 6 faces in a column
Image faces = { 0 }; // Vertical column image
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, size, size };
if (layoutType == CUBEMAP_LINE_VERTICAL)
{
faces = image;
for (int i = 0; i < 6; i++) faceRecs[i].y = size*i;
}
else if (layoutType == CUBEMAP_PANORAMA)
{
// TODO: Convert panorama image to square faces...
}
else
{
if (layoutType == CUBEMAP_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = size*i;
else if (layoutType == CUBEMAP_CROSS_THREE_BY_FOUR)
{
faceRecs[0].x = size; faceRecs[0].y = size;
faceRecs[1].x = size; faceRecs[1].y = 3*size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = 0; faceRecs[4].y = size;
faceRecs[5].x = 2*size; faceRecs[5].y = size;
}
else if (layoutType == CUBEMAP_CROSS_FOUR_BY_THREE)
{
faceRecs[0].x = 2*size; faceRecs[0].y = size;
faceRecs[1].x = 0; faceRecs[1].y = size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = size; faceRecs[4].y = size;
faceRecs[5].x = 3*size; faceRecs[5].y = size;
}
// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);
// TODO: Image formating does not work with compressed textures!
}
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size });
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");
UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");
return cubemap;
}
// Load texture for rendering (framebuffer) // Load texture for rendering (framebuffer)
// NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer // NOTE: Render texture is loaded by default with RGBA color attachment and depth RenderBuffer
RenderTexture2D LoadRenderTexture(int width, int height) RenderTexture2D LoadRenderTexture(int width, int height)
@ -668,7 +588,7 @@ Vector4 *GetImageDataNormalized(Image image)
pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31); pixels[i].x = (float)((pixel & 0b1111100000000000) >> 11)*(1.0f/31);
pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31); pixels[i].y = (float)((pixel & 0b0000011111000000) >> 6)*(1.0f/31);
pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31); pixels[i].z = (float)((pixel & 0b0000000000111110) >> 1)*(1.0f/31);
pixels[i].w = ((pixel & 0b0000000000000001) == 0) ? 0.0f : 1.0f; pixels[i].w = ((pixel & 0b0000000000000001) == 0)? 0.0f : 1.0f;
} break; } break;
case UNCOMPRESSED_R5G6B5: case UNCOMPRESSED_R5G6B5:
@ -825,14 +745,27 @@ void ExportImage(Image image, const char *fileName)
{ {
int success = 0; int success = 0;
#if defined(SUPPORT_IMAGE_EXPORT)
// NOTE: Getting Color array as RGBA unsigned char values // NOTE: Getting Color array as RGBA unsigned char values
unsigned char *imgData = (unsigned char *)GetImageData(image); unsigned char *imgData = (unsigned char *)GetImageData(image);
#if defined(SUPPORT_FILEFORMAT_PNG)
if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4); if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4);
#else
if (false) {}
#endif
#if defined(SUPPORT_FILEFORMAT_BMP)
else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData);
#endif
#if defined(SUPPORT_FILEFORMAT_TGA)
else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData); else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData);
#endif
#if defined(SUPPORT_FILEFORMAT_JPG)
else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100 else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // JPG quality: between 1 and 100
#endif
#if defined(SUPPORT_FILEFORMAT_KTX)
else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName); else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
#endif
else if (IsFileExtension(fileName, ".raw")) else if (IsFileExtension(fileName, ".raw"))
{ {
// Export raw pixel data (without header) // Export raw pixel data (without header)
@ -842,10 +775,11 @@ void ExportImage(Image image, const char *fileName)
fclose(rawFile); fclose(rawFile);
} }
free(imgData);
#endif
if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName); if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName);
else TraceLog(LOG_WARNING, "Image could not be exported."); else TraceLog(LOG_WARNING, "Image could not be exported.");
free(imgData);
} }
// Export image as code file (.h) defining an array of bytes // Export image as code file (.h) defining an array of bytes
@ -880,7 +814,7 @@ void ExportImageAsCode(Image image, const char *fileName)
fprintf(txtFile, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format); fprintf(txtFile, "#define %s_FORMAT %i // raylib internal pixel format\n\n", varFileName, image.format);
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0) ? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]); for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)image.data)[i]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]); fprintf(txtFile, "0x%x };\n", ((unsigned char *)image.data)[dataSize - 1]);
fclose(txtFile); fclose(txtFile);
@ -1050,7 +984,7 @@ void ImageFormat(Image *image, int newFormat)
r = (unsigned char)(round(pixels[i].x*31.0f)); r = (unsigned char)(round(pixels[i].x*31.0f));
g = (unsigned char)(round(pixels[i].y*31.0f)); g = (unsigned char)(round(pixels[i].y*31.0f));
b = (unsigned char)(round(pixels[i].z*31.0f)); b = (unsigned char)(round(pixels[i].z*31.0f));
a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f)) ? 1 : 0; a = (pixels[i].w > ((float)ALPHA_THRESHOLD/255.0f))? 1 : 0;
((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a; ((unsigned short *)image->data)[i] = (unsigned short)r << 11 | (unsigned short)g << 6 | (unsigned short)b << 1 | (unsigned short)a;
} }
@ -1133,7 +1067,9 @@ void ImageFormat(Image *image, int newFormat)
if (image->mipmaps > 1) if (image->mipmaps > 1)
{ {
image->mipmaps = 1; image->mipmaps = 1;
#if defined(SUPPORT_IMAGE_MANIPULATION)
if (image->data != NULL) ImageMipmaps(image); if (image->data != NULL) ImageMipmaps(image);
#endif
} }
} }
else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted"); else TraceLog(LOG_WARNING, "Image data format is compressed, can not be converted");
@ -1202,38 +1138,6 @@ void ImageAlphaClear(Image *image, Color color, float threshold)
ImageFormat(image, prevFormat); ImageFormat(image, prevFormat);
} }
// Crop image depending on alpha value
void ImageAlphaCrop(Image *image, float threshold)
{
Color *pixels = GetImageData(*image);
int xMin = 65536; // Define a big enough number
int xMax = 0;
int yMin = 65536;
int yMax = 0;
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
if (pixels[y*image->width + x].a > (unsigned char)(threshold*255.0f))
{
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
}
}
}
Rectangle crop = { xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
free(pixels);
// Check for not empty image brefore cropping
if (!((xMax < xMin) || (yMax < yMin))) ImageCrop(image, crop);
}
// Premultiply alpha channel // Premultiply alpha channel
void ImageAlphaPremultiply(Image *image) void ImageAlphaPremultiply(Image *image)
{ {
@ -1259,6 +1163,90 @@ void ImageAlphaPremultiply(Image *image)
#if defined(SUPPORT_IMAGE_MANIPULATION) #if defined(SUPPORT_IMAGE_MANIPULATION)
// Load cubemap from image, multiple image cubemap layouts supported
TextureCubemap LoadTextureCubemap(Image image, int layoutType)
{
TextureCubemap cubemap = { 0 };
if (layoutType == CUBEMAP_AUTO_DETECT) // Try to automatically guess layout type
{
// Check image width/height to determine the type of cubemap provided
if (image.width > image.height)
{
if ((image.width/6) == image.height) { layoutType = CUBEMAP_LINE_HORIZONTAL; cubemap.width = image.width/6; }
else if ((image.width/4) == (image.height/3)) { layoutType = CUBEMAP_CROSS_FOUR_BY_THREE; cubemap.width = image.width/4; }
else if (image.width >= (int)((float)image.height*1.85f)) { layoutType = CUBEMAP_PANORAMA; cubemap.width = image.width/4; }
}
else if (image.height > image.width)
{
if ((image.height/6) == image.width) { layoutType = CUBEMAP_LINE_VERTICAL; cubemap.width = image.height/6; }
else if ((image.width/3) == (image.height/4)) { layoutType = CUBEMAP_CROSS_THREE_BY_FOUR; cubemap.width = image.width/3; }
}
cubemap.height = cubemap.width;
}
int size = cubemap.width;
if (layoutType != CUBEMAP_AUTO_DETECT)
{
//unsigned int dataSize = GetPixelDataSize(size, size, format);
//void *facesData = malloc(size*size*dataSize*6); // Get memory for 6 faces in a column
Image faces = { 0 }; // Vertical column image
Rectangle faceRecs[6] = { 0 }; // Face source rectangles
for (int i = 0; i < 6; i++) faceRecs[i] = (Rectangle){ 0, 0, size, size };
if (layoutType == CUBEMAP_LINE_VERTICAL)
{
faces = image;
for (int i = 0; i < 6; i++) faceRecs[i].y = size*i;
}
else if (layoutType == CUBEMAP_PANORAMA)
{
// TODO: Convert panorama image to square faces...
}
else
{
if (layoutType == CUBEMAP_LINE_HORIZONTAL) for (int i = 0; i < 6; i++) faceRecs[i].x = size*i;
else if (layoutType == CUBEMAP_CROSS_THREE_BY_FOUR)
{
faceRecs[0].x = size; faceRecs[0].y = size;
faceRecs[1].x = size; faceRecs[1].y = 3*size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = 0; faceRecs[4].y = size;
faceRecs[5].x = 2*size; faceRecs[5].y = size;
}
else if (layoutType == CUBEMAP_CROSS_FOUR_BY_THREE)
{
faceRecs[0].x = 2*size; faceRecs[0].y = size;
faceRecs[1].x = 0; faceRecs[1].y = size;
faceRecs[2].x = size; faceRecs[2].y = 0;
faceRecs[3].x = size; faceRecs[3].y = 2*size;
faceRecs[4].x = size; faceRecs[4].y = size;
faceRecs[5].x = 3*size; faceRecs[5].y = size;
}
// Convert image data to 6 faces in a vertical column, that's the optimum layout for loading
faces = GenImageColor(size, size*6, MAGENTA);
ImageFormat(&faces, image.format);
// TODO: Image formating does not work with compressed textures!
}
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, size*i, size, size });
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
if (cubemap.id == 0) TraceLog(LOG_WARNING, "Cubemap image could not be loaded.");
UnloadImage(faces);
}
else TraceLog(LOG_WARNING, "Cubemap image layout can not be detected.");
return cubemap;
}
// Crop an image to area defined by a rectangle // Crop an image to area defined by a rectangle
// NOTE: Security checks are performed in case rectangle goes out of bounds // NOTE: Security checks are performed in case rectangle goes out of bounds
void ImageCrop(Image *image, Rectangle crop) void ImageCrop(Image *image, Rectangle crop)
@ -1309,6 +1297,38 @@ void ImageCrop(Image *image, Rectangle crop)
} }
} }
// Crop image depending on alpha value
void ImageAlphaCrop(Image *image, float threshold)
{
Color *pixels = GetImageData(*image);
int xMin = 65536; // Define a big enough number
int xMax = 0;
int yMin = 65536;
int yMax = 0;
for (int y = 0; y < image->height; y++)
{
for (int x = 0; x < image->width; x++)
{
if (pixels[y*image->width + x].a > (unsigned char)(threshold*255.0f))
{
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
}
}
}
Rectangle crop = { xMin, yMin, (xMax + 1) - xMin, (yMax + 1) - yMin };
free(pixels);
// Check for not empty image brefore cropping
if (!((xMax < xMin) || (yMax < yMin))) ImageCrop(image, crop);
}
// Resize and image to new size // Resize and image to new size
// NOTE: Uses stb default scaling filters (both bicubic): // NOTE: Uses stb default scaling filters (both bicubic):
// STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM // STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
@ -1611,7 +1631,7 @@ Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount)
if (palCount >= maxPaletteSize) if (palCount >= maxPaletteSize)
{ {
i = image.width*image.height; // Finish palette get i = image.width*image.height; // Finish palette get
printf("WARNING: Image palette is greater than %i colors!\n", maxPaletteSize); TraceLog(LOG_WARNING, "Image palette is greater than %i colors!", maxPaletteSize);
} }
} }
} }
@ -2146,7 +2166,6 @@ void ImageColorReplace(Image *image, Color color, Color replace)
} }
#endif // SUPPORT_IMAGE_MANIPULATION #endif // SUPPORT_IMAGE_MANIPULATION
#if defined(SUPPORT_IMAGE_GENERATION)
// Generate image: plain color // Generate image: plain color
Image GenImageColor(int width, int height, Color color) Image GenImageColor(int width, int height, Color color)
{ {
@ -2161,6 +2180,7 @@ Image GenImageColor(int width, int height, Color color)
return image; return image;
} }
#if defined(SUPPORT_IMAGE_GENERATION)
// Generate image: vertical gradient // Generate image: vertical gradient
Image GenImageGradientV(int width, int height, Color top, Color bottom) Image GenImageGradientV(int width, int height, Color top, Color bottom)
{ {
@ -2211,7 +2231,7 @@ Image GenImageGradientH(int width, int height, Color left, Color right)
Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer) Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer)
{ {
Color *pixels = (Color *)malloc(width*height*sizeof(Color)); Color *pixels = (Color *)malloc(width*height*sizeof(Color));
float radius = (width < height) ? (float)width/2.0f : (float)height/2.0f; float radius = (width < height)? (float)width/2.0f : (float)height/2.0f;
float centerX = (float)width/2.0f; float centerX = (float)width/2.0f;
float centerY = (float)height/2.0f; float centerY = (float)height/2.0f;
@ -2509,7 +2529,7 @@ void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangl
{ {
Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height }; Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height };
Vector2 origin = { 0.0f, 0.0f }; Vector2 origin = { 0.0f, 0.0f };
DrawTexturePro(texture, source, quad, origin, 0.0f, tint); DrawTexturePro(texture, source, quad, origin, 0.0f, tint);
} }
@ -3173,25 +3193,27 @@ static int SaveKTX(Image image, const char *fileName)
{ {
KTXHeader ktxHeader; KTXHeader ktxHeader;
// KTX identifier (v2.2) // KTX identifier (v1.1)
//unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' }; //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
//unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
const char ktxIdentifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
// Get the image header // Get the image header
strcpy(ktxHeader.id, "«KTX 11»\r\n\x1A\n"); // KTX 1.1 signature strncpy(ktxHeader.id, ktxIdentifier, 12); // KTX 1.1 signature
ktxHeader.endianness = 0; ktxHeader.endianness = 0;
ktxHeader.glType = 0; // Obtained from image.format ktxHeader.glType = 0; // Obtained from image.format
ktxHeader.glTypeSize = 1; ktxHeader.glTypeSize = 1;
ktxHeader.glFormat = 0; // Obtained from image.format ktxHeader.glFormat = 0; // Obtained from image.format
ktxHeader.glInternalFormat = 0; // Obtained from image.format ktxHeader.glInternalFormat = 0; // Obtained from image.format
ktxHeader.glBaseInternalFormat = 0; ktxHeader.glBaseInternalFormat = 0;
ktxHeader.width = image.width; ktxHeader.width = image.width;
ktxHeader.height = image.height; ktxHeader.height = image.height;
ktxHeader.depth = 0; ktxHeader.depth = 0;
ktxHeader.elements = 0; ktxHeader.elements = 0;
ktxHeader.faces = 1; ktxHeader.faces = 1;
ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats) ktxHeader.mipmapLevels = image.mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
ktxHeader.keyValueDataSize = 0; // No extra data after the header ktxHeader.keyValueDataSize = 0; // No extra data after the header
rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function rlGetGlTextureFormats(image.format, &ktxHeader.glInternalFormat, &ktxHeader.glFormat, &ktxHeader.glType); // rlgl module function
ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only ktxHeader.glBaseInternalFormat = ktxHeader.glFormat; // KTX 1.1 only