diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml
index 9e87b5870..7a92c208a 100644
--- a/.github/workflows/build_windows.yml
+++ b/.github/workflows/build_windows.yml
@@ -40,10 +40,10 @@ jobs:
ziptarget: "win64"
- compiler: msvc16
ARCH: "x86"
- VSARCHPATH: "Win32"
+ VSARCHPATH: "Win32"
ziptarget: "win32"
- compiler: msvc16
- ARCH: "x64"
+ ARCH: "x64"
VSARCHPATH: "x64"
ziptarget: "win64"
- compiler: msvc16
@@ -61,7 +61,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@master
-
+
- name: Setup Release Version
run: |
echo "RELEASE_NAME=raylib-${{ github.event.release.tag_name }}_${{ matrix.ziptarget }}_${{ matrix.compiler }}" >> $GITHUB_ENV
@@ -69,7 +69,7 @@ jobs:
if: github.event_name == 'release' && github.event.action == 'published'
- name: Setup Environment
- run: |
+ run: |
dir
mkdir build
cd build
@@ -98,7 +98,7 @@ jobs:
if: |
matrix.compiler == 'mingw-w64' &&
matrix.arch == 'i686'
-
+
- name: Build Library (MinGW-w64 64bit)
run: |
cd src
@@ -144,7 +144,7 @@ jobs:
with:
name: ${{ env.RELEASE_NAME }}.zip
path: ./build/${{ env.RELEASE_NAME }}.zip
-
+
- name: Upload Artifact to Release
uses: softprops/action-gh-release@v1
with:
diff --git a/examples/Makefile b/examples/Makefile
index c93cf53d9..9ae8bb480 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -665,6 +665,7 @@ SHADERS = \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
shaders/shaders_lightmap_rendering \
+ shaders/shaders_mandelbrot_set \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
diff --git a/examples/Makefile.Web b/examples/Makefile.Web
index 38059f227..0e9b9f92f 100644
--- a/examples/Makefile.Web
+++ b/examples/Makefile.Web
@@ -665,6 +665,7 @@ SHADERS = \
shaders/shaders_hybrid_rendering \
shaders/shaders_julia_set \
shaders/shaders_lightmap_rendering \
+ shaders/shaders_mandelbrot_set \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
@@ -1311,6 +1312,10 @@ shaders/shaders_lightmap_rendering: shaders/shaders_lightmap_rendering.c
--preload-file shaders/resources/cubicmap_atlas.png@resources/cubicmap_atlas.png \
--preload-file shaders/resources/spark_flame.png@resources/spark_flame.png
+shaders/shaders_mandelbrot_set: shaders/shaders_mandelbrot_set.c
+ $(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
+ --preload-file shaders/resources/shaders/glsl100/mandelbrot_set.fs@resources/shaders/glsl100/mandelbrot_set.fs
+
shaders/shaders_mesh_instancing: shaders/shaders_mesh_instancing.c
$(CC) -o $@$(EXT) $< $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) \
--preload-file shaders/resources/shaders/glsl100/lighting_instancing.vs@resources/shaders/glsl100/lighting_instancing.vs \
diff --git a/examples/README.md b/examples/README.md
index 15065c193..bbb0a0388 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -17,9 +17,9 @@ You may find it easier to use than other toolchains, especially when it comes to
- `zig build [module]` to compile all examples for a module (e.g. `zig build core`)
- `zig build [example]` to compile _and run_ a particular example (e.g. `zig build core_basic_window`)
-## EXAMPLES COLLECTION [TOTAL: 186]
+## EXAMPLES COLLECTION [TOTAL: 187]
-### category: core [44]
+### category: core [45]
Examples using raylib[core](../src/rcore.c) platform functionality like window creation, inputs, drawing modes and system functionality.
@@ -69,6 +69,7 @@ Examples using raylib[core](../src/rcore.c) platform functionality like window c
| [core_highdpi_testbed](core/core_highdpi_testbed.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_screen_recording](core/core_screen_recording.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Ramon Santamaria](https://github.com/raysan5) |
| [core_clipboard_text](core/core_clipboard_text.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Robin](https://github.com/RobinsAviary) |
+| [core_text_file_loading](core/core_text_file_loading.c) |
| ⭐☆☆☆ | 5.5 | 5.6 | [Aanjishnu Bhattacharyya](https://github.com/NimComPoo-04) |
### category: shapes [32]
@@ -104,8 +105,7 @@ Examples using raylib shapes drawing functionality, provided by raylib [shapes](
| [shapes_pie_chart](shapes/shapes_pie_chart.c) |
| ⭐⭐⭐☆ | 5.5 | 5.6 | [Gideon Serfontein](https://github.com/GideonSerf) |
| [shapes_kaleidoscope](shapes/shapes_kaleidoscope.c) |
| ⭐⭐☆☆ | 5.5 | 5.6 | [Hugo ARNAL](https://github.com/hugoarnal) |
| [shapes_clock_of_clocks](shapes/shapes_clock_of_clocks.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
-| [shapes_math_sine_cosine](shapes/shapes_math_sine_cosine.c) |
| ⭐⭐☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
-| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) |
| ⭐☆☆☆ | 5.6 | 5.6-dev | [[Balamurugan R]](https://github.com/[Bala050814]) |
+| [shapes_mouse_trail](shapes/shapes_mouse_trail.c) |
| ⭐☆☆☆ | 5.6 | 5.6-dev | [Balamurugan R](https://github.com/Bala050814) |
| [shapes_simple_particles](shapes/shapes_simple_particles.c) |
| ⭐⭐☆☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
| [shapes_starfield_effect](shapes/shapes_starfield_effect.c) |
| ⭐⭐☆☆ | 5.5 | 5.6-dev | [JP Mortiboys](https://github.com/themushroompirates) |
@@ -196,7 +196,7 @@ Examples using raylib models functionality, including models loading/generation
| [models_basic_voxel](models/models_basic_voxel.c) |
| ⭐⭐☆☆ | 5.5 | 5.5 | [Tim Little](https://github.com/timlittle) |
| [models_rotating_cube](models/models_rotating_cube.c) |
| ⭐☆☆☆ | 5.6-dev | 5.6-dev | [Jopestpe](https://github.com/jopestpe) |
-### category: shaders [30]
+### category: shaders [31]
Examples using raylib shaders functionality, including shaders loading, parameters configuration and drawing using them (model shaders and postprocessing shaders). This functionality is directly provided by raylib [rlgl](../src/rlgl.c) module.
@@ -232,6 +232,7 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| [shaders_lightmap_rendering](shaders/shaders_lightmap_rendering.c) |
| ⭐⭐⭐☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
| [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) |
| ⭐⭐⭐☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
| [shaders_depth_rendering](shaders/shaders_depth_rendering.c) |
| ⭐⭐⭐☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
+| [shaders_mandelbrot_set](shaders/shaders_mandelbrot_set.c) |
| ⭐⭐⭐☆ | 5.6 | 5.6 | [Jordi Santonja](https://github.com/JordSant) |
### category: audio [8]
diff --git a/examples/core/core_3d_camera_first_person.c b/examples/core/core_3d_camera_first_person.c
index 8f4dc70fb..64368c4aa 100644
--- a/examples/core/core_3d_camera_first_person.c
+++ b/examples/core/core_3d_camera_first_person.c
@@ -119,7 +119,6 @@ int main(void)
// Some default standard keyboard/mouse inputs are hardcoded to simplify use
// For advanced camera controls, it's recommended to compute camera movement manually
UpdateCamera(&camera, cameraMode); // Update camera
-
/*
// Camera PRO usage example (EXPERIMENTAL)
// This new camera function allows custom movement/rotation values to be directly provided
diff --git a/examples/core/core_render_texture.c b/examples/core/core_render_texture.c
index 47dc66e0f..e30220a73 100644
--- a/examples/core/core_render_texture.c
+++ b/examples/core/core_render_texture.c
@@ -26,7 +26,7 @@ int main(void)
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - render texture");
-
+
// Define a render texture to render
int renderTextureWidth = 300;
int renderTextureHeight = 300;
@@ -62,14 +62,14 @@ int main(void)
//-----------------------------------------------------
// Draw our scene to the render texture
BeginTextureMode(target);
-
+
ClearBackground(SKYBLUE);
-
+
DrawRectangle(0, 0, 20, 20, RED);
DrawCircleV(ballPosition, (float)ballRadius, MAROON);
-
+
EndTextureMode();
-
+
// Draw render texture to main framebuffer
BeginDrawing();
@@ -77,14 +77,14 @@ int main(void)
// Draw our render texture with rotation applied
// NOTE 1: We set the origin of the texture to the center of the render texture
- // NOTE 2: We flip vertically the texture setting negative source rectangle height
- DrawTexturePro(target.texture,
+ // NOTE 2: We flip vertically the texture setting negative source rectangle height
+ DrawTexturePro(target.texture,
(Rectangle){ 0, 0, (float)target.texture.width, (float)-target.texture.height },
(Rectangle){ screenWidth/2.0f, screenHeight/2.0f, (float)target.texture.width, (float)target.texture.height },
(Vector2){ target.texture.width/2.0f, target.texture.height/2.0f }, rotation, WHITE);
DrawText("DRAWING BOUNCING BALL INSIDE RENDER TEXTURE!", 10, screenHeight - 40, 20, BLACK);
-
+
DrawFPS(10, 10);
diff --git a/examples/core/core_text_file_loading.c b/examples/core/core_text_file_loading.c
index 4b334e811..ed48f7d36 100644
--- a/examples/core/core_text_file_loading.c
+++ b/examples/core/core_text_file_loading.c
@@ -64,7 +64,7 @@ int main(void)
if (lines[i][j] == ' ')
{
// Making a C Style string by adding a '\0' at the required location so that we can use the MeasureText function
- lines[i][j] = '\0';
+ lines[i][j] = '\0';
// Checking if the text has crossed the wrapWidth, then going back and inserting a newline
if (MeasureText(lines[i] + lastWrapStart, fontSize) > wrapWidth)
@@ -88,16 +88,16 @@ int main(void)
for (int i = 0; i < lineCount; i++)
{
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
- textHeight += size.y + 10;
+ Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
+ textHeight += (int)size.y + 10;
}
// A simple scrollbar on the side to show how far we have red into the file
Rectangle scrollBar = {
- .x = screenWidth - 5,
+ .x = (float)screenWidth - 5,
.y = 0,
.width = 5,
- .height = screenHeight*100/(textHeight - screenHeight) // Scrollbar height is just a percentage
+ .height = screenHeight*100.0f/(textHeight - screenHeight) // Scrollbar height is just a percentage
};
SetTargetFPS(60);
@@ -112,13 +112,13 @@ int main(void)
cam.target.y -= scroll*fontSize*1.5f; // Choosing an arbitrary speed for scroll
if (cam.target.y < 0) cam.target.y = 0; // Snapping to 0 if we go too far back
-
- // Ensuring that the camera does not scroll past all text
+
+ // Ensuring that the camera does not scroll past all text
if (cam.target.y > textHeight - screenHeight + textTop)
- cam.target.y = textHeight - screenHeight + textTop;
+ cam.target.y = (float)textHeight - screenHeight + textTop;
// Computing the position of the scrollBar depending on the percentage of text covered
- scrollBar.y = Lerp(textTop, screenHeight - scrollBar.height, (cam.target.y - textTop)/(textHeight - screenHeight));
+ scrollBar.y = Lerp((float)textTop, (float)screenHeight - scrollBar.height, (float)(cam.target.y - textTop)/(textHeight - screenHeight));
//----------------------------------------------------------------------------------
// Draw
@@ -132,13 +132,13 @@ int main(void)
for (int i = 0, t = textTop; i < lineCount; i++)
{
// Each time we go through and calculate the height of the text to move the cursor appropriately
- Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], fontSize, 2);
-
+ Vector2 size = MeasureTextEx(GetFontDefault(), lines[i], (float)fontSize, 2);
+
DrawText(lines[i], 10, t, fontSize, RED);
- // Inserting extra space for real newlines,
+ // Inserting extra space for real newlines,
// wrapped lines are rendered closer together
- t += size.y + 10;
+ t += (int)size.y + 10;
}
EndMode2D();
diff --git a/examples/examples_list.txt b/examples/examples_list.txt
index b0504100e..4805a37ec 100644
--- a/examples/examples_list.txt
+++ b/examples/examples_list.txt
@@ -51,6 +51,7 @@ core;core_directory_files;★☆☆☆;5.5;5.6;2025;2025;"Hugo ARNAL";@hugoarnal
core;core_highdpi_testbed;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_screen_recording;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Ramon Santamaria";@raysan5
core;core_clipboard_text;★☆☆☆;5.6-dev;5.6-dev;2025;2025;"Robin";@RobinsAviary
+core;core_text_file_loading;★☆☆☆;5.5;5.6;0;0;"Aanjishnu Bhattacharyya";@NimComPoo-04
shapes;shapes_basic_shapes;★☆☆☆;1.0;4.2;2014;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bouncing_ball;★☆☆☆;2.5;2.5;2013;2025;"Ramon Santamaria";@raysan5
shapes;shapes_bullet_hell;★☆☆☆;5.6;5.6;2025;2025;"Zero";@zerohorsepower
@@ -161,6 +162,7 @@ shaders;shaders_texture_rendering;★★☆☆;2.0;3.7;2019;2025;"Michał Ciesie
shaders;shaders_texture_outline;★★★☆;4.0;4.0;2021;2025;"Serenity Skiff";@GoldenThumbs
shaders;shaders_texture_waves;★★☆☆;2.5;3.7;2019;2025;"Anata";@anatagawa
shaders;shaders_julia_set;★★★☆;2.5;4.0;2019;2025;"Josh Colclough";@joshcol9232
+shaders;shaders_mandelbrot_set;★★★☆;5.6;5.6;2025;2025;"Jordi Santonja";@JordSant
shaders;shaders_eratosthenes_sieve;★★★☆;2.5;4.0;2019;2025;"ProfJski";@ProfJski
shaders;shaders_fog_rendering;★★★☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
shaders;shaders_simple_mask;★★☆☆;2.5;3.7;2019;2025;"Chris Camacho";@chriscamacho
diff --git a/examples/models/models_decals.c b/examples/models/models_decals.c
new file mode 100644
index 000000000..af1ecfc6d
--- /dev/null
+++ b/examples/models/models_decals.c
@@ -0,0 +1,538 @@
+/*******************************************************************************************
+*
+* raylib [models] example - decals
+*
+* Example complexity rating: [★★★★] 4/4
+*
+* Example originally created with raylib 5.6-dev
+*
+* Example contributed by JP Mortiboys (@themushroompirates) and reviewed by Ramon Santamaria (@raysan5)
+* Based on previous work by @mrdoob
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 JP Mortiboys (@themushroompirates) and Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+
+#include "raymath.h"
+
+#include // Required for: memcpy()
+
+#undef FLT_MAX
+#define FLT_MAX 340282346638528859811704183484516925440.0f // Maximum value of a float, from bit pattern 01111111011111111111111111111111
+
+#define MAX_DECALS 256
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct MeshBuilder {
+ int vertexCount;
+ int vertexCapacity;
+ Vector3 *vertices;
+ Vector2 *uvs;
+} MeshBuilder;
+
+//------------------------------------------------------------------------------------
+// Module Functions Declaration
+//------------------------------------------------------------------------------------
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3]);
+static void FreeMeshBuilder(MeshBuilder *mb);
+static Mesh BuildMesh(MeshBuilder *mb);
+static Mesh GenMeshDecal(Mesh inputMesh, Ray ray);
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s);
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+ InitWindow(screenWidth, screenHeight, "raylib [models] example - decals");
+
+ // Define the camera to look into our 3d world
+ Camera camera = { 0 };
+ camera.position = (Vector3){ 5.0f, 5.0f, 5.0f }; // Camera position
+ camera.target = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera looking at point
+ camera.up = (Vector3){ 0.0f, 1.6f, 0.0f }; // Camera up vector (rotation towards target)
+ camera.fovy = 45.0f; // Camera field-of-view Y
+ camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
+
+ // Load character model
+ Model model = LoadModel("resources/models/obj/character.obj");
+
+ // Apply character skin
+ Texture2D modelTexture = LoadTexture("resources/models/obj/character_diffuse.png");
+ SetTextureFilter(modelTexture, TEXTURE_FILTER_BILINEAR);
+ model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = modelTexture;
+
+ BoundingBox modelBBox = GetMeshBoundingBox(model.meshes[0]); // Get mesh bounding box
+
+ camera.target = Vector3Lerp(modelBBox.min, modelBBox.max, 0.5f);
+ camera.position = Vector3Scale(modelBBox.max, 1.0f);
+ camera.position.x *= 0.1f;
+
+ float modelSize = fminf(
+ fminf(fabsf(modelBBox.max.x - modelBBox.min.x), fabsf(modelBBox.max.y - modelBBox.min.y)),
+ fabsf(modelBBox.max.z - modelBBox.min.z));
+
+ camera.position = (Vector3){ 0.0f, modelBBox.max.y*1.2f, modelSize*3.0f };
+
+ float decalSize = modelSize*0.25f;
+ float decalOffset = 0.01f;
+
+ Model placementCube = LoadModelFromMesh(GenMeshCube(decalSize, decalSize, decalSize));
+ placementCube.materials[0].maps[0].color = LIME;
+
+ Material decalMaterial = LoadMaterialDefault();
+ decalMaterial.maps[0].color = YELLOW;
+
+ Image decalImage = LoadImage("resources/raylib_logo.png");
+ ImageResizeNN(&decalImage, decalImage.width/4, decalImage.height/4);
+ Texture decalTexture = LoadTextureFromImage(decalImage);
+ UnloadImage(decalImage);
+
+ SetTextureFilter(decalTexture, TEXTURE_FILTER_BILINEAR);
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].texture = decalTexture;
+ decalMaterial.maps[MATERIAL_MAP_DIFFUSE].color = RAYWHITE;
+
+ // We're going to use these to build up our decal meshes
+ // They'll resize automatically as we go, we'll free them at the end
+ MeshBuilder meshBuilders[2] = { 0 };
+
+ bool showModel = true;
+ Model decalModels[MAX_DECALS] = { 0 };
+ int decalCount = 0;
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) UpdateCamera(&camera, CAMERA_THIRD_PERSON);
+
+ if (IsKeyPressed(KEY_SPACE)) showModel = !showModel;
+
+ // Display information about closest hit
+ RayCollision collision = { 0 };
+ collision.distance = FLT_MAX;
+ collision.hit = false;
+
+ // Get mouse ray
+ Ray ray = GetScreenToWorldRay(GetMousePosition(), camera);
+
+ // Check ray collision against bounding box first, before trying the full ray-mesh test
+ RayCollision boxHitInfo = GetRayCollisionBox(ray, modelBBox);
+
+ if ((boxHitInfo.hit) && (decalCount < MAX_DECALS))
+ {
+ // Check ray collision against model meshes
+ RayCollision meshHitInfo = { 0 };
+ for (int m = 0; m < model.meshCount; m++)
+ {
+ // NOTE: We consider the model.transform for the collision check but
+ // it can be checked against any transform Matrix, used when checking against same
+ // model drawn multiple times with multiple transforms
+ meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
+ if (meshHitInfo.hit)
+ {
+ // Save the closest hit mesh
+ if (!collision.hit || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo;
+ }
+ }
+
+ if (meshHitInfo.hit) collision = meshHitInfo;
+ }
+
+ // Add decal to mesh on hit point
+ if (collision.hit && IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && (decalCount < MAX_DECALS))
+ {
+ // Create the transformation to project the decal
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){ 0.0f, 1.0f, 0.0f });
+
+ // Spin the placement around a bit
+ splat = MatrixMultiply(splat, MatrixRotateZ(DEG2RAD*((float)GetRandomValue(-180, 180))));
+ Matrix splatInv = MatrixInvert(splat);
+
+ // Reset the mesh builders
+ meshBuilders[0].vertexCount = 0;
+ meshBuilders[1].vertexCount = 0;
+
+ // We'll be flip-flopping between the two mesh builders
+ // Reading from one and writing to the other, then swapping
+ int mbIndex = 0;
+
+ // First pass, just get any triangle inside the bounding box (for each mesh of the model)
+ for (int meshIndex = 0; meshIndex < model.meshCount; meshIndex++)
+ {
+ Mesh mesh = model.meshes[meshIndex];
+ for (int tri = 0; tri < mesh.triangleCount; tri++)
+ {
+ Vector3 vertices[3] = { 0 };
+
+ // The way we calculate the vertices of the mesh triangle
+ // depend on whether the mesh vertices are indexed or not
+ if (mesh.indices == 0)
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[3*3*tri + 3*v + 0],
+ mesh.vertices[3*3*tri + 3*v + 1],
+ mesh.vertices[3*3*tri + 3*v + 2]
+ };
+ }
+ }
+ else
+ {
+ for (int v = 0; v < 3; v++)
+ {
+ vertices[v] = (Vector3){
+ mesh.vertices[ 3*mesh.indices[3*tri+0] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+1] + v],
+ mesh.vertices[ 3*mesh.indices[3*tri+2] + v]
+ };
+ }
+ }
+
+ // Transform all 3 vertices of the triangle
+ // and check if they are inside our decal box
+ int insideCount = 0;
+ for (int i = 0; i < 3; i++)
+ {
+ // To splat space
+ Vector3 v = Vector3Transform(vertices[i], splat);
+
+ if ((fabsf(v.x) < decalSize) || (fabsf(v.y) <= decalSize) || (fabsf(v.z) <= decalSize)) insideCount++;
+
+ // We need to keep the transformed vertex
+ vertices[i] = v;
+ }
+
+ // If any of them are inside, we add the triangle - we'll clip it later
+ if (insideCount > 0) AddTriangleToMeshBuilder(&meshBuilders[mbIndex], vertices);
+ }
+ }
+
+ // Clipping time! We need to clip against all 6 directions
+ Vector3 planes[6] = {
+ { 1, 0, 0 },
+ { -1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, -1, 0 },
+ { 0, 0, 1 },
+ { 0, 0, -1 }
+ };
+
+ for (int face = 0; face < 6; face++)
+ {
+ // Swap current model builder (so we read from the one we just wrote to)
+ mbIndex = 1 - mbIndex;
+
+ MeshBuilder *inMesh = &meshBuilders[1 - mbIndex];
+ MeshBuilder *outMesh = &meshBuilders[mbIndex];
+
+ // Reset write builder
+ outMesh->vertexCount = 0;
+
+ float s = 0.5f*decalSize;
+
+ for (int i = 0; i < inMesh->vertexCount; i += 3)
+ {
+ Vector3 nV1, nV2, nV3, nV4;
+
+ float d1 = Vector3DotProduct(inMesh->vertices[ i + 0 ], planes[face] ) - s;
+ float d2 = Vector3DotProduct(inMesh->vertices[ i + 1 ], planes[face] ) - s;
+ float d3 = Vector3DotProduct(inMesh->vertices[ i + 2 ], planes[face] ) - s;
+
+ int v1Out = (d1 > 0);
+ int v2Out = (d2 > 0);
+ int v3Out = (d3 > 0);
+
+ // Calculate, how many vertices of the face lie outside of the clipping plane
+ int total = v1Out + v2Out + v3Out;
+
+ switch (total)
+ {
+ case 0:
+ {
+ // The entire face lies inside of the plane, no clipping needed
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){inMesh->vertices[i], inMesh->vertices[i+1], inMesh->vertices[i+2]});
+ } break;
+ case 1:
+ {
+ // One vertex lies outside of the plane, perform clipping
+ if (v1Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i], nV2, planes[face], s);
+ }
+
+ if (v2Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 2];
+ nV3 = ClipSegment(inMesh->vertices[i + 1], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 1], nV2, planes[face], s);
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV3, nV2, nV1});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV2, nV3, nV4});
+ break;
+ }
+
+ if (v3Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = inMesh->vertices[i + 1];
+ nV3 = ClipSegment(inMesh->vertices[i + 2], nV1, planes[face], s);
+ nV4 = ClipSegment(inMesh->vertices[i + 2], nV2, planes[face], s);
+ }
+
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV4, nV3, nV2});
+ } break;
+ case 2:
+ {
+ // Two vertices lies outside of the plane, perform clipping
+ if (!v1Out)
+ {
+ nV1 = inMesh->vertices[i];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v2Out)
+ {
+ nV1 = inMesh->vertices[i + 1];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i + 2], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+
+ if (!v3Out)
+ {
+ nV1 = inMesh->vertices[i + 2];
+ nV2 = ClipSegment(nV1, inMesh->vertices[i], planes[face], s);
+ nV3 = ClipSegment(nV1, inMesh->vertices[i + 1], planes[face], s);
+ AddTriangleToMeshBuilder(outMesh, (Vector3[3]){nV1, nV2, nV3});
+ }
+ } break;
+ case 3: // The entire face lies outside of the plane, so let's discard the corresponding vertices
+ default: break;
+ }
+ }
+ }
+
+ // Now we just need to re-transform the vertices
+ MeshBuilder *theMesh = &meshBuilders[mbIndex];
+
+ // Allocate room for UVs
+ if (theMesh->vertexCount > 0)
+ {
+ theMesh->uvs = (Vector2 *)MemAlloc(sizeof(Vector2)*theMesh->vertexCount);
+
+ for (int i = 0; i < theMesh->vertexCount; i++)
+ {
+ // Calculate the UVs based on the projected coords
+ // They are clipped to (-decalSize .. decalSize) and we want them (0..1)
+ theMesh->uvs[i].x = (theMesh->vertices[i].x/decalSize + 0.5f);
+ theMesh->uvs[i].y = (theMesh->vertices[i].y/decalSize + 0.5f);
+
+ // From splat space to world space
+ theMesh->vertices[i] = Vector3Transform(theMesh->vertices[i], splatInv);
+
+ // Tiny nudge in the normal direction so it renders properly over the mesh
+ theMesh->vertices[i] = Vector3Add(theMesh->vertices[i], Vector3Scale(collision.normal, decalOffset));
+ }
+
+ // Decal model data ready, create it and add it
+ int decalIndex = decalCount++;
+ decalModels[decalIndex] = LoadModelFromMesh(BuildMesh(theMesh));
+ decalModels[decalIndex].materials[0] = decalMaterial;
+ }
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(RAYWHITE);
+
+ BeginMode3D(camera);
+ // Draw the model at the origin and default scale
+ if (showModel) DrawModel(model, (Vector3){0.0f, 0.0f, 0.0f}, 1.0f, WHITE);
+
+ // Draw the decal models
+ for (int i = 0; i < decalCount; i++) DrawModel(decalModels[i], (Vector3){0}, 1.0f, WHITE);
+
+ // If we hit the mesh, draw the box for the decal
+ if (collision.hit)
+ {
+ Vector3 origin = Vector3Add(collision.point, Vector3Scale(collision.normal, 1.0f));
+ Matrix splat = MatrixLookAt(collision.point, origin, (Vector3){0,1,0});
+ placementCube.transform = MatrixInvert(splat);
+ DrawModel(placementCube, (Vector3){0}, 1.0f, Fade(WHITE, 0.5f));
+ }
+
+ DrawGrid(10, 10.0f);
+ EndMode3D();
+
+ float yPos = 10;
+ float x0 = GetScreenWidth() - 300;
+ float x1 = x0 + 100;
+ float x2 = x1 + 100;
+
+ DrawText("Vertices", x1, yPos, 10, LIME);
+ DrawText("Triangles", x2, yPos, 10, LIME);
+ yPos += 15;
+
+ int vertexCount = 0;
+ int triangleCount = 0;
+
+ for (int i = 0; i < model.meshCount; i++)
+ {
+ vertexCount += model.meshes[i].vertexCount;
+ triangleCount += model.meshes[i].triangleCount;
+ }
+
+ DrawText("Main model", x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ yPos += 15;
+
+ for (int i = 0; i < decalCount; i++)
+ {
+ DrawText(TextFormat("Decal #%d", i+1), x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", decalModels[i].meshes[0].triangleCount), x2, yPos, 10, LIME);
+
+ vertexCount += decalModels[i].meshes[0].vertexCount;
+ triangleCount += decalModels[i].meshes[0].triangleCount;
+ yPos += 15;
+ }
+
+ DrawText("TOTAL", x0, yPos, 10, LIME);
+ DrawText(TextFormat("%d", vertexCount), x1, yPos, 10, LIME);
+ DrawText(TextFormat("%d", triangleCount), x2, yPos, 10, LIME);
+ yPos += 15;
+
+ DrawText("Hold RMB to move camera", 10, 430, 10, GRAY);
+ DrawText("(c) Character model and texture from kenney.nl", screenWidth - 260, screenHeight - 20, 10, GRAY);
+
+ DrawFPS(10, 10);
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadModel(model);
+ UnloadTexture(modelTexture);
+
+ // TODO: WARNING: This line crashes program on closing
+ //for (int i = 0; i < decalCount; i++) UnloadModel(decalModels[i]);
+
+ UnloadTexture(decalTexture);
+
+ FreeMeshBuilder(&meshBuilders[0]);
+ FreeMeshBuilder(&meshBuilders[1]);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+// Add triangles to mesh builder (dynamic array manager)
+static void AddTriangleToMeshBuilder(MeshBuilder *mb, Vector3 vertices[3])
+{
+ // Reallocate and copy if we need to
+ if (mb->vertexCapacity <= (mb->vertexCount + 3))
+ {
+ int newVertexCapacity = (1 + (mb->vertexCapacity/256))*256;
+ Vector3 *newVertices = (Vector3 *)MemAlloc(newVertexCapacity*sizeof(Vector3));
+
+ if (mb->vertexCapacity > 0)
+ {
+ memcpy(newVertices, mb->vertices, mb->vertexCount*sizeof(Vector3));
+ MemFree(mb->vertices);
+ }
+
+ mb->vertices = newVertices;
+ mb->vertexCapacity = newVertexCapacity;
+ }
+
+ // Add 3 vertices
+ int index = mb->vertexCount;
+ mb->vertexCount += 3;
+
+ for (int i = 0; i < 3; i++) mb->vertices[index+i] = vertices[i];
+}
+
+// Free mesh builder
+static void FreeMeshBuilder(MeshBuilder *mb)
+{
+ MemFree(mb->vertices);
+ if (mb->uvs) MemFree(mb->uvs);
+ *mb = (MeshBuilder){ 0 };
+}
+
+// Build a Mesh from MeshBuilder data
+static Mesh BuildMesh(MeshBuilder *mb)
+{
+ Mesh outMesh = { 0 };
+
+ outMesh.vertexCount = mb->vertexCount;
+ outMesh.triangleCount = mb->vertexCount/3;
+ outMesh.vertices = MemAlloc(outMesh.vertexCount*3*sizeof(float));
+ if (mb->uvs) outMesh.texcoords = MemAlloc(outMesh.vertexCount*2*sizeof(float));
+
+ for (int i = 0; i < mb->vertexCount; i++)
+ {
+ outMesh.vertices[3*i+0] = mb->vertices[i].x;
+ outMesh.vertices[3*i+1] = mb->vertices[i].y;
+ outMesh.vertices[3*i+2] = mb->vertices[i].z;
+
+ if (mb->uvs)
+ {
+ outMesh.texcoords[2*i+0] = mb->uvs[i].x;
+ outMesh.texcoords[2*i+1] = mb->uvs[i].y;
+ }
+ }
+
+ UploadMesh(&outMesh, false);
+
+ return outMesh;
+}
+
+// Clip segment
+static Vector3 ClipSegment(Vector3 v0, Vector3 v1, Vector3 p, float s)
+{
+ float d0 = Vector3DotProduct(v0, p) - s;
+ float d1 = Vector3DotProduct(v1, p) - s;
+ float s0 = d0/(d0 - d1);
+
+ Vector3 position = Vector3Lerp(v0, v1, s0);
+
+ return position;
+}
diff --git a/examples/models/models_decals.png b/examples/models/models_decals.png
new file mode 100644
index 000000000..48e027fe2
Binary files /dev/null and b/examples/models/models_decals.png differ
diff --git a/examples/models/resources/models/obj/character.mtl b/examples/models/resources/models/obj/character.mtl
new file mode 100644
index 000000000..96b272b29
--- /dev/null
+++ b/examples/models/resources/models/obj/character.mtl
@@ -0,0 +1,12 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl skin
+Ns 86.470579
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 0.000000
+illum 9
diff --git a/examples/models/resources/models/obj/character.obj b/examples/models/resources/models/obj/character.obj
new file mode 100644
index 000000000..be7e47863
--- /dev/null
+++ b/examples/models/resources/models/obj/character.obj
@@ -0,0 +1,3454 @@
+# Blender v2.83.2 OBJ File: ''
+# www.blender.org
+mtllib character.mtl
+o characterMedium
+v 0.410751 3.453012 0.200817
+v 0.176931 3.516046 -0.492870
+v 0.176931 3.069885 -0.492870
+v 0.193767 2.961166 0.489574
+v 0.193767 3.452389 0.455386
+v 0.400606 2.998632 0.217911
+v 0.400606 3.035397 -0.212411
+v 0.410751 3.483905 -0.212411
+v 0.188780 3.698580 0.247489
+v 0.188780 3.731344 -0.224509
+v 0.188780 2.741884 -0.224509
+v 0.188780 2.664058 0.281677
+v 0.338542 2.788810 0.205190
+v 0.323730 3.496119 -0.410188
+v 0.323730 3.441588 0.352035
+v 0.338542 3.642598 0.223085
+v 0.338542 2.852551 -0.208748
+v 0.176295 2.876968 -0.427238
+v 0.323730 3.072495 -0.410188
+v 0.193131 2.735571 0.459728
+v 0.323730 2.996823 0.381949
+v 0.338542 3.655763 -0.208748
+v 0.176295 3.660861 -0.399904
+v 0.193131 3.617279 0.405342
+v 0.180529 3.275434 -0.517282
+v 0.197366 3.218354 0.478425
+v 0.409350 3.230555 0.194491
+v 0.403118 3.253443 -0.219099
+v 0.429171 3.009897 0.014208
+v 0.439316 3.472003 0.009934
+v 0.198303 3.743473 0.020506
+v 0.198303 2.669343 0.029053
+v 0.286423 2.928726 -0.357824
+v 0.286423 2.767836 0.367046
+v 0.286423 3.636701 -0.357824
+v 0.301893 3.594941 0.358830
+v 0.357587 2.802252 0.025342
+v 0.322536 3.266541 -0.423686
+v 0.327481 3.227505 0.360122
+v 0.357587 3.654801 0.017864
+v 0.434369 3.238045 0.005717
+v 0.111250 2.648599 -0.113100
+v 0.129723 2.623841 0.000772
+v 0.110155 2.617475 0.111510
+v 0.098894 2.551101 -0.119944
+v 0.140309 2.525439 -0.009396
+v 0.098894 2.517193 0.100599
+v 0.208678 2.515187 -0.122760
+v 0.245812 2.502890 -0.002447
+v 0.208678 2.483677 0.109699
+v 0.271570 2.206755 -0.145013
+v 0.319908 2.187368 0.032075
+v 0.271570 2.177688 0.191096
+v 0.303127 1.441376 -0.106186
+v 0.355115 1.410218 0.080975
+v 0.289850 1.402806 0.240428
+v 0.260948 1.763152 0.232137
+v 0.307393 1.770383 0.075582
+v 0.260948 1.788246 -0.089088
+v 0.247213 2.324639 0.153241
+v 0.247213 2.354879 -0.163591
+v 0.115069 1.290704 0.269082
+v 0.017798 1.168477 -0.035384
+v 0.183067 1.284675 -0.183271
+v 0.084912 3.522239 -0.501146
+v 0.084912 3.064342 -0.512888
+v 0.084912 2.943401 0.510254
+v 0.084912 3.458095 0.476066
+v 0.090590 3.723567 0.254122
+v 0.090590 3.746935 -0.231142
+v 0.090590 2.722769 -0.231142
+v 0.090590 2.643034 0.288310
+v 0.084607 2.864935 -0.440534
+v 0.084607 2.702693 0.473189
+v 0.084607 3.673055 -0.413200
+v 0.084607 3.629352 0.421907
+v 0.086637 3.278739 -0.526585
+v 0.086636 3.215177 0.507309
+v 0.095154 3.754534 0.020506
+v 0.060191 2.658972 -0.154656
+v 0.053444 2.613782 0.136010
+v 0.047516 2.554504 -0.139039
+v 0.047516 2.514067 0.124693
+v 0.100126 2.519134 -0.142488
+v 0.100126 2.479805 0.136555
+v 0.130264 2.209162 -0.175208
+v 0.130264 2.175989 0.226360
+v 0.145386 1.454041 -0.168399
+v 0.145386 1.399946 0.290329
+v 0.125174 1.790136 -0.123980
+v 0.125174 1.762047 0.266843
+v 0.118592 2.321896 0.187758
+v 0.118592 2.358026 -0.194066
+v 0.064118 0.867640 -0.065778
+v 0.139275 0.844466 0.140266
+v 0.257486 0.890374 -0.145882
+v 0.359097 0.900878 0.061199
+v 0.074195 0.752219 -0.105874
+v 0.147259 0.698792 0.087905
+v 0.263534 0.755735 -0.191206
+v 0.364126 0.730329 0.010206
+v 0.092608 0.518587 -0.156357
+v 0.161208 0.488124 0.011298
+v 0.257654 0.503497 -0.235568
+v 0.342662 0.497755 -0.059963
+v 0.100936 1.052740 0.183646
+v 0.362186 1.124208 0.082677
+v 0.035605 1.007707 -0.051248
+v 0.244578 1.066754 -0.153714
+v 0.055029 1.214705 -0.163442
+v 0.255589 1.328226 0.210676
+v 0.140172 0.882954 -0.138230
+v 0.262287 0.869133 0.135226
+v 0.152224 0.756748 -0.186384
+v 0.268705 0.704238 0.080827
+v 0.163237 0.508650 -0.221611
+v 0.266438 0.484781 0.003128
+v 0.113057 1.038591 -0.152600
+v 0.246990 1.089520 0.173845
+v 0.054756 1.198160 0.101170
+v 0.310361 1.325851 -0.067512
+v 0.060255 0.853278 0.049460
+v 0.343613 0.899484 -0.056313
+v 0.071380 0.718974 0.002418
+v 0.350589 0.741909 -0.110914
+v 0.091684 0.503566 -0.057160
+v 0.339310 0.499423 -0.163148
+v 0.344611 1.099522 -0.066307
+v 0.028575 1.027615 0.082498
+v 0.455190 2.450647 -0.082374
+v 0.462809 2.465601 0.006612
+v 0.448972 2.441031 0.081440
+v 0.434408 2.252116 -0.088512
+v 0.448014 2.213438 0.029647
+v 0.428671 2.233589 0.135751
+v 0.442147 2.332059 0.110493
+v 1.328482 2.369486 -0.025838
+v 0.448115 2.351334 -0.094647
+v 0.717408 2.422497 -0.064617
+v 0.727228 2.428632 0.006928
+v 0.711866 2.404597 0.073618
+v 0.698886 2.236229 -0.077850
+v 0.706620 2.199933 0.027458
+v 0.693774 2.219717 0.102536
+v 0.705784 2.307478 0.109237
+v 0.945792 2.289033 0.134562
+v 0.711103 2.324656 -0.097021
+v 1.329792 2.357378 0.034079
+v 1.323088 2.354750 0.089928
+v 1.305094 2.214479 -0.036920
+v 1.300746 2.180356 0.051271
+v 1.300117 2.200886 0.110979
+v 1.313884 2.273778 0.121339
+v 1.509906 2.320435 -0.046242
+v 1.319060 2.287920 -0.055202
+v 0.930288 2.200850 0.122871
+v 0.936312 2.211617 -0.068478
+v 0.952059 2.307598 -0.088140
+v 0.936310 2.172915 0.046302
+v 0.968273 2.418404 0.023926
+v 0.961626 2.413997 -0.054054
+v 0.955096 2.394653 0.096614
+v 0.330881 2.488142 0.003375
+v 0.305188 2.468017 0.099597
+v 0.315496 2.226114 -0.122984
+v 0.320825 2.354873 -0.139518
+v 0.303439 2.230228 0.158131
+v 0.309166 2.327404 0.136383
+v 0.348316 2.192029 0.031171
+v 0.315498 2.485255 -0.117814
+v 1.401711 2.330388 -0.053750
+v 1.402313 2.325266 0.037149
+v 1.368471 2.326110 0.116069
+v 1.380995 2.227921 -0.070645
+v 1.378716 2.209659 0.062973
+v 1.340428 2.225900 0.146512
+v 1.351661 2.274332 0.162481
+v 1.795120 2.206148 -0.017422
+v 1.399326 2.275373 -0.096810
+v 1.525167 2.312472 0.043161
+v 1.504512 2.310743 0.126497
+v 1.486518 2.218486 -0.062778
+v 1.505804 2.196043 0.068815
+v 1.481542 2.209545 0.157907
+v 1.495307 2.257487 0.173365
+v 1.626749 2.173789 0.059473
+v 1.500484 2.266789 -0.090058
+v 1.809535 2.198612 0.054630
+v 1.788894 2.200041 0.121791
+v 1.762707 2.137646 -0.030749
+v 1.779807 2.119442 0.075304
+v 1.756964 2.132012 0.147105
+v 1.774950 2.163872 0.159563
+v 1.797727 2.160531 0.057501
+v 1.780926 2.169733 -0.052734
+v 1.607462 2.193023 -0.059653
+v 1.616252 2.226447 0.154119
+v 1.602486 2.185360 0.140125
+v 1.646111 2.273569 0.036250
+v 1.630851 2.280393 -0.044683
+v 1.621429 2.234418 -0.084348
+v 1.625457 2.272087 0.111690
+v 1.379530 2.252804 0.224500
+v 1.371148 2.204101 0.211689
+v 1.461364 2.245535 0.213279
+v 1.452982 2.196833 0.200468
+v 1.424118 2.225873 0.279904
+v 1.419068 2.175998 0.270241
+v 1.481443 2.235304 0.220739
+v 1.476394 2.185430 0.211076
+v 1.509712 2.198027 0.341520
+v 1.506171 2.163050 0.334743
+v 1.549915 2.204642 0.300027
+v 1.546374 2.169665 0.293251
+v 0.262061 0.256721 -0.179629
+v 0.125851 0.263241 -0.073885
+v 0.264548 0.252916 -0.065338
+v 0.141817 0.268149 -0.192735
+v 0.270091 0.253667 -0.122910
+v 0.125675 0.264206 -0.137064
+v 0.206420 0.264077 -0.203655
+v 0.230977 0.000692 0.289805
+v 0.342493 0.000690 0.270761
+v 0.163985 0.000688 -0.230879
+v 0.270393 0.000686 -0.245194
+v 0.144177 0.000691 0.033839
+v 0.288000 0.000691 0.291562
+v 0.372899 0.000687 -0.002369
+v 0.227192 0.000686 -0.254522
+v 0.257567 0.000689 0.016768
+v 0.137243 0.000692 0.170051
+v 0.391563 0.000688 0.127957
+v 0.273728 0.000690 0.160912
+v 0.338169 0.000686 -0.146682
+v 0.108448 0.000690 -0.113832
+v 0.239700 0.000687 -0.142594
+v 0.167568 0.000692 0.233611
+v 0.383765 0.000689 0.197667
+v 0.281809 0.000691 0.232984
+v 0.309290 0.000686 -0.218277
+v 0.229983 0.000687 -0.223266
+v 0.118360 0.000689 -0.190507
+v 0.130135 0.000690 -0.034828
+v 0.349068 0.000687 -0.064281
+v 0.249487 0.000688 -0.055304
+v 0.387775 0.000687 0.061323
+v 0.265648 0.000689 0.088840
+v 0.129773 0.000692 0.103416
+v 0.232718 0.085533 0.288274
+v 0.363576 0.085530 0.268239
+v 0.154897 0.085528 -0.243375
+v 0.260403 0.080414 -0.243911
+v 0.128135 0.085532 0.035193
+v 0.299506 0.085532 0.289325
+v 0.383870 0.085527 -0.003576
+v 0.214830 0.085527 -0.261124
+v 0.132008 0.085533 0.181044
+v 0.405763 0.085528 0.135972
+v 0.339530 0.085526 -0.157915
+v 0.096516 0.085530 -0.123177
+v 0.167580 0.085533 0.249102
+v 0.395495 0.085529 0.210885
+v 0.304116 0.077122 -0.204676
+v 0.110617 0.085530 -0.206279
+v 0.114426 0.085531 -0.038332
+v 0.357741 0.085527 -0.069335
+v 0.401320 0.085528 0.064622
+v 0.123244 0.085533 0.109694
+v 0.235360 0.121957 0.282892
+v 0.342479 0.121955 0.271351
+v 0.155498 0.140203 -0.234632
+v 0.258674 0.141703 -0.233045
+v 0.147943 0.140206 0.045064
+v 0.367478 0.140202 0.015099
+v 0.209678 0.140554 -0.248081
+v 0.151504 0.140207 0.167879
+v 0.387046 0.140203 0.131704
+v 0.326827 0.140201 -0.142554
+v 0.113117 0.142231 -0.125673
+v 0.174977 0.140207 0.230696
+v 0.378520 0.140204 0.201276
+v 0.291506 0.139635 -0.192779
+v 0.127237 0.141691 -0.187001
+v 0.134396 0.140206 -0.008056
+v 0.354118 0.140202 -0.035038
+v 0.382905 0.140203 0.065200
+v 0.143705 0.140207 0.101330
+v 0.244012 0.174412 0.250246
+v 0.312400 0.174411 0.237719
+v 0.154929 0.197920 -0.224667
+v 0.244653 0.200889 -0.226557
+v 0.200247 0.182648 0.039626
+v 0.320975 0.193251 0.026737
+v 0.200815 0.200081 -0.230324
+v 0.176892 0.181218 0.144060
+v 0.349336 0.193278 0.128903
+v 0.299466 0.209667 -0.141685
+v 0.117610 0.203001 -0.122411
+v 0.197637 0.187029 0.207154
+v 0.340156 0.188834 0.188204
+v 0.275703 0.199069 -0.189682
+v 0.130048 0.198871 -0.180965
+v 0.183002 0.199344 -0.013043
+v 0.295575 0.215862 -0.011766
+v 0.341167 0.191744 0.072780
+v 0.191423 0.184576 0.092515
+v 0.338887 0.000686 -0.105818
+v 0.244594 0.000688 -0.098949
+v 0.116803 0.000690 -0.073995
+v 0.348659 0.085527 -0.113812
+v 0.102306 0.085531 -0.080271
+v 0.339594 0.140202 -0.089574
+v 0.118165 0.140205 -0.060612
+v 0.304014 0.215861 -0.085942
+v 0.129758 0.215864 -0.062783
+v 0.261646 0.242079 -0.188306
+v 0.230162 0.234212 -0.224732
+v 0.193922 0.242264 -0.221201
+v 0.165941 0.245963 -0.208302
+v 0.280499 0.229314 -0.077601
+v 0.279868 0.243470 -0.137553
+v 0.127675 0.236447 -0.179834
+v 0.120948 0.240070 -0.122668
+v 0.128658 0.229317 -0.058955
+v 0.189612 0.231437 -0.029962
+v 0.259835 0.229315 -0.044259
+v 0.190037 0.256893 -0.038329
+v -0.410268 3.453012 0.200817
+v -0.176448 3.516046 -0.492870
+v -0.176448 3.069885 -0.492870
+v -0.193285 2.961166 0.489574
+v -0.193285 3.452389 0.455386
+v -0.400123 2.998632 0.217911
+v -0.400123 3.035397 -0.212411
+v -0.410268 3.483905 -0.212411
+v -0.188297 3.698580 0.247489
+v -0.188298 3.731344 -0.224509
+v -0.188298 2.741884 -0.224509
+v -0.188298 2.664058 0.281677
+v -0.338060 2.788810 0.205190
+v -0.323248 3.496119 -0.410188
+v -0.323248 3.441588 0.352035
+v -0.338059 3.642598 0.223085
+v -0.338060 2.852551 -0.208748
+v -0.175812 2.876968 -0.427238
+v -0.323248 3.072495 -0.410188
+v -0.192649 2.735571 0.459728
+v -0.323248 2.996823 0.381949
+v -0.338060 3.655763 -0.208748
+v -0.175812 3.660861 -0.399904
+v -0.192648 3.617279 0.405342
+v -0.180047 3.275434 -0.517282
+v 0.000241 3.527937 -0.505363
+v 0.000241 3.059241 -0.517105
+v -0.196883 3.218354 0.478425
+v 0.000241 2.927055 0.514236
+v 0.000241 3.457695 0.495095
+v -0.408868 3.230555 0.194491
+v -0.402636 3.253443 -0.219099
+v -0.428688 3.009897 0.014208
+v -0.438833 3.472003 0.009934
+v 0.000241 3.735282 0.260225
+v 0.000241 3.756304 -0.237245
+v -0.197821 3.743473 0.020506
+v -0.197821 2.669343 0.029053
+v 0.000241 2.716923 -0.237245
+v 0.000241 2.623689 0.294413
+v -0.285941 2.928726 -0.357824
+v -0.285941 2.767836 0.367046
+v -0.285941 3.636701 -0.357824
+v -0.301410 3.594941 0.358830
+v -0.357105 2.802252 0.025342
+v 0.000241 2.853864 -0.452768
+v -0.322054 3.266541 -0.423686
+v 0.000241 2.695371 0.485576
+v -0.326999 3.227505 0.360122
+v -0.357105 3.654801 0.017864
+v 0.000241 3.684277 -0.419779
+v 0.000241 3.640461 0.434294
+v 0.000241 3.279187 -0.533908
+v 0.000241 3.212254 0.507793
+v -0.433886 3.238045 0.005717
+v 0.000241 3.765371 0.020506
+v 0.000241 2.608866 0.157665
+v 0.000241 2.662452 -0.152277
+v -0.110768 2.648599 -0.113100
+v -0.129241 2.623841 0.000772
+v -0.109673 2.617475 0.111510
+v 0.000241 2.511192 0.146864
+v 0.000241 2.557636 -0.161210
+v -0.098412 2.551101 -0.119944
+v -0.139827 2.525439 -0.009396
+v -0.098412 2.517193 0.100599
+v 0.000241 2.476242 0.161267
+v 0.000241 2.522766 -0.165241
+v -0.208196 2.515187 -0.122760
+v -0.245330 2.502890 -0.002447
+v -0.208196 2.483677 0.109699
+v 0.000241 2.174426 0.258809
+v 0.000241 2.211377 -0.202993
+v -0.271088 2.206755 -0.145013
+v -0.319426 2.187368 0.032075
+v -0.271088 2.177688 0.191096
+v 0.000241 1.398135 0.309651
+v 0.000241 1.463624 -0.206620
+v -0.302644 1.441376 -0.106186
+v -0.354291 1.410232 0.081480
+v -0.288561 1.402802 0.240545
+v 0.000241 1.761031 0.298778
+v -0.260465 1.763152 0.232137
+v -0.306911 1.770383 0.075582
+v -0.260465 1.788246 -0.089088
+v 0.000241 1.791875 -0.156086
+v -0.246731 2.324639 0.153241
+v -0.246731 2.354880 -0.163592
+v 0.000241 2.360921 -0.206229
+v 0.000241 2.319373 0.219519
+v -0.113364 1.290662 0.268232
+v -0.018429 1.168483 -0.035181
+v -0.184480 1.284700 -0.183080
+v -0.000316 1.168480 -0.035282
+v -0.084430 3.522239 -0.501146
+v -0.084430 3.064342 -0.512888
+v -0.084430 2.943401 0.510254
+v -0.084429 3.458095 0.476066
+v -0.090108 3.723567 0.254122
+v -0.090108 3.746935 -0.231142
+v -0.090108 2.722769 -0.231142
+v -0.090108 2.643034 0.288310
+v -0.084125 2.864935 -0.440534
+v -0.084125 2.702693 0.473189
+v -0.084125 3.673055 -0.413200
+v -0.084125 3.629352 0.421907
+v -0.086154 3.278739 -0.526585
+v -0.086154 3.215177 0.507309
+v -0.094671 3.754534 0.020506
+v -0.059709 2.658972 -0.154656
+v -0.052962 2.613782 0.136010
+v -0.047034 2.554504 -0.139039
+v -0.047034 2.514068 0.124693
+v -0.099643 2.519134 -0.142488
+v -0.099643 2.479805 0.136555
+v -0.129782 2.209162 -0.175208
+v -0.129782 2.175989 0.226360
+v -0.144904 1.454041 -0.168399
+v -0.144904 1.399946 0.290329
+v -0.124691 1.790136 -0.123980
+v -0.124691 1.762047 0.266843
+v -0.118110 2.321897 0.187758
+v -0.118110 2.358026 -0.194066
+v 0.000241 1.284807 0.281643
+v 0.000241 1.284807 -0.179892
+v -0.065606 0.867575 -0.068223
+v -0.137184 0.844409 0.139088
+v -0.260316 0.890440 -0.144957
+v -0.358304 0.900967 0.063854
+v -0.076447 0.752149 -0.108154
+v -0.146162 0.698757 0.086858
+v -0.267231 0.755783 -0.190189
+v -0.364320 0.730428 0.012933
+v -0.095873 0.518518 -0.158302
+v -0.161565 0.488099 0.010515
+v -0.262272 0.503526 -0.234639
+v -0.344217 0.497838 -0.057588
+v -0.097973 1.052652 0.181831
+v -0.360885 1.124295 0.085420
+v -0.036763 1.007622 -0.054166
+v -0.247441 1.066813 -0.152981
+v -0.057083 1.214724 -0.162813
+v -0.253453 1.328216 0.210857
+v -0.001001 1.201565 -0.157958
+v -0.142896 0.882948 -0.139342
+v -0.260245 0.869150 0.136185
+v -0.155858 0.756730 -0.187298
+v -0.267706 0.704276 0.081887
+v -0.167628 0.508623 -0.222321
+v -0.266919 0.484820 0.004171
+v -0.115942 1.038571 -0.154153
+v -0.244148 1.089522 0.174570
+v -0.053830 1.198178 0.101779
+v -0.310544 1.325896 -0.066387
+v 0.000415 1.184651 0.093554
+v -0.059751 0.853190 0.046927
+v -0.344866 0.899585 -0.053907
+v -0.071771 0.718897 0.000070
+v -0.352883 0.742005 -0.108402
+v -0.093234 0.503499 -0.059137
+v -0.342657 0.499502 -0.160814
+v -0.345917 1.099626 -0.063848
+v -0.027398 1.027503 0.079441
+v -0.454708 2.450647 -0.082374
+v -0.462326 2.465601 0.006612
+v -0.448490 2.441031 0.081440
+v -0.433925 2.252116 -0.088512
+v -0.447532 2.213438 0.029647
+v -0.428189 2.233589 0.135751
+v -0.441665 2.332059 0.110493
+v -1.328000 2.369487 -0.025839
+v -0.447632 2.351334 -0.094647
+v -0.716926 2.422497 -0.064618
+v -0.726745 2.428632 0.006928
+v -0.711384 2.404597 0.073617
+v -0.698403 2.236229 -0.077851
+v -0.706138 2.199933 0.027457
+v -0.693291 2.219717 0.102535
+v -0.705302 2.307478 0.109236
+v -0.945310 2.289035 0.134561
+v -0.710620 2.324656 -0.097021
+v -1.329309 2.357379 0.034077
+v -1.322606 2.354751 0.089927
+v -1.304611 2.214480 -0.036921
+v -1.300263 2.180357 0.051270
+v -1.299635 2.200886 0.110977
+v -1.313401 2.273779 0.121337
+v -1.509424 2.320436 -0.046244
+v -1.318578 2.287921 -0.055203
+v -0.929806 2.200852 0.122871
+v -0.935830 2.211618 -0.068479
+v -0.951576 2.307599 -0.088141
+v -0.935828 2.172916 0.046301
+v -0.967791 2.418405 0.023925
+v -0.961144 2.413998 -0.054055
+v -0.954614 2.394654 0.096613
+v -0.330399 2.488142 0.003375
+v -0.304706 2.468017 0.099597
+v -0.315013 2.226115 -0.122984
+v -0.320343 2.354873 -0.139518
+v -0.302957 2.230229 0.158131
+v -0.308683 2.327404 0.136383
+v -0.347834 2.192029 0.031171
+v -0.315016 2.485255 -0.117814
+v -1.401229 2.330389 -0.053752
+v -1.401832 2.325267 0.037148
+v -1.367989 2.326111 0.116068
+v -1.380512 2.227921 -0.070646
+v -1.378233 2.209659 0.062972
+v -1.339946 2.225900 0.146510
+v -1.351179 2.274333 0.162479
+v -1.794637 2.206148 -0.017425
+v -1.398844 2.275373 -0.096812
+v -1.524685 2.312473 0.043160
+v -1.504030 2.310744 0.126495
+v -1.486035 2.218486 -0.062780
+v -1.505322 2.196043 0.068813
+v -1.481060 2.209546 0.157905
+v -1.494826 2.257488 0.173364
+v -1.626266 2.173790 0.059471
+v -1.500002 2.266789 -0.090059
+v -1.809052 2.198613 0.054628
+v -1.788411 2.200042 0.121789
+v -1.762224 2.137647 -0.030751
+v -1.779324 2.119443 0.075302
+v -1.756481 2.132013 0.147103
+v -1.774468 2.163872 0.159561
+v -1.797244 2.160531 0.057499
+v -1.780442 2.169733 -0.052736
+v -1.606979 2.193023 -0.059655
+v -1.615770 2.226447 0.154117
+v -1.602004 2.185361 0.140123
+v -1.645628 2.273569 0.036248
+v -1.630368 2.280394 -0.044685
+v -1.620946 2.234419 -0.084350
+v -1.624974 2.272088 0.111689
+v -1.379048 2.252805 0.224499
+v -1.370666 2.204103 0.211687
+v -1.460882 2.245536 0.213278
+v -1.452500 2.196834 0.200466
+v -1.423636 2.225874 0.279902
+v -1.418586 2.176000 0.270239
+v -1.480961 2.235306 0.220738
+v -1.475912 2.185432 0.211075
+v -1.509230 2.198029 0.341518
+v -1.505689 2.163052 0.334741
+v -1.549433 2.204644 0.300026
+v -1.545892 2.169667 0.293249
+v -0.265503 0.256741 -0.179040
+v -0.128605 0.263213 -0.074647
+v -0.266996 0.252931 -0.064922
+v -0.145572 0.268133 -0.193156
+v -0.273029 0.253686 -0.122348
+v -0.128976 0.264181 -0.137721
+v -0.210161 0.264081 -0.203502
+v -0.234285 0.000684 0.289802
+v -0.345794 0.000685 0.270758
+v -0.167301 0.000685 -0.230884
+v -0.273702 0.000685 -0.245200
+v -0.147492 0.000684 0.033835
+v -0.291304 0.000684 0.291559
+v -0.376200 0.000685 -0.002375
+v -0.230503 0.000685 -0.254528
+v -0.260875 0.000685 0.016763
+v -0.140559 0.000683 0.170049
+v -0.394861 0.000685 0.127952
+v -0.277034 0.000684 0.160908
+v -0.341473 0.000685 -0.146689
+v -0.111766 0.000684 -0.113835
+v -0.243010 0.000685 -0.142600
+v -0.170881 0.000684 0.233609
+v -0.387064 0.000685 0.197662
+v -0.285114 0.000684 0.232981
+v -0.312595 0.000685 -0.218283
+v -0.233294 0.000685 -0.223272
+v -0.121678 0.000684 -0.190511
+v -0.133452 0.000684 -0.034831
+v -0.352371 0.000685 -0.064287
+v -0.252796 0.000685 -0.055309
+v -0.391075 0.000685 0.061317
+v -0.268955 0.000685 0.088836
+v -0.133089 0.000684 0.103414
+v -0.236024 0.085525 0.288271
+v -0.366872 0.085526 0.268235
+v -0.158210 0.085526 -0.243380
+v -0.263710 0.080414 -0.243917
+v -0.131449 0.085526 0.035190
+v -0.302807 0.085526 0.289322
+v -0.387167 0.085527 -0.003582
+v -0.218139 0.085526 -0.261130
+v -0.135320 0.085525 0.181042
+v -0.409058 0.085527 0.135967
+v -0.342831 0.085527 -0.157921
+v -0.099833 0.085525 -0.123180
+v -0.170889 0.085525 0.249100
+v -0.398790 0.085527 0.210881
+v -0.307420 0.077122 -0.204682
+v -0.113933 0.085526 -0.206283
+v -0.117741 0.085526 -0.038335
+v -0.361040 0.085527 -0.069341
+v -0.404616 0.085527 0.064617
+v -0.126558 0.085525 0.109692
+v -0.238664 0.121950 0.282890
+v -0.345776 0.121951 0.271347
+v -0.158809 0.140201 -0.234637
+v -0.261978 0.141703 -0.233051
+v -0.151253 0.140201 0.045061
+v -0.370775 0.140202 0.015093
+v -0.212986 0.140554 -0.248087
+v -0.154814 0.140200 0.167876
+v -0.390340 0.140202 0.131699
+v -0.330126 0.140202 -0.142561
+v -0.116431 0.142227 -0.125676
+v -0.178285 0.140200 0.230694
+v -0.381814 0.140202 0.201272
+v -0.294809 0.139635 -0.192786
+v -0.130550 0.141688 -0.187006
+v -0.137707 0.140201 -0.008060
+v -0.357415 0.140202 -0.035044
+v -0.386200 0.140202 0.065195
+v -0.147016 0.140200 0.101327
+v -0.247314 0.174407 0.250243
+v -0.315698 0.174407 0.237716
+v -0.158239 0.197919 -0.224671
+v -0.247956 0.200890 -0.226562
+v -0.203553 0.182644 0.039623
+v -0.324272 0.193250 0.026732
+v -0.204122 0.200081 -0.230329
+v -0.180198 0.181212 0.144057
+v -0.352631 0.193276 0.128898
+v -0.302766 0.209668 -0.141691
+v -0.120922 0.202998 -0.122415
+v -0.200942 0.187023 0.207151
+v -0.343452 0.188832 0.188200
+v -0.279004 0.199070 -0.189688
+v -0.133359 0.198869 -0.180969
+v -0.186309 0.199341 -0.013046
+v -0.298874 0.215861 -0.011771
+v -0.344463 0.191743 0.072775
+v -0.194729 0.184572 0.092512
+v -0.342190 0.000685 -0.105824
+v -0.247903 0.000685 -0.098954
+v -0.120121 0.000684 -0.073998
+v -0.351959 0.085527 -0.113818
+v -0.105622 0.085526 -0.080274
+v -0.342893 0.140202 -0.089580
+v -0.121478 0.140201 -0.060615
+v -0.307313 0.215861 -0.085948
+v -0.133068 0.215860 -0.062786
+v -0.264947 0.242080 -0.188311
+v -0.233465 0.234212 -0.224737
+v -0.197228 0.242264 -0.221206
+v -0.169248 0.245962 -0.208306
+v -0.283799 0.229314 -0.077606
+v -0.283168 0.243471 -0.137559
+v -0.130985 0.236445 -0.179838
+v -0.124258 0.240067 -0.122671
+v -0.131967 0.229313 -0.058958
+v -0.192917 0.231434 -0.029966
+v -0.263136 0.229314 -0.044264
+v -0.192377 0.256884 -0.038600
+v -1.684602 2.165335 -0.045203
+v -1.679243 2.158687 0.143613
+v -1.727340 2.236091 0.045438
+v -1.702795 2.146616 0.067387
+v -1.695118 2.195160 0.156839
+v -1.712502 2.243271 -0.031055
+v -1.700694 2.202076 -0.068543
+v -1.706693 2.236064 0.116739
+v 1.685084 2.165334 -0.045201
+v 1.679725 2.158686 0.143615
+v 1.727823 2.236091 0.045440
+v 1.703278 2.146616 0.067389
+v 1.695601 2.195159 0.156841
+v 1.712985 2.243270 -0.031053
+v 1.701177 2.202075 -0.068541
+v 1.707175 2.236064 0.116741
+v 1.566276 2.184916 0.064144
+v 1.555779 2.241967 0.163742
+v 1.570378 2.300414 -0.045463
+v 1.560956 2.250603 -0.087203
+v 1.564984 2.291415 0.119094
+v 1.546990 2.205754 -0.061216
+v 1.542014 2.197453 0.149016
+v 1.585639 2.293020 0.039706
+v -1.565794 2.184916 0.064142
+v -1.555298 2.241968 0.163740
+v -1.569896 2.300415 -0.045465
+v -1.560474 2.250604 -0.087204
+v -1.564502 2.291416 0.119092
+v -1.546507 2.205755 -0.061217
+v -1.541532 2.197453 0.149014
+v -1.585157 2.293021 0.039704
+v 0.817599 2.223923 -0.073164
+v 0.817657 2.186424 0.036880
+v 0.839517 2.418247 -0.059336
+v 0.833481 2.399625 0.085116
+v 0.812031 2.210284 0.112704
+v 0.831581 2.316127 -0.092581
+v 0.836919 2.423518 0.015427
+v -0.817117 2.223924 -0.073165
+v -0.817175 2.186424 0.036879
+v -0.839035 2.418248 -0.059336
+v -0.832999 2.399626 0.085115
+v -0.811549 2.210284 0.112703
+v -0.831098 2.316128 -0.092581
+v -0.836436 2.423519 0.015427
+v 0.000241 1.579583 0.304214
+v 0.334021 1.590260 0.078120
+v 0.000241 1.627749 -0.181353
+v 0.277708 1.583014 0.235970
+v 0.282037 1.614811 -0.097637
+v 0.135280 1.622088 -0.146189
+v 0.135280 1.580997 0.278586
+v -0.333345 1.590268 0.078406
+v -0.276778 1.583012 0.236050
+v -0.281555 1.614811 -0.097637
+v -0.134797 1.622088 -0.146189
+v -0.134797 1.580997 0.278586
+v 0.266259 1.970420 0.211617
+v 0.266259 1.997501 -0.117050
+v 0.000241 1.967728 0.278793
+v 0.313651 1.978875 0.053829
+v 0.000241 2.001626 -0.179539
+v 0.127719 1.969018 0.246602
+v 0.127719 1.999649 -0.149594
+v -0.265777 1.970420 0.211617
+v -0.265777 1.997501 -0.117050
+v -0.313168 1.978875 0.053829
+v -0.127236 1.969018 0.246602
+v -0.127236 1.999649 -0.149594
+v 1.122344 2.200868 0.116925
+v 1.142700 2.297759 -0.071671
+v 1.154038 2.387891 0.029002
+v 1.136979 2.281405 0.127950
+v 1.127844 2.213048 -0.052699
+v 1.133873 2.176636 0.048787
+v 1.152195 2.391741 -0.039946
+v 1.146233 2.374701 0.093271
+v -1.121862 2.200869 0.116924
+v -1.142218 2.297760 -0.071672
+v -1.153556 2.387892 0.029001
+v -1.136497 2.281407 0.127949
+v -1.127362 2.213049 -0.052700
+v -1.133391 2.176636 0.048786
+v -1.151713 2.391742 -0.039947
+v -1.145751 2.374702 0.093270
+v 0.581107 2.319769 0.109865
+v 0.586750 2.337995 -0.095834
+v 0.593441 2.436572 -0.073496
+v 0.600412 2.447117 0.006770
+v 0.587561 2.422814 0.077529
+v 0.577991 2.206686 0.028552
+v 0.568364 2.226653 0.119143
+v 0.573788 2.244173 -0.083181
+v -0.580625 2.319769 0.109865
+v -0.586267 2.337995 -0.095834
+v -0.592958 2.436572 -0.073496
+v -0.599929 2.447117 0.006770
+v -0.587078 2.422814 0.077529
+v -0.577509 2.206685 0.028552
+v -0.567881 2.226653 0.119143
+v -0.573305 2.244173 -0.083181
+v 0.069151 0.811140 -0.084140
+v 0.143267 0.769931 0.115422
+v 0.361608 0.814996 0.037936
+v 0.265496 0.785043 0.109763
+v 0.146190 0.822050 -0.160339
+v 0.347095 0.821727 -0.081373
+v 0.065815 0.785709 0.027417
+v -0.070991 0.811069 -0.086508
+v -0.141651 0.769890 0.114305
+v -0.361270 0.815091 0.040619
+v -0.263946 0.785076 0.110766
+v -0.149333 0.822031 -0.161359
+v -0.348828 0.821822 -0.078922
+v -0.065734 0.785628 0.024971
+vt 0.424701 0.840048
+vt 0.423209 0.793785
+vt 0.461737 0.792426
+vt 0.464884 0.838834
+vt 0.468357 0.881332
+vt 0.416097 0.891155
+vt 0.382303 0.875623
+vt 0.388845 0.838885
+vt 0.386734 0.795098
+vt 0.579037 0.844668
+vt 0.567369 0.879717
+vt 0.544300 0.865660
+vt 0.547922 0.837220
+vt 0.549707 0.794263
+vt 0.582610 0.796170
+vt 0.598269 0.849956
+vt 0.602276 0.796592
+vt 0.621565 0.796099
+vt 0.617431 0.855287
+vt 0.601115 0.901709
+vt 0.583674 0.890608
+vt 0.580062 0.754791
+vt 0.546804 0.757119
+vt 0.544177 0.724490
+vt 0.573455 0.711359
+vt 0.598626 0.752337
+vt 0.595019 0.704367
+vt 0.617289 0.699781
+vt 0.620532 0.750242
+vt 0.349273 0.747190
+vt 0.347330 0.708825
+vt 0.370455 0.709217
+vt 0.379997 0.749138
+vt 0.352581 0.794437
+vt 0.329588 0.744940
+vt 0.331063 0.794428
+vt 0.315002 0.794084
+vt 0.314985 0.741795
+vt 0.314901 0.703498
+vt 0.329344 0.703695
+vt 0.354491 0.840733
+vt 0.357743 0.880856
+vt 0.332172 0.842510
+vt 0.333959 0.884940
+vt 0.315019 0.885796
+vt 0.315031 0.842108
+vt 0.414559 0.747483
+vt 0.399518 0.701783
+vt 0.448949 0.694770
+vt 0.456853 0.745548
+vt 0.505141 0.748829
+vt 0.508784 0.706093
+vt 0.507142 0.792801
+vt 0.508074 0.837122
+vt 0.514661 0.872259
+vt 0.419137 0.937326
+vt 0.478349 0.922822
+vt 0.424097 0.965195
+vt 0.486594 0.948330
+vt 0.495723 0.973192
+vt 0.428443 0.990876
+vt 0.345577 0.936058
+vt 0.314782 0.941388
+vt 0.375705 0.922558
+vt 0.532102 0.902649
+vt 0.545515 0.922196
+vt 0.559814 0.940878
+vt 0.436532 0.655316
+vt 0.362648 0.645806
+vt 0.382595 0.577465
+vt 0.445393 0.577416
+vt 0.535122 0.656711
+vt 0.561397 0.634699
+vt 0.607811 0.622342
+vt 0.339216 0.643866
+vt 0.314578 0.640560
+vt 0.510735 0.577421
+vt 0.559529 0.577420
+vt 0.444090 0.534948
+vt 0.509270 0.534980
+vt 0.347826 0.577463
+vt 0.314959 0.577465
+vt 0.314357 0.535019
+vt 0.343869 0.535021
+vt 0.327559 0.284656
+vt 0.332242 0.271386
+vt 0.359600 0.274896
+vt 0.357633 0.299914
+vt 0.321315 0.250312
+vt 0.314290 0.247970
+vt 0.314171 0.231740
+vt 0.334433 0.243039
+vt 0.382847 0.535032
+vt 0.558656 0.534925
+vt 0.325529 0.253434
+vt 0.351430 0.248123
+vt 0.319754 0.286217
+vt 0.333829 0.303559
+vt 0.418691 0.370972
+vt 0.389352 0.351632
+vt 0.418603 0.335552
+vt 0.431990 0.354981
+vt 0.338145 0.328760
+vt 0.366602 0.325961
+vt 0.377808 0.356778
+vt 0.343676 0.358303
+vt 0.335864 0.210609
+vt 0.314003 0.207365
+vt 0.314103 0.176477
+vt 0.345144 0.178504
+vt 0.387039 0.219621
+vt 0.390341 0.194177
+vt 0.422363 0.207716
+vt 0.418946 0.229929
+vt 0.345500 0.054288
+vt 0.315138 0.054235
+vt 0.315528 0.018181
+vt 0.347504 0.018238
+vt 0.376599 0.479159
+vt 0.415450 0.479198
+vt 0.416158 0.512649
+vt 0.378862 0.512649
+vt 0.417869 0.054390
+vt 0.379180 0.054356
+vt 0.383732 0.018359
+vt 0.421058 0.018359
+vt 0.344804 0.479148
+vt 0.345824 0.512586
+vt 0.343730 0.404567
+vt 0.376072 0.404566
+vt 0.374336 0.441555
+vt 0.343784 0.441555
+vt 0.416751 0.128948
+vt 0.377222 0.128952
+vt 0.374628 0.091879
+vt 0.414680 0.091883
+vt 0.414734 0.404572
+vt 0.414742 0.441555
+vt 0.344319 0.128948
+vt 0.314426 0.128944
+vt 0.314749 0.091873
+vt 0.343495 0.091877
+vt 0.377580 0.274898
+vt 0.379110 0.250741
+vt 0.414096 0.254865
+vt 0.413016 0.274926
+vt 0.383845 0.322909
+vt 0.415778 0.316747
+vt 0.785443 0.156150
+vt 0.764725 0.156147
+vt 0.765086 0.122612
+vt 0.785862 0.122612
+vt 0.799682 0.217712
+vt 0.787967 0.231864
+vt 0.787944 0.209717
+vt 0.806383 0.217712
+vt 0.817931 0.209717
+vt 0.817908 0.231864
+vt 0.313408 0.304910
+vt 0.313716 0.329378
+vt 0.371733 0.216071
+vt 0.314416 0.404567
+vt 0.314870 0.441555
+vt 0.315301 0.479147
+vt 0.315731 0.512570
+vt 0.379817 0.180762
+vt 0.313963 0.358401
+vt 0.313509 0.286997
+vt 0.603163 0.577407
+vt 0.606192 0.534877
+vt 0.745241 0.200706
+vt 0.748033 0.232049
+vt 0.860635 0.200706
+vt 0.857842 0.232049
+vt 0.709972 0.232115
+vt 0.709972 0.200711
+vt 0.709972 0.171386
+vt 0.709972 0.163211
+vt 0.711885 0.163092
+vt 0.722930 0.172839
+vt 0.895904 0.232115
+vt 0.895904 0.200711
+vt 0.882945 0.172839
+vt 0.893990 0.163092
+vt 0.895904 0.163211
+vt 0.895904 0.171386
+vt 0.746436 0.108499
+vt 0.728058 0.108499
+vt 0.727994 0.095821
+vt 0.746362 0.095822
+vt 0.742320 0.156136
+vt 0.722900 0.156121
+vt 0.728122 0.122612
+vt 0.746509 0.122612
+vt 0.820432 0.156150
+vt 0.806711 0.156148
+vt 0.806948 0.122612
+vt 0.820014 0.122612
+vt 0.863555 0.156136
+vt 0.841092 0.156147
+vt 0.840811 0.122612
+vt 0.859366 0.122612
+vt 0.820810 0.095822
+vt 0.806988 0.095820
+vt 0.807180 0.054984
+vt 0.822926 0.054984
+vt 0.820412 0.108499
+vt 0.806968 0.108499
+vt 0.859513 0.095822
+vt 0.859440 0.108499
+vt 0.840859 0.095821
+vt 0.785464 0.108499
+vt 0.765055 0.108499
+vt 0.765025 0.095821
+vt 0.785065 0.095822
+vt 0.765027 0.054984
+vt 0.748996 0.054984
+vt 0.749674 0.016269
+vt 0.765051 0.016269
+vt 0.840857 0.054984
+vt 0.856880 0.054984
+vt 0.782949 0.054984
+vt 0.729510 0.054983
+vt 0.799277 0.156148
+vt 0.882975 0.156121
+vt 0.798935 0.095820
+vt 0.798699 0.054984
+vt 0.877882 0.095821
+vt 0.876366 0.054983
+vt 0.730059 0.016269
+vt 0.798960 0.108499
+vt 0.877818 0.108499
+vt 0.877753 0.122612
+vt 0.798985 0.122612
+vt 0.840838 0.016269
+vt 0.856202 0.016269
+vt 0.782896 0.016268
+vt 0.798648 0.016268
+vt 0.449700 0.220684
+vt 0.449796 0.204123
+vt 0.480859 0.204123
+vt 0.480685 0.220695
+vt 0.449654 0.257610
+vt 0.449682 0.238404
+vt 0.480652 0.238492
+vt 0.480599 0.257655
+vt 0.449661 0.302478
+vt 0.449646 0.286082
+vt 0.480577 0.286036
+vt 0.480601 0.302370
+vt 0.449670 0.274956
+vt 0.480593 0.274987
+vt 0.377299 0.292342
+vt 0.412883 0.292280
+vt 0.427685 0.190243
+vt 0.435707 0.203873
+vt 0.566812 0.286023
+vt 0.566812 0.275036
+vt 0.595577 0.275057
+vt 0.595566 0.286095
+vt 0.566827 0.354952
+vt 0.566822 0.326817
+vt 0.595512 0.326825
+vt 0.595500 0.354952
+vt 0.566782 0.238670
+vt 0.566782 0.220717
+vt 0.595706 0.220705
+vt 0.595699 0.238600
+vt 0.566815 0.302227
+vt 0.595550 0.302456
+vt 0.449673 0.326828
+vt 0.480612 0.326823
+vt 0.449765 0.354952
+vt 0.480773 0.354952
+vt 0.936048 0.768188
+vt 0.936053 0.746623
+vt 0.924192 0.740812
+vt 0.923121 0.760166
+vt 0.936018 0.819789
+vt 0.936059 0.797784
+vt 0.916592 0.805110
+vt 0.913699 0.821253
+vt 0.935973 0.782601
+vt 0.915423 0.782034
+vt 0.911752 0.319669
+vt 0.933272 0.316595
+vt 0.941824 0.333084
+vt 0.910614 0.334381
+vt 0.566800 0.257742
+vt 0.595621 0.257734
+vt 0.566790 0.204124
+vt 0.595682 0.204124
+vt 0.506526 0.274998
+vt 0.506548 0.257674
+vt 0.532519 0.257694
+vt 0.532485 0.275009
+vt 0.506620 0.220701
+vt 0.506734 0.204123
+vt 0.532625 0.204124
+vt 0.532558 0.220707
+vt 0.532559 0.238577
+vt 0.506530 0.302339
+vt 0.506519 0.286032
+vt 0.532490 0.286028
+vt 0.532482 0.302308
+vt 0.506529 0.326822
+vt 0.532468 0.326821
+vt 0.506639 0.354952
+vt 0.532541 0.354952
+vt 0.420373 0.176908
+vt 0.414725 0.374942
+vt 0.885913 0.762972
+vt 0.885325 0.783977
+vt 0.889616 0.328988
+vt 0.912643 0.364253
+vt 0.892080 0.360976
+vt 0.879460 0.743643
+vt 0.891324 0.803735
+vt 0.891345 0.819504
+vt 0.896713 0.317960
+vt 0.936077 0.838896
+vt 0.917882 0.833832
+vt 0.948365 0.733420
+vt 0.934622 0.732855
+vt 0.849376 0.815349
+vt 0.850748 0.805248
+vt 0.836471 0.804603
+vt 0.835136 0.812201
+vt 0.845468 0.793376
+vt 0.831510 0.796107
+vt 0.917673 0.409579
+vt 0.942118 0.402143
+vt 0.940634 0.420541
+vt 0.917720 0.427678
+vt 0.838529 0.771488
+vt 0.832166 0.765778
+vt 0.818658 0.776896
+vt 0.825597 0.780492
+vt 0.891695 0.833437
+vt 0.868327 0.735148
+vt 0.887944 0.727402
+vt 0.871512 0.724326
+vt 0.941792 0.356512
+vt 0.824181 0.797634
+vt 0.812448 0.795354
+vt 0.828406 0.817321
+vt 0.830746 0.786410
+vt 0.844654 0.780574
+vt 0.900278 0.405603
+vt 0.901378 0.423637
+vt 0.844856 0.823697
+vt 0.876501 0.831755
+vt 0.877480 0.819001
+vt 0.863616 0.818497
+vt 0.861307 0.830073
+vt 0.872376 0.787311
+vt 0.872238 0.768855
+vt 0.858562 0.774738
+vt 0.859427 0.790645
+vt 0.895628 0.374273
+vt 0.915135 0.377867
+vt 0.917627 0.391481
+vt 0.899177 0.387570
+vt 0.865460 0.753064
+vt 0.851461 0.762485
+vt 0.857000 0.744904
+vt 0.845674 0.754660
+vt 0.942698 0.370129
+vt 0.943603 0.383745
+vt 0.878174 0.804814
+vt 0.865024 0.805893
+vt 0.914557 0.725788
+vt 0.924213 0.719241
+vt 0.914994 0.703678
+vt 0.906472 0.711107
+vt 0.881044 0.356556
+vt 0.875706 0.338668
+vt 0.863509 0.352136
+vt 0.879002 0.362548
+vt 0.863138 0.381292
+vt 0.852273 0.373989
+vt 0.885267 0.719886
+vt 0.871271 0.716399
+vt 0.894062 0.694357
+vt 0.896674 0.686606
+vt 0.881207 0.690837
+vt 0.886620 0.697803
+vt 0.822979 0.016268
+vt 0.807221 0.016268
+vt 0.875816 0.016269
+vt 0.767140 0.911152
+vt 0.774189 0.910992
+vt 0.771025 0.901580
+vt 0.764041 0.893569
+vt 0.762619 0.936895
+vt 0.770492 0.925697
+vt 0.696701 0.941705
+vt 0.711877 0.936747
+vt 0.712850 0.911002
+vt 0.696555 0.911002
+vt 0.714237 0.884771
+vt 0.699642 0.883044
+vt 0.663963 0.911002
+vt 0.680259 0.911002
+vt 0.684668 0.883866
+vt 0.669298 0.887352
+vt 0.666683 0.936525
+vt 0.681635 0.941705
+vt 0.736641 0.940160
+vt 0.745745 0.941028
+vt 0.748883 0.911001
+vt 0.739015 0.911001
+vt 0.747331 0.888913
+vt 0.738188 0.889775
+vt 0.652548 0.923774
+vt 0.650728 0.911086
+vt 0.654009 0.898398
+vt 0.729146 0.911001
+vt 0.728658 0.888542
+vt 0.727561 0.938163
+vt 0.685829 0.695635
+vt 0.692503 0.712229
+vt 0.708990 0.708576
+vt 0.708432 0.689949
+vt 0.636358 0.838542
+vt 0.651216 0.838339
+vt 0.651688 0.827846
+vt 0.635893 0.827677
+vt 0.781184 0.780586
+vt 0.761434 0.786870
+vt 0.765163 0.797322
+vt 0.785169 0.791226
+vt 0.644587 0.767637
+vt 0.662889 0.772774
+vt 0.667608 0.758644
+vt 0.648575 0.752749
+vt 0.673889 0.744932
+vt 0.655645 0.733289
+vt 0.636687 0.810221
+vt 0.652656 0.811979
+vt 0.655557 0.797710
+vt 0.638034 0.794237
+vt 0.751425 0.706855
+vt 0.736307 0.719414
+vt 0.743897 0.740484
+vt 0.762033 0.731608
+vt 0.770097 0.809706
+vt 0.787648 0.803114
+vt 0.775207 0.821912
+vt 0.791133 0.816315
+vt 0.756045 0.773861
+vt 0.741140 0.776355
+vt 0.746963 0.789506
+vt 0.749903 0.756858
+vt 0.738081 0.763188
+vt 0.728583 0.733966
+vt 0.733420 0.750248
+vt 0.683428 0.721761
+vt 0.690265 0.735383
+vt 0.699037 0.717821
+vt 0.675902 0.773849
+vt 0.678758 0.763215
+vt 0.663860 0.828975
+vt 0.666038 0.813500
+vt 0.651369 0.848259
+vt 0.662989 0.848260
+vt 0.662721 0.839648
+vt 0.726155 0.711178
+vt 0.718851 0.717725
+vt 0.763232 0.827184
+vt 0.767474 0.837667
+vt 0.779325 0.835265
+vt 0.753212 0.799839
+vt 0.758294 0.814508
+vt 0.683588 0.751217
+vt 0.658905 0.785523
+vt 0.671987 0.788046
+vt 0.669398 0.798853
+vt 0.770171 0.848260
+vt 0.779396 0.848260
+vt 0.737140 0.805935
+vt 0.745139 0.819551
+vt 0.691125 0.756638
+vt 0.696225 0.747399
+vt 0.671483 0.841478
+vt 0.672536 0.832167
+vt 0.695283 0.790443
+vt 0.692294 0.778048
+vt 0.684106 0.807013
+vt 0.755272 0.840706
+vt 0.757876 0.848260
+vt 0.689617 0.767062
+vt 0.751837 0.830942
+vt 0.726011 0.777908
+vt 0.724135 0.790230
+vt 0.727747 0.767067
+vt 0.723221 0.747063
+vt 0.728335 0.757320
+vt 0.702554 0.734897
+vt 0.676496 0.818660
+vt 0.669902 0.848260
+vt 0.715282 0.734795
+vt 0.744649 0.834372
+vt 0.747224 0.843692
+vt 0.678439 0.843499
+vt 0.679462 0.835501
+vt 0.740023 0.822211
+vt 0.676559 0.848260
+vt 0.718747 0.798862
+vt 0.731506 0.809276
+vt 0.681201 0.821956
+vt 0.749698 0.848260
+vt 0.689595 0.809913
+vt 0.701454 0.798968
+vt 0.731965 0.694501
+vt 0.685748 0.848259
+vt 0.686221 0.838135
+vt 0.741199 0.848260
+vt 0.688336 0.824075
+vt 0.697257 0.814380
+vt 0.734432 0.824734
+vt 0.739082 0.837215
+vt 0.710682 0.811176
+vt 0.725362 0.813361
+vt 0.794502 0.834892
+vt 0.769187 0.749663
+vt 0.775611 0.765710
+vt 0.794901 0.848257
+vt 0.640929 0.781632
+vt 0.666521 0.709568
+vt 0.636356 0.848259
+vt 0.205395 0.840356
+vt 0.165057 0.839231
+vt 0.168249 0.792680
+vt 0.206812 0.794023
+vt 0.214392 0.891615
+vt 0.161589 0.882055
+vt 0.241265 0.839077
+vt 0.247916 0.875817
+vt 0.243291 0.795273
+vt 0.050187 0.844482
+vt 0.081566 0.837294
+vt 0.084989 0.865972
+vt 0.061577 0.879960
+vt 0.047164 0.795723
+vt 0.080136 0.794155
+vt 0.030751 0.849572
+vt 0.011363 0.854676
+vt 0.008122 0.795077
+vt 0.027453 0.795879
+vt 0.044980 0.890795
+vt 0.027199 0.901816
+vt 0.050209 0.754404
+vt 0.083344 0.757041
+vt 0.057188 0.711303
+vt 0.086190 0.724548
+vt 0.031763 0.751718
+vt 0.009998 0.749349
+vt 0.013882 0.699460
+vt 0.035870 0.704195
+vt 0.280653 0.747292
+vt 0.249910 0.749310
+vt 0.259406 0.709407
+vt 0.282503 0.708944
+vt 0.277433 0.794536
+vt 0.300327 0.744987
+vt 0.298944 0.794473
+vt 0.300463 0.703752
+vt 0.275598 0.840835
+vt 0.272406 0.880931
+vt 0.297897 0.842557
+vt 0.296112 0.884965
+vt 0.215427 0.747718
+vt 0.173187 0.745804
+vt 0.181086 0.695152
+vt 0.230402 0.702057
+vt 0.124974 0.748995
+vt 0.121499 0.706399
+vt 0.122778 0.792952
+vt 0.121636 0.837433
+vt 0.114850 0.872809
+vt 0.211767 0.938667
+vt 0.151460 0.924131
+vt 0.206881 0.967319
+vt 0.202444 0.993810
+vt 0.133578 0.975415
+vt 0.143009 0.950086
+vt 0.284332 0.935822
+vt 0.254612 0.922405
+vt 0.097049 0.903456
+vt 0.083305 0.923173
+vt 0.068619 0.942013
+vt 0.194143 0.656045
+vt 0.184361 0.577417
+vt 0.247489 0.577466
+vt 0.266383 0.646033
+vt 0.095483 0.657314
+vt 0.069552 0.635446
+vt 0.023577 0.623156
+vt 0.289968 0.643994
+vt 0.071392 0.577421
+vt 0.119669 0.577423
+vt 0.120835 0.534998
+vt 0.185223 0.534962
+vt 0.282127 0.577464
+vt 0.284898 0.535025
+vt 0.299459 0.284656
+vt 0.269410 0.300468
+vt 0.267320 0.274905
+vt 0.294776 0.271386
+vt 0.306484 0.250312
+vt 0.293315 0.242924
+vt 0.245931 0.535039
+vt 0.071962 0.534946
+vt 0.275823 0.248153
+vt 0.301489 0.253434
+vt 0.307265 0.286217
+vt 0.293325 0.304171
+vt 0.208695 0.372787
+vt 0.194848 0.354981
+vt 0.207736 0.335642
+vt 0.238048 0.352770
+vt 0.289297 0.329143
+vt 0.284195 0.358809
+vt 0.249789 0.357798
+vt 0.260662 0.326638
+vt 0.291825 0.210419
+vt 0.282910 0.178142
+vt 0.240092 0.219225
+vt 0.207156 0.229503
+vt 0.203883 0.206876
+vt 0.237038 0.193441
+vt 0.284744 0.054246
+vt 0.283530 0.018181
+vt 0.253997 0.479174
+vt 0.252661 0.512749
+vt 0.215378 0.512749
+vt 0.215164 0.479218
+vt 0.212078 0.054277
+vt 0.209691 0.018239
+vt 0.247220 0.018239
+vt 0.250975 0.054268
+vt 0.285805 0.479156
+vt 0.285667 0.512634
+vt 0.285068 0.404567
+vt 0.285942 0.441555
+vt 0.255333 0.441555
+vt 0.252561 0.404567
+vt 0.211458 0.128944
+vt 0.214464 0.091875
+vt 0.254730 0.091874
+vt 0.251290 0.128949
+vt 0.214951 0.441555
+vt 0.213861 0.404572
+vt 0.284433 0.128947
+vt 0.285957 0.091875
+vt 0.249199 0.274905
+vt 0.212908 0.274933
+vt 0.211924 0.254886
+vt 0.247827 0.250786
+vt 0.210380 0.317703
+vt 0.243254 0.323720
+vt 0.634500 0.156150
+vt 0.634082 0.122612
+vt 0.654909 0.122612
+vt 0.655078 0.156147
+vt 0.620451 0.217712
+vt 0.631999 0.209717
+vt 0.631977 0.231864
+vt 0.985614 0.217712
+vt 0.973899 0.231864
+vt 0.973876 0.209717
+vt 0.255597 0.215743
+vt 0.247850 0.179997
+vt 0.028247 0.577410
+vt 0.025045 0.534903
+vt 0.674703 0.200706
+vt 0.671910 0.232049
+vt 0.931173 0.200706
+vt 0.933965 0.232049
+vt 0.697013 0.172839
+vt 0.708058 0.163092
+vt 0.908862 0.172839
+vt 0.897817 0.163092
+vt 0.673508 0.108499
+vt 0.673582 0.095822
+vt 0.691950 0.095821
+vt 0.691886 0.108499
+vt 0.677624 0.156136
+vt 0.673434 0.122612
+vt 0.691822 0.122612
+vt 0.697044 0.156121
+vt 0.971375 0.156150
+vt 0.971794 0.122612
+vt 0.984917 0.122612
+vt 0.985209 0.156148
+vt 0.928252 0.156136
+vt 0.932441 0.122612
+vt 0.951042 0.122612
+vt 0.950589 0.156147
+vt 0.970997 0.095822
+vt 0.968881 0.054984
+vt 0.984631 0.054984
+vt 0.984867 0.095820
+vt 0.971395 0.108499
+vt 0.984892 0.108499
+vt 0.932368 0.108499
+vt 0.932294 0.095822
+vt 0.950965 0.095821
+vt 0.634480 0.108499
+vt 0.634879 0.095822
+vt 0.654938 0.095821
+vt 0.654923 0.108499
+vt 0.654936 0.054984
+vt 0.654925 0.016269
+vt 0.670270 0.016269
+vt 0.670948 0.054984
+vt 0.934928 0.054984
+vt 0.950969 0.054984
+vt 0.636994 0.054984
+vt 0.690377 0.054983
+vt 0.620779 0.156148
+vt 0.908832 0.156121
+vt 0.621056 0.095820
+vt 0.621248 0.054984
+vt 0.913926 0.095821
+vt 0.915498 0.054983
+vt 0.689838 0.016269
+vt 0.621036 0.108499
+vt 0.913990 0.108499
+vt 0.914054 0.122612
+vt 0.621016 0.122612
+vt 0.935606 0.016269
+vt 0.950999 0.016269
+vt 0.621289 0.016268
+vt 0.637047 0.016268
+vt 0.176090 0.220682
+vt 0.145191 0.220694
+vt 0.145087 0.204123
+vt 0.175901 0.204123
+vt 0.176179 0.257611
+vt 0.145241 0.257656
+vt 0.145210 0.238484
+vt 0.176125 0.238395
+vt 0.176168 0.302520
+vt 0.145242 0.302415
+vt 0.145255 0.286054
+vt 0.176196 0.286099
+vt 0.145244 0.274996
+vt 0.176147 0.274965
+vt 0.213159 0.292296
+vt 0.249624 0.292358
+vt 0.190858 0.203868
+vt 0.204472 0.190753
+vt 0.059422 0.286044
+vt 0.031066 0.286124
+vt 0.031049 0.275075
+vt 0.059417 0.275048
+vt 0.059492 0.354952
+vt 0.031128 0.354952
+vt 0.031124 0.326827
+vt 0.059475 0.326819
+vt 0.059279 0.238666
+vt 0.030929 0.238598
+vt 0.030921 0.220705
+vt 0.059276 0.220716
+vt 0.031084 0.302521
+vt 0.059440 0.302276
+vt 0.176146 0.326829
+vt 0.145236 0.326824
+vt 0.175964 0.354952
+vt 0.145141 0.354952
+vt 0.936052 0.597770
+vt 0.923354 0.589708
+vt 0.924484 0.570357
+vt 0.936057 0.576206
+vt 0.936019 0.649366
+vt 0.913751 0.650767
+vt 0.916692 0.634633
+vt 0.936061 0.627368
+vt 0.915592 0.611553
+vt 0.935975 0.612170
+vt 0.797433 0.319246
+vt 0.796272 0.333957
+vt 0.827484 0.332708
+vt 0.818957 0.316206
+vt 0.059362 0.257746
+vt 0.031009 0.257741
+vt 0.030934 0.204124
+vt 0.059305 0.204124
+vt 0.118260 0.275008
+vt 0.093911 0.275019
+vt 0.093876 0.257696
+vt 0.118252 0.257676
+vt 0.118222 0.220700
+vt 0.093831 0.220705
+vt 0.093754 0.204124
+vt 0.118173 0.204123
+vt 0.093831 0.238570
+vt 0.118261 0.302386
+vt 0.093919 0.302358
+vt 0.093909 0.286048
+vt 0.118265 0.286051
+vt 0.118262 0.326824
+vt 0.093936 0.326823
+vt 0.118215 0.354952
+vt 0.093852 0.354952
+vt 0.208452 0.175985
+vt 0.212772 0.376778
+vt 0.885489 0.613407
+vt 0.886139 0.592404
+vt 0.775283 0.328531
+vt 0.777696 0.360523
+vt 0.798255 0.363832
+vt 0.879743 0.573056
+vt 0.891403 0.648951
+vt 0.891428 0.633182
+vt 0.782396 0.317514
+vt 0.936077 0.668483
+vt 0.917897 0.663357
+vt 0.934937 0.562431
+vt 0.948678 0.563037
+vt 0.849446 0.644672
+vt 0.835215 0.641481
+vt 0.836574 0.633887
+vt 0.850848 0.634574
+vt 0.831637 0.625377
+vt 0.845604 0.622687
+vt 0.803215 0.409166
+vt 0.803234 0.427265
+vt 0.826158 0.420164
+vt 0.827672 0.401768
+vt 0.838730 0.600779
+vt 0.825771 0.609744
+vt 0.818842 0.606128
+vt 0.832383 0.595050
+vt 0.891712 0.662885
+vt 0.868635 0.564528
+vt 0.871852 0.553715
+vt 0.888276 0.556840
+vt 0.827416 0.356136
+vt 0.824304 0.626881
+vt 0.812578 0.624567
+vt 0.828470 0.646582
+vt 0.830902 0.615677
+vt 0.844827 0.609883
+vt 0.785826 0.405163
+vt 0.786898 0.423198
+vt 0.844902 0.653006
+vt 0.876523 0.661158
+vt 0.861333 0.659431
+vt 0.863677 0.647862
+vt 0.877540 0.648407
+vt 0.872530 0.616702
+vt 0.859570 0.619998
+vt 0.858753 0.604088
+vt 0.872446 0.598246
+vt 0.781225 0.373826
+vt 0.784753 0.387128
+vt 0.803196 0.391068
+vt 0.800726 0.377450
+vt 0.851688 0.591814
+vt 0.865716 0.582435
+vt 0.845924 0.583972
+vt 0.857280 0.574250
+vt 0.829185 0.383372
+vt 0.828300 0.369754
+vt 0.878275 0.634222
+vt 0.865123 0.635262
+vt 0.914893 0.555304
+vt 0.906852 0.540600
+vt 0.915395 0.533196
+vt 0.924568 0.548786
+vt 0.761358 0.338190
+vt 0.766667 0.356086
+vt 0.749140 0.351639
+vt 0.737870 0.373475
+vt 0.748724 0.380794
+vt 0.764617 0.362075
+vt 0.885620 0.549316
+vt 0.871635 0.545787
+vt 0.894491 0.523813
+vt 0.887040 0.527237
+vt 0.881647 0.520255
+vt 0.897126 0.516070
+vt 0.968828 0.016268
+vt 0.984580 0.016268
+vt 0.916038 0.016269
+vt 0.934523 0.917621
+vt 0.931424 0.935204
+vt 0.938408 0.927193
+vt 0.941572 0.917780
+vt 0.930002 0.891877
+vt 0.937875 0.903075
+vt 0.864084 0.887068
+vt 0.863938 0.917771
+vt 0.880234 0.917771
+vt 0.879260 0.892026
+vt 0.867026 0.945729
+vt 0.881621 0.944002
+vt 0.831347 0.917772
+vt 0.836681 0.941421
+vt 0.852052 0.944907
+vt 0.847642 0.917771
+vt 0.834066 0.892248
+vt 0.849018 0.887068
+vt 0.904024 0.888613
+vt 0.906398 0.917771
+vt 0.916266 0.917771
+vt 0.913129 0.887745
+vt 0.905572 0.938997
+vt 0.914714 0.939860
+vt 0.819931 0.904999
+vt 0.818111 0.917687
+vt 0.821392 0.930376
+vt 0.896042 0.940231
+vt 0.896530 0.917771
+vt 0.894944 0.890609
+vt 0.686042 0.524352
+vt 0.708647 0.518689
+vt 0.709177 0.537312
+vt 0.692687 0.540948
+vt 0.636372 0.667162
+vt 0.635921 0.656300
+vt 0.651714 0.656493
+vt 0.651227 0.666984
+vt 0.781285 0.609428
+vt 0.785249 0.620097
+vt 0.765233 0.626167
+vt 0.761520 0.615688
+vt 0.644711 0.596297
+vt 0.648718 0.581418
+vt 0.667739 0.587337
+vt 0.663002 0.601458
+vt 0.655822 0.561957
+vt 0.674036 0.573634
+vt 0.636733 0.638857
+vt 0.638119 0.622878
+vt 0.655630 0.626375
+vt 0.652694 0.640638
+vt 0.751631 0.535644
+vt 0.762210 0.560416
+vt 0.744045 0.569271
+vt 0.736483 0.548184
+vt 0.787716 0.631988
+vt 0.770153 0.638555
+vt 0.791176 0.645197
+vt 0.775239 0.650769
+vt 0.756154 0.602668
+vt 0.747050 0.618300
+vt 0.741245 0.605142
+vt 0.750033 0.585655
+vt 0.738203 0.591970
+vt 0.733559 0.579024
+vt 0.728733 0.562733
+vt 0.683603 0.550467
+vt 0.699215 0.546547
+vt 0.690416 0.564106
+vt 0.678881 0.591921
+vt 0.676012 0.602550
+vt 0.666074 0.642176
+vt 0.663882 0.657641
+vt 0.651365 0.677015
+vt 0.662728 0.668313
+vt 0.662980 0.677015
+vt 0.726341 0.539931
+vt 0.719028 0.546474
+vt 0.779342 0.664126
+vt 0.767486 0.666511
+vt 0.763261 0.656022
+vt 0.758344 0.643339
+vt 0.753283 0.628664
+vt 0.683726 0.579931
+vt 0.658998 0.614197
+vt 0.672082 0.616741
+vt 0.669471 0.627536
+vt 0.779389 0.677016
+vt 0.770165 0.677015
+vt 0.745182 0.648362
+vt 0.737201 0.634733
+vt 0.696399 0.576131
+vt 0.691285 0.585364
+vt 0.672552 0.660852
+vt 0.671485 0.670160
+vt 0.692397 0.606771
+vt 0.695369 0.619169
+vt 0.684166 0.635721
+vt 0.757870 0.677015
+vt 0.755280 0.669527
+vt 0.689760 0.595785
+vt 0.751861 0.659762
+vt 0.724212 0.618997
+vt 0.726110 0.606671
+vt 0.727889 0.595831
+vt 0.728493 0.586086
+vt 0.723396 0.575823
+vt 0.702738 0.563637
+vt 0.676524 0.647357
+vt 0.669891 0.677015
+vt 0.715467 0.563548
+vt 0.747228 0.672502
+vt 0.744669 0.663180
+vt 0.679473 0.664199
+vt 0.678437 0.672191
+vt 0.740064 0.651011
+vt 0.676547 0.677015
+vt 0.731566 0.638069
+vt 0.718813 0.627622
+vt 0.681227 0.650664
+vt 0.749692 0.677015
+vt 0.689654 0.638630
+vt 0.701529 0.627703
+vt 0.732176 0.523263
+vt 0.685735 0.677015
+vt 0.686228 0.666838
+vt 0.741198 0.677015
+vt 0.688358 0.652787
+vt 0.697308 0.643104
+vt 0.734468 0.653528
+vt 0.739084 0.666015
+vt 0.710741 0.639927
+vt 0.725417 0.642145
+vt 0.794526 0.663780
+vt 0.769330 0.578484
+vt 0.775733 0.594543
+vt 0.794904 0.677014
+vt 0.641034 0.610282
+vt 0.666728 0.538248
+vt 0.636356 0.677015
+vn 0.9457 0.1443 0.2913
+vn 0.9564 -0.0041 0.2922
+vn 0.9998 -0.0209 -0.0009
+vn 0.9824 0.1864 0.0134
+vn 0.7379 0.6737 0.0405
+vn 0.7078 0.6423 0.2941
+vn 0.6460 0.4611 0.6084
+vn 0.7695 0.1073 0.6296
+vn 0.7886 0.0331 0.6140
+vn 0.3103 0.2935 -0.9042
+vn 0.3025 0.7212 -0.6232
+vn 0.6054 0.6169 -0.5030
+vn 0.7379 0.2250 -0.6362
+vn 0.7562 -0.0103 -0.6543
+vn 0.3308 0.0001 -0.9437
+vn 0.1084 0.3109 -0.9442
+vn 0.0989 0.0136 -0.9950
+vn -0.0000 0.0197 -0.9998
+vn -0.0000 0.3126 -0.9499
+vn -0.0000 0.7558 -0.6548
+vn 0.1472 0.7442 -0.6515
+vn 0.3550 -0.2096 -0.9110
+vn 0.7477 -0.1850 -0.6378
+vn 0.6791 -0.4538 -0.5770
+vn 0.3752 -0.5647 -0.7350
+vn 0.1368 -0.2014 -0.9699
+vn 0.1695 -0.6011 -0.7810
+vn 0.0000 -0.6130 -0.7901
+vn -0.0000 -0.2004 -0.9797
+vn 0.4474 -0.0538 0.8927
+vn 0.4742 -0.5231 0.7082
+vn 0.7731 -0.4655 0.4308
+vn 0.8083 -0.0705 0.5845
+vn 0.4476 0.0625 0.8920
+vn 0.1322 -0.0587 0.9895
+vn 0.1444 0.0607 0.9877
+vn -0.0000 0.0525 0.9986
+vn 0.0000 -0.0698 0.9976
+vn 0.0000 -0.6245 0.7810
+vn 0.2144 -0.6358 0.7415
+vn 0.4047 0.1590 0.9005
+vn 0.3492 0.5807 0.7354
+vn 0.1784 0.2024 0.9629
+vn 0.2000 0.6209 0.7580
+vn 0.0000 0.6376 0.7704
+vn -0.0000 0.1969 0.9804
+vn 0.9553 -0.1362 0.2625
+vn 0.8333 -0.5293 0.1596
+vn 0.8217 -0.5659 -0.0678
+vn 0.9850 -0.1721 -0.0131
+vn 0.9458 -0.1792 -0.2708
+vn 0.7735 -0.5442 -0.3250
+vn 0.9657 -0.0170 -0.2589
+vn 0.9520 0.1879 -0.2416
+vn 0.7174 0.6660 -0.2046
+vn 0.2950 0.9058 0.3042
+vn 0.3086 0.9496 0.0553
+vn 0.1702 0.9347 0.3120
+vn 0.1370 0.9891 0.0545
+vn 0.0000 0.9989 0.0475
+vn 0.0000 0.9489 0.3155
+vn 0.2964 0.9341 -0.1988
+vn 0.1395 0.9681 -0.2083
+vn 0.0000 0.9774 -0.2113
+vn 0.5914 -0.8002 -0.0998
+vn 0.4555 -0.8719 0.1795
+vn 0.6394 -0.6842 0.3507
+vn 0.8795 -0.4694 -0.0788
+vn 0.4438 -0.7827 -0.4363
+vn 0.1549 -0.8154 -0.5578
+vn 0.0000 -0.8224 -0.5689
+vn 0.2065 -0.9492 0.2376
+vn -0.0000 -0.9727 0.2319
+vn 0.6646 -0.5276 -0.5291
+vn 0.2417 -0.5411 -0.8054
+vn 0.7131 0.6934 0.1032
+vn 0.5830 0.4427 -0.6813
+vn 0.3650 -0.6772 0.6388
+vn -0.0000 -0.7727 0.6348
+vn 0.0000 0.2392 0.9710
+vn 0.3422 0.2291 0.9113
+vn 0.2187 0.9685 0.1193
+vn 0.2776 0.7794 -0.5617
+vn 0.0000 0.4232 0.9060
+vn 0.2215 0.4915 0.8423
+vn 0.5299 0.4783 0.7003
+vn 0.3187 0.1528 -0.9355
+vn 0.2344 0.7167 0.6568
+vn 0.2099 0.4105 -0.8874
+vn 0.3673 -0.9301 0.0098
+vn 0.3974 -0.5924 -0.7008
+vn 0.1794 -0.6195 -0.7642
+vn 0.0690 -0.9969 -0.0385
+vn 0.1877 0.1073 -0.9763
+vn 0.2476 0.0854 -0.9651
+vn 0.4933 -0.2459 -0.8344
+vn 0.2022 -0.1020 -0.9740
+vn 0.2329 0.2954 0.9266
+vn 0.0000 0.3022 0.9532
+vn -0.0000 0.1792 0.9838
+vn 0.2403 0.1796 0.9539
+vn 0.2128 0.2478 0.9452
+vn 0.4914 -0.2255 0.8412
+vn 0.1337 -0.5254 0.8403
+vn 0.1148 0.2277 0.9669
+vn 0.2362 0.0566 0.9700
+vn 0.0000 0.0526 0.9986
+vn -0.0009 -0.0926 0.9957
+vn 0.2385 -0.0982 0.9662
+vn 0.7220 0.1360 -0.6784
+vn 0.9918 0.1212 0.0408
+vn 0.9923 0.0130 0.1231
+vn 0.7610 0.0535 -0.6465
+vn 0.6859 0.0936 0.7216
+vn 0.6979 -0.1956 0.6890
+vn 0.2849 0.1291 -0.9498
+vn 0.2636 0.0932 -0.9601
+vn 0.2253 -0.1212 -0.9667
+vn 0.6874 -0.1083 -0.7181
+vn 0.7076 0.0146 -0.7065
+vn 0.2536 0.0037 -0.9673
+vn 0.9995 -0.0294 0.0078
+vn 0.6908 0.0535 0.7211
+vn 0.6725 0.0801 0.7358
+vn 0.9981 0.0555 0.0252
+vn 0.2430 0.0914 0.9657
+vn -0.0000 0.0953 0.9955
+vn 0.0000 0.0740 0.9973
+vn 0.2426 0.0741 0.9673
+vn 0.2022 0.9739 0.1031
+vn 0.2013 0.6974 0.6878
+vn 0.1541 0.6819 0.7150
+vn 0.1655 0.9817 0.0947
+vn 0.3004 0.0419 -0.9529
+vn 0.1688 0.0258 -0.9853
+vn 0.4500 -0.1523 0.8799
+vn -0.4454 -0.1944 0.8740
+vn -0.3460 -0.2779 0.8962
+vn 0.3766 -0.1964 0.9053
+vn 0.5997 -0.3336 0.7274
+vn 0.8694 -0.0087 -0.4940
+vn 0.0000 0.3057 -0.9521
+vn 0.0000 0.1113 -0.9938
+vn 0.2453 0.2787 0.9285
+vn 0.0000 -0.1176 -0.9931
+vn 0.0000 0.0149 -0.9999
+vn -0.0000 0.1493 -0.9888
+vn 0.0000 0.0659 -0.9978
+vn 0.6091 0.0343 0.7924
+vn 0.0000 -0.0920 -0.9958
+vn 0.0000 0.1404 -0.9901
+vn 0.0000 -0.4846 -0.8747
+vn 0.1067 -0.4160 0.9031
+vn 0.3116 -0.0248 -0.9499
+vn -0.0013 -0.6103 0.7922
+vn 0.0003 -0.9575 0.2883
+vn -0.0006 -0.9977 -0.0685
+vn -0.5755 -0.7952 -0.1911
+vn -0.5898 -0.6462 0.4843
+vn -0.0011 -0.1368 -0.9906
+vn -0.1764 -0.3704 -0.9120
+vn -0.0020 -0.7436 -0.6687
+vn -0.9340 -0.1822 0.3072
+vn -0.9184 0.0606 -0.3909
+vn -0.9107 0.0462 -0.4104
+vn -0.9365 -0.1814 0.3002
+vn -0.9426 -0.1215 0.3112
+vn -0.9450 -0.1377 -0.2966
+vn -0.9243 -0.0652 -0.3762
+vn -0.9228 -0.2105 0.3226
+vn 0.8756 0.0396 -0.4815
+vn 0.9476 -0.0151 0.3190
+vn 0.9181 -0.0664 0.3906
+vn 0.9077 0.0723 -0.4133
+vn -0.4433 -0.1404 -0.8853
+vn 0.3698 -0.0259 -0.9287
+vn 0.3708 0.1432 -0.9176
+vn -0.4292 0.0769 -0.8999
+vn 0.8919 0.1157 -0.4372
+vn 0.9256 -0.1284 0.3562
+vn 0.9305 -0.2256 0.2887
+vn 0.8784 -0.1012 -0.4671
+vn 0.8901 0.1775 -0.4199
+vn 0.9257 -0.0826 0.3690
+vn -0.3939 0.2181 -0.8929
+vn -0.4115 0.2799 -0.8674
+vn 0.3324 0.2377 -0.9127
+vn 0.3702 -0.2797 0.8858
+vn -0.3684 -0.3290 0.8695
+vn -0.3734 -0.3396 0.8633
+vn 0.3699 -0.3096 0.8760
+vn -0.3218 -0.2828 0.9036
+vn -0.9240 -0.1780 0.3384
+vn -0.9034 -0.0051 0.4289
+vn -0.1555 0.0783 0.9847
+vn 0.2807 -0.0015 -0.9598
+vn -0.4512 0.0172 -0.8923
+vn 0.4510 -0.2961 0.8420
+vn -0.9203 -0.0430 -0.3889
+vn -0.9785 0.0388 -0.2025
+vn 0.1337 0.2725 -0.9528
+vn -0.6002 0.0760 -0.7962
+vn 0.6684 0.1792 0.7219
+vn 0.9807 0.1591 0.1132
+vn 0.0231 -0.5921 0.8055
+vn -0.0441 -0.9976 -0.0530
+vn -0.0785 -0.9958 -0.0464
+vn -0.0514 -0.6426 0.7645
+vn 0.1031 0.6834 0.7227
+vn 0.0614 0.1922 0.9794
+vn -0.0142 0.1514 0.9884
+vn 0.0418 0.7022 0.7108
+vn 0.0286 0.0423 -0.9987
+vn 0.1078 0.7277 -0.6773
+vn 0.0901 0.7629 -0.6402
+vn 0.0343 0.0455 -0.9984
+vn 0.1349 0.9851 0.1063
+vn 0.0795 0.9895 0.1207
+vn 0.2886 0.7054 -0.6474
+vn 0.2213 0.7031 -0.6758
+vn 0.1543 0.8126 -0.5621
+vn 0.1374 0.9816 0.1329
+vn 0.3013 0.9452 0.1258
+vn 0.1981 0.8835 -0.4245
+vn 0.0229 -0.9997 -0.0021
+vn 0.0623 -0.6655 -0.7438
+vn 0.0341 -0.7440 -0.6674
+vn 0.1430 -0.9897 0.0080
+vn 0.0423 0.1045 0.9936
+vn 0.0253 -0.6320 0.7746
+vn 0.0240 -0.7308 0.6822
+vn -0.3127 0.2099 0.9264
+vn 0.0965 0.0398 -0.9945
+vn -0.1350 0.1050 -0.9853
+vn -0.0256 -0.6368 -0.7706
+vn -0.0322 -0.6542 -0.7556
+vn 0.1349 0.8453 0.5169
+vn -0.4932 0.4930 0.7168
+vn -0.0139 0.8416 0.5400
+vn 0.0750 0.8493 -0.5225
+vn -0.1172 0.0807 -0.9898
+vn 0.2518 0.9644 0.0807
+vn -0.1514 -0.7066 -0.6913
+vn 0.0599 -0.9980 0.0190
+vn 0.1047 0.7466 0.6570
+vn 0.0280 0.9910 0.1306
+vn -0.0336 0.7148 0.6986
+vn 0.0289 0.7181 0.6953
+vn 0.0847 0.9874 0.1334
+vn -0.1332 -0.6247 0.7694
+vn -0.1064 -0.9942 -0.0166
+vn -0.0407 -0.9991 0.0079
+vn -0.0547 -0.6278 0.7764
+vn -0.0227 0.1091 0.9938
+vn 0.0379 0.0500 -0.9980
+vn 0.0584 0.7850 -0.6168
+vn 0.0999 0.7937 -0.6001
+vn 0.0656 0.0439 -0.9969
+vn -0.0380 -0.6635 -0.7472
+vn 0.0085 -0.6713 -0.7411
+vn 0.8732 -0.4872 0.0139
+vn 0.1845 0.8730 0.4514
+vn 0.2209 0.9735 0.0600
+vn -0.5726 -0.6425 0.5092
+vn -0.1516 -0.9884 -0.0104
+vn 0.1681 -0.8946 0.4139
+vn 0.3284 0.3520 0.8765
+vn 0.1938 0.8999 -0.3906
+vn 0.0779 0.1056 -0.9914
+vn 0.2088 0.0236 -0.9777
+vn 0.4326 0.8074 -0.4012
+vn 0.8096 0.4726 -0.3482
+vn 0.6046 -0.1712 -0.7779
+vn 0.4070 0.9114 0.0607
+vn 0.9199 0.3892 0.0477
+vn -0.3275 -0.9444 -0.0292
+vn -0.1998 -0.8212 -0.5345
+vn 0.2486 -0.8576 -0.4502
+vn 0.4146 -0.9085 0.0525
+vn 0.0541 0.2120 0.9758
+vn -0.2886 -0.7432 0.6036
+vn 0.1971 -0.7858 0.5863
+vn 0.5629 -0.0268 0.8261
+vn -0.0910 -0.8166 -0.5699
+vn 0.5147 0.8181 0.2567
+vn 0.2374 -0.8666 -0.4388
+vn 0.9324 -0.3612 0.0109
+vn 0.7483 0.4975 0.4388
+vn 0.3372 0.8276 0.4488
+vn -0.1555 -0.8122 -0.5622
+vn 0.0736 0.0760 -0.9944
+vn 0.1485 0.0722 -0.9863
+vn -0.1638 -0.8029 -0.5731
+vn 0.3115 0.9481 0.0636
+vn 0.3176 0.8353 0.4488
+vn 0.3268 0.8416 0.4299
+vn 0.3667 0.9284 0.0598
+vn -0.0652 -0.7833 0.6183
+vn -0.1876 -0.9821 -0.0192
+vn -0.2699 -0.9624 -0.0318
+vn -0.1672 -0.7777 0.6060
+vn 0.2008 0.1620 0.9661
+vn 0.1350 0.2102 0.9683
+vn 0.2863 0.8648 -0.4125
+vn 0.3527 0.8371 -0.4183
+vn -0.5104 0.6254 0.5902
+vn -0.7359 -0.6521 0.1822
+vn -0.5788 -0.7442 0.3334
+vn -0.4153 0.5623 0.7151
+vn 0.3722 -0.5937 -0.7135
+vn 0.7782 -0.6218 -0.0880
+vn 0.0267 -0.7229 0.6905
+vn 0.5714 0.7000 -0.4283
+vn 0.1233 0.3691 0.9212
+vn 0.8710 0.4712 0.1392
+vn 0.8376 0.2166 -0.5015
+vn -0.0000 -1.0000 0.0000
+vn 0.0084 -0.6750 -0.7378
+vn 0.3680 -0.6369 -0.6774
+vn 0.6015 -0.6121 -0.5133
+vn -0.6355 -0.6986 -0.3287
+vn -0.3370 -0.7295 -0.5952
+vn -0.7034 -0.7107 -0.0097
+vn -0.5972 -0.8019 0.0184
+vn 0.6442 -0.7370 -0.2048
+vn 0.6648 -0.7399 -0.1029
+vn 0.6664 -0.7454 0.0181
+vn 0.6517 -0.7303 0.2050
+vn -0.5592 -0.6963 0.4499
+vn -0.6826 -0.7042 0.1955
+vn -0.6484 -0.7443 0.1597
+vn -0.6932 -0.7206 0.0148
+vn 0.7022 -0.6799 -0.2114
+vn 0.6342 -0.7655 -0.1091
+vn -0.2498 -0.6440 0.7231
+vn 0.1061 -0.6663 0.7381
+vn 0.4440 -0.6813 0.5820
+vn 0.6185 -0.7625 -0.1899
+vn -0.6115 -0.7763 0.1532
+vn 0.6837 0.0752 0.7259
+vn 0.1525 0.1246 0.9804
+vn 0.4903 0.1374 -0.8606
+vn 0.7599 0.1599 -0.6301
+vn -0.9665 0.0230 0.2556
+vn -0.9782 0.0452 0.2028
+vn 0.9493 0.0983 -0.2986
+vn 0.9839 0.0914 -0.1536
+vn 0.9960 0.0812 0.0373
+vn 0.9159 0.1392 -0.3765
+vn 0.9780 0.0775 -0.1938
+vn -0.7453 0.1106 0.6575
+vn -0.9495 0.1270 0.2870
+vn -0.9970 0.0745 -0.0194
+vn -0.8740 0.0598 -0.4823
+vn -0.9951 0.0798 0.0585
+vn -0.8303 0.5511 0.0824
+vn -0.8523 0.3910 0.3476
+vn -0.9916 0.1283 0.0146
+vn -0.8484 0.5290 -0.0195
+vn -0.7014 0.4470 0.5552
+vn -0.8576 0.4754 0.1962
+vn 0.9409 0.0844 0.3281
+vn 0.8080 0.4997 0.3121
+vn 0.4611 0.4221 0.7805
+vn 0.8317 0.4977 -0.2460
+vn 0.8603 0.4813 -0.1678
+vn 0.7603 0.2592 -0.5956
+vn 0.8765 0.3184 -0.3611
+vn 0.0027 0.0640 -0.9979
+vn 0.0179 0.2134 -0.9768
+vn 0.5328 0.2307 -0.8142
+vn -0.3109 0.0989 0.9453
+vn -0.2355 0.3923 0.8892
+vn -0.9029 0.1928 -0.3842
+vn -0.5381 0.2055 -0.8174
+vn -0.5082 0.0300 -0.8607
+vn -0.9301 0.2315 0.2851
+vn -0.9798 0.1938 -0.0499
+vn 0.8834 0.4680 0.0259
+vn 0.9585 0.0708 -0.2762
+vn 0.8740 0.4463 -0.1921
+vn 0.9188 0.3598 -0.1622
+vn -0.8756 0.2043 0.4377
+vn -0.9977 0.0637 -0.0225
+vn 0.4477 0.8941 0.0123
+vn 0.4095 0.8844 0.2238
+vn 0.4740 0.2525 -0.8436
+vn 0.7825 0.3019 -0.5445
+vn 0.3908 0.8872 0.2453
+vn 0.4131 0.9101 -0.0329
+vn 0.7671 0.6409 -0.0280
+vn -0.5579 0.2025 -0.8048
+vn -0.0554 0.2166 -0.9747
+vn 0.4242 0.8999 -0.1010
+vn -0.9151 0.1009 -0.3904
+vn -0.3681 0.9119 0.1818
+vn -0.4525 0.6615 0.5981
+vn -0.3940 0.9187 -0.0283
+vn -0.4085 0.8532 0.3243
+vn -0.5208 0.8521 0.0525
+vn 0.2601 0.7859 0.5609
+vn 0.8501 0.4447 -0.2822
+vn -0.1194 0.7620 0.6365
+vn -0.8841 0.1773 -0.4324
+vn -0.4165 0.3095 -0.8548
+vn 0.3278 0.3994 -0.8562
+vn 0.6951 0.4915 -0.5247
+vn -0.9970 0.0755 -0.0137
+vn -0.1212 0.4521 -0.8837
+vn -0.1949 0.4563 0.8682
+vn -0.7707 0.2211 0.5976
+vn 0.8312 0.5333 -0.1575
+vn 0.6322 0.7536 0.1800
+vn 0.2893 0.7521 0.5922
+vn -0.9457 0.1443 0.2913
+vn -0.9824 0.1864 0.0134
+vn -0.9998 -0.0209 -0.0009
+vn -0.9564 -0.0041 0.2922
+vn -0.7078 0.6423 0.2941
+vn -0.7379 0.6737 0.0405
+vn -0.7695 0.1073 0.6296
+vn -0.6460 0.4611 0.6084
+vn -0.7886 0.0331 0.6140
+vn -0.3103 0.2935 -0.9042
+vn -0.7379 0.2250 -0.6362
+vn -0.6054 0.6169 -0.5030
+vn -0.3025 0.7212 -0.6232
+vn -0.3308 0.0001 -0.9437
+vn -0.7562 -0.0103 -0.6543
+vn -0.1084 0.3109 -0.9442
+vn -0.0989 0.0136 -0.9950
+vn -0.1472 0.7442 -0.6515
+vn -0.3550 -0.2096 -0.9110
+vn -0.7477 -0.1850 -0.6378
+vn -0.3752 -0.5647 -0.7350
+vn -0.6791 -0.4538 -0.5770
+vn -0.1368 -0.2014 -0.9699
+vn -0.1695 -0.6011 -0.7810
+vn -0.4474 -0.0538 0.8927
+vn -0.8083 -0.0705 0.5845
+vn -0.7731 -0.4655 0.4308
+vn -0.4742 -0.5231 0.7082
+vn -0.4476 0.0625 0.8920
+vn -0.1322 -0.0587 0.9895
+vn -0.1444 0.0607 0.9877
+vn -0.2144 -0.6358 0.7415
+vn -0.4047 0.1590 0.9005
+vn -0.3492 0.5807 0.7354
+vn -0.1784 0.2024 0.9629
+vn -0.2000 0.6209 0.7580
+vn -0.9553 -0.1362 0.2625
+vn -0.9850 -0.1721 -0.0131
+vn -0.8217 -0.5659 -0.0678
+vn -0.8333 -0.5293 0.1596
+vn -0.9458 -0.1792 -0.2708
+vn -0.7735 -0.5442 -0.3250
+vn -0.9657 -0.0170 -0.2589
+vn -0.9520 0.1879 -0.2416
+vn -0.7174 0.6660 -0.2046
+vn -0.2950 0.9058 0.3042
+vn -0.3086 0.9496 0.0553
+vn -0.1702 0.9347 0.3120
+vn -0.1370 0.9891 0.0545
+vn -0.2964 0.9341 -0.1988
+vn -0.1395 0.9681 -0.2083
+vn -0.5914 -0.8002 -0.0998
+vn -0.8795 -0.4694 -0.0788
+vn -0.6394 -0.6842 0.3507
+vn -0.4555 -0.8719 0.1795
+vn -0.4438 -0.7827 -0.4363
+vn -0.1549 -0.8154 -0.5578
+vn -0.2065 -0.9492 0.2376
+vn -0.2417 -0.5411 -0.8054
+vn -0.6646 -0.5276 -0.5291
+vn -0.5830 0.4427 -0.6813
+vn -0.7131 0.6934 0.1032
+vn -0.3650 -0.6772 0.6388
+vn -0.3422 0.2291 0.9113
+vn -0.2776 0.7794 -0.5617
+vn -0.2187 0.9685 0.1193
+vn -0.2215 0.4915 0.8423
+vn -0.5299 0.4783 0.7003
+vn -0.3187 0.1528 -0.9355
+vn -0.2344 0.7167 0.6568
+vn -0.2099 0.4105 -0.8874
+vn -0.3673 -0.9301 0.0098
+vn -0.0690 -0.9969 -0.0385
+vn -0.1794 -0.6195 -0.7642
+vn -0.3974 -0.5924 -0.7008
+vn -0.1877 0.1073 -0.9763
+vn -0.2022 -0.1020 -0.9740
+vn -0.4933 -0.2459 -0.8344
+vn -0.2476 0.0854 -0.9651
+vn -0.2329 0.2954 0.9266
+vn -0.2403 0.1796 0.9539
+vn -0.2128 0.2478 0.9452
+vn -0.1148 0.2277 0.9669
+vn -0.1337 -0.5254 0.8403
+vn -0.4914 -0.2255 0.8412
+vn -0.2364 0.0565 0.9700
+vn -0.2399 -0.1022 0.9654
+vn -0.7225 0.1357 -0.6780
+vn -0.7618 0.0546 -0.6455
+vn -0.9917 0.0127 0.1276
+vn -0.9918 0.1202 0.0423
+vn -0.6966 -0.1992 0.6893
+vn -0.6855 0.0928 0.7222
+vn -0.2849 0.1291 -0.9498
+vn -0.2631 0.0936 -0.9602
+vn -0.2253 -0.1212 -0.9667
+vn -0.2536 0.0037 -0.9673
+vn -0.7077 0.0144 -0.7064
+vn -0.6874 -0.1083 -0.7181
+vn -0.9995 -0.0294 0.0078
+vn -0.9982 0.0549 0.0255
+vn -0.6726 0.0797 0.7357
+vn -0.6908 0.0535 0.7211
+vn -0.2430 0.0914 0.9657
+vn -0.2426 0.0740 0.9673
+vn -0.2022 0.9739 0.1031
+vn -0.1655 0.9817 0.0947
+vn -0.1541 0.6819 0.7150
+vn -0.2013 0.6974 0.6878
+vn -0.1688 0.0258 -0.9853
+vn -0.3004 0.0419 -0.9529
+vn -0.4369 -0.1528 0.8864
+vn -0.3610 -0.1963 0.9117
+vn 0.3613 -0.2783 0.8900
+vn 0.4588 -0.1943 0.8670
+vn -0.5930 -0.3361 0.7317
+vn -0.8740 -0.0068 -0.4859
+vn -0.2453 0.2787 0.9285
+vn -0.6091 0.0343 0.7924
+vn -0.1059 -0.4199 0.9014
+vn -0.3165 -0.0232 -0.9483
+vn 0.5913 -0.6474 0.4808
+vn 0.5748 -0.7942 -0.1971
+vn 0.1734 -0.3703 -0.9126
+vn 0.9391 -0.1828 0.2909
+vn 0.9414 -0.1820 0.2838
+vn 0.9035 0.0456 -0.4262
+vn 0.9115 0.0601 -0.4068
+vn 0.9472 -0.1220 0.2966
+vn 0.9282 -0.2111 0.3065
+vn 0.9176 -0.0657 -0.3922
+vn 0.9397 -0.1373 -0.3132
+vn -0.8826 0.0408 -0.4683
+vn -0.9147 0.0729 -0.3974
+vn -0.9113 -0.0659 0.4065
+vn -0.9426 -0.0146 0.3336
+vn 0.4306 -0.1368 -0.8921
+vn 0.4136 0.0768 -0.9072
+vn -0.3866 0.1436 -0.9110
+vn -0.3825 -0.0232 -0.9236
+vn -0.8993 0.1163 -0.4216
+vn -0.8859 -0.1006 -0.4528
+vn -0.9258 -0.2249 0.3039
+vn -0.9193 -0.1278 0.3722
+vn -0.8971 0.1781 -0.4043
+vn -0.9193 -0.0821 0.3850
+vn 0.3966 0.2797 -0.8743
+vn 0.3785 0.2178 -0.8996
+vn -0.3480 0.2379 -0.9068
+vn -0.3550 -0.2796 0.8921
+vn -0.3548 -0.3094 0.8823
+vn 0.3881 -0.3399 0.8567
+vn 0.3832 -0.3294 0.8629
+vn 0.3361 -0.2834 0.8982
+vn 0.1673 0.0823 0.9825
+vn 0.9087 -0.0107 0.4173
+vn 0.9291 -0.1794 0.3233
+vn 0.4369 0.0163 -0.8994
+vn -0.2959 -0.0015 -0.9552
+vn -0.4374 -0.2958 0.8492
+vn 0.9138 -0.0443 -0.4037
+vn 0.9765 0.0369 -0.2121
+vn 0.5910 0.0741 -0.8033
+vn -0.1439 0.2747 -0.9507
+vn -0.9780 0.1679 0.1240
+vn -0.6588 0.1851 0.7292
+vn -0.0231 -0.5921 0.8055
+vn 0.0514 -0.6426 0.7645
+vn 0.0785 -0.9958 -0.0464
+vn 0.0441 -0.9976 -0.0530
+vn -0.1031 0.6834 0.7227
+vn -0.0417 0.7022 0.7107
+vn 0.0142 0.1514 0.9884
+vn -0.0614 0.1922 0.9794
+vn -0.0286 0.0423 -0.9987
+vn -0.0343 0.0455 -0.9984
+vn -0.0901 0.7629 -0.6402
+vn -0.1078 0.7277 -0.6773
+vn -0.0795 0.9895 0.1207
+vn -0.1349 0.9851 0.1063
+vn -0.2213 0.7031 -0.6758
+vn -0.2886 0.7054 -0.6474
+vn -0.1543 0.8126 -0.5621
+vn -0.1981 0.8835 -0.4245
+vn -0.3013 0.9452 0.1258
+vn -0.1374 0.9816 0.1329
+vn -0.0229 -0.9997 -0.0021
+vn -0.1430 -0.9897 0.0080
+vn -0.0341 -0.7440 -0.6674
+vn -0.0623 -0.6655 -0.7438
+vn -0.0423 0.1045 0.9936
+vn 0.3127 0.2099 0.9264
+vn -0.0240 -0.7308 0.6822
+vn -0.0253 -0.6320 0.7746
+vn 0.1350 0.1050 -0.9853
+vn -0.0965 0.0398 -0.9945
+vn 0.0256 -0.6368 -0.7706
+vn 0.0322 -0.6542 -0.7556
+vn -0.1349 0.8453 0.5169
+vn 0.0139 0.8416 0.5400
+vn 0.4932 0.4930 0.7168
+vn 0.1172 0.0807 -0.9898
+vn -0.0750 0.8493 -0.5225
+vn -0.2518 0.9644 0.0807
+vn -0.0599 -0.9980 0.0190
+vn 0.1514 -0.7066 -0.6913
+vn -0.1047 0.7466 0.6570
+vn -0.0280 0.9910 0.1306
+vn -0.0847 0.9874 0.1334
+vn -0.0289 0.7181 0.6953
+vn 0.0336 0.7148 0.6986
+vn 0.1332 -0.6247 0.7694
+vn 0.0547 -0.6278 0.7764
+vn 0.0407 -0.9991 0.0079
+vn 0.1064 -0.9942 -0.0166
+vn 0.0227 0.1091 0.9938
+vn -0.0379 0.0500 -0.9980
+vn -0.0656 0.0439 -0.9969
+vn -0.0999 0.7937 -0.6001
+vn -0.0584 0.7850 -0.6168
+vn 0.0380 -0.6635 -0.7472
+vn -0.0085 -0.6713 -0.7411
+vn -0.8732 -0.4872 0.0139
+vn -0.2209 0.9735 0.0600
+vn -0.1845 0.8730 0.4514
+vn 0.5726 -0.6425 0.5092
+vn -0.1681 -0.8946 0.4139
+vn 0.1516 -0.9884 -0.0104
+vn -0.3284 0.3520 0.8765
+vn -0.0779 0.1056 -0.9914
+vn -0.1938 0.8999 -0.3906
+vn -0.2088 0.0236 -0.9777
+vn -0.6045 -0.1712 -0.7779
+vn -0.8096 0.4726 -0.3482
+vn -0.4326 0.8074 -0.4012
+vn -0.9199 0.3892 0.0477
+vn -0.4070 0.9114 0.0607
+vn 0.3275 -0.9444 -0.0292
+vn -0.4146 -0.9085 0.0526
+vn -0.2486 -0.8576 -0.4502
+vn 0.1998 -0.8212 -0.5345
+vn -0.0541 0.2120 0.9758
+vn -0.5629 -0.0268 0.8261
+vn -0.1971 -0.7858 0.5863
+vn 0.2886 -0.7432 0.6036
+vn 0.0910 -0.8166 -0.5699
+vn -0.2374 -0.8666 -0.4388
+vn -0.5147 0.8181 0.2567
+vn -0.9324 -0.3612 0.0109
+vn -0.7483 0.4975 0.4388
+vn -0.3372 0.8276 0.4487
+vn 0.1555 -0.8122 -0.5622
+vn 0.1638 -0.8029 -0.5731
+vn -0.1485 0.0722 -0.9863
+vn -0.0736 0.0760 -0.9944
+vn -0.3115 0.9481 0.0636
+vn -0.3667 0.9284 0.0598
+vn -0.3268 0.8416 0.4299
+vn -0.3176 0.8353 0.4488
+vn 0.0652 -0.7833 0.6183
+vn 0.1672 -0.7777 0.6060
+vn 0.2699 -0.9624 -0.0318
+vn 0.1876 -0.9821 -0.0192
+vn -0.1350 0.2102 0.9683
+vn -0.2008 0.1620 0.9661
+vn -0.2863 0.8648 -0.4125
+vn -0.3527 0.8371 -0.4183
+vn 0.5104 0.6254 0.5902
+vn 0.4153 0.5623 0.7151
+vn 0.5788 -0.7442 0.3334
+vn 0.7359 -0.6521 0.1822
+vn -0.0267 -0.7229 0.6905
+vn -0.7782 -0.6218 -0.0880
+vn -0.3722 -0.5937 -0.7135
+vn -0.5714 0.7000 -0.4283
+vn -0.1233 0.3691 0.9212
+vn -0.8710 0.4712 0.1392
+vn -0.8425 0.2212 -0.4912
+vn -0.6016 -0.6121 -0.5133
+vn -0.3680 -0.6369 -0.6774
+vn -0.0084 -0.6750 -0.7378
+vn 0.6355 -0.6986 -0.3287
+vn 0.3370 -0.7295 -0.5952
+vn 0.7034 -0.7107 -0.0097
+vn 0.5971 -0.8019 0.0184
+vn -0.6648 -0.7399 -0.1029
+vn -0.6442 -0.7370 -0.2047
+vn -0.6517 -0.7302 0.2050
+vn -0.6664 -0.7454 0.0181
+vn 0.5592 -0.6963 0.4499
+vn 0.6826 -0.7042 0.1954
+vn 0.6484 -0.7443 0.1597
+vn 0.6931 -0.7206 0.0148
+vn -0.6342 -0.7655 -0.1091
+vn -0.7022 -0.6799 -0.2114
+vn 0.2498 -0.6440 0.7231
+vn -0.1061 -0.6663 0.7381
+vn -0.4440 -0.6813 0.5820
+vn -0.6185 -0.7625 -0.1899
+vn 0.6115 -0.7763 0.1532
+vn -0.1525 0.1246 0.9804
+vn -0.6837 0.0753 0.7259
+vn -0.7599 0.1599 -0.6301
+vn -0.4904 0.1374 -0.8606
+vn 0.9782 0.0451 0.2028
+vn 0.9665 0.0229 0.2556
+vn -0.9839 0.0914 -0.1535
+vn -0.9493 0.0983 -0.2986
+vn -0.9960 0.0812 0.0373
+vn -0.9780 0.0775 -0.1937
+vn -0.9159 0.1393 -0.3765
+vn 0.9495 0.1269 0.2870
+vn 0.7453 0.1105 0.6575
+vn 0.9970 0.0744 -0.0194
+vn 0.8740 0.0597 -0.4823
+vn 0.9951 0.0798 0.0585
+vn 0.8523 0.3909 0.3475
+vn 0.8304 0.5511 0.0824
+vn 0.9916 0.1283 0.0146
+vn 0.8484 0.5290 -0.0195
+vn 0.8577 0.4753 0.1961
+vn 0.7014 0.4469 0.5552
+vn -0.9409 0.0844 0.3281
+vn -0.4611 0.4221 0.7805
+vn -0.8080 0.4997 0.3121
+vn -0.8603 0.4813 -0.1678
+vn -0.8317 0.4977 -0.2460
+vn -0.8765 0.3184 -0.3610
+vn -0.7604 0.2592 -0.5955
+vn -0.0027 0.0640 -0.9979
+vn -0.5328 0.2307 -0.8142
+vn -0.0179 0.2134 -0.9768
+vn 0.3109 0.0989 0.9453
+vn 0.2355 0.3923 0.8892
+vn 0.5083 0.0300 -0.8607
+vn 0.5382 0.2055 -0.8174
+vn 0.9029 0.1928 -0.3841
+vn 0.9798 0.1938 -0.0499
+vn 0.9302 0.2314 0.2851
+vn -0.8834 0.4680 0.0259
+vn -0.9585 0.0708 -0.2762
+vn -0.8740 0.4463 -0.1920
+vn -0.9188 0.3598 -0.1622
+vn 0.9977 0.0636 -0.0225
+vn 0.8756 0.2043 0.4376
+vn -0.4095 0.8845 0.2238
+vn -0.4477 0.8941 0.0123
+vn -0.7826 0.3019 -0.5445
+vn -0.4740 0.2525 -0.8436
+vn -0.4131 0.9101 -0.0329
+vn -0.3908 0.8872 0.2454
+vn -0.7671 0.6409 -0.0280
+vn 0.0554 0.2166 -0.9747
+vn 0.5579 0.2025 -0.8048
+vn -0.4242 0.8999 -0.1010
+vn 0.9151 0.1009 -0.3904
+vn 0.4525 0.6614 0.5981
+vn 0.3681 0.9118 0.1818
+vn 0.3940 0.9187 -0.0283
+vn 0.5208 0.8521 0.0525
+vn 0.4086 0.8532 0.3243
+vn -0.2601 0.7859 0.5609
+vn -0.8501 0.4447 -0.2822
+vn 0.1194 0.7620 0.6365
+vn 0.4148 0.3089 -0.8559
+vn 0.8842 0.1771 -0.4323
+vn -0.6931 0.4946 -0.5244
+vn -0.3279 0.4006 -0.8556
+vn 0.9973 0.0714 -0.0155
+vn 0.1210 0.4544 -0.8825
+vn 0.7698 0.2210 0.5987
+vn 0.1922 0.4608 0.8664
+vn -0.8281 0.5387 -0.1555
+vn -0.6279 0.7573 0.1795
+vn -0.2868 0.7541 0.5909
+usemtl skin
+s 1
+f 1/1/1 27/2/2 41/3/3 30/4/4
+f 1/1/1 30/4/4 40/5/5 16/6/6
+f 1/1/1 16/6/6 36/7/7 15/8/8
+f 1/1/1 15/8/8 39/9/9 27/2/2
+f 2/10/10 23/11/11 35/12/12 14/13/13
+f 2/10/10 14/13/13 38/14/14 25/15/15
+f 65/16/16 77/17/17 380/18/18 353/19/19
+f 65/16/16 353/19/19 378/20/20 75/21/21
+f 3/22/22 25/15/15 38/14/14 19/23/23
+f 3/22/22 19/23/23 33/24/24 18/25/25
+f 66/26/26 73/27/27 373/28/28 354/29/29
+f 66/26/26 354/29/29 380/18/18 77/17/17
+f 4/30/30 20/31/31 34/32/32 21/33/33
+f 4/30/30 21/33/33 39/9/9 26/34/34
+f 67/35/35 78/36/36 381/37/37 356/38/38
+f 67/35/35 356/38/38 375/39/39 74/40/40
+f 5/41/41 26/34/34 39/9/9 15/8/8
+f 5/41/41 15/8/8 36/7/7 24/42/42
+f 68/43/43 76/44/44 379/45/45 357/46/46
+f 68/43/43 357/46/46 381/37/37 78/36/36
+f 6/47/47 13/48/48 37/49/49 29/50/50
+f 6/47/47 29/50/50 41/3/3 27/2/2
+f 6/47/47 27/2/2 39/9/9 21/33/33
+f 6/47/47 21/33/33 34/32/32 13/48/48
+f 7/51/51 17/52/52 33/24/24 19/23/23
+f 7/51/51 19/23/23 38/14/14 28/53/53
+f 7/51/51 28/53/53 41/3/3 29/50/50
+f 7/51/51 29/50/50 37/49/49 17/52/52
+f 8/54/54 28/53/53 38/14/14 14/13/13
+f 8/54/54 14/13/13 35/12/12 22/55/55
+f 8/54/54 22/55/55 40/5/5 30/4/4
+f 8/54/54 30/4/4 41/3/3 28/53/53
+f 9/56/56 16/6/6 40/5/5 31/57/57
+f 69/58/58 79/59/59 383/60/60 362/61/61
+f 69/62/58 362/63/61 379/45/45 76/44/44
+f 9/64/56 24/42/42 36/7/7 16/6/6
+f 10/65/62 22/55/55 35/12/12 23/11/11
+f 70/66/63 75/21/21 378/20/20 363/67/64
+f 70/66/63 363/67/64 383/60/60 79/59/59
+f 10/65/62 31/57/57 40/5/5 22/55/55
+f 32/68/65 12/69/66 44/70/67 43/71/68
+f 11/72/69 18/25/25 33/24/24 17/52/52
+f 11/72/69 17/52/52 37/49/49 32/68/65
+f 71/73/70 366/74/71 373/28/28 73/27/27
+f 12/69/66 32/68/65 37/49/49 13/48/48
+f 12/69/66 13/48/48 34/32/32 20/31/31
+f 72/75/72 74/40/40 375/39/39 367/76/73
+f 71/73/70 11/72/69 42/77/74 80/78/75
+f 42/77/74 43/71/68 46/79/76 45/80/77
+f 81/81/78 384/82/79 389/83/80 83/84/81
+f 11/72/69 32/68/65 43/71/68 42/77/74
+f 72/75/72 367/76/73 384/82/79 81/81/78
+f 45/85/77 46/86/76 49/87/82 48/88/83
+f 83/89/81 389/90/80 394/91/84 85/92/85
+f 43/71/68 44/70/67 47/93/86 46/79/76
+f 80/78/75 42/77/74 45/80/77 82/94/87
+f 46/86/76 47/95/86 50/96/88 49/87/82
+f 82/97/87 45/85/77 48/88/83 84/98/89
+f 169/99/90 165/100/91 133/101/92 134/102/93
+f 93/103/94 61/104/95 51/105/96 86/106/97
+f 92/107/98 417/108/99 399/109/100 87/110/101
+f 168/111/102 167/112/103 135/113/104 136/114/105
+f 741/115/106 735/116/107 404/117/108 89/118/109
+f 739/119/110 736/120/111 55/121/112 54/122/113
+f 736/123/111 738/124/114 56/125/115 55/126/112
+f 740/127/116 739/119/110 54/122/113 88/128/117
+f 753/129/118 748/130/119 59/131/120 90/132/121
+f 750/133/122 747/134/123 57/135/124 58/136/125
+f 748/130/119 750/137/122 58/138/125 59/131/120
+f 752/139/126 749/140/127 409/141/128 91/142/129
+f 163/143/130 164/144/131 132/145/132 131/146/133
+f 85/92/85 394/91/84 417/108/99 92/107/98
+f 84/98/89 48/88/83 61/104/95 93/103/94
+f 165/100/91 166/147/134 138/148/135 133/101/92
+f 119/149/136 106/150/137 95/151/138 113/152/139
+f 55/153/112 56/154/115 111/155/140
+f 55/156/112 121/157/141 54/158/113
+f 395/159/142 84/98/89 93/103/94 416/160/143
+f 50/96/88 85/92/85 92/107/98 60/161/144
+f 747/134/123 752/139/126 91/142/129 57/135/124
+f 751/162/145 753/129/118 90/132/121 413/163/146
+f 737/164/147 740/127/116 88/128/117 405/165/148
+f 738/124/114 741/115/106 89/118/109 56/125/115
+f 60/161/144 92/107/98 87/110/101 53/166/149
+f 416/160/143 93/103/94 86/106/97 400/167/150
+f 390/168/151 82/97/87 84/98/89 395/159/142
+f 385/169/152 80/78/75 82/94/87 390/170/151
+f 47/95/86 83/89/81 85/92/85 50/96/88
+f 12/69/66 72/75/72 81/81/78 44/70/67
+f 44/70/67 81/81/78 83/84/81 47/93/86
+f 366/74/71 71/73/70 80/78/75 385/169/152
+f 12/69/66 20/31/31 74/40/40 72/75/72
+f 11/72/69 71/73/70 73/27/27 18/25/25
+f 10/65/62 70/66/63 79/59/59 31/57/57
+f 10/65/62 23/11/11 75/21/21 70/66/63
+f 9/64/56 69/62/58 76/44/44 24/42/42
+f 9/56/56 31/57/57 79/59/59 69/58/58
+f 5/41/41 68/43/43 78/36/36 26/34/34
+f 5/41/41 24/42/42 76/44/44 68/43/43
+f 4/30/30 67/35/35 74/40/40 20/31/31
+f 4/30/30 26/34/34 78/36/36 67/35/35
+f 3/22/22 66/26/26 77/17/17 25/15/15
+f 3/22/22 18/25/25 73/27/27 66/26/26
+f 2/10/10 65/16/16 75/21/21 23/11/11
+f 2/10/10 25/15/15 77/17/17 65/16/16
+f 62/171/153 56/154/115 89/172/109
+f 64/173/154 88/174/117 54/158/113
+f 404/175/108 451/176/155 62/171/153 89/172/109
+f 482/177/156 421/178/157 63/179/158 120/180/159
+f 405/181/148 88/174/117 64/173/154 452/182/160
+f 110/183/161 63/184/158 421/185/157 471/186/162
+f 797/187/163 791/188/164 98/189/165 124/190/166
+f 129/191/167 108/192/168 94/193/169 122/194/170
+f 128/195/171 107/196/172 97/197/173 123/198/174
+f 118/199/175 109/200/176 96/201/177 112/202/178
+f 125/203/179 101/204/180 105/205/181 127/206/182
+f 796/207/183 793/208/184 101/204/180 125/203/179
+f 114/209/185 795/210/186 100/211/187
+f 794/212/188 792/213/189 99/214/190 115/215/191
+f 103/216/192 126/217/193 216/218/194 327/219/195
+f 114/209/185 100/211/187 104/220/196 116/221/197
+f 115/215/191 99/214/190 103/216/192 117/222/198
+f 124/190/166 98/189/165 102/223/199 126/217/193
+f 110/183/161 64/173/154 109/200/176 118/199/175
+f 121/157/141 55/156/112 107/196/172 128/195/171
+f 120/180/159 63/179/158 108/192/168 129/191/167
+f 111/155/140 62/171/153 106/150/137 119/149/136
+f 55/153/112 111/155/140 119/149/136 107/224/172
+f 63/184/158 110/183/161 118/199/175 108/225/168
+f 101/226/180 115/215/191 117/222/198 105/227/181
+f 98/228/165 114/209/185 116/221/197 102/229/199
+f 126/217/193 102/223/199 220/230/200 216/218/194
+f 793/231/184 794/212/188 115/215/191 101/226/180
+f 791/232/164 795/210/186 114/209/185 98/228/165
+f 108/225/168 118/199/175 112/202/178 94/233/169
+f 64/173/154 110/183/161 471/186/162 452/182/160
+f 107/224/172 119/149/136 113/152/139 97/234/173
+f 116/221/197 104/220/196 221/235/201 218/236/202
+f 62/171/153 120/180/159 129/191/167 106/150/137
+f 64/173/154 121/157/141 128/195/171 109/200/176
+f 99/214/190 124/190/166 126/217/193 103/216/192
+f 105/227/181 117/222/198 217/237/203 219/238/204
+f 796/207/183 125/203/179 100/211/187
+f 100/211/187 125/203/179 127/206/182 104/220/196
+f 109/200/176 128/195/171 123/198/174 96/201/177
+f 106/150/137 129/191/167 122/194/170 95/151/138
+f 792/213/189 797/187/163 124/190/166 99/214/190
+f 451/176/155 482/177/156 120/180/159 62/171/153
+f 62/171/153 111/155/140 56/154/115
+f 64/173/154 54/158/113 121/157/141
+f 781/239/205 780/240/206 143/241/207 144/242/208
+f 779/243/209 775/244/210 145/245/211 141/246/212
+f 776/247/213 777/248/214 139/249/215 147/250/216
+f 777/248/214 778/251/217 140/252/218 139/249/215
+f 166/147/134 170/253/219 130/254/220 138/148/135
+f 164/144/131 168/111/102 136/114/105 132/145/132
+f 170/253/219 163/143/130 131/146/133 130/254/220
+f 167/112/103 169/255/90 134/256/93 135/113/104
+f 765/257/221 761/258/222 148/259/223 137/260/224
+f 764/261/225 763/262/226 150/263/227 151/264/228
+f 762/265/229 759/266/230 152/267/231 153/268/232
+f 763/262/226 760/269/233 155/270/234 150/263/227
+f 778/251/217 779/243/209 141/246/212 140/252/218
+f 782/271/235 776/247/213 147/250/216 142/272/236
+f 775/244/210 781/239/205 144/242/208 145/245/211
+f 780/273/206 782/271/235 142/272/236 143/274/207
+f 149/275/237 153/276/232 177/277/238 173/278/239
+f 155/279/234 137/280/224 171/281/240 179/282/241
+f 137/280/224 148/283/223 172/284/242 171/281/240
+f 151/285/228 150/286/227 174/287/243 175/288/244
+f 760/269/233 765/257/221 137/260/224 155/270/234
+f 766/289/245 762/265/229 153/268/232 149/290/237
+f 759/266/230 764/291/225 151/292/228 152/267/231
+f 761/258/222 766/289/245 149/290/237 148/259/223
+f 727/293/246 724/294/247 162/295/248 160/296/249
+f 725/297/250 722/298/251 159/299/252 156/300/253
+f 162/295/248 724/294/247 146/301/254
+f 726/302/255 723/303/256 161/304/257 158/305/258
+f 721/306/259 726/302/255 158/305/258 157/307/260
+f 725/297/250 156/300/253 146/301/254
+f 722/308/251 721/306/259 157/307/260 159/309/252
+f 723/303/256 727/293/246 160/296/249 161/304/257
+f 53/166/149 52/310/261 169/255/90 167/112/103
+f 48/88/83 49/87/82 163/143/130 170/253/219
+f 50/96/88 60/161/144 168/111/102 164/144/131
+f 61/104/95 48/88/83 170/253/219 166/147/134
+f 51/105/96 61/104/95 166/147/134 165/100/91
+f 49/87/82 50/96/88 164/144/131 163/143/130
+f 60/161/144 53/166/149 167/112/103 168/111/102
+f 52/311/261 51/105/96 165/100/91 169/99/90
+f 172/284/242 173/278/239 181/312/262 180/313/263
+f 176/314/264 175/288/244 183/315/265 184/316/266
+f 173/278/239 177/277/238 185/317/267 181/312/262
+f 179/282/241 171/281/240 154/318/268 187/319/269
+f 152/320/231 151/285/228 175/288/244 176/314/264
+f 148/283/223 149/275/237 173/278/239 172/284/242
+f 150/321/227 155/279/234 179/282/241 174/322/243
+f 153/276/232 152/323/231 176/324/264 177/277/238
+f 703/325/270 702/326/271 178/327/272 195/328/273
+f 702/326/271 699/329/274 188/330/275 178/327/272
+f 700/331/276 697/332/277 190/333/278 191/334/279
+f 701/335/280 698/336/281 192/337/282 193/338/283
+f 174/322/243 179/282/241 187/319/269 182/339/284
+f 184/340/266 185/317/267 205/341/285 206/342/286
+f 175/288/244 174/287/243 182/343/284 183/315/265
+f 171/281/240 172/284/242 180/313/263 154/318/268
+f 194/344/287 193/338/283 192/337/282 191/345/279
+f 195/328/273 194/344/287 191/345/279 190/346/278
+f 178/327/272 188/330/275 194/344/287 195/328/273
+f 188/330/275 189/347/288 193/338/283 194/344/287
+f 704/348/289 701/335/280 193/338/283 189/347/288
+f 698/349/281 700/331/276 191/334/279 192/350/282
+f 699/329/274 704/348/289 189/347/288 188/330/275
+f 697/351/277 703/325/270 195/328/273 190/346/278
+f 710/352/290 708/353/291 201/354/292 196/355/293
+f 712/356/294 709/357/295 202/358/296 199/359/297
+f 711/360/298 705/361/299 186/362/300 198/363/301
+f 709/357/295 706/364/302 197/365/303 202/358/296
+f 706/364/302 711/366/298 198/367/301 197/365/303
+f 705/361/299 710/368/290 196/369/293 186/362/300
+f 707/370/304 712/356/294 199/359/297 200/371/305
+f 708/353/291 707/370/304 200/371/305 201/354/292
+f 203/372/306 204/373/307 208/374/308 207/375/309
+f 176/314/264 184/316/266 206/376/286 204/377/307
+f 185/317/267 177/277/238 203/372/306 205/341/285
+f 177/277/238 176/324/264 204/373/307 203/372/306
+f 208/378/308 210/379/310 214/380/311 212/381/312
+f 204/377/307 206/376/286 210/379/310 208/378/308
+f 205/341/285 203/372/306 207/375/309 209/382/313
+f 206/342/286 205/341/285 209/382/313 210/383/310
+f 211/384/314 212/385/312 214/386/311 213/387/315
+f 209/382/313 207/375/309 211/384/314 213/387/315
+f 210/383/310 209/382/313 213/387/315 214/386/311
+f 207/375/309 208/374/308 212/385/312 211/384/314
+f 104/220/196 127/206/182 215/388/316 221/235/201
+f 127/206/182 105/205/181 219/389/204 215/388/316
+f 102/229/199 116/221/197 218/236/202 220/390/200
+f 117/222/198 103/216/192 327/219/195 217/237/203
+f 241/391/317 229/392/318 225/393/319 240/394/320
+f 242/395/321 224/396/322 229/392/318 241/391/317
+f 248/397/323 226/398/324 230/399/317 247/400/317
+f 247/400/317 230/399/317 228/401/325 246/402/326
+f 239/403/317 233/404/317 232/405/327 238/406/328
+f 237/407/329 231/408/330 233/404/317 239/403/317
+f 309/409/331 235/410/332 236/411/317 308/412/317
+f 308/412/317 236/411/317 234/413/333 307/414/334
+f 222/415/335 237/407/329 239/403/317 227/416/336
+f 227/416/336 239/403/317 238/406/328 223/417/337
+f 235/410/332 242/395/321 241/391/317 236/411/317
+f 236/411/317 241/391/317 240/394/320 234/413/333
+f 230/399/317 245/418/317 244/419/338 228/401/325
+f 226/398/324 243/420/339 245/418/317 230/399/317
+f 233/404/317 247/400/317 246/402/326 232/405/327
+f 231/408/330 248/397/323 247/400/317 233/404/317
+f 223/421/337 250/422/340 254/423/341 227/424/336
+f 225/425/319 252/426/342 263/427/343 240/428/320
+f 243/429/339 265/430/344 311/431/345 309/432/331
+f 228/433/325 255/434/346 267/435/347 246/436/326
+f 246/436/326 267/435/347 258/437/348 232/438/327
+f 234/439/333 259/440/349 310/441/350 307/442/334
+f 237/443/329 261/444/351 257/445/352 231/446/330
+f 240/428/320 263/427/343 259/440/349 234/439/333
+f 309/432/331 311/431/345 260/447/353 235/448/332
+f 235/448/332 260/447/353 264/449/354 242/450/321
+f 253/451/355 273/452/356 284/453/357 265/430/344
+f 268/454/358 287/455/359 273/452/356 253/451/355
+f 261/444/351 280/456/360 276/457/361 257/445/352
+f 262/458/362 281/459/363 270/460/364 250/422/340
+f 255/434/346 274/461/365 286/462/366 267/435/347
+f 263/427/343 282/463/367 278/464/368 259/440/349
+f 256/465/369 275/466/370 272/467/371 252/426/342
+f 249/468/372 269/469/373 280/456/360 261/444/351
+f 264/449/354 283/470/374 271/471/375 251/472/376
+f 257/445/352 276/457/361 287/455/359 268/454/358
+f 311/431/345 313/473/377 279/474/378 260/447/353
+f 258/437/348 277/475/379 281/459/363 262/458/362
+f 252/426/342 272/467/371 282/463/367 263/427/343
+f 266/476/380 285/477/381 274/461/365 255/434/346
+f 310/441/350 312/478/382 285/477/381 266/476/380
+f 251/472/376 271/471/375 275/479/370 256/480/369
+f 267/435/347 286/462/366 277/475/379 258/437/348
+f 260/447/353 279/474/378 283/470/374 264/449/354
+f 313/473/377 315/481/383 298/482/384 279/474/378
+f 277/475/379 296/483/385 300/484/386 281/459/363
+f 272/467/371 291/485/387 301/486/388 282/463/367
+f 285/477/381 304/487/389 293/488/390 274/461/365
+f 312/478/382 314/489/391 304/487/389 285/477/381
+f 271/471/375 290/490/392 294/491/393 275/479/370
+f 286/462/366 305/492/394 296/483/385 277/475/379
+f 279/474/378 298/482/384 302/493/395 283/470/374
+f 273/452/356 292/494/396 303/495/397 284/453/357
+f 287/455/359 306/496/398 292/494/396 273/452/356
+f 280/456/360 299/497/399 295/498/400 276/457/361
+f 281/459/363 300/484/386 289/499/401 270/460/364
+f 274/461/365 293/488/390 305/492/394 286/462/366
+f 282/463/367 301/486/388 297/500/402 278/464/368
+f 275/466/370 294/501/393 291/485/387 272/467/371
+f 269/469/373 288/502/403 299/497/399 280/456/360
+f 283/470/374 302/493/395 290/490/392 271/471/375
+f 276/457/361 295/498/400 306/496/398 287/455/359
+f 290/490/392 302/493/395 322/503/404 319/504/405
+f 301/486/388 291/485/387 317/505/406 316/506/407
+f 302/493/395 298/482/384 323/507/408 322/503/404
+f 291/485/387 294/501/393 318/508/409 317/505/406
+f 315/481/383 303/495/397 325/509/410 324/510/411
+f 297/500/402 301/486/388 316/506/407 321/511/412
+f 294/491/393 290/490/392 319/504/405 318/512/409
+f 314/489/391 297/500/402 321/511/412 320/513/413
+f 303/495/397 304/487/389 326/514/414 325/509/410
+f 269/469/373 270/460/364 289/499/401 288/502/403
+f 300/484/386 296/483/385 295/498/400 299/497/399
+f 306/496/398 295/498/400 296/483/385 305/492/394
+f 305/492/394 293/488/390 292/494/396 306/496/398
+f 303/495/397 292/494/396 293/488/390 304/487/389
+f 304/487/389 314/489/391 320/513/413 326/514/414
+f 298/482/384 315/481/383 324/510/411 323/507/408
+f 278/464/368 297/500/402 314/489/391 312/478/382
+f 284/453/357 303/495/397 315/481/383 313/473/377
+f 259/440/349 278/464/368 312/478/382 310/441/350
+f 265/430/344 284/453/357 313/473/377 311/431/345
+f 227/424/336 254/423/341 249/468/372 222/515/335
+f 245/418/317 308/412/317 307/414/334 244/419/338
+f 243/420/339 309/409/331 308/412/317 245/418/317
+f 221/516/201 215/517/316 316/506/407 317/505/406
+f 318/512/409 319/504/405 221/518/201
+f 221/516/201 317/505/406 318/508/409
+f 219/519/204 217/520/203 320/513/413 321/511/412
+f 220/521/200 218/522/202 322/503/404 323/507/408
+f 215/517/316 219/519/204 321/511/412 316/506/407
+f 218/522/202 221/518/201 319/504/405 322/503/404
+f 327/523/195 216/524/194 324/510/411 325/509/410
+f 325/509/410 326/514/414 327/523/195
+f 217/520/203 327/523/195 326/514/414 320/513/413
+f 216/524/194 220/521/200 323/507/408 324/510/411
+f 222/515/335 249/468/372 261/444/351 237/443/329
+f 242/450/321 264/449/354 251/472/376 224/525/322
+f 248/526/323 268/454/358 253/451/355 226/527/324
+f 224/525/322 251/472/376 256/480/369 229/528/318
+f 231/446/330 257/445/352 268/454/358 248/526/323
+f 307/442/334 310/441/350 266/476/380 244/529/338
+f 232/438/327 258/437/348 262/458/362 238/530/328
+f 244/529/338 266/476/380 255/434/346 228/433/325
+f 226/527/324 253/451/355 265/430/344 243/429/339
+f 229/531/318 256/465/369 252/426/342 225/425/319
+f 238/530/328 262/458/362 250/422/340 223/421/337
+f 299/497/399 288/502/403 289/499/401 300/484/386
+f 250/422/340 270/460/364 254/423/341
+f 254/423/341 269/469/373 249/468/372
+f 269/469/373 254/423/341 270/460/364
+f 328/532/415 361/533/416 382/534/417 358/535/418
+f 328/532/415 343/536/419 377/537/420 361/533/416
+f 328/532/415 342/538/421 371/539/422 343/536/419
+f 328/532/415 358/535/418 376/540/423 342/538/421
+f 329/541/424 341/542/425 370/543/426 350/544/427
+f 329/541/424 352/545/428 374/546/429 341/542/425
+f 422/547/430 353/548/19 380/549/18 434/550/431
+f 422/547/430 432/551/432 378/552/20 353/548/19
+f 330/553/433 346/554/434 374/546/429 352/545/428
+f 330/553/433 345/555/435 368/556/436 346/554/434
+f 423/557/437 354/558/29 373/559/28 430/560/438
+f 423/557/437 434/550/431 380/549/18 354/558/29
+f 331/561/439 348/562/440 369/563/441 347/564/442
+f 331/561/439 355/565/443 376/540/423 348/562/440
+f 424/566/444 356/38/38 381/37/37 435/567/445
+f 424/566/444 431/568/446 375/39/39 356/38/38
+f 332/569/447 342/538/421 376/540/423 355/565/443
+f 332/569/447 351/570/448 371/539/422 342/538/421
+f 425/571/449 357/46/46 379/45/45 433/572/450
+f 425/571/449 435/567/445 381/37/37 357/46/46
+f 333/573/451 360/574/452 372/575/453 340/576/454
+f 333/573/451 358/535/418 382/534/417 360/574/452
+f 333/573/451 348/562/440 376/540/423 358/535/418
+f 333/573/451 340/576/454 369/563/441 348/562/440
+f 334/577/455 346/554/434 368/556/436 344/578/456
+f 334/577/455 359/579/457 374/546/429 346/554/434
+f 334/577/455 360/574/452 382/534/417 359/579/457
+f 334/577/455 344/578/456 372/575/453 360/574/452
+f 335/580/458 341/542/425 374/546/429 359/579/457
+f 335/580/458 349/581/459 370/543/426 341/542/425
+f 335/580/458 361/533/416 377/537/420 349/581/459
+f 335/580/458 359/579/457 382/534/417 361/533/416
+f 336/582/460 364/583/461 377/537/420 343/536/419
+f 426/584/462 362/585/61 383/586/60 436/587/463
+f 426/588/462 433/572/450 379/45/45 362/63/61
+f 336/589/460 343/536/419 371/539/422 351/570/448
+f 337/590/464 350/544/427 370/543/426 349/581/459
+f 427/591/465 363/592/64 378/552/20 432/551/432
+f 427/591/465 436/587/463 383/586/60 363/592/64
+f 337/590/464 349/581/459 377/537/420 364/583/461
+f 365/593/466 387/594/467 388/595/468 339/596/469
+f 338/597/470 344/578/456 368/556/436 345/555/435
+f 338/597/470 365/593/466 372/575/453 344/578/456
+f 428/598/471 430/560/438 373/559/28 366/599/71
+f 339/596/469 340/576/454 372/575/453 365/593/466
+f 339/596/469 347/564/442 369/563/441 340/576/454
+f 429/600/472 367/76/73 375/39/39 431/568/446
+f 428/598/471 437/601/473 386/602/474 338/597/470
+f 386/602/474 391/603/475 392/604/476 387/594/467
+f 438/605/477 440/606/478 389/83/80 384/82/79
+f 338/597/470 386/602/474 387/594/467 365/593/466
+f 429/600/472 438/605/477 384/82/79 367/76/73
+f 391/607/475 396/608/479 397/609/480 392/610/476
+f 440/611/478 442/612/481 394/91/84 389/90/80
+f 387/594/467 392/604/476 393/613/482 388/595/468
+f 437/601/473 439/614/483 391/603/475 386/602/474
+f 392/610/476 397/609/480 398/615/484 393/616/482
+f 439/617/483 441/618/485 396/608/479 391/607/475
+f 530/619/486 495/620/487 494/621/488 526/622/489
+f 450/623/490 443/624/491 401/625/492 415/626/493
+f 449/627/494 444/628/495 399/109/100 417/108/99
+f 529/629/496 497/630/497 496/631/498 528/632/499
+f 746/633/500 446/634/501 404/117/108 735/116/107
+f 744/635/502 406/636/503 407/637/504 742/638/505
+f 742/639/505 407/640/504 408/641/506 743/642/507
+f 745/643/508 445/644/509 406/636/503 744/635/502
+f 758/645/510 447/646/511 412/647/512 755/648/513
+f 756/649/514 411/650/515 410/651/516 754/652/517
+f 755/648/513 412/647/512 411/653/515 756/654/514
+f 757/655/518 448/656/519 409/141/128 749/140/127
+f 524/657/520 492/658/521 493/659/522 525/660/523
+f 442/612/481 449/627/494 417/108/99 394/91/84
+f 441/618/485 450/623/490 415/626/493 396/608/479
+f 526/622/489 494/621/488 499/661/524 527/662/525
+f 479/663/526 473/664/527 454/665/528 465/666/529
+f 407/667/504 470/668/530 408/669/506
+f 407/670/504 406/671/503 481/672/531
+f 395/159/142 416/160/143 450/623/490 441/618/485
+f 398/615/484 414/673/532 449/627/494 442/612/481
+f 754/652/517 410/651/516 448/656/519 757/655/518
+f 751/162/145 413/163/146 447/646/511 758/645/510
+f 737/164/147 405/165/148 445/644/509 745/643/508
+f 743/642/507 408/641/506 446/634/501 746/633/500
+f 414/673/532 403/674/533 444/628/495 449/627/494
+f 416/160/143 400/167/150 443/624/491 450/623/490
+f 390/168/151 395/159/142 441/618/485 439/617/483
+f 385/675/152 390/676/151 439/614/483 437/601/473
+f 393/616/482 398/615/484 442/612/481 440/611/478
+f 339/596/469 388/595/468 438/605/477 429/600/472
+f 388/595/468 393/613/482 440/606/478 438/605/477
+f 366/599/71 385/675/152 437/601/473 428/598/471
+f 339/596/469 429/600/472 431/568/446 347/564/442
+f 338/597/470 345/555/435 430/560/438 428/598/471
+f 337/590/464 364/583/461 436/587/463 427/591/465
+f 337/590/464 427/591/465 432/551/432 350/544/427
+f 336/589/460 351/570/448 433/572/450 426/588/462
+f 336/582/460 426/584/462 436/587/463 364/583/461
+f 332/569/447 355/565/443 435/567/445 425/571/449
+f 332/569/447 425/571/449 433/572/450 351/570/448
+f 331/561/439 347/564/442 431/568/446 424/566/444
+f 331/561/439 424/566/444 435/567/445 355/565/443
+f 330/553/433 352/545/428 434/550/431 423/557/437
+f 330/553/433 423/557/437 430/560/438 345/555/435
+f 329/541/424 350/544/427 432/551/432 422/547/430
+f 329/541/424 422/547/430 434/550/431 352/545/428
+f 418/677/534 446/678/501 408/669/506
+f 420/679/535 406/671/503 445/680/509
+f 404/175/108 446/678/501 418/677/534 451/176/155
+f 482/177/156 480/681/536 419/682/537 421/178/157
+f 405/181/148 452/182/160 420/679/535 445/680/509
+f 469/683/538 471/186/162 421/185/157 419/684/537
+f 804/685/539 485/686/540 457/687/541 798/688/542
+f 490/689/543 483/690/544 453/691/545 467/692/546
+f 489/693/547 484/694/548 456/695/549 466/696/550
+f 478/697/551 472/698/552 455/699/553 468/700/554
+f 486/701/555 488/702/556 464/703/557 460/704/558
+f 803/705/559 486/701/555 460/704/558 800/706/560
+f 802/707/561 474/708/562 459/709/563
+f 801/710/564 475/711/565 458/712/566 799/713/567
+f 462/714/568 688/715/569 577/716/570 487/717/571
+f 474/708/562 476/718/572 463/719/573 459/709/563
+f 475/711/565 477/720/574 462/714/568 458/712/566
+f 485/686/540 487/717/571 461/721/575 457/687/541
+f 469/683/538 478/697/551 468/700/554 420/679/535
+f 481/672/531 489/693/547 466/696/550 407/670/504
+f 480/681/536 490/689/543 467/692/546 419/682/537
+f 470/668/530 479/663/526 465/666/529 418/677/534
+f 407/667/504 466/722/550 479/663/526 470/668/530
+f 419/684/537 467/723/546 478/697/551 469/683/538
+f 460/724/558 464/725/557 477/720/574 475/711/565
+f 457/726/541 461/727/575 476/718/572 474/708/562
+f 487/717/571 577/716/570 581/728/576 461/721/575
+f 800/729/560 460/724/558 475/711/565 801/710/564
+f 798/730/542 457/726/541 474/708/562 802/707/561
+f 467/723/546 453/731/545 472/698/552 478/697/551
+f 420/679/535 452/182/160 471/186/162 469/683/538
+f 466/722/550 456/732/549 473/664/527 479/663/526
+f 476/718/572 579/733/577 582/734/578 463/719/573
+f 418/677/534 465/666/529 490/689/543 480/681/536
+f 420/679/535 468/700/554 489/693/547 481/672/531
+f 458/712/566 462/714/568 487/717/571 485/686/540
+f 464/725/557 580/735/579 578/736/580 477/720/574
+f 459/709/563 486/701/555 803/705/559
+f 459/709/563 463/719/573 488/702/556 486/701/555
+f 468/700/554 455/699/553 484/694/548 489/693/547
+f 465/666/529 454/665/528 483/690/544 490/689/543
+f 799/713/567 458/712/566 485/686/540 804/685/539
+f 451/176/155 418/677/534 480/681/536 482/177/156
+f 418/677/534 408/669/506 470/668/530
+f 420/679/535 481/672/531 406/671/503
+f 789/737/581 505/738/582 504/739/583 788/740/584
+f 787/741/585 502/742/586 506/743/587 783/744/588
+f 784/745/589 508/746/590 500/747/591 785/748/592
+f 785/748/592 500/747/591 501/749/593 786/750/594
+f 527/662/525 499/661/524 491/751/595 531/752/596
+f 525/660/523 493/659/522 497/630/497 529/629/496
+f 531/752/596 491/751/595 492/658/521 524/657/520
+f 528/632/499 496/631/498 495/753/487 530/754/486
+f 773/755/597 498/756/598 509/757/599 769/758/600
+f 772/759/601 512/760/602 511/761/603 771/762/604
+f 770/763/605 514/764/606 513/765/607 767/766/608
+f 771/762/604 511/761/603 516/767/609 768/768/610
+f 786/750/594 501/749/593 502/742/586 787/741/585
+f 790/769/611 503/770/612 508/746/590 784/745/589
+f 783/744/588 506/743/587 505/738/582 789/737/581
+f 788/771/584 504/772/583 503/770/612 790/769/611
+f 510/773/613 534/774/614 538/775/615 514/776/606
+f 516/777/609 540/778/616 532/779/617 498/780/598
+f 498/780/598 532/779/617 533/781/618 509/782/599
+f 512/783/602 536/784/619 535/785/620 511/786/603
+f 768/768/610 516/767/609 498/756/598 773/755/597
+f 774/787/621 510/788/613 514/764/606 770/763/605
+f 767/766/608 513/765/607 512/789/602 772/790/601
+f 769/758/600 509/757/599 510/788/613 774/787/621
+f 734/791/622 521/792/623 523/793/624 731/794/625
+f 732/795/626 517/796/627 520/797/628 729/798/629
+f 731/794/625 523/793/624 507/799/630
+f 733/800/631 519/801/632 522/802/633 730/803/634
+f 728/804/635 518/805/636 519/801/632 733/800/631
+f 507/799/630 517/796/627 732/795/626
+f 729/806/629 520/807/628 518/805/636 728/804/635
+f 730/803/634 522/802/633 521/792/623 734/791/622
+f 403/674/533 528/632/499 530/754/486 402/808/637
+f 396/608/479 531/752/596 524/657/520 397/609/480
+f 398/615/484 525/660/523 529/629/496 414/673/532
+f 415/626/493 527/662/525 531/752/596 396/608/479
+f 401/625/492 526/622/489 527/662/525 415/626/493
+f 397/609/480 524/657/520 525/660/523 398/615/484
+f 414/673/532 529/629/496 528/632/499 403/674/533
+f 402/809/637 530/619/486 526/622/489 401/625/492
+f 533/781/618 541/810/638 542/811/639 534/774/614
+f 537/812/640 545/813/641 544/814/642 536/784/619
+f 534/774/614 542/811/639 546/815/643 538/775/615
+f 540/778/616 548/816/644 515/817/645 532/779/617
+f 513/818/607 537/812/640 536/784/619 512/783/602
+f 509/782/599 533/781/618 534/774/614 510/773/613
+f 511/819/603 535/820/620 540/778/616 516/777/609
+f 514/776/606 538/775/615 537/821/640 513/822/607
+f 695/823/646 556/824/647 539/825/648 694/826/649
+f 694/826/649 539/825/648 549/827/650 691/828/651
+f 692/829/652 552/830/653 551/831/654 689/832/655
+f 693/833/656 554/834/657 553/835/658 690/836/659
+f 535/820/620 543/837/660 548/816/644 540/778/616
+f 545/838/641 567/839/661 566/840/662 546/815/643
+f 536/784/619 544/814/642 543/841/660 535/785/620
+f 532/779/617 515/817/645 541/810/638 533/781/618
+f 555/842/663 552/843/653 553/835/658 554/834/657
+f 556/824/647 551/844/654 552/843/653 555/842/663
+f 539/825/648 556/824/647 555/842/663 549/827/650
+f 549/827/650 555/842/663 554/834/657 550/845/664
+f 696/846/665 550/845/664 554/834/657 693/833/656
+f 690/847/659 553/848/658 552/830/653 692/829/652
+f 691/828/651 549/827/650 550/845/664 696/846/665
+f 689/849/655 551/844/654 556/824/647 695/823/646
+f 718/850/666 557/851/667 562/852/668 716/853/669
+f 720/854/670 560/855/671 563/856/672 717/857/673
+f 719/858/674 559/859/675 547/860/676 713/861/677
+f 717/857/673 563/856/672 558/862/678 714/863/679
+f 714/863/679 558/862/678 559/864/675 719/865/674
+f 713/861/677 547/860/676 557/866/667 718/867/666
+f 715/868/680 561/869/681 560/855/671 720/854/670
+f 716/853/669 562/852/668 561/869/681 715/868/680
+f 564/870/682 568/871/683 569/872/684 565/873/685
+f 537/812/640 565/874/685 567/875/661 545/813/641
+f 546/815/643 566/840/662 564/870/682 538/775/615
+f 538/775/615 564/870/682 565/873/685 537/821/640
+f 569/876/684 573/877/686 575/878/687 571/879/688
+f 565/874/685 569/876/684 571/879/688 567/875/661
+f 566/840/662 570/880/689 568/871/683 564/870/682
+f 567/839/661 571/881/688 570/880/689 566/840/662
+f 572/882/690 574/883/691 575/884/687 573/885/686
+f 570/880/689 574/883/691 572/882/690 568/871/683
+f 571/881/688 575/884/687 574/883/691 570/880/689
+f 568/871/683 572/882/690 573/885/686 569/872/684
+f 463/719/573 582/734/578 576/886/692 488/702/556
+f 488/702/556 576/886/692 580/887/579 464/703/557
+f 461/727/575 581/888/576 579/733/577 476/718/572
+f 477/720/574 578/736/580 688/715/569 462/714/568
+f 602/889/317 601/890/693 586/891/694 590/892/695
+f 603/893/696 602/889/317 590/892/695 585/894/697
+f 609/895/698 608/896/317 591/897/317 587/898/699
+f 608/896/317 607/899/700 589/900/701 591/897/317
+f 600/901/317 599/902/702 593/903/703 594/904/317
+f 598/905/704 600/901/317 594/904/317 592/906/705
+f 670/907/706 669/908/317 597/909/317 596/910/707
+f 669/908/317 668/911/708 595/912/709 597/909/317
+f 583/913/710 588/914/711 600/901/317 598/905/704
+f 588/914/711 584/915/712 599/902/702 600/901/317
+f 596/910/707 597/909/317 602/889/317 603/893/696
+f 597/909/317 595/912/709 601/890/693 602/889/317
+f 591/897/317 589/900/701 605/916/713 606/917/317
+f 587/898/699 591/897/317 606/917/317 604/918/714
+f 594/904/317 593/903/703 607/899/700 608/896/317
+f 592/906/705 594/904/317 608/896/317 609/895/698
+f 584/919/712 588/920/711 615/921/715 611/922/716
+f 586/923/694 601/924/693 624/925/717 613/926/718
+f 604/927/714 670/928/706 672/929/719 626/930/720
+f 589/931/701 607/932/700 628/933/721 616/934/722
+f 607/932/700 593/935/703 619/936/723 628/933/721
+f 595/937/709 668/938/708 671/939/724 620/940/725
+f 598/941/704 592/942/705 618/943/726 622/944/727
+f 601/924/693 595/937/709 620/940/725 624/925/717
+f 670/928/706 596/945/707 621/946/728 672/929/719
+f 596/945/707 603/947/696 625/948/729 621/946/728
+f 614/949/730 626/930/720 645/950/731 634/951/732
+f 629/952/733 614/949/730 634/951/732 648/953/734
+f 622/944/727 618/943/726 637/954/735 641/955/736
+f 623/956/737 611/922/716 631/957/738 642/958/739
+f 616/934/722 628/933/721 647/959/740 635/960/741
+f 624/925/717 620/940/725 639/961/742 643/962/743
+f 617/963/744 613/926/718 633/964/745 636/965/746
+f 610/966/747 622/944/727 641/955/736 630/967/748
+f 625/948/729 612/968/749 632/969/750 644/970/751
+f 618/943/726 629/952/733 648/953/734 637/954/735
+f 672/929/719 621/946/728 640/971/752 674/972/753
+f 619/936/723 623/956/737 642/958/739 638/973/754
+f 613/926/718 624/925/717 643/962/743 633/964/745
+f 627/974/755 616/934/722 635/960/741 646/975/756
+f 671/939/724 627/974/755 646/975/756 673/976/757
+f 612/968/749 617/977/744 636/978/746 632/969/750
+f 628/933/721 619/936/723 638/973/754 647/959/740
+f 621/946/728 625/948/729 644/970/751 640/971/752
+f 674/972/753 640/971/752 659/979/758 676/980/759
+f 638/973/754 642/958/739 661/981/760 657/982/761
+f 633/964/745 643/962/743 662/983/762 652/984/763
+f 646/975/756 635/960/741 654/985/764 665/986/765
+f 673/976/757 646/975/756 665/986/765 675/987/766
+f 632/969/750 636/978/746 655/988/767 651/989/768
+f 647/959/740 638/973/754 657/982/761 666/990/769
+f 640/971/752 644/970/751 663/991/770 659/979/758
+f 634/951/732 645/950/731 664/992/771 653/993/772
+f 648/953/734 634/951/732 653/993/772 667/994/773
+f 641/955/736 637/954/735 656/995/774 660/996/775
+f 642/958/739 631/957/738 650/997/776 661/981/760
+f 635/960/741 647/959/740 666/990/769 654/985/764
+f 643/962/743 639/961/742 658/998/777 662/983/762
+f 636/965/746 633/964/745 652/984/763 655/999/767
+f 630/967/748 641/955/736 660/996/775 649/1000/778
+f 644/970/751 632/969/750 651/989/768 663/991/770
+f 637/954/735 648/953/734 667/994/773 656/995/774
+f 651/989/768 680/1001/779 683/1002/780 663/991/770
+f 662/983/762 677/1003/781 678/1004/782 652/984/763
+f 663/991/770 683/1002/780 684/1005/783 659/979/758
+f 652/984/763 678/1004/782 679/1006/784 655/999/767
+f 676/980/759 685/1007/785 686/1008/786 664/992/771
+f 658/998/777 682/1009/787 677/1003/781 662/983/762
+f 655/988/767 679/1010/784 680/1001/779 651/989/768
+f 675/987/766 681/1011/788 682/1009/787 658/998/777
+f 664/992/771 686/1008/786 687/1012/789 665/986/765
+f 630/967/748 649/1000/778 650/997/776 631/957/738
+f 661/981/760 660/996/775 656/995/774 657/982/761
+f 667/994/773 666/990/769 657/982/761 656/995/774
+f 666/990/769 667/994/773 653/993/772 654/985/764
+f 664/992/771 665/986/765 654/985/764 653/993/772
+f 665/986/765 687/1012/789 681/1011/788 675/987/766
+f 659/979/758 684/1005/783 685/1007/785 676/980/759
+f 639/961/742 673/976/757 675/987/766 658/998/777
+f 645/950/731 674/972/753 676/980/759 664/992/771
+f 620/940/725 671/939/724 673/976/757 639/961/742
+f 626/930/720 672/929/719 674/972/753 645/950/731
+f 588/920/711 583/1013/710 610/966/747 615/921/715
+f 606/917/317 605/916/713 668/911/708 669/908/317
+f 604/918/714 606/917/317 669/908/317 670/907/706
+f 582/1014/578 678/1004/782 677/1003/781 576/1015/692
+f 679/1010/784 582/1016/578 680/1001/779
+f 582/1014/578 679/1006/784 678/1004/782
+f 580/1017/579 682/1009/787 681/1011/788 578/1018/580
+f 581/1019/576 684/1005/783 683/1002/780 579/1020/577
+f 576/1015/692 677/1003/781 682/1009/787 580/1017/579
+f 579/1020/577 683/1002/780 680/1001/779 582/1016/578
+f 688/1021/569 686/1008/786 685/1007/785 577/1022/570
+f 686/1008/786 688/1021/569 687/1012/789
+f 578/1018/580 681/1011/788 687/1012/789 688/1021/569
+f 577/1022/570 685/1007/785 684/1005/783 581/1019/576
+f 583/1013/710 598/941/704 622/944/727 610/966/747
+f 603/947/696 585/1023/697 612/968/749 625/948/729
+f 609/1024/698 587/1025/699 614/949/730 629/952/733
+f 585/1023/697 590/1026/695 617/977/744 612/968/749
+f 592/942/705 609/1024/698 629/952/733 618/943/726
+f 668/938/708 605/1027/713 627/974/755 671/939/724
+f 593/935/703 599/1028/702 623/956/737 619/936/723
+f 605/1027/713 589/931/701 616/934/722 627/974/755
+f 587/1025/699 604/927/714 626/930/720 614/949/730
+f 590/1029/695 586/923/694 613/926/718 617/963/744
+f 599/1028/702 584/919/712 611/922/716 623/956/737
+f 660/996/775 661/981/760 650/997/776 649/1000/778
+f 611/922/716 615/921/715 631/957/738
+f 615/921/715 610/966/747 630/967/748
+f 630/967/748 631/957/738 615/921/715
+f 557/851/667 689/849/655 695/823/646 562/852/668
+f 560/855/671 691/828/651 696/846/665 563/856/672
+f 559/859/675 690/847/659 692/829/652 547/860/676
+f 563/856/672 696/846/665 693/833/656 558/862/678
+f 558/862/678 693/833/656 690/836/659 559/864/675
+f 547/860/676 692/829/652 689/832/655 557/866/667
+f 561/869/681 694/826/649 691/828/651 560/855/671
+f 562/852/668 695/823/646 694/826/649 561/869/681
+f 196/355/293 201/354/292 703/325/270 697/351/277
+f 199/359/297 202/358/296 704/348/289 699/329/274
+f 198/363/301 186/362/300 700/331/276 698/349/281
+f 202/358/296 197/365/303 701/335/280 704/348/289
+f 197/365/303 198/367/301 698/336/281 701/335/280
+f 186/362/300 196/369/293 697/332/277 700/331/276
+f 200/371/305 199/359/297 699/329/274 702/326/271
+f 201/354/292 200/371/305 702/326/271 703/325/270
+f 187/319/269 154/318/268 707/370/304 708/353/291
+f 154/318/268 180/313/263 712/356/294 707/370/304
+f 183/315/265 182/343/284 710/368/290 705/361/299
+f 185/317/267 184/340/266 711/366/298 706/364/302
+f 181/312/262 185/317/267 706/364/302 709/357/295
+f 184/316/266 183/315/265 705/361/299 711/360/298
+f 180/313/263 181/312/262 709/357/295 712/356/294
+f 182/339/284 187/319/269 708/353/291 710/352/290
+f 548/816/644 716/853/669 715/868/680 515/817/645
+f 515/817/645 715/868/680 720/854/670 541/810/638
+f 544/814/642 713/861/677 718/867/666 543/841/660
+f 546/815/643 714/863/679 719/865/674 545/838/641
+f 542/811/639 717/857/673 714/863/679 546/815/643
+f 545/813/641 719/858/674 713/861/677 544/814/642
+f 541/810/638 720/854/670 717/857/673 542/811/639
+f 543/837/660 718/850/666 716/853/669 548/816/644
+f 139/249/215 140/252/218 727/293/246 723/303/256
+f 143/274/207 142/272/236 721/306/259 722/308/251
+f 145/245/211 144/242/208 725/297/250
+f 142/272/236 147/250/216 726/302/255 721/306/259
+f 147/250/216 139/249/215 723/303/256 726/302/255
+f 141/246/212 145/245/211 724/294/247
+f 144/242/208 143/241/207 722/298/251 725/297/250
+f 140/252/218 141/246/212 724/294/247 727/293/246
+f 500/747/591 730/803/634 734/791/622 501/749/593
+f 504/772/583 729/806/629 728/804/635 503/770/612
+f 505/738/582 506/743/587 732/795/626
+f 503/770/612 728/804/635 733/800/631 508/746/590
+f 508/746/590 733/800/631 730/803/634 500/747/591
+f 502/742/586 731/794/625 506/743/587
+f 505/738/582 732/795/626 729/798/629 504/739/583
+f 501/749/593 734/791/622 731/794/625 502/742/586
+f 410/651/516 743/642/507 746/633/500 448/656/519
+f 413/163/146 737/164/147 745/643/508 447/646/511
+f 447/646/511 745/643/508 744/635/502 412/647/512
+f 411/650/515 742/639/505 743/642/507 410/651/516
+f 412/647/512 744/635/502 742/638/505 411/653/515
+f 448/656/519 746/633/500 735/116/107 409/141/128
+f 57/135/124 91/142/129 741/115/106 738/124/114
+f 413/163/146 90/132/121 740/127/116 737/164/147
+f 90/132/121 59/131/120 739/119/110 740/127/116
+f 58/136/125 57/135/124 738/124/114 736/123/111
+f 59/131/120 58/138/125 736/120/111 739/119/110
+f 91/142/129 409/141/128 735/116/107 741/115/106
+f 400/167/150 751/162/145 758/645/510 443/624/491
+f 403/674/533 754/652/517 757/655/518 444/628/495
+f 444/628/495 757/655/518 749/140/127 399/109/100
+f 401/625/492 755/648/513 756/654/514 402/809/637
+f 402/808/637 756/649/514 754/652/517 403/674/533
+f 443/624/491 758/645/510 755/648/513 401/625/492
+f 400/167/150 86/106/97 753/129/118 751/162/145
+f 53/166/149 87/110/101 752/139/126 747/134/123
+f 87/110/101 399/109/100 749/140/127 752/139/126
+f 51/105/96 52/311/261 750/137/122 748/130/119
+f 52/310/261 53/166/149 747/134/123 750/133/122
+f 86/106/97 51/105/96 748/130/119 753/129/118
+f 160/296/249 162/295/248 766/289/245 761/258/222
+f 156/300/253 159/299/252 764/291/225 759/266/230
+f 162/295/248 146/301/254 762/265/229 766/289/245
+f 158/305/258 161/304/257 765/257/221 760/269/233
+f 157/307/260 158/305/258 760/269/233 763/262/226
+f 146/301/254 156/300/253 759/266/230 762/265/229
+f 159/309/252 157/307/260 763/262/226 764/261/225
+f 161/304/257 160/296/249 761/258/222 765/257/221
+f 521/792/623 769/758/600 774/787/621 523/793/624
+f 517/796/627 767/766/608 772/790/601 520/797/628
+f 523/793/624 774/787/621 770/763/605 507/799/630
+f 519/801/632 768/768/610 773/755/597 522/802/633
+f 518/805/636 771/762/604 768/768/610 519/801/632
+f 507/799/630 770/763/605 767/766/608 517/796/627
+f 520/807/628 772/759/601 771/762/604 518/805/636
+f 522/802/633 773/755/597 769/758/600 521/792/623
+f 134/102/93 133/101/92 782/271/235 780/273/206
+f 136/114/105 135/113/104 781/239/205 775/244/210
+f 133/101/92 138/148/135 776/247/213 782/271/235
+f 131/146/133 132/145/132 779/243/209 778/251/217
+f 130/254/220 131/146/133 778/251/217 777/248/214
+f 138/148/135 130/254/220 777/248/214 776/247/213
+f 132/145/132 136/114/105 775/244/210 779/243/209
+f 135/113/104 134/256/93 780/240/206 781/239/205
+f 495/620/487 788/771/584 790/769/611 494/621/488
+f 497/630/497 783/744/588 789/737/581 496/631/498
+f 494/621/488 790/769/611 784/745/589 499/661/524
+f 492/658/521 786/750/594 787/741/585 493/659/522
+f 491/751/595 785/748/592 786/750/594 492/658/521
+f 499/661/524 784/745/589 785/748/592 491/751/595
+f 493/659/522 787/741/585 783/744/588 497/630/497
+f 496/631/498 789/737/581 788/740/584 495/753/487
+f 506/743/587 507/799/630 732/795/626
+f 145/245/211 146/301/254 724/294/247
+f 506/743/587 731/794/625 507/799/630
+f 145/245/211 725/297/250 146/301/254
+f 95/151/138 122/194/170 797/187/163 792/213/189
+f 96/201/177 123/198/174 796/207/183
+f 94/233/169 112/202/178 795/210/186 791/232/164
+f 97/234/173 113/152/139 794/212/188 793/231/184
+f 113/152/139 95/151/138 792/213/189 794/212/188
+f 112/202/178 96/201/177 795/210/186
+f 123/198/174 97/197/173 793/208/184 796/207/183
+f 122/194/170 94/193/169 791/188/164 797/187/163
+f 454/665/528 799/713/567 804/685/539 483/690/544
+f 484/694/548 455/699/553 803/705/559
+f 453/731/545 798/730/542 802/707/561 472/698/552
+f 456/732/549 800/729/560 801/710/564 473/664/527
+f 473/664/527 801/710/564 799/713/567 454/665/528
+f 472/698/552 802/707/561 455/699/553
+f 484/694/548 803/705/559 800/706/560 456/695/549
+f 483/690/544 804/685/539 798/688/542 453/691/545
+f 455/699/553 459/709/563 803/705/559
+f 96/201/177 100/211/187 795/210/186
+f 455/699/553 802/707/561 459/709/563
+f 96/201/177 796/207/183 100/211/187
diff --git a/examples/models/resources/models/obj/character_diffuse.png b/examples/models/resources/models/obj/character_diffuse.png
new file mode 100644
index 000000000..0fae9d894
Binary files /dev/null and b/examples/models/resources/models/obj/character_diffuse.png differ
diff --git a/examples/models/resources/raylib_logo.png b/examples/models/resources/raylib_logo.png
new file mode 100644
index 000000000..15bbaa2f4
Binary files /dev/null and b/examples/models/resources/raylib_logo.png differ
diff --git a/examples/others/web_basic_window.png b/examples/others/web_basic_window.png
new file mode 100644
index 000000000..346184417
Binary files /dev/null and b/examples/others/web_basic_window.png differ
diff --git a/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs
new file mode 100644
index 000000000..fb6dee8b3
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl100/mandelbrot_set.fs
@@ -0,0 +1,62 @@
+#version 100
+
+#define PI 3.1415926535897932384626433832795
+
+precision highp float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+// NOTE: Maximum number of shader for-loop iterations depend on GPU,
+// For example, on RasperryPi for this examply only supports up to 60
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+// WebGL shaders for loop iteration limit only const
+const int maxIterationsLimit = 20000;
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ for (int iter = 0; iter < maxIterationsLimit; ++iter)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (iter >= maxIterations)
+ {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ return;
+ }
+ if (aa + bb > max2)
+ {
+ float normR = float(iter - (iter/55)*55)/55.0;
+ float normG = float(iter - (iter/69)*69)/69.0;
+ float normB = float(iter - (iter/40)*40)/40.0;
+
+ gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ return;
+ }
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+ }
+
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+}
diff --git a/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs
new file mode 100644
index 000000000..5da3ef437
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl120/mandelbrot_set.fs
@@ -0,0 +1,59 @@
+#version 120
+
+#define PI 3.1415926535897932384626433832795
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+// NOTE: Maximum number of shader for-loop iterations depend on GPU,
+// For example, on RasperryPi for this examply only supports up to 60
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ int iter = 0;
+ while (iter < maxIterations)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (aa + bb > max2)
+ break;
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+
+ ++iter;
+ }
+
+ if (iter >= maxIterations)
+ {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+ else
+ {
+ float normR = float(iter - (iter/55)*55)/55.0;
+ float normG = float(iter - (iter/69)*69)/69.0;
+ float normB = float(iter - (iter/40)*40)/40.0;
+
+ gl_FragColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ }
+}
diff --git a/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs
new file mode 100644
index 000000000..bde74565f
--- /dev/null
+++ b/examples/shaders/resources/shaders/glsl330/mandelbrot_set.fs
@@ -0,0 +1,58 @@
+#version 330
+
+#define PI 3.1415926535897932384626433832795
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+uniform vec2 offset; // Offset of the scale
+uniform float zoom; // Zoom of the scale
+uniform int maxIterations; // Max iterations per pixel
+
+const float max = 4.0; // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
+const float max2 = max*max; // Square of max to avoid computing square root
+
+void main()
+{
+ // The pixel coordinates are scaled so they are on the mandelbrot scale
+ // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
+ vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
+ c.x += offset.x;
+ c.y += offset.y;
+ float a = 0.0;
+ float b = 0.0;
+
+ // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
+ // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
+ // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i
+
+ int iter = 0;
+ for (iter = 0; iter < maxIterations; ++iter)
+ {
+ float aa = a*a;
+ float bb = b*b;
+ if (aa + bb > max2)
+ break;
+
+ float twoab = 2.0*a*b;
+ a = aa - bb + c.x;
+ b = twoab + c.y;
+ }
+
+ if (iter >= maxIterations)
+ {
+ finalColor = vec4(0.0, 0.0, 0.0, 1.0);
+ }
+ else
+ {
+ float normR = float(iter%55)/55.0;
+ float normG = float(iter%69)/69.0;
+ float normB = float(iter%40)/40.0;
+
+ finalColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
+ }
+}
diff --git a/examples/shaders/shaders_mandelbrot_set.c b/examples/shaders/shaders_mandelbrot_set.c
new file mode 100644
index 000000000..a373c518a
--- /dev/null
+++ b/examples/shaders/shaders_mandelbrot_set.c
@@ -0,0 +1,229 @@
+/*******************************************************************************************
+*
+* raylib [shaders] example - mandelbrot set
+*
+* Example complexity rating: [★★★☆] 3/4
+*
+* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version
+*
+* NOTE: Shaders used in this example are #version 330 (OpenGL 3.3)
+*
+* Example originally created with raylib 5.6, last time updated with raylib 5.6
+*
+* Example contributed by Jordi Santonja (@JordSant)
+* Based on previous work by Josh Colclough (@joshcol9232)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025 Jordi Santonja (@JordSant)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include
+
+#if defined(PLATFORM_DESKTOP)
+ #define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+ #define GLSL_VERSION 100
+#endif
+
+// A few good interesting places
+const float pointsOfInterest[6][3] =
+{
+ { -1.76826775f, -0.00422996283f, 28435.9238f },
+ { 0.322004497f, -0.0357099883f, 56499.7266f },
+ { -0.748880744f, -0.0562955774f, 9237.59082f },
+ { -1.78385007f, -0.0156200649f, 14599.5283f },
+ { -0.0985441282f, -0.924688697f, 26259.8535f },
+ { 0.317785531f, -0.0322612226f, 29297.9258f },
+};
+
+const int screenWidth = 800;
+const int screenHeight = 450;
+const float zoomSpeed = 1.01f;
+const float offsetSpeedMul = 2.0f;
+
+const float startingZoom = 0.6f;
+const float startingOffset[2] = { -0.5f, 0.0f };
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ InitWindow(screenWidth, screenHeight, "raylib [shaders] example - mandelbrot set");
+
+ // Load mandelbrot set shader
+ // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
+ Shader shader = LoadShader(0, TextFormat("resources/shaders/glsl%i/mandelbrot_set.fs", GLSL_VERSION));
+
+ // Create a RenderTexture2D to be used for render to texture
+ RenderTexture2D target = LoadRenderTexture(GetScreenWidth(), GetScreenHeight());
+
+ // Offset and zoom to draw the mandelbrot set at. (centered on screen and default size)
+ float offset[2] = { startingOffset[0], startingOffset[1] };
+ float zoom = startingZoom;
+ // Depending on the zoom the mximum number of iterations must be adapted to get more detail as we zzoom in
+ // The solution is not perfect, so a control has been added to increase/decrease the number of iterations with UP/DOWN keys
+#if defined(PLATFORM_DESKTOP)
+ int maxIterations = 333;
+ float maxIterationsMultiplier = 166.5f;
+#else
+ int maxIterations = 43;
+ float maxIterationsMultiplier = 22.0f;
+#endif
+
+ // Get variable (uniform) locations on the shader to connect with the program
+ // NOTE: If uniform variable could not be found in the shader, function returns -1
+ int zoomLoc = GetShaderLocation(shader, "zoom");
+ int offsetLoc = GetShaderLocation(shader, "offset");
+ int maxIterationsLoc = GetShaderLocation(shader, "maxIterations");
+
+ // Upload the shader uniform values!
+ SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2);
+ SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT);
+
+ bool showControls = true; // Show controls
+
+ SetTargetFPS(60); // Set our game to run at 60 frames-per-second
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ bool updateShader = false;
+
+ // Press [1 - 6] to reset c to a point of interest
+ if (IsKeyPressed(KEY_ONE) ||
+ IsKeyPressed(KEY_TWO) ||
+ IsKeyPressed(KEY_THREE) ||
+ IsKeyPressed(KEY_FOUR) ||
+ IsKeyPressed(KEY_FIVE) ||
+ IsKeyPressed(KEY_SIX))
+ {
+ int interestIndex = 0;
+ if (IsKeyPressed(KEY_ONE)) interestIndex = 0;
+ else if (IsKeyPressed(KEY_TWO)) interestIndex = 1;
+ else if (IsKeyPressed(KEY_THREE)) interestIndex = 2;
+ else if (IsKeyPressed(KEY_FOUR)) interestIndex = 3;
+ else if (IsKeyPressed(KEY_FIVE)) interestIndex = 4;
+ else if (IsKeyPressed(KEY_SIX)) interestIndex = 5;
+
+ offset[0] = pointsOfInterest[interestIndex][0];
+ offset[1] = pointsOfInterest[interestIndex][1];
+ zoom = pointsOfInterest[interestIndex][2];
+ updateShader = true;
+ }
+
+ // If "R" is pressed, reset zoom and offset
+ if (IsKeyPressed(KEY_R))
+ {
+ offset[0] = startingOffset[0];
+ offset[1] = startingOffset[1];
+ zoom = startingZoom;
+ updateShader = true;
+ }
+
+ if (IsKeyPressed(KEY_F1)) showControls = !showControls; // Toggle whether or not to show controls
+
+ // Change number of max iterations with UP and DOWN keys
+ // WARNING: Increasing the number of max iterations greatly impacts performance
+ if (IsKeyPressed(KEY_UP))
+ {
+ maxIterationsMultiplier *= 1.4f;
+ updateShader = true;
+ }
+ else if (IsKeyPressed(KEY_DOWN))
+ {
+ maxIterationsMultiplier /= 1.4f;
+ updateShader = true;
+ }
+
+ // If either left or right button is pressed, zoom in/out
+ if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
+ {
+ // Change zoom. If Mouse left -> zoom in. Mouse right -> zoom out
+ zoom *= IsMouseButtonDown(MOUSE_BUTTON_LEFT)? zoomSpeed : (1.0f/zoomSpeed);
+
+ const Vector2 mousePos = GetMousePosition();
+ Vector2 offsetVelocity;
+ // Find the velocity at which to change the camera. Take the distance of the mouse
+ // From the center of the screen as the direction, and adjust magnitude based on the current zoom
+ offsetVelocity.x = (mousePos.x/(float)screenWidth - 0.5f)*offsetSpeedMul/zoom;
+ offsetVelocity.y = (mousePos.y/(float)screenHeight - 0.5f)*offsetSpeedMul/zoom;
+
+ // Apply move velocity to camera
+ offset[0] += GetFrameTime()*offsetVelocity.x;
+ offset[1] += GetFrameTime()*offsetVelocity.y;
+
+ updateShader = true;
+ }
+
+ // In case a parameter has been changed, update the shader values
+ if (updateShader)
+ {
+ // As we zoom in, increase the number of max iterations to get more detail
+ // Aproximate formula, but it works-ish
+ maxIterations = (int)(sqrtf(2.0f*sqrtf(fabsf(1.0f - sqrtf(37.5f*zoom))))*maxIterationsMultiplier);
+
+ // Update the shader uniform values!
+ SetShaderValue(shader, zoomLoc, &zoom, SHADER_UNIFORM_FLOAT);
+ SetShaderValue(shader, offsetLoc, offset, SHADER_UNIFORM_VEC2);
+ SetShaderValue(shader, maxIterationsLoc, &maxIterations, SHADER_UNIFORM_INT);
+ }
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ // Using a render texture to draw Mandelbrot set
+ BeginTextureMode(target); // Enable drawing to texture
+ ClearBackground(BLACK); // Clear the render texture
+
+ // Draw a rectangle in shader mode to be used as shader canvas
+ // NOTE: Rectangle uses font white character texture coordinates,
+ // So shader can not be applied here directly because input vertexTexCoord
+ // Do not represent full screen coordinates (space where want to apply shader)
+ DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLACK);
+ EndTextureMode();
+
+ BeginDrawing();
+ ClearBackground(BLACK); // Clear screen background
+
+ // Draw the saved texture and rendered mandelbrot set with shader
+ // NOTE: We do not invert texture on Y, already considered inside shader
+ BeginShaderMode(shader);
+ // WARNING: If FLAG_WINDOW_HIGHDPI is enabled, HighDPI monitor scaling should be considered
+ // When rendering the RenderTexture2D to fit in the HighDPI scaled Window
+ DrawTextureEx(target.texture, (Vector2){ 0.0f, 0.0f }, 0.0f, 1.0f, WHITE);
+ EndShaderMode();
+
+ if (showControls)
+ {
+ DrawText("Press Mouse buttons right/left to zoom in/out and move", 10, 15, 10, RAYWHITE);
+ DrawText("Press F1 to toggle these controls", 10, 30, 10, RAYWHITE);
+ DrawText("Press [1 - 6] to change point of interest", 10, 45, 10, RAYWHITE);
+ DrawText("Press UP | DOWN to change number of iterations", 10, 60, 10, RAYWHITE);
+ DrawText("Press R to recenter the camera", 10, 75, 10, RAYWHITE);
+ }
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ UnloadShader(shader); // Unload shader
+ UnloadRenderTexture(target); // Unload render texture
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
diff --git a/examples/shaders/shaders_mandelbrot_set.png b/examples/shaders/shaders_mandelbrot_set.png
new file mode 100644
index 000000000..6d112931d
Binary files /dev/null and b/examples/shaders/shaders_mandelbrot_set.png differ
diff --git a/examples/shapes/shapes_clock_of_clocks.c b/examples/shapes/shapes_clock_of_clocks.c
index 493e53b5e..3fc24aa92 100644
--- a/examples/shapes/shapes_clock_of_clocks.c
+++ b/examples/shapes/shapes_clock_of_clocks.c
@@ -14,6 +14,9 @@
* Copyright (c) 2025 JP Mortiboys (@themushroompirates)
*
********************************************************************************************/
+#if defined(WIN32)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
#include "raylib.h"
diff --git a/examples/shapes/shapes_lines_drawing.c b/examples/shapes/shapes_lines_drawing.c
new file mode 100644
index 000000000..9347acaf3
--- /dev/null
+++ b/examples/shapes/shapes_lines_drawing.c
@@ -0,0 +1,146 @@
+/*******************************************************************************************
+*
+* raylib [shapes] example - lines drawing
+*
+* Example complexity rating: [★☆☆☆] 1/4
+*
+* Example originally created with raylib 5.6-dev, last time updated with raylib 5.6
+*
+* Example contributed by Robin (@RobinsAviary) and reviewed by Ramon Santamaria (@raysan5)
+*
+* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+* BSD-like license that allows static linking with closed source software
+*
+* Copyright (c) 2025-2025 Robin (@RobinsAviary)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int main(void)
+{
+ // Initialization
+ //--------------------------------------------------------------------------------------
+ const int screenWidth = 800;
+ const int screenHeight = 450;
+
+ InitWindow(screenWidth, screenHeight, "raylib [shapes] example - lines drawing");
+
+ // Hint text that shows before you click the screen
+ bool startText = true;
+
+ // The mouse's position on the previous frame
+ Vector2 mousePositionPrevious = GetMousePosition();
+
+ // The canvas to draw lines on
+ RenderTexture canvas = LoadRenderTexture(screenWidth, screenHeight);
+
+ // The background color of the canvas
+ const Color backgroundColor = RAYWHITE;
+
+ // The line's thickness
+ float lineThickness = 8.0f;
+ // The lines hue (in HSV, from 0-360)
+ float lineHue = 0.0f;
+
+ // Clear the canvas to the background color
+ BeginTextureMode(canvas);
+ ClearBackground(backgroundColor);
+ EndTextureMode();
+ //--------------------------------------------------------------------------------------
+
+ // Main game loop
+ while (!WindowShouldClose()) // Detect window close button or ESC key
+ {
+ // Update
+ //----------------------------------------------------------------------------------
+ // Disable the hint text once the user clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && startText)
+ {
+ startText = false;
+ }
+
+ // Clear the canvas when the user middle-clicks
+ if (IsMouseButtonPressed(MOUSE_BUTTON_MIDDLE))
+ {
+ BeginTextureMode(canvas);
+ ClearBackground(backgroundColor);
+ EndTextureMode();
+ }
+
+ // Store whether the left and right buttons are down
+ bool leftButtonDown = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
+ bool rightButtonDown = IsMouseButtonDown(MOUSE_BUTTON_RIGHT);
+
+ if (leftButtonDown || rightButtonDown)
+ {
+ // The color for the line
+ Color drawColor;
+
+ if (leftButtonDown)
+ {
+ // Increase the hue value by the distance our cursor has moved since the last frame (divided by 3)
+ lineHue += Vector2Distance(mousePositionPrevious, GetMousePosition())/3.0f;
+
+ // While the hue is >=360, subtract it to bring it down into the range 0-360
+ // This is more visually accurate than resetting to zero
+ while (lineHue >= 360.0f)
+ {
+ lineHue -= 360.0f;
+ }
+
+ // Create the final color
+ drawColor = ColorFromHSV(lineHue, 1.0f, 1.0f);
+ }
+ else if (rightButtonDown)
+ {
+ // Use the background color as an "eraser"
+ drawColor = backgroundColor;
+ }
+
+ // Draw the line onto the canvas
+ BeginTextureMode(canvas);
+ // Circles act as "caps", smoothing corners
+ DrawCircleV(mousePositionPrevious, lineThickness/2.0f, drawColor);
+ DrawCircleV(GetMousePosition(), lineThickness/2.0f, drawColor);
+ DrawLineEx(mousePositionPrevious, GetMousePosition(), lineThickness, drawColor);
+ EndTextureMode();
+ }
+
+ // Update line thickness based on mousewheel
+ lineThickness += GetMouseWheelMove();
+ lineThickness = Clamp(lineThickness, 1.0, 500.0f);
+
+ // Update mouse's previous position
+ mousePositionPrevious = GetMousePosition();
+ //----------------------------------------------------------------------------------
+
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ // Draw the render texture to the screen, flipped vertically to make it appear top-side up
+ DrawTextureRec(canvas.texture, (Rectangle){ 0.0f, 0.0f, (float)canvas.texture.width,(float)-canvas.texture.height }, Vector2Zero(), WHITE);
+
+ // Draw the preview circle
+ if (!leftButtonDown) DrawCircleLinesV(GetMousePosition(), lineThickness/2.0f, (Color){ 127, 127, 127, 127 });
+
+ // Draw the hint text
+ if (startText) DrawText("try clicking and dragging!", 275, 215, 20, LIGHTGRAY);
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+
+ // De-Initialization
+ //--------------------------------------------------------------------------------------
+ // Unload the canvas render texture
+ UnloadRenderTexture(canvas);
+
+ CloseWindow(); // Close window and OpenGL context
+ //--------------------------------------------------------------------------------------
+
+ return 0;
+}
\ No newline at end of file
diff --git a/examples/shapes/shapes_lines_drawing.png b/examples/shapes/shapes_lines_drawing.png
new file mode 100644
index 000000000..59ef65934
Binary files /dev/null and b/examples/shapes/shapes_lines_drawing.png differ
diff --git a/examples/shapes/shapes_simple_particles.c b/examples/shapes/shapes_simple_particles.c
index 7c2a598c2..c5d9612c3 100644
--- a/examples/shapes/shapes_simple_particles.c
+++ b/examples/shapes/shapes_simple_particles.c
@@ -74,7 +74,7 @@ int main(void)
// Definition of particles
Particle *particles = (Particle*)RL_CALLOC(MAX_PARTICLES, sizeof(Particle)); // Particle array
CircularBuffer circularBuffer = { 0, 0, particles };
-
+
// Particle emitter parameters
int emissionRate = -2; // Negative: on average every -X frames. Positive: particles per frame
ParticleType currentType = WATER;
@@ -100,7 +100,7 @@ int main(void)
// Update the parameters of each particle
UpdateParticles(&circularBuffer, screenWidth, screenHeight);
-
+
// Remove dead particles from the circular buffer
UpdateCircularBuffer(&circularBuffer);
@@ -252,10 +252,10 @@ static void UpdateParticles(CircularBuffer *circularBuffer, int screenWidth, int
// Disable particle when out of screen
Vector2 center = circularBuffer->buffer[i].position;
float radius = circularBuffer->buffer[i].radius;
-
+
if ((center.x < -radius) || (center.x > (screenWidth + radius)) ||
(center.y < -radius) || (center.y > (screenHeight + radius)))
- {
+ {
circularBuffer->buffer[i].alive = false;
}
}
diff --git a/projects/VS2022/examples/core_text_file_loading.vcxproj b/projects/VS2022/examples/core_text_file_loading.vcxproj
index c2e25e042..15324701d 100644
--- a/projects/VS2022/examples/core_text_file_loading.vcxproj
+++ b/projects/VS2022/examples/core_text_file_loading.vcxproj
@@ -51,7 +51,7 @@
- {6B1A933E-71B8-4C1F-9E79-02D98830E671}
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}
Win32Proj
core_text_file_loading
10.0
diff --git a/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj b/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj
new file mode 100644
index 000000000..4ed5581e1
--- /dev/null
+++ b/projects/VS2022/examples/shaders_mandelbrot_set.vcxproj
@@ -0,0 +1,569 @@
+
+
+
+
+ Debug.DLL
+ ARM64
+
+
+ Debug.DLL
+ Win32
+
+
+ Debug.DLL
+ x64
+
+
+ Debug
+ ARM64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release.DLL
+ ARM64
+
+
+ Release.DLL
+ Win32
+
+
+ Release.DLL
+ x64
+
+
+ Release
+ ARM64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}
+ Win32Proj
+ shaders_mandelbrot_set
+ 10.0
+ shaders_mandelbrot_set
+
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ true
+ $(DefaultPlatformToolset)
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+ Application
+ false
+ $(DefaultPlatformToolset)
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ true
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ false
+ $(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)\
+ $(SolutionDir)\build\$(ProjectName)\obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+ $(SolutionDir)..\..\examples\shaders
+ WindowsLocalDebugger
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ /FS %(AdditionalOptions)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;PLATFORM_DESKTOP;%(PreprocessorDefinitions)
+ CompileAsC
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+ Copy Debug DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);PLATFORM_DESKTOP
+ $(SolutionDir)..\..\src;%(AdditionalIncludeDirectories)
+ CompileAsC
+ true
+
+
+ Console
+ true
+ true
+ true
+ raylib.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winmm.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+ $(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\
+
+
+ xcopy /y /d "$(SolutionDir)\build\raylib\bin\$(Platform)\$(Configuration)\raylib.dll" "$(SolutionDir)\build\$(ProjectName)\bin\$(Platform)\$(Configuration)"
+
+
+ Copy Release DLL to output directory
+
+
+
+
+
+
+
+
+
+
+ {e89d61ac-55de-4482-afd4-df7242ebc859}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/projects/VS2022/raylib.sln b/projects/VS2022/raylib.sln
index 7a7eca297..ec35ed5e5 100644
--- a/projects/VS2022/raylib.sln
+++ b/projects/VS2022/raylib.sln
@@ -391,7 +391,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_highdpi_testbed", "exa
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_screen_recording", "examples\core_screen_recording.vcxproj", "{9DE2FC01-A839-4F89-8319-9071D4C54821}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{6B1A933E-71B8-4C1F-9E79-02D98830E671}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core_text_file_loading", "examples\core_text_file_loading.vcxproj", "{2F578155-D51F-4C03-AB7F-5C5122CA46CC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shaders_mandelbrot_set", "examples\shaders_mandelbrot_set.vcxproj", "{1C829D1A-892C-451C-AF0B-AC65C85F5CC6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -4847,6 +4849,54 @@ Global
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x64.Build.0 = Release|x64
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.ActiveCfg = Release|Win32
{9DE2FC01-A839-4F89-8319-9071D4C54821}.Release|x86.Build.0 = Release|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.ActiveCfg = Debug|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x64.Build.0 = Debug|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.ActiveCfg = Debug|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Debug|x86.Build.0 = Debug|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|ARM64.Build.0 = Release|ARM64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.ActiveCfg = Release|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x64.Build.0 = Release|x64
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.ActiveCfg = Release|Win32
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC}.Release|x86.Build.0 = Release|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.ActiveCfg = Debug.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|ARM64.Build.0 = Debug.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.ActiveCfg = Debug.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x64.Build.0 = Debug.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.ActiveCfg = Debug.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug.DLL|x86.Build.0 = Debug.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|ARM64.Build.0 = Debug|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.ActiveCfg = Debug|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x64.Build.0 = Debug|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.ActiveCfg = Debug|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Debug|x86.Build.0 = Debug|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.ActiveCfg = Release.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|ARM64.Build.0 = Release.DLL|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.ActiveCfg = Release.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x64.Build.0 = Release.DLL|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.ActiveCfg = Release.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release.DLL|x86.Build.0 = Release.DLL|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.ActiveCfg = Release|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|ARM64.Build.0 = Release|ARM64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.ActiveCfg = Release|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x64.Build.0 = Release|x64
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.ActiveCfg = Release|Win32
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -5044,6 +5094,8 @@ Global
{EA4AD5A7-DB95-43C0-9A67-2D94146BCF91} = {278D8859-20B1-428F-8448-064F46E1F021}
{1ACC8236-EF4E-44B0-BD0C-AB1D95D5890F} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
{9DE2FC01-A839-4F89-8319-9071D4C54821} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {2F578155-D51F-4C03-AB7F-5C5122CA46CC} = {6C82BAAE-BDDF-457D-8FA8-7E2490B07035}
+ {1C829D1A-892C-451C-AF0B-AC65C85F5CC6} = {5317807F-61D4-4E0F-B6DC-2D9F12621ED9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E926C768-6307-4423-A1EC-57E95B1FAB29}
diff --git a/src/Makefile b/src/Makefile
index 0d4ca9ac7..4369d8084 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -283,7 +283,7 @@ ifeq ($(TARGET_PLATFORM),PLATFORM_DESKTOP_GLFW)
endif
endif
ifeq ($(TARGET_PLATFORM),PLATFORM_DRM)
- ifeq ($(USE_RPI_CROSS_COMPILER),TRUE)
+ ifeq ($(USE_RPI_CROSSCOMPILER),TRUE)
# Define RPI cross-compiler
#CC = armv6j-hardfloat-linux-gnueabi-gcc
CC = $(RPI_TOOLCHAIN)/bin/$(RPI_TOOLCHAIN_NAME)-gcc
diff --git a/src/external/rlsw.h b/src/external/rlsw.h
index 49050f848..bc7a813d3 100644
--- a/src/external/rlsw.h
+++ b/src/external/rlsw.h
@@ -6,7 +6,7 @@
* rlsw is a custom OpenGL 1.1-style implementation on software, intended to provide all
* functionality available on rlgl.h library used by raylib, becoming a direct software
* rendering replacement for OpenGL 1.1 backend and allowing to run raylib on GPU-less
-* devices when required.
+* devices when required
*
* FEATURES:
* - Rendering to custom internal framebuffer with multiple color modes supported:
@@ -115,16 +115,12 @@
#define SW_GL_FRAMEBUFFER_COPY_BGRA true
#endif
-#ifndef SW_GL_BINDING_COPY_TEXTURE
- #define SW_GL_BINDING_COPY_TEXTURE true
-#endif
-
#ifndef SW_COLOR_BUFFER_BITS
- #define SW_COLOR_BUFFER_BITS 24
+ #define SW_COLOR_BUFFER_BITS 32 //< 32 (rgba), 16 (rgb packed) or 8 (rgb packed)
#endif
#ifndef SW_DEPTH_BUFFER_BITS
- #define SW_DEPTH_BUFFER_BITS 16
+ #define SW_DEPTH_BUFFER_BITS 16 //< 24, 16 or 8
#endif
#ifndef SW_MAX_PROJECTION_STACK_SIZE
@@ -156,6 +152,12 @@
#define SW_CLIP_EPSILON 1e-4f
#endif
+#ifdef __cplusplus
+ #define CURLY_INIT(name) name
+#else
+ #define CURLY_INIT(name) (name)
+#endif
+
//----------------------------------------------------------------------------------
// OpenGL Compatibility Types
//----------------------------------------------------------------------------------
@@ -376,7 +378,7 @@ typedef double GLclampd;
#define glDrawArrays(m, o, c) swDrawArrays((m), (o), (c))
#define glGenTextures(c, v) swGenTextures((c), (v))
#define glDeleteTextures(c, v) swDeleteTextures((c), (v))
-#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), SW_GL_BINDING_COPY_TEXTURE, (p))
+#define glTexImage2D(tr, l, if, w, h, b, f, t, p) swTexImage2D((w), (h), (f), (t), (p))
#define glTexParameteri(tr, pname, param) swTexParameteri((pname), (param))
#define glBindTexture(tr, id) swBindTexture((id))
@@ -591,7 +593,7 @@ SWAPI void swDrawArrays(SWdraw mode, int offset, int count);
SWAPI void swGenTextures(int count, uint32_t *textures);
SWAPI void swDeleteTextures(int count, uint32_t *textures);
-SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data);
+SWAPI void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data);
SWAPI void swTexParameteri(int param, int value);
SWAPI void swBindTexture(uint32_t id);
@@ -609,6 +611,65 @@ SWAPI void swBindTexture(uint32_t id);
#include
#include // Required for: floorf(), fabsf()
+#if defined(__FMA__) && defined(__AVX2__)
+# define SW_HAS_FMA_AVX2
+# include
+#endif
+
+#if defined(__FMA__) && defined(__AVX__)
+# define SW_HAS_FMA_AVX
+# include
+#endif
+
+#if defined(__AVX2__)
+# define SW_HAS_AVX2
+# include
+#endif
+
+#if defined(__AVX__)
+# define SW_HAS_AVX
+# include
+#endif
+
+#if defined(__SSE4_2__)
+# define SW_HAS_SSE42
+# include
+#endif
+
+#if defined(__SSE4_1__)
+# define SW_HAS_SSE41
+# include
+#endif
+
+#if defined(__SSSE3__)
+# define SW_HAS_SSSE3
+# include
+#endif
+
+#if defined(__SSE3__)
+# define SW_HAS_SSE3
+# include
+#endif
+
+#if defined(__SSE2__)
+# define SW_HAS_SSE2
+# include
+#endif
+
+#if defined(__SSE__)
+# define SW_HAS_SSE
+# include
+#endif
+
+#if defined(__ARM_NEON) || defined(__aarch64__)
+# if defined(__ARM_FEATURE_FMA)
+# define SW_HAS_NEON_FMA
+# else
+# define SW_HAS_NEON
+# endif
+# include
+#endif
+
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@@ -619,7 +680,69 @@ SWAPI void swBindTexture(uint32_t id);
#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS/8)
#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS/8)
-#define SW_STATE_CHECK(flags) ((RLSW.stateFlags & (flags)) == (flags))
+#if (SW_COLOR_BUFFER_BITS == 8)
+ #define COLOR_TYPE uint8_t
+ #define COLOR_IS_PACKED 1
+ #define PACK_COLOR(r,g,b) ((((uint8_t)((r)*7+0.5f))&0x07)<<5 | (((uint8_t)((g)*7+0.5f))&0x07)<<2 | ((uint8_t)((b)*3+0.5f))&0x03)
+ #define UNPACK_R(p) (((p)>>5)&0x07)
+ #define UNPACK_G(p) (((p)>>2)&0x07)
+ #define UNPACK_B(p) ((p)&0x03)
+ #define SCALE_R(v) ((v)*255+3)/7
+ #define SCALE_G(v) ((v)*255+3)/7
+ #define SCALE_B(v) ((v)*255+1)/3
+ #define TO_FLOAT_R(v) ((v)*(1.0f/7.0f))
+ #define TO_FLOAT_G(v) ((v)*(1.0f/7.0f))
+ #define TO_FLOAT_B(v) ((v)*(1.0f/3.0f))
+#elif (SW_COLOR_BUFFER_BITS == 16)
+ #define COLOR_TYPE uint16_t
+ #define COLOR_IS_PACKED 1
+ #define PACK_COLOR(r,g,b) ((((uint16_t)((r)*31+0.5f))&0x1F)<<11 | (((uint16_t)((g)*63+0.5f))&0x3F)<<5 | ((uint16_t)((b)*31+0.5f))&0x1F)
+ #define UNPACK_R(p) (((p)>>11)&0x1F)
+ #define UNPACK_G(p) (((p)>>5)&0x3F)
+ #define UNPACK_B(p) ((p)&0x1F)
+ #define SCALE_R(v) ((v)*255+15)/31
+ #define SCALE_G(v) ((v)*255+31)/63
+ #define SCALE_B(v) ((v)*255+15)/31
+ #define TO_FLOAT_R(v) ((v)*(1.0f/31.0f))
+ #define TO_FLOAT_G(v) ((v)*(1.0f/63.0f))
+ #define TO_FLOAT_B(v) ((v)*(1.0f/31.0f))
+#else // 32 bits
+ #define COLOR_TYPE uint8_t
+ #define COLOR_IS_PACKED 0
+#endif
+
+#if (SW_DEPTH_BUFFER_BITS == 8)
+ #define DEPTH_TYPE uint8_t
+ #define DEPTH_IS_PACKED 1
+ #define DEPTH_MAX UINT8_MAX
+ #define DEPTH_SCALE (1.0f/UINT8_MAX)
+ #define PACK_DEPTH(d) ((DEPTH_TYPE)((d)*DEPTH_MAX))
+ #define UNPACK_DEPTH(p) (p)
+#elif (SW_DEPTH_BUFFER_BITS == 16)
+ #define DEPTH_TYPE uint16_t
+ #define DEPTH_IS_PACKED 1
+ #define DEPTH_MAX UINT16_MAX
+ #define DEPTH_SCALE (1.0f/UINT16_MAX)
+ #define PACK_DEPTH(d) ((DEPTH_TYPE)((d)*DEPTH_MAX))
+ #define UNPACK_DEPTH(p) (p)
+#else // 24 bits
+ #define DEPTH_TYPE uint8_t
+ #define DEPTH_IS_PACKED 0
+ #define DEPTH_MAX 0xFFFFFF
+ #define DEPTH_SCALE (1.0f/0xFFFFFF)
+ #define PACK_DEPTH_0(d) (((uint32_t)((d)*DEPTH_MAX)>>16)&0xFF)
+ #define PACK_DEPTH_1(d) (((uint32_t)((d)*DEPTH_MAX)>>8)&0xFF)
+ #define PACK_DEPTH_2(d) ((uint32_t)((d)*DEPTH_MAX)&0xFF)
+ #define UNPACK_DEPTH(p) (((p)[0]<<16)|((p)[1]<<8)|(p)[2])
+#endif
+
+#define GET_COLOR_PTR(ptr, offset) ((void*)((uint8_t*)(ptr) + (offset)*SW_COLOR_PIXEL_SIZE))
+#define GET_DEPTH_PTR(ptr, offset) ((void*)((uint8_t*)(ptr) + (offset)*SW_DEPTH_PIXEL_SIZE))
+#define INC_COLOR_PTR(ptr) ((ptr) = (void*)((uint8_t*)(ptr) + SW_COLOR_PIXEL_SIZE))
+#define INC_DEPTH_PTR(ptr) ((ptr) = (void*)((uint8_t*)(ptr) + SW_DEPTH_PIXEL_SIZE))
+
+#define SW_STATE_CHECK(flags) (SW_STATE_CHECK_EX(RLSW.stateFlags, (flags)))
+#define SW_STATE_CHECK_EX(state, flags) (((state) & (flags)) == (flags))
#define SW_STATE_SCISSOR_TEST (1 << 0)
#define SW_STATE_TEXTURE_2D (1 << 1)
@@ -668,16 +791,10 @@ typedef struct {
} sw_vertex_t;
typedef struct {
- // Dirty hack for copied data
- // TODO: Rework copied image handling
- union {
- const void *cptr; // NOTE: Is used for all data reads
- void *ptr; // WARNING: Should only be used to allocate and free data
- } pixels;
+ uint8_t *pixels; // Texture pixels (RGBA32)
int width, height; // Dimensions of the texture
int wMinus1, hMinus1; // Dimensions minus one
- sw_pixelformat_t format; // Pixel format (internal representation)
SWfilter minFilter; // Minification filter
SWfilter magFilter; // Magnification filter
@@ -687,9 +804,6 @@ typedef struct {
float tx; // Texel width
float ty; // Texel height
-
- bool copy; // Flag indicating whether memory has been allocated
-
} sw_texture_t;
typedef struct {
@@ -765,7 +879,6 @@ typedef struct {
int freeTextureIdCount;
uint32_t stateFlags;
-
} sw_context_t;
//----------------------------------------------------------------------------------
@@ -850,11 +963,7 @@ static inline int sw_clampi(int v, int min, int max)
return v;
}
-static inline void sw_lerp_vertex_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float t)
+static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float t)
{
const float tInv = 1.0f - t;
@@ -881,11 +990,7 @@ static inline void sw_lerp_vertex_PTCH(
out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t;
}
-static inline void sw_get_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT a,
- const sw_vertex_t *SW_RESTRICT b,
- float scale)
+static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale)
{
// Calculate gradients for Position
out->position[0] = (b->position[0] - a->position[0])*scale;
@@ -910,9 +1015,7 @@ static inline void sw_get_vertex_grad_PTCH(
out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale;
}
-static inline void sw_add_vertex_grad_PTCH(
- sw_vertex_t *SW_RESTRICT out,
- const sw_vertex_t *SW_RESTRICT gradients)
+static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients)
{
// Add gradients to Position
out->position[0] += gradients->position[0];
@@ -937,8 +1040,83 @@ static inline void sw_add_vertex_grad_PTCH(
out->homogeneous[3] += gradients->homogeneous[3];
}
-// Half floating point management functions
-static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
+static inline void sw_float_to_unorm8_simd(uint8_t dst[4], const float src[4])
+{
+#if defined(SW_HAS_NEON)
+ float32x4_t values = vld1q_f32(src);
+ float32x4_t scaled = vmulq_n_f32(values, 255.0f);
+ scaled = vminq_f32(vmaxq_f32(scaled, vdupq_n_f32(0.0f)), vdupq_n_f32(255.0f));
+ uint32x4_t clamped = vcvtq_u32_f32(scaled);
+
+ uint16x4_t narrow16 = vmovn_u32(clamped);
+ uint8x8_t narrow8 = vmovn_u16(vcombine_u16(narrow16, narrow16));
+
+ vst1_lane_u32((uint32_t*)dst, vreinterpret_u32_u8(narrow8), 0);
+#elif defined(SW_HAS_SSE41)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ scaled = _mm_max_ps(_mm_min_ps(scaled, _mm_set1_ps(255.0f)), _mm_setzero_ps());
+ __m128i clamped = _mm_cvtps_epi32(scaled);
+
+ clamped = _mm_packus_epi32(clamped, clamped);
+ clamped = _mm_packus_epi16(clamped, clamped);
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#elif defined(SW_HAS_SSE2)
+ __m128 values = _mm_loadu_ps(src);
+ __m128 scaled = _mm_mul_ps(values, _mm_set1_ps(255.0f));
+ scaled = _mm_max_ps(_mm_min_ps(scaled, _mm_set1_ps(255.0f)), _mm_setzero_ps());
+ __m128i clamped = _mm_cvtps_epi32(scaled);
+
+ clamped = _mm_packs_epi32(clamped, clamped);
+ clamped = _mm_packus_epi16(clamped, clamped);
+ *(uint32_t*)dst = _mm_cvtsi128_si32(clamped);
+#else
+ for (int i = 0; i < 4; i++)
+ {
+ float val = src[i]*255.0f;
+ val = (val > 255.0f)? 255.0f : val;
+ val = (val < 0.0f)? 0.0f : val;
+ dst[i] = (uint8_t)(val + 0.5f);
+ }
+#endif
+}
+
+static inline void sw_float_from_unorm8_simd(float dst[4], const uint8_t src[4])
+{
+#if defined(SW_HAS_NEON)
+ uint32x4_t bytes = vdupq_n_u32(0);
+ bytes = vld1q_lane_u32((const uint32_t*)src, bytes, 0);
+
+ uint8x8_t bytes8 = vreinterpret_u8_u32(vget_low_u32(bytes));
+ uint16x8_t bytes16 = vmovl_u8(bytes8);
+ uint32x4_t ints = vmovl_u16(vget_low_u16(bytes16));
+
+ float32x4_t floats = vcvtq_f32_u32(ints);
+ floats = vmulq_n_f32(floats, 1.0f/255.0f);
+ vst1q_f32(dst, floats);
+#elif defined(SW_HAS_SSE41)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src);
+ __m128i ints = _mm_cvtepu8_epi32(bytes);
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f));
+ _mm_storeu_ps(dst, floats);
+#elif defined(SW_HAS_SSE2)
+ __m128i bytes = _mm_cvtsi32_si128(*(const uint32_t*)src);
+ bytes = _mm_unpacklo_epi8(bytes, _mm_setzero_si128());
+ __m128i ints = _mm_unpacklo_epi16(bytes, _mm_setzero_si128());
+ __m128 floats = _mm_cvtepi32_ps(ints);
+ floats = _mm_mul_ps(floats, _mm_set1_ps(1.0f/255.0f));
+ _mm_storeu_ps(dst, floats);
+#else
+ dst[0] = (float)src[0]/255.0f;
+ dst[1] = (float)src[1]/255.0f;
+ dst[2] = (float)src[2]/255.0f;
+ dst[3] = (float)src[3]/255.0f;
+#endif
+}
+
+// Half conversion functions
+static inline uint32_t sw_half_to_float_ui(uint16_t h)
{
uint32_t s = (uint32_t)(h & 0x8000) << 16;
int32_t em = h & 0x7fff;
@@ -956,14 +1134,14 @@ static inline uint32_t sw_f16_to_f32_ui(uint16_t h)
return s | r;
}
-static inline float sw_f16_to_f32(sw_half_t y)
+static inline float sw_half_to_float(sw_half_t y)
{
- union { float f; uint32_t i; } v = { .i = sw_f16_to_f32_ui(y) };
+ union { float f; uint32_t i; } v = { .i = sw_half_to_float_ui(y) };
return v.f;
}
-static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
+static inline uint16_t sw_half_from_float_ui(uint32_t ui)
{
int32_t s = (ui >> 16) & 0x8000;
int32_t em = ui & 0x7fffffff;
@@ -983,14 +1161,15 @@ static inline uint16_t sw_f16_from_f32_ui(uint32_t ui)
return (uint16_t)(s | h);
}
-static inline sw_half_t sw_f16_from_f32(float i)
+static inline sw_half_t sw_half_from_float(float i)
{
union { float f; uint32_t i; } v;
v.f = i;
- return sw_f16_from_f32_ui(v.i);
+ return sw_half_from_float_ui(v.i);
}
// Framebuffer management functions
+//-------------------------------------------------------------------------------------------
static inline bool sw_framebuffer_load(int w, int h)
{
int size = w*h;
@@ -999,7 +1178,11 @@ static inline bool sw_framebuffer_load(int w, int h)
if (RLSW.framebuffer.color == NULL) return false;
RLSW.framebuffer.depth = SW_MALLOC(SW_DEPTH_PIXEL_SIZE*size);
- if (RLSW.framebuffer.depth == NULL) return false;
+ if (RLSW.framebuffer.depth == NULL)
+ {
+ SW_FREE(RLSW.framebuffer.color);
+ return false;
+ }
RLSW.framebuffer.width = w;
RLSW.framebuffer.height = h;
@@ -1019,11 +1202,15 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
- void *newColor = SW_REALLOC(RLSW.framebuffer.color, newSize);
+ void *newColor = SW_REALLOC(RLSW.framebuffer.color, SW_COLOR_PIXEL_SIZE*newSize);
if (newColor == NULL) return false;
- void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, newSize);
- if (newDepth == NULL) return false;
+ void *newDepth = SW_REALLOC(RLSW.framebuffer.depth, SW_DEPTH_PIXEL_SIZE*newSize);
+ if (newDepth == NULL)
+ {
+ SW_FREE(newColor);
+ return false;
+ }
RLSW.framebuffer.color = newColor;
RLSW.framebuffer.depth = newDepth;
@@ -1035,314 +1222,221 @@ static inline bool sw_framebuffer_resize(int w, int h)
return true;
}
-static inline void *sw_framebuffer_get_color_addr(const void *ptr, uint32_t offset)
-{
- return (uint8_t *)ptr + offset*SW_COLOR_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_color_addr(void **ptr)
-{
- *ptr = (void *)(((uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void sw_framebuffer_inc_const_color_addr(const void **ptr)
-{
- *ptr = (const void *)(((const uint8_t *)*ptr) + SW_COLOR_PIXEL_SIZE);
-}
-
-static inline void *sw_framebuffer_get_depth_addr(const void *ptr, uint32_t offset)
-{
- return (uint8_t *)ptr + offset*SW_DEPTH_PIXEL_SIZE;
-}
-
-static inline void sw_framebuffer_inc_depth_addr(void* *ptr)
-{
- *ptr = (void*)(((uint8_t *)*ptr) + SW_DEPTH_PIXEL_SIZE);
-}
-
-#if (SW_COLOR_BUFFER_BITS == 8) // RGB - (3:3:2)
static inline void sw_framebuffer_read_color(float dst[4], const void *src)
{
- uint8_t pixel = ((uint8_t *)src)[0];
-
- dst[0] = ((pixel >> 5) & 0x07)*(1.0f/7.0f);
- dst[1] = ((pixel >> 2) & 0x07)*(1.0f/7.0f);
- dst[2] = (pixel & 0x03)*(1.0f/3.0f);
+#if COLOR_IS_PACKED
+ COLOR_TYPE pixel = ((COLOR_TYPE*)src)[0];
+ dst[0] = TO_FLOAT_R(UNPACK_R(pixel));
+ dst[1] = TO_FLOAT_G(UNPACK_G(pixel));
+ dst[2] = TO_FLOAT_B(UNPACK_B(pixel));
dst[3] = 1.0f;
+#else
+ sw_float_from_unorm8_simd(dst, src);
+#endif
}
static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
{
- uint8_t pixel = ((const uint8_t *)src)[0];
-
- uint8_t r = (pixel >> 5) & 0x07;
- uint8_t g = (pixel >> 2) & 0x07;
- uint8_t b = pixel & 0x03;
-
- dst[0] = (r*255 + 3)/7;
- dst[1] = (g*255 + 3)/7;
- dst[2] = (b*255 + 1)/3;
+#if COLOR_IS_PACKED
+ COLOR_TYPE pixel = ((COLOR_TYPE*)src)[0];
+ dst[0] = SCALE_R(UNPACK_R(pixel));
+ dst[1] = SCALE_G(UNPACK_G(pixel));
+ dst[2] = SCALE_B(UNPACK_B(pixel));
dst[3] = 255;
+#else
+ const COLOR_TYPE *p = (const COLOR_TYPE*)src;
+ dst[0] = p[0];
+ dst[1] = p[1];
+ dst[2] = p[2];
+ dst[3] = p[3];
+#endif
}
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
+static inline void sw_framebuffer_write_color(void *dst, const float src[4])
{
- uint8_t r = ((uint8_t)(color[0]*UINT8_MAX) >> 5) & 0x07;
- uint8_t g = ((uint8_t)(color[1]*UINT8_MAX) >> 5) & 0x07;
- uint8_t b = ((uint8_t)(color[2]*UINT8_MAX) >> 6) & 0x03;
-
- ((uint8_t *)dst)[0] = (r << 5) | (g << 2) | b;
+#if COLOR_IS_PACKED
+ ((COLOR_TYPE*)dst)[0] = PACK_COLOR(src[0], src[1], src[2]);
+#else
+ sw_float_to_unorm8_simd(dst, src);
+#endif
}
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
+static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[4])
{
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
-
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
-
- uint8_t *p = (uint8_t *)ptr;
-
+#if COLOR_IS_PACKED
+ COLOR_TYPE packed = PACK_COLOR(color[0], color[1], color[2]);
+ COLOR_TYPE *p = (COLOR_TYPE*)ptr;
+#else
+ COLOR_TYPE r = sw_clampi(color[0]*255, 0, 255);
+ COLOR_TYPE g = sw_clampi(color[1]*255, 0, 255);
+ COLOR_TYPE b = sw_clampi(color[2]*255, 0, 255);
+ COLOR_TYPE a = sw_clampi(color[3]*255, 0, 255);
+ COLOR_TYPE *p = (COLOR_TYPE*)ptr;
+#endif
+
if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
{
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
{
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 16) // RGB - (5:6:5)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- uint16_t pixel = ((uint16_t *)src)[0];
-
- dst[0] = ((pixel >> 11) & 0x1F)*(1.0f/31.0f);
- dst[1] = ((pixel >> 5) & 0x3F)*(1.0f/63.0f);
- dst[2] = (pixel & 0x1F)*(1.0f/31.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- uint16_t pixel = ((const uint16_t *)src)[0];
-
- uint8_t r = (pixel >> 11) & 0x1F;
- uint8_t g = (pixel >> 5) & 0x3F;
- uint8_t b = pixel & 0x1F;
-
- dst[0] = (r*255 + 15)/31;
- dst[1] = (g*255 + 31)/63;
- dst[2] = (b*255 + 15)/31;
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*31.0f + 0.5f) & 0x1F;
- uint8_t g = (uint8_t)(color[1]*63.0f + 0.5f) & 0x3F;
- uint8_t b = (uint8_t)(color[2]*31.0f + 0.5f) & 0x1F;
-
- ((uint16_t *)dst)[0] = (r << 11) | (g << 5) | b;
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g_16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b_16 = (uint16_t)(color[2]*31.0f + 0.5f);
-
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g_16 & 0x3F) << 5) | (b_16 & 0x1F);
-
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = packedColor;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = packedColor;
- }
-}
-
-#elif (SW_COLOR_BUFFER_BITS == 24) // RGB - (8:8:8)
-
-static inline void sw_framebuffer_read_color(float dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0]*(1.0f/255.0f);
- dst[1] = ((uint8_t *)src)[1]*(1.0f/255.0f);
- dst[2] = ((uint8_t *)src)[2]*(1.0f/255.0f);
- dst[3] = 1.0f;
-}
-
-static inline void sw_framebuffer_read_color8(uint8_t dst[4], const void *src)
-{
- dst[0] = ((uint8_t *)src)[0];
- dst[1] = ((uint8_t *)src)[1];
- dst[2] = ((uint8_t *)src)[2];
- dst[3] = 255;
-}
-
-static inline void sw_framebuffer_write_color(void *dst, const float color[3])
-{
- ((uint8_t *)dst)[0] = (uint8_t)(color[0]*UINT8_MAX);
- ((uint8_t *)dst)[1] = (uint8_t)(color[1]*UINT8_MAX);
- ((uint8_t *)dst)[2] = (uint8_t)(color[2]*UINT8_MAX);
-}
-
-static inline void sw_framebuffer_fill_color(void *ptr, int size, const float color[3])
-{
- uint8_t r = (uint8_t)(color[0]*255.0f);
- uint8_t g = (uint8_t)(color[1]*255.0f);
- uint8_t b = (uint8_t)(color[2]*255.0f);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
+#if COLOR_IS_PACKED
+ COLOR_TYPE *row = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++) *row++ = packed;
+#else
+ COLOR_TYPE *row = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
+ for (int x = 0; x < w; x++)
{
- *curPtr++ = r;
- *curPtr++ = g;
- *curPtr++ = b;
+ *row++ = r;
+ *row++ = g;
+ *row++ = b;
+ *row++ = a;
}
+#endif
}
}
else
{
+#if COLOR_IS_PACKED
+ for (int i = 0; i < size; i++) *p++ = packed;
+#else
for (int i = 0; i < size; i++)
{
*p++ = r;
*p++ = g;
*p++ = b;
+ *p++ = a;
}
+#endif
}
}
-#endif // SW_COLOR_BUFFER_BITS
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
-
static inline float sw_framebuffer_read_depth(const void *src)
{
- return (float)((uint8_t *)src)[0]*(1.0f/UINT8_MAX);
+#if DEPTH_IS_PACKED
+ return ((DEPTH_TYPE*)src)[0]*DEPTH_SCALE;
+#else
+ const DEPTH_TYPE *p = (const DEPTH_TYPE*)src;
+ uint32_t d = UNPACK_DEPTH(p);
+ return d*DEPTH_SCALE;
+#endif
}
static inline void sw_framebuffer_write_depth(void *dst, float depth)
{
- ((uint8_t *)dst)[0] = (uint8_t)(depth*UINT8_MAX);
+#if DEPTH_IS_PACKED
+ ((DEPTH_TYPE*)dst)[0] = PACK_DEPTH(depth);
+#else
+ DEPTH_TYPE *p = (DEPTH_TYPE*)dst;
+ p[0] = PACK_DEPTH_0(depth);
+ p[1] = PACK_DEPTH_1(depth);
+ p[2] = PACK_DEPTH_2(depth);
+#endif
}
static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
{
- uint8_t d8 = (uint8_t)(value*UINT8_MAX);
- uint8_t *p = (uint8_t *)ptr;
-
+#if DEPTH_IS_PACKED
+ DEPTH_TYPE d = PACK_DEPTH(value);
+ DEPTH_TYPE *p = (DEPTH_TYPE*)ptr;
+#else
+ DEPTH_TYPE d0 = PACK_DEPTH_0(value);
+ DEPTH_TYPE d1 = PACK_DEPTH_1(value);
+ DEPTH_TYPE d2 = PACK_DEPTH_2(value);
+ DEPTH_TYPE *p = (DEPTH_TYPE*)ptr;
+#endif
+
if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
{
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
{
- uint8_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d8;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d8;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 16)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- return (float)((uint16_t *)src)[0]*(1.0f/UINT16_MAX);
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- ((uint16_t *)dst)[0] = (uint16_t)(depth*UINT16_MAX);
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint16_t d16 = (uint16_t)(value*UINT16_MAX);
- uint16_t *p = (uint16_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint16_t *curPtr = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
- for (int xCount = 0; xCount < wScissor; xCount++) *curPtr++ = d16;
- }
- }
- else
- {
- for (int i = 0; i < size; i++) *p++ = d16;
- }
-}
-
-#elif (SW_DEPTH_BUFFER_BITS == 24)
-
-static inline float sw_framebuffer_read_depth(const void *src)
-{
- uint32_t depth24 = (((uint8_t *)src)[0] << 16) |
- (((uint8_t *)src)[1] << 8) |
- ((uint8_t *)src)[2];
-
- return depth24/(float)0xFFFFFF;
-}
-
-static inline void sw_framebuffer_write_depth(void *dst, float depth)
-{
- uint32_t depth24 = (uint32_t)(depth*0xFFFFFF);
-
- ((uint8_t *)dst)[0] = (depth24 >> 16) & 0xFF;
- ((uint8_t *)dst)[1] = (depth24 >> 8) & 0xFF;
- ((uint8_t *)dst)[2] = depth24 & 0xFF;
-}
-
-static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
-{
- uint32_t d32 = (uint32_t)(value*UINT32_MAX);
- uint8_t d_byte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t d_byte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t d_byte2 = (uint8_t)(d32 & 0xFF);
-
- uint8_t *p = (uint8_t *)ptr;
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- uint8_t *curPtr = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
- for (int xCount = 0; xCount < wScissor; xCount++)
+#if DEPTH_IS_PACKED
+ DEPTH_TYPE *row = p + y*RLSW.framebuffer.width + RLSW.scMin[0];
+ for (int x = 0; x < w; x++) *row++ = d;
+#else
+ DEPTH_TYPE *row = p + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
+ for (int x = 0; x < w; x++)
{
- *curPtr++ = d_byte0;
- *curPtr++ = d_byte1;
- *curPtr++ = d_byte2;
+ *row++ = d0;
+ *row++ = d1;
+ *row++ = d2;
+ }
+#endif
+ }
+ }
+ else
+ {
+#if DEPTH_IS_PACKED
+ for (int i = 0; i < size; i++) *p++ = d;
+#else
+ for (int i = 0; i < size; i++)
+ {
+ *p++ = d0;
+ *p++ = d1;
+ *p++ = d2;
+ }
+#endif
+ }
+}
+
+static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth)
+{
+#if COLOR_IS_PACKED
+ COLOR_TYPE packedColor = PACK_COLOR(color[0], color[1], color[2]);
+ COLOR_TYPE *pColor = (COLOR_TYPE*)colorPtr;
+#else
+ COLOR_TYPE r = sw_clampi(color[0]*255, 0, 255);
+ COLOR_TYPE g = sw_clampi(color[1]*255, 0, 255);
+ COLOR_TYPE b = sw_clampi(color[2]*255, 0, 255);
+ COLOR_TYPE a = sw_clampi(color[3]*255, 0, 255);
+ COLOR_TYPE *pColor = (COLOR_TYPE*)colorPtr;
+#endif
+
+#if DEPTH_IS_PACKED
+ DEPTH_TYPE d = PACK_DEPTH(depth);
+ DEPTH_TYPE *pDepth = (DEPTH_TYPE*)depthPtr;
+#else
+ DEPTH_TYPE d0 = PACK_DEPTH_0(depth);
+ DEPTH_TYPE d1 = PACK_DEPTH_1(depth);
+ DEPTH_TYPE d2 = PACK_DEPTH_2(depth);
+ DEPTH_TYPE *pDepth = (DEPTH_TYPE*)depthPtr;
+#endif
+
+ if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
+ {
+ int w = RLSW.scMax[0] - RLSW.scMin[0] + 1;
+ for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
+ {
+#if COLOR_IS_PACKED
+ COLOR_TYPE *rowColor = pColor + y*RLSW.framebuffer.width + RLSW.scMin[0];
+#else
+ COLOR_TYPE *rowColor = pColor + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
+#endif
+
+#if DEPTH_IS_PACKED
+ DEPTH_TYPE *rowDepth = pDepth + y*RLSW.framebuffer.width + RLSW.scMin[0];
+#else
+ DEPTH_TYPE *rowDepth = pDepth + 3*(y*RLSW.framebuffer.width + RLSW.scMin[0]);
+#endif
+
+ for (int x = 0; x < w; x++)
+ {
+#if COLOR_IS_PACKED
+ *rowColor++ = packedColor;
+#else
+ *rowColor++ = r;
+ *rowColor++ = g;
+ *rowColor++ = b;
+ *rowColor++ = a;
+#endif
+
+#if DEPTH_IS_PACKED
+ *rowDepth++ = d;
+#else
+ *rowDepth++ = d0;
+ *rowDepth++ = d1;
+ *rowDepth++ = d2;
+#endif
}
}
}
@@ -1350,140 +1444,27 @@ static inline void sw_framebuffer_fill_depth(void *ptr, int size, float value)
{
for (int i = 0; i < size; i++)
{
- *p++ = d_byte0;
- *p++ = d_byte1;
- *p++ = d_byte2;
+#if COLOR_IS_PACKED
+ *pColor++ = packedColor;
+#else
+ *pColor++ = r;
+ *pColor++ = g;
+ *pColor++ = b;
+ *pColor++ = a;
+#endif
+
+#if DEPTH_IS_PACKED
+ *pDepth++ = d;
+#else
+ *pDepth++ = d0;
+ *pDepth++ = d1;
+ *pDepth++ = d2;
+#endif
}
}
}
-#endif // SW_DEPTH_BUFFER_BITS
-
-static inline void sw_framebuffer_fill(void *colorPtr, void *depthPtr, int size, float color[4], float depth_value)
-{
-#if (SW_COLOR_BUFFER_BITS == 8)
- // Calculate and pack 3:3:2 color
- // Scale color components to the max value for each bit depth and round
- uint8_t r8 = (uint8_t)(color[0]*7.0f + 0.5f);
- uint8_t g8 = (uint8_t)(color[1]*7.0f + 0.5f);
- uint8_t b8 = (uint8_t)(color[2]*3.0f + 0.5f);
- // Pack the components into a single byte
- uint8_t packedColor = ((r8 & 0x07) << 5) | ((g8 & 0x07) << 2) | (b8 & 0x03);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 16)
- // Calculate and pack 5:6:5 color
- // Scale color components to the max value for each bit depth and round
- uint16_t r16 = (uint16_t)(color[0]*31.0f + 0.5f);
- uint16_t g16 = (uint16_t)(color[1]*63.0f + 0.5f);
- uint16_t b16 = (uint16_t)(color[2]*31.0f + 0.5f);
- // Pack the components into a 16-bit value
- uint16_t packedColor = ((r16 & 0x1F) << 11) | ((g16 & 0x3F) << 5) | (b16 & 0x1F);
- uint16_t *cptr = (uint16_t *)colorPtr;
-#elif (SW_COLOR_BUFFER_BITS == 24)
- // Calculate 8:8:8 color components
- uint8_t r24 = (uint8_t)(color[0]*255.0f);
- uint8_t g24 = (uint8_t)(color[1]*255.0f);
- uint8_t b24 = (uint8_t)(color[2]*255.0f);
- uint8_t *cptr = (uint8_t *)colorPtr;
-#endif
-
-#if (SW_DEPTH_BUFFER_BITS == 8)
- // Calculate 8-bit depth
- uint8_t d8 = (uint8_t)(depth_value*UINT8_MAX);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 16)
- // Calculate 16-bit depth
- uint16_t d16 = (uint16_t)(depth_value*UINT16_MAX);
- uint16_t *dptr = (uint16_t *)depthPtr;
-#elif (SW_DEPTH_BUFFER_BITS == 24)
- // Calculate 24-bit depth and pre-calculate bytes
- uint32_t d32 = (uint32_t)(depth_value*UINT32_MAX);
- uint8_t dByte0 = (uint8_t)((d32 >> 16) & 0xFF);
- uint8_t dByte1 = (uint8_t)((d32 >> 8) & 0xFF);
- uint8_t dByte2 = (uint8_t)(d32 & 0xFF);
- uint8_t *dptr = (uint8_t *)depthPtr;
-#endif
-
- if (RLSW.stateFlags & SW_STATE_SCISSOR_TEST)
- {
- int wScissor = RLSW.scMax[0] - RLSW.scMin[0] + 1;
- for (int y = RLSW.scMin[1]; y <= RLSW.scMax[1]; y++)
- {
- int rowStartIdx = y*RLSW.framebuffer.width + RLSW.scMin[0];
-
- // Calculate starting pointers for the current row within the scissor rectangle
- #if (SW_COLOR_BUFFER_BITS == 8)
- uint8_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- uint16_t *curCPtr = cptr + rowStartIdx;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- uint8_t *curCPtr = cptr + 3*rowStartIdx;
- #endif
-
- #if (SW_DEPTH_BUFFER_BITS == 8)
- uint8_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- uint16_t *curDPtr = dptr + rowStartIdx;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- uint8_t *curDPtr = dptr + 3*rowStartIdx;
- #endif
-
- // Fill the current row within the scissor rectangle
- for (int xCount = 0; xCount < wScissor; xCount++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *curCPtr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *curCPtr++ = r24;
- *curCPtr++ = g24;
- *curCPtr++ = b24;
- #endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *curDPtr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *curDPtr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *curDPtr++ = dByte0;
- *curDPtr++ = dByte1;
- *curDPtr++ = dByte2;
- #endif
- }
- }
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- // Write color
- #if (SW_COLOR_BUFFER_BITS == 8)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 16)
- *cptr++ = packedColor;
- #elif (SW_COLOR_BUFFER_BITS == 24)
- *cptr++ = r24;
- *cptr++ = g24;
- *cptr++ = b24;
- #endif
-
- // Write depth
- #if (SW_DEPTH_BUFFER_BITS == 8)
- *dptr++ = d8;
- #elif (SW_DEPTH_BUFFER_BITS == 16)
- *dptr++ = d16;
- #elif (SW_DEPTH_BUFFER_BITS == 24)
- *dptr++ = dByte0;
- *dptr++ = dByte1;
- *dptr++ = dByte2;
- #endif
- }
-}
-
-#define DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(name, DST_PTR_T) \
+#define DEFINE_FRAMEBUFFER_COPY_BEGIN(name, DST_PTR_T) \
static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
{ \
const void *src = RLSW.framebuffer.color; \
@@ -1493,23 +1474,13 @@ static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST
uint8_t color[4]; \
sw_framebuffer_read_color8(color, src); \
-#define DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_copy_to_##name(int x, int y, int w, int h, DST_PTR_T *dst) \
-{ \
- const void *src = RLSW.framebuffer.color; \
- \
- for (int iy = y; iy < h; iy++) { \
- for (int ix = x; ix < w; ix++) { \
- float color[4]; \
- sw_framebuffer_read_color(color, src); \
-
#define DEFINE_FRAMEBUFFER_COPY_END() \
- sw_framebuffer_inc_const_color_addr(&src); \
+ INC_COLOR_PTR(src); \
} \
} \
}
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYSCALE, uint8_t)
{
// NTSC grayscale conversion: Y = 0.299R + 0.587G + 0.114B
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1517,7 +1488,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYSCALE, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(GRAYALPHA, uint8_t)
{
// Convert RGB to grayscale using NTSC formula
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1529,7 +1500,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G6B5, uint16_t)
{
// Convert 8-bit RGB to 5:6:5 format
uint8_t r5 = (color[0]*31 + 127)/255;
@@ -1546,7 +1517,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1562,7 +1533,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
@@ -1579,7 +1550,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1596,7 +1567,7 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_COPY_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1613,145 +1584,42 @@ DEFINE_FRAMEBUFFER_COPY_U32_BEGIN(R8G8B8A8, uint8_t)
}
DEFINE_FRAMEBUFFER_COPY_END()
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32, float)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-DEFINE_FRAMEBUFFER_COPY_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_COPY_END()
-
-#define DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(name, DST_PTR_T) \
+#define DEFINE_FRAMEBUFFER_BLIT_BEGIN(name, DST_PTR_T) \
static inline void sw_framebuffer_blit_to_##name( \
int xDst, int yDst, int wDst, int hDst, \
int xSrc, int ySrc, int wSrc, int hSrc, \
DST_PTR_T *dst) \
{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
+ const uint8_t *srcBase = (uint8_t*)RLSW.framebuffer.color; \
int fbWidth = RLSW.framebuffer.width; \
\
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
+ uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
+ uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
\
for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
+ uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
int sy = yFix >> 16; \
\
for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
+ uint32_t xFix = dx*xScale; \
int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
+ const void *srcPtr = GET_COLOR_PTR(srcBase, sy*fbWidth + sx); \
uint8_t color[4]; \
sw_framebuffer_read_color8(color, srcPtr); \
-#define DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(name, DST_PTR_T) \
-static inline void sw_framebuffer_blit_to_##name( \
- int xDst, int yDst, int wDst, int hDst, \
- int xSrc, int ySrc, int wSrc, int hSrc, \
- DST_PTR_T *dst) \
-{ \
- const uint8_t *srcBase = RLSW.framebuffer.color; \
- int fbWidth = RLSW.framebuffer.width; \
- \
- uint32_t xScale = ((uint32_t)wSrc << 16)/(uint32_t)wDst; \
- uint32_t yScale = ((uint32_t)hSrc << 16)/(uint32_t)hDst; \
- \
- for (int dy = 0; dy < hDst; dy++) { \
- uint32_t yFix = ((uint32_t)ySrc << 16) + dy*yScale; \
- int sy = yFix >> 16; \
- \
- for (int dx = 0; dx < wDst; dx++) { \
- uint32_t xFix = dx*xScale; \
- int sx = xFix >> 16; \
- const void *srcPtr = sw_framebuffer_get_color_addr(srcBase, sy*fbWidth + sx); \
- float color[4]; \
- sw_framebuffer_read_color(color, srcPtr); \
-
#define DEFINE_FRAMEBUFFER_BLIT_END() \
} \
} \
}
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYSCALE, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYSCALE, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
*dst++ = gray;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(GRAYALPHA, uint8_t)
{
uint8_t gray = (uint8_t)((color[0]*299 + color[1]*587 + color[2]*114 + 500)/1000);
@@ -1762,7 +1630,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(GRAYALPHA, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G6B5, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g6 = (color[1]*63 + 127)/255;
@@ -1778,7 +1646,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G6B5, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1794,7 +1662,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8, uint8_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R5G5B5A1, uint16_t)
{
uint8_t r5 = (color[0]*31 + 127)/255;
uint8_t g5 = (color[1]*31 + 127)/255;
@@ -1811,7 +1679,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R5G5B5A1, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R4G4B4A4, uint16_t)
{
uint8_t r4 = (color[0]*15 + 127)/255;
uint8_t g4 = (color[1]*15 + 127)/255;
@@ -1828,7 +1696,7 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R4G4B4A4, uint16_t)
}
DEFINE_FRAMEBUFFER_BLIT_END()
-DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
+DEFINE_FRAMEBUFFER_BLIT_BEGIN(R8G8B8A8, uint8_t)
{
#if SW_GL_FRAMEBUFFER_COPY_BGRA
dst[0] = color[2];
@@ -1844,89 +1712,10 @@ DEFINE_FRAMEBUFFER_BLIT_U32_BEGIN(R8G8B8A8, uint8_t)
dst += 4;
}
DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32, uint8_t)
-{
- dst[0] = color[0];
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R32G32B32A32, float)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = color[2];
- dst[1] = color[1];
- dst[2] = color[0];
-#else // RGBA
- dst[0] = color[0];
- dst[1] = color[1];
- dst[2] = color[2];
-#endif
- dst[3] = color[3];
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16, sw_half_t)
-{
- dst[0] = sw_f16_from_f32(color[0]);
- dst++;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
-
- dst += 3;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
-
-DEFINE_FRAMEBUFFER_BLIT_F32_BEGIN(R16G16B16A16, sw_half_t)
-{
-#if SW_GL_FRAMEBUFFER_COPY_BGRA
- dst[0] = sw_f16_from_f32(color[2]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[0]);
-#else // RGBA
- dst[0] = sw_f16_from_f32(color[0]);
- dst[1] = sw_f16_from_f32(color[1]);
- dst[2] = sw_f16_from_f32(color[2]);
-#endif
- dst[3] = sw_f16_from_f32(color[3]);
-
- dst += 4;
-}
-DEFINE_FRAMEBUFFER_BLIT_END()
+//-------------------------------------------------------------------------------------------
// Pixel format management functions
-
+//-------------------------------------------------------------------------------------------
static inline int sw_get_pixel_format(SWformat format, SWtype type)
{
int channels = 0;
@@ -1979,210 +1768,179 @@ static inline int sw_get_pixel_format(SWformat format, SWtype type)
return SW_PIXELFORMAT_UNKNOWN;
}
-int sw_get_pixel_bytes(sw_pixelformat_t format)
+static inline void sw_get_pixel(uint8_t *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
{
- int bpp = 0;
-
switch (format)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 1; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE:
+ {
+ uint8_t gray = ((const uint8_t*)pixels)[offset];
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*2];
+ color[0] = src[0];
+ color[1] = src[0];
+ color[2] = src[0];
+ color[3] = src[1];
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 5) & 0x3F)*255/63; // G (6 bits)
+ color[2] = (pixel & 0x1F)*255/31; // B (5 bits)
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*3];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = 255;
+ break;
+ }
case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 4*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 4*4; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 2; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 2*3; break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 2*4; break;
- default: break;
- }
-
- return bpp;
-}
-
-static inline void sw_get_pixel_grayscale(float *color, const void *pixels, uint32_t offset)
-{
- float gray = (float)((uint8_t *)pixels)[offset]*(1.0f/255);
-
- color[0] = gray;
- color[1] = gray;
- color[2] = gray;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_16(float *color, const void *pixels, uint32_t offset)
-{
- float value = sw_f16_to_f32(((sw_half_t *)pixels)[offset]);
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_red_32(float *color, const void *pixels, uint32_t offset)
-{
- float value = ((float *)pixels)[offset];
-
- color[0] = value;
- color[1] = value;
- color[2] = value;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_grayscale_alpha(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixelData = (const uint8_t *)pixels + 2*offset;
-
- color[0] = color[1] = color[2] = (float)pixelData[0]*(1.0f/255);
- color[3] = (float)pixelData[1]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgb_565(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7E0) >> 5)/63;
- color[2] = (float)(pixel & 0x1F)/31;
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (const uint8_t *)pixels + 3*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 3*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgb_323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 3*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = 1.0f;
-}
-
-static inline void sw_get_pixel_rgba_5551(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF800) >> 11)/31;
- color[1] = (float)((pixel & 0x7C0) >> 6)/31;
- color[2] = (float)((pixel & 0x3E) >> 1)/31;
- color[3] = (float)(pixel & 0x1);
-}
-
-static inline void sw_get_pixel_rgba_4444(float *color, const void *pixels, uint32_t offset)
-{
- uint16_t pixel = ((uint16_t *)pixels)[offset];
-
- color[0] = (float)((pixel & 0xF000) >> 12)/15;
- color[1] = (float)((pixel & 0xF00) >> 8)/15;
- color[2] = (float)((pixel & 0xF0) >> 4)/15;
- color[3] = (float)(pixel & 0xF)/15;
-}
-
-static inline void sw_get_pixel_rgba_8888(float *color, const void *pixels, uint32_t offset)
-{
- const uint8_t *pixel = (uint8_t *)pixels + 4*offset;
-
- color[0] = (float)pixel[0]*(1.0f/255);
- color[1] = (float)pixel[1]*(1.0f/255);
- color[2] = (float)pixel[2]*(1.0f/255);
- color[3] = (float)pixel[3]*(1.0f/255);
-}
-
-static inline void sw_get_pixel_rgba_16161616(float *color, const void *pixels, uint32_t offset)
-{
- const sw_half_t *pixel = (sw_half_t *)pixels + 4*offset;
-
- color[0] = sw_f16_to_f32(pixel[0]);
- color[1] = sw_f16_to_f32(pixel[1]);
- color[2] = sw_f16_to_f32(pixel[2]);
- color[3] = sw_f16_to_f32(pixel[3]);
-}
-
-static inline void sw_get_pixel_rgba_32323232(float *color, const void *pixels, uint32_t offset)
-{
- const float *pixel = (float *)pixels + 4*offset;
-
- color[0] = pixel[0];
- color[1] = pixel[1];
- color[2] = pixel[2];
- color[3] = pixel[3];
-}
-
-static inline void sw_get_pixel(float *color, const void *pixels, uint32_t offset, sw_pixelformat_t format)
-{
- switch (format)
- {
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_get_pixel_grayscale(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_get_pixel_grayscale_alpha(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_get_pixel_rgb_565(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_get_pixel_rgb_888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_get_pixel_rgba_5551(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_get_pixel_rgba_4444(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_get_pixel_rgba_8888(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_get_pixel_red_32(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_get_pixel_rgb_323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_get_pixel_rgba_32323232(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_get_pixel_red_16(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_get_pixel_rgb_161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_get_pixel_rgba_16161616(color, pixels, offset); break;
- case SW_PIXELFORMAT_UNKNOWN: break;
- default: break;
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 11) & 0x1F)*255/31; // R (5 bits)
+ color[1] = ((pixel >> 6) & 0x1F)*255/31; // G (5 bits)
+ color[2] = ((pixel >> 1) & 0x1F)*255/31; // B (5 bits)
+ color[3] = (pixel & 0x01)*255; // A (1 bit)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4:
+ {
+ uint16_t pixel = ((const uint16_t*)pixels)[offset];
+ color[0] = ((pixel >> 12) & 0x0F)*255/15; // R (4 bits)
+ color[1] = ((pixel >> 8) & 0x0F)*255/15; // G (4 bits)
+ color[2] = ((pixel >> 4) & 0x0F)*255/15; // B (4 bits)
+ color[3] = (pixel & 0x0F)*255/15; // A (4 bits)
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8:
+ {
+ const uint8_t *src = &((const uint8_t*)pixels)[offset*4];
+ color[0] = src[0];
+ color[1] = src[1];
+ color[2] = src[2];
+ color[3] = src[3];
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ {
+ float val = ((const float*)pixels)[offset];
+ uint8_t gray = (uint8_t)(val*255.0f);
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ {
+ const float *src = &((const float*)pixels)[offset*3];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ {
+ const float *src = &((const float*)pixels)[offset*4];
+ color[0] = (uint8_t)(src[0]*255.0f);
+ color[1] = (uint8_t)(src[1]*255.0f);
+ color[2] = (uint8_t)(src[2]*255.0f);
+ color[3] = (uint8_t)(src[3]*255.0f);
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ {
+ uint16_t val = ((const uint16_t*)pixels)[offset];
+ uint8_t gray = sw_half_to_float(val)/255.0f;
+ color[0] = gray;
+ color[1] = gray;
+ color[2] = gray;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*3];
+ color[0] = sw_half_to_float(src[0])/255.0f;
+ color[1] = sw_half_to_float(src[1])/255.0f;
+ color[2] = sw_half_to_float(src[2])/255.0f;
+ color[3] = 255;
+ break;
+ }
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ {
+ const uint16_t *src = &((const uint16_t*)pixels)[offset*4];
+ color[0] = sw_half_to_float(src[0])/255.0f;
+ color[1] = sw_half_to_float(src[1])/255.0f;
+ color[2] = sw_half_to_float(src[2])/255.0f;
+ color[3] = sw_half_to_float(src[3])/255.0f;
+ break;
+ }
+ case SW_PIXELFORMAT_UNKNOWN:
+ default:
+ {
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ color[3] = 0;
+ break;
+ }
}
}
+//-------------------------------------------------------------------------------------------
// Texture sampling functionality
+//-------------------------------------------------------------------------------------------
+static inline void sw_texture_fetch(float* color, const sw_texture_t* tex, int x, int y)
+{
+ sw_float_from_unorm8_simd(color, &tex->pixels[4*(y*tex->width + x)]);
+}
static inline void sw_texture_sample_nearest(float *color, const sw_texture_t *tex, float u, float v)
{
u = (tex->sWrap == SW_REPEAT)? sw_fract(u) : sw_saturate(u);
v = (tex->tWrap == SW_REPEAT)? sw_fract(v) : sw_saturate(v);
- int x = u*tex->width, y = v*tex->height;
+ int x = u*tex->width;
+ int y = v*tex->height;
- sw_get_pixel(color, tex->pixels.cptr, y*tex->width + x, tex->format);
+ sw_texture_fetch(color, tex, x, y);
}
static inline void sw_texture_sample_linear(float *color, const sw_texture_t *tex, float u, float v)
{
- // TODO: REVIEW: With a bit more cleverness we could clearly reduce the
+ // TODO: With a bit more cleverness we could clearly reduce the
// number of operations here, but for now it works fine.
- float xf = u*tex->width - 0.5f;
- float yf = v*tex->height - 0.5f;
+ float xf = (u*tex->width) - 0.5f;
+ float yf = (v*tex->height) - 0.5f;
- int x0 = (int)floorf(xf);
- int y0 = (int)floorf(yf);
+ float fx = sw_fract(xf);
+ float fy = sw_fract(yf);
- float fx = xf - x0;
- float fy = yf - y0;
+ int x0 = (int)xf;
+ int y0 = (int)yf;
int x1 = x0 + 1;
int y1 = y0 + 1;
+ // NOTE: If the textures are POT we could avoid the division for SW_REPEAT
+
if (tex->sWrap == SW_CLAMP)
{
x0 = (x0 > tex->wMinus1)? tex->wMinus1 : x0;
@@ -2206,10 +1964,10 @@ static inline void sw_texture_sample_linear(float *color, const sw_texture_t *te
}
float c00[4], c10[4], c01[4], c11[4];
- sw_get_pixel(c00, tex->pixels.cptr, y0*tex->width + x0, tex->format);
- sw_get_pixel(c10, tex->pixels.cptr, y0*tex->width + x1, tex->format);
- sw_get_pixel(c01, tex->pixels.cptr, y1*tex->width + x0, tex->format);
- sw_get_pixel(c11, tex->pixels.cptr, y1*tex->width + x1, tex->format);
+ sw_texture_fetch(c00, tex, x0, y0);
+ sw_texture_fetch(c10, tex, x1, y0);
+ sw_texture_fetch(c01, tex, x0, y1);
+ sw_texture_fetch(c11, tex, x1, y1);
for (int i = 0; i < 4; i++)
{
@@ -2241,9 +1999,10 @@ static inline void sw_texture_sample(float *color, const sw_texture_t *tex, floa
default: break;
}
}
+//-------------------------------------------------------------------------------------------
-// Color Blending functionality
-
+// Color blending functionality
+//-------------------------------------------------------------------------------------------
static inline void sw_factor_zero(float *SW_RESTRICT factor, const float *SW_RESTRICT src, const float *SW_RESTRICT dst)
{
factor[0] = factor[1] = factor[2] = factor[3] = 0.0f;
@@ -2316,17 +2075,19 @@ static inline void sw_blend_colors(float *SW_RESTRICT dst/*[4]*/, const float *S
dst[2] = srcFactor[2]*src[2] + dstFactor[2]*dst[2];
dst[3] = srcFactor[3]*src[3] + dstFactor[3]*dst[3];
}
+//-------------------------------------------------------------------------------------------
// Projection helper functions
-
+//-------------------------------------------------------------------------------------------
static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4])
{
screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalfSize[0];
screen[1] = RLSW.vpCenter[1] - ndc[1]*RLSW.vpHalfSize[1];
}
+//-------------------------------------------------------------------------------------------
-// Polygon Clipping management
-
+// Polygon clipping management
+//-------------------------------------------------------------------------------------------
#define DEFINE_CLIP_FUNC(name, FUNC_IS_INSIDE, FUNC_COMPUTE_T) \
static inline int sw_clip_##name( \
sw_vertex_t output[SW_MAX_CLIPPED_POLYGON_VERTICES], \
@@ -2358,9 +2119,10 @@ static inline int sw_clip_##name(
\
return outputCount; \
}
+//-------------------------------------------------------------------------------------------
// Frustum cliping functions
-
+//-------------------------------------------------------------------------------------------
#define IS_INSIDE_PLANE_W(h) ((h)[3] >= SW_CLIP_EPSILON)
#define IS_INSIDE_PLANE_X_POS(h) ((h)[0] <= (h)[3])
#define IS_INSIDE_PLANE_X_NEG(h) (-(h)[0] <= (h)[3])
@@ -2384,9 +2146,10 @@ DEFINE_CLIP_FUNC(y_pos, IS_INSIDE_PLANE_Y_POS, COMPUTE_T_PLANE_Y_POS)
DEFINE_CLIP_FUNC(y_neg, IS_INSIDE_PLANE_Y_NEG, COMPUTE_T_PLANE_Y_NEG)
DEFINE_CLIP_FUNC(z_pos, IS_INSIDE_PLANE_Z_POS, COMPUTE_T_PLANE_Z_POS)
DEFINE_CLIP_FUNC(z_neg, IS_INSIDE_PLANE_Z_NEG, COMPUTE_T_PLANE_Z_NEG)
+//-------------------------------------------------------------------------------------------
// Scissor clip functions
-
+//-------------------------------------------------------------------------------------------
#define COMPUTE_T_SCISSOR_X_MIN(hPrev, hCurr) (((RLSW.scClipMin[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMin[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMin[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_X_MAX(hPrev, hCurr) (((RLSW.scClipMax[0])*(hPrev)[3] - (hPrev)[0])/(((hCurr)[0] - (RLSW.scClipMax[0])*(hCurr)[3]) - ((hPrev)[0] - (RLSW.scClipMax[0])*(hPrev)[3])))
#define COMPUTE_T_SCISSOR_Y_MIN(hPrev, hCurr) (((RLSW.scClipMin[1])*(hPrev)[3] - (hPrev)[1])/(((hCurr)[1] - (RLSW.scClipMin[1])*(hCurr)[3]) - ((hPrev)[1] - (RLSW.scClipMin[1])*(hPrev)[3])))
@@ -2401,9 +2164,9 @@ DEFINE_CLIP_FUNC(scissor_x_min, IS_INSIDE_SCISSOR_X_MIN, COMPUTE_T_SCISSOR_X_MIN
DEFINE_CLIP_FUNC(scissor_x_max, IS_INSIDE_SCISSOR_X_MAX, COMPUTE_T_SCISSOR_X_MAX)
DEFINE_CLIP_FUNC(scissor_y_min, IS_INSIDE_SCISSOR_Y_MIN, COMPUTE_T_SCISSOR_Y_MIN)
DEFINE_CLIP_FUNC(scissor_y_max, IS_INSIDE_SCISSOR_Y_MAX, COMPUTE_T_SCISSOR_Y_MAX)
+//-------------------------------------------------------------------------------------------
-// Main clip function
-
+// Main polygon clip function
static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int *vertexCounter)
{
static sw_vertex_t tmp[SW_MAX_CLIPPED_POLYGON_VERTICES];
@@ -2443,7 +2206,7 @@ static inline bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VE
}
// Triangle rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_triangle_face_culling(void)
{
// NOTE: Face culling is done before clipping to avoid unnecessary computations.
@@ -2506,23 +2269,23 @@ static inline void sw_triangle_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2577,12 +2340,21 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
} \
\
/* Pre-calculate the starting pointers for the framebuffer row */ \
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \
+ void *cptr = GET_COLOR_PTR(RLSW.framebuffer.color, y*RLSW.framebuffer.width + xStart); \
+ void *dptr = GET_DEPTH_PTR(RLSW.framebuffer.depth, y*RLSW.framebuffer.width + xStart); \
\
/* Scanline rasterization */ \
for (int x = xStart; x < xEnd; x++) \
{ \
+ /* Pixel color computation */ \
+ float wRcp = 1.0f/w; \
+ float srcColor[4] = { \
+ color[0]*wRcp, \
+ color[1]*wRcp, \
+ color[2]*wRcp, \
+ color[3]*wRcp \
+ }; \
+ \
/* Test and write depth */ \
if (ENABLE_DEPTH_TEST) \
{ \
@@ -2593,15 +2365,6 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
\
sw_framebuffer_write_depth(dptr, z); \
\
- /* Pixel color computation */ \
- float wRcp = 1.0f/w; \
- float srcColor[4] = { \
- color[0]*wRcp, \
- color[1]*wRcp, \
- color[2]*wRcp, \
- color[3]*wRcp \
- }; \
- \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
@@ -2618,12 +2381,7 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
{ \
float dstColor[4]; \
sw_framebuffer_read_color(dstColor, cptr); \
- \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- \
sw_framebuffer_write_color(cptr, dstColor); \
} \
else \
@@ -2645,8 +2403,8 @@ static inline void FUNC_NAME(const sw_texture_t *tex, const sw_vertex_t *start,
v += dvDx; \
} \
\
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ INC_COLOR_PTR(cptr); \
+ INC_DEPTH_PTR(dptr); \
} \
}
@@ -2771,20 +2529,25 @@ static inline void sw_triangle_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Quad rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_quad_face_culling(void)
{
// NOTE: Face culling is done before clipping to avoid unnecessary computations.
@@ -2853,23 +2616,23 @@ static inline void sw_quad_clip_and_project(void)
// Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes
- const float invW = 1.0f/v->homogeneous[3];
- v->homogeneous[3] = invW;
+ const float wRcp = 1.0f/v->homogeneous[3];
+ v->homogeneous[3] = wRcp;
// Division of XYZ coordinates by weight
- v->homogeneous[0] *= invW;
- v->homogeneous[1] *= invW;
- v->homogeneous[2] *= invW;
+ v->homogeneous[0] *= wRcp;
+ v->homogeneous[1] *= wRcp;
+ v->homogeneous[2] *= wRcp;
// Division of texture coordinates (perspective-correct)
- v->texcoord[0] *= invW;
- v->texcoord[1] *= invW;
+ v->texcoord[0] *= wRcp;
+ v->texcoord[1] *= wRcp;
// Division of colors (perspective-correct)
- v->color[0] *= invW;
- v->color[1] *= invW;
- v->color[2] *= invW;
- v->color[3] *= invW;
+ v->color[0] *= wRcp;
+ v->color[1] *= wRcp;
+ v->color[2] *= wRcp;
+ v->color[3] *= wRcp;
// Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous);
@@ -2892,8 +2655,8 @@ static inline bool sw_quad_is_axis_aligned(void)
float dx = v1[0] - v0[0];
float dy = v1[1] - v0[1];
- if (fabsf(dx) > 1e-6f && fabsf(dy) < 1e-6f) horizontal++;
- else if (fabsf(dy) > 1e-6f && fabsf(dx) < 1e-6f) vertical++;
+ if ((fabsf(dx) > 1e-6f) && (fabsf(dy) < 1e-6f)) horizontal++;
+ else if ((fabsf(dy) > 1e-6f) && (fabsf(dx) < 1e-6f)) vertical++;
else return false; // Diagonal edge -> not axis-aligned
}
@@ -2902,76 +2665,40 @@ static inline bool sw_quad_is_axis_aligned(void)
static inline void sw_quad_sort_cw(const sw_vertex_t* *output)
{
- // Sort 4 quad vertices into clockwise order with fixed layout:
- //
- // v0 -- v1
- // | |
- // v3 -- v2
- //
- // The goal is:
- // - v0: top-left (minimum Y, then minimum X)
- // - v1: top-right (minimum Y row, maximum X)
- // - v2: bottom-right (maximum Y, maximum X)
- // - v3: bottom-left (maximum Y, minimum X)
const sw_vertex_t *input = RLSW.vertexBuffer;
- // Separate vertices into top and bottom based on Y-coordinate
- const sw_vertex_t *top[2] = {NULL, NULL};
- const sw_vertex_t *bottom[2] = {NULL, NULL};
- int topCount = 0, bottomCount = 0;
+ // Calculate the centroid of the quad
+ float cx = (input[0].screen[0] + input[1].screen[0] +
+ input[2].screen[0] + input[3].screen[0])*0.25f;
+ float cy = (input[0].screen[1] + input[1].screen[1] +
+ input[2].screen[1] + input[3].screen[1])*0.25f;
- // Find minimum and maximum Y
- float minY = input[0].screen[1];
- float maxY = input[0].screen[1];
+ // Calculate the angle of each vertex relative to the center
+ // and assign them directly to their correct position
+ const sw_vertex_t *corners[4] = { 0 };
- for (int i = 1; i < 4; i++)
- {
- if (input[i].screen[1] < minY) minY = input[i].screen[1];
- if (input[i].screen[1] > maxY) maxY = input[i].screen[1];
- }
-
- // Separate vertices based on Y-coordinate
for (int i = 0; i < 4; i++)
{
- if (input[i].screen[1] == minY && topCount < 2) top[topCount++] = &input[i];
- else if (input[i].screen[1] == maxY && bottomCount < 2) bottom[bottomCount++] = &input[i];
+ float dx = input[i].screen[0] - cx;
+ float dy = input[i].screen[1] - cy;
+
+ // Determine the quadrant (clockwise from top-left)
+ // top-left: dx < 0, dy < 0
+ // top-right: dx >= 0, dy < 0
+ // bottom-right: dx >= 0, dy >= 0
+ // bottom-left: dx < 0, dy >= 0
+
+ int idx;
+ if (dy < 0) idx = (dx < 0)? 0 : 1; // Top row
+ else idx = (dx < 0)? 3 : 2; // Bottom row
+
+ corners[idx] = &input[i];
}
- // If we don't have enough top/bottom vertices (e.g., Y values are all different),
- // classify vertices as top or bottom based on whether they're closer to minY or maxY
- for (int i = 0; i < 4; i++)
- {
- if ((topCount < 2) && (&input[i] != top[0]) && (&input[i] != bottom[0]) && (&input[i] != bottom[1]))
- {
- if (fabsf(input[i].screen[1] - minY) <= fabsf(input[i].screen[1] - maxY)) top[topCount++] = &input[i];
- }
- if ((bottomCount < 2) && (&input[i] != top[0]) && (&input[i] != top[1]) && (&input[i] != bottom[0]))
- {
- if (fabsf(input[i].screen[1] - maxY) < fabsf(input[i].screen[1] - minY)) bottom[bottomCount++] = &input[i];
- }
- }
-
- // Sort top vertices by X (left to right)
- if ((topCount == 2) && (top[0]->screen[0] > top[1]->screen[0]))
- {
- const sw_vertex_t *temp = top[0];
- top[0] = top[1];
- top[1] = temp;
- }
-
- // Sort bottom vertices by X (left to right)
- if (bottomCount == 2 && bottom[0]->screen[0] > bottom[1]->screen[0])
- {
- const sw_vertex_t *temp = bottom[0];
- bottom[0] = bottom[1];
- bottom[1] = temp;
- }
-
- // Assign vertices in clockwise order as per the required layout
- output[0] = top[0]; // v0: top-left
- output[1] = top[topCount-1]; // v1: top-right
- output[2] = bottom[bottomCount-1]; // v2: bottom-right
- output[3] = bottom[0]; // v3: bottom-left
+ output[0] = corners[0]; // top-left
+ output[1] = corners[1]; // top-right
+ output[2] = corners[2]; // bottom-right
+ output[3] = corners[3]; // bottom-left
}
// TODO: REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth,
@@ -2997,7 +2724,7 @@ static inline void FUNC_NAME(void)
int width = xMax - xMin; \
int height = yMax - yMin; \
\
- if (width == 0 || height == 0) return; \
+ if ((width == 0) || (height == 0)) return; \
\
float wRcp = (width > 0.0f)? 1.0f/width : 0.0f; \
float hRcp = (height > 0.0f)? 1.0f/height : 0.0f; \
@@ -3046,8 +2773,8 @@ static inline void FUNC_NAME(void)
\
for (int y = yMin; y < yMax; y++) \
{ \
- void *cptr = sw_framebuffer_get_color_addr(cDstBase, y*wDst + xMin); \
- void *dptr = sw_framebuffer_get_depth_addr(dDstBase, y*wDst + xMin); \
+ void *cptr = GET_COLOR_PTR(cDstBase, y*wDst + xMin); \
+ void *dptr = GET_DEPTH_PTR(dDstBase, y*wDst + xMin); \
\
float z = zScanline; \
float u = uScanline; \
@@ -3063,6 +2790,14 @@ static inline void FUNC_NAME(void)
/* Scanline rasterization */ \
for (int x = xMin; x < xMax; x++) \
{ \
+ /* Pixel color computation */ \
+ float srcColor[4] = { \
+ color[0], \
+ color[1], \
+ color[2], \
+ color[3] \
+ }; \
+ \
/* Test and write depth */ \
if (ENABLE_DEPTH_TEST) \
{ \
@@ -3073,14 +2808,6 @@ static inline void FUNC_NAME(void)
\
sw_framebuffer_write_depth(dptr, z); \
\
- /* Pixel color computation */ \
- float srcColor[4] = { \
- color[0], \
- color[1], \
- color[2], \
- color[3] \
- }; \
- \
if (ENABLE_TEXTURE) \
{ \
float texColor[4]; \
@@ -3095,13 +2822,7 @@ static inline void FUNC_NAME(void)
{ \
float dstColor[4]; \
sw_framebuffer_read_color(dstColor, cptr); \
- \
sw_blend_colors(dstColor, srcColor); \
- dstColor[0] = sw_saturate(dstColor[0]); \
- dstColor[1] = sw_saturate(dstColor[1]); \
- dstColor[2] = sw_saturate(dstColor[2]); \
- dstColor[3] = sw_saturate(dstColor[3]); \
- \
sw_framebuffer_write_color(cptr, dstColor); \
} \
else sw_framebuffer_write_color(cptr, srcColor); \
@@ -3119,8 +2840,8 @@ static inline void FUNC_NAME(void)
v += tcDx[1]; \
} \
\
- sw_framebuffer_inc_color_addr(&cptr); \
- sw_framebuffer_inc_depth_addr(&dptr); \
+ INC_COLOR_PTR(cptr); \
+ INC_DEPTH_PTR(dptr); \
} \
\
zScanline += zDy; \
@@ -3157,15 +2878,19 @@ static inline void sw_quad_render(void)
if (RLSW.vertexCounter < 3) return;
- if (RLSW.vertexCounter == 4 && sw_quad_is_axis_aligned())
+ uint32_t state = RLSW.stateFlags;
+ if (RLSW.currentTexture == 0) state &= ~SW_STATE_TEXTURE_2D;
+ if ((RLSW.srcFactor == SW_ONE) && (RLSW.dstFactor == SW_ZERO)) state &= ~SW_STATE_BLEND;
+
+ if ((RLSW.vertexCounter == 4) && sw_quad_is_axis_aligned())
{
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_DEPTH_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) sw_quad_raster_axis_aligned_TEX_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_TEX_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) sw_quad_raster_axis_aligned_BLEND();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) sw_quad_raster_axis_aligned_DEPTH();
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) sw_quad_raster_axis_aligned_TEX();
else sw_quad_raster_axis_aligned();
return;
}
@@ -3183,20 +2908,21 @@ static inline void sw_quad_render(void)
} \
}
- if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
- else if (SW_STATE_CHECK(SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
- else if (SW_STATE_CHECK(SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
+ if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_TEX_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_TEX_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_BLEND)) TRIANGLE_RASTER(sw_triangle_raster_BLEND)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_DEPTH_TEST)) TRIANGLE_RASTER(sw_triangle_raster_DEPTH)
+ else if (SW_STATE_CHECK_EX(state, SW_STATE_TEXTURE_2D)) TRIANGLE_RASTER(sw_triangle_raster_TEX)
else TRIANGLE_RASTER(sw_triangle_raster)
#undef TRIANGLE_RASTER
}
+//-------------------------------------------------------------------------------------------
// Line rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_line_clip_coord(float q, float p, float *t0, float *t1)
{
if (fabsf(p) < SW_CLIP_EPSILON)
@@ -3304,7 +3030,7 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
int dy = y2 - y1; \
\
/* Handling of lines that are more horizontal or vertical */ \
- if (dx == 0 && dy == 0) \
+ if ((dx == 0) && (dy == 0)) \
{ \
/* TODO: A point should be rendered here */ \
return; \
@@ -3360,7 +3086,8 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
for (int i = 0; i != longLen; i += sgnInc) \
{ \
int offset = (y1 + i)*fbWidth + (x1 + (j >> 16)); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
+ void *dptr = GET_DEPTH_PTR(dBuffer, offset); \
+ void *cptr = NULL; \
\
if (ENABLE_DEPTH_TEST) \
{ \
@@ -3370,13 +3097,12 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
\
sw_framebuffer_write_depth(dptr, z); \
\
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
+ cptr = GET_COLOR_PTR(cBuffer, offset); \
\
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
sw_framebuffer_read_color(dstColor, cptr); \
- \
sw_blend_colors(dstColor, color); \
sw_framebuffer_write_color(cptr, dstColor); \
} \
@@ -3396,7 +3122,8 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
for (int i = 0; i != longLen; i += sgnInc) \
{ \
int offset = (y1 + (j >> 16))*fbWidth + (x1 + i); \
- void *dptr = sw_framebuffer_get_depth_addr(dBuffer, offset); \
+ void *dptr = GET_DEPTH_PTR(dBuffer, offset); \
+ void *cptr = NULL; \
\
if (ENABLE_DEPTH_TEST) \
{ \
@@ -3406,17 +3133,16 @@ static inline void FUNC_NAME(const sw_vertex_t *v0, const sw_vertex_t *v1) \
\
sw_framebuffer_write_depth(dptr, z); \
\
- void *cptr = sw_framebuffer_get_color_addr(cBuffer, offset); \
+ cptr = GET_COLOR_PTR(cBuffer, offset); \
\
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
sw_framebuffer_read_color(dstColor, cptr); \
- \
sw_blend_colors(dstColor, color); \
sw_framebuffer_write_color(cptr, dstColor); \
} \
- else sw_framebuffer_write_color(cptr, color); \
+ else sw_framebuffer_write_color(cptr, color); \
\
discardB: \
j += decInc; \
@@ -3444,7 +3170,7 @@ void FUNC_NAME(const sw_vertex_t *v1, const sw_vertex_t *v2) \
\
RASTER_FUNC(v1, v2); \
\
- if (dx != 0 && abs(dy/dx) < 1) \
+ if ((dx != 0) && (abs(dy/dx) < 1)) \
{ \
int wy = (int)((RLSW.lineWidth - 1.0f)*abs(dx)/sqrtf(dx*dx + dy*dy)); \
wy >>= 1; \
@@ -3507,9 +3233,10 @@ static inline void sw_line_render(sw_vertex_t *vertices)
else sw_line_raster(&vertices[0], &vertices[1]);
}
}
+//-------------------------------------------------------------------------------------------
// Point rendering logic
-
+//-------------------------------------------------------------------------------------------
static inline bool sw_point_clip_and_project(sw_vertex_t *v)
{
if (v->homogeneous[3] != 1.0f)
@@ -3551,18 +3278,18 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \
{ \
if (CHECK_BOUNDS == 1) \
{ \
- if (x < RLSW.vpMin[0] || x >= RLSW.vpMax[0]) return; \
- if (y < RLSW.vpMin[1] || y >= RLSW.vpMax[1]) return; \
+ if ((x < RLSW.vpMin[0]) || (x >= RLSW.vpMax[0])) return; \
+ if ((y < RLSW.vpMin[1]) || (y >= RLSW.vpMax[1])) return; \
} \
else if (CHECK_BOUNDS == SW_SCISSOR_TEST) \
{ \
- if (x < RLSW.scMin[0] || x >= RLSW.scMax[0]) return; \
- if (y < RLSW.scMin[1] || y >= RLSW.scMax[1]) return; \
+ if ((x < RLSW.scMin[0]) || (x >= RLSW.scMax[0])) return; \
+ if ((y < RLSW.scMin[1]) || (y >= RLSW.scMax[1])) return; \
} \
\
int offset = y*RLSW.framebuffer.width + x; \
\
- void *dptr = sw_framebuffer_get_depth_addr(RLSW.framebuffer.depth, offset); \
+ void *dptr = GET_DEPTH_PTR(RLSW.framebuffer.depth, offset); \
\
if (ENABLE_DEPTH_TEST) \
{ \
@@ -3572,13 +3299,12 @@ static inline void FUNC_NAME(int x, int y, float z, const float color[4]) \
\
sw_framebuffer_write_depth(dptr, z); \
\
- void *cptr = sw_framebuffer_get_color_addr(RLSW.framebuffer.color, offset); \
+ void *cptr = GET_COLOR_PTR(RLSW.framebuffer.color, offset); \
\
if (ENABLE_COLOR_BLEND) \
{ \
float dstColor[4]; \
sw_framebuffer_read_color(dstColor, cptr); \
- \
sw_blend_colors(dstColor, color); \
sw_framebuffer_write_color(cptr, dstColor); \
} \
@@ -3674,9 +3400,10 @@ static inline void sw_point_render(sw_vertex_t *v)
else sw_point_raster(v->screen[0], v->screen[1], v->homogeneous[2], v->color);
}
}
+//-------------------------------------------------------------------------------------------
// Polygon modes mendering logic
-
+//-------------------------------------------------------------------------------------------
static inline void sw_poly_point_render(void)
{
for (int i = 0; i < RLSW.vertexCounter; i++) sw_point_render(&RLSW.vertexBuffer[i]);
@@ -3687,9 +3414,14 @@ static inline void sw_poly_line_render(void)
const sw_vertex_t *vertices = RLSW.vertexBuffer;
int cm1 = RLSW.vertexCounter - 1;
- for (int i = 0; i < cm1; i++) sw_line_render((sw_vertex_t[2]){ vertices[i], vertices[i + 1] });
+ for (int i = 0; i < cm1; i++)
+ {
+ sw_vertex_t verts[2] = { vertices[i], vertices[i + 1] };
+ sw_line_render(verts);
+ }
- sw_line_render((sw_vertex_t[2]){ vertices[cm1], vertices[0] });
+ sw_vertex_t verts[2] = { vertices[cm1], vertices[0] };
+ sw_line_render(verts);
}
static inline void sw_poly_fill_render(void)
@@ -3711,19 +3443,19 @@ static inline bool sw_is_texture_valid(uint32_t id)
if (id == 0) valid = false;
else if (id >= SW_MAX_TEXTURES) valid = false;
- else if (RLSW.loadedTextures[id].pixels.cptr == 0) valid = false;
+ else if (RLSW.loadedTextures[id].pixels == NULL) valid = false;
return true;
}
static inline bool sw_is_texture_filter_valid(int filter)
{
- return (filter == SW_NEAREST || filter == SW_LINEAR);
+ return ((filter == SW_NEAREST) || (filter == SW_LINEAR));
}
static inline bool sw_is_texture_wrap_valid(int wrap)
{
- return (wrap == SW_REPEAT || wrap == SW_CLAMP);
+ return ((wrap == SW_REPEAT) || (wrap == SW_CLAMP));
}
static inline bool sw_is_draw_mode_valid(int mode)
@@ -3806,6 +3538,7 @@ static inline bool sw_is_blend_dst_factor_valid(int blend)
return result;
}
+//-------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -3817,10 +3550,10 @@ bool swInit(int w, int h)
swViewport(0, 0, w, h);
swScissor(0, 0, w, h);
- RLSW.loadedTextures = SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
+ RLSW.loadedTextures = (sw_texture_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(sw_texture_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
- RLSW.freeTextureIds = SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
+ RLSW.freeTextureIds = (uint32_t *)SW_MALLOC(SW_MAX_TEXTURES*sizeof(uint32_t));
if (RLSW.loadedTextures == NULL) { swClose(); return false; }
RLSW.clearColor[0] = 0.0f;
@@ -3859,26 +3592,24 @@ bool swInit(int w, int h)
RLSW.polyMode = SW_FILL;
RLSW.cullFace = SW_BACK;
- static const float defTex[3*2*2] = {
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f,
+ static uint32_t defaultTex[3*2*2] = {
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF,
+ 0xFFFFFFFF
};
- RLSW.loadedTextures[0].pixels.cptr = defTex;
+ RLSW.loadedTextures[0].pixels = (uint8_t*)defaultTex;
RLSW.loadedTextures[0].width = 2;
RLSW.loadedTextures[0].height = 2;
RLSW.loadedTextures[0].wMinus1 = 1;
RLSW.loadedTextures[0].hMinus1 = 1;
- RLSW.loadedTextures[0].format = SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32;
RLSW.loadedTextures[0].minFilter = SW_NEAREST;
RLSW.loadedTextures[0].magFilter = SW_NEAREST;
RLSW.loadedTextures[0].sWrap = SW_REPEAT;
RLSW.loadedTextures[0].tWrap = SW_REPEAT;
RLSW.loadedTextures[0].tx = 0.5f;
RLSW.loadedTextures[0].ty = 0.5f;
- RLSW.loadedTextures[0].copy = false;
RLSW.loadedTextureCount = 1;
@@ -3887,10 +3618,13 @@ bool swInit(int w, int h)
void swClose(void)
{
+ // NOTE: Starts at texture 1, texture 0 does not have to be freed
for (int i = 1; i < RLSW.loadedTextureCount; i++)
{
- sw_texture_t *texture = &RLSW.loadedTextures[i];
- if (sw_is_texture_valid(i) && texture->copy) SW_FREE(texture->pixels.ptr);
+ if (sw_is_texture_valid(i))
+ {
+ SW_FREE(RLSW.loadedTextures[i].pixels);
+ }
}
SW_FREE(RLSW.framebuffer.color);
@@ -3898,7 +3632,7 @@ void swClose(void)
SW_FREE(RLSW.loadedTextures);
SW_FREE(RLSW.freeTextureIds);
- RLSW = (sw_context_t) { 0 };
+ RLSW = CURLY_INIT(sw_context_t) { 0 };
}
bool swResizeFramebuffer(int w, int h)
@@ -3908,7 +3642,7 @@ bool swResizeFramebuffer(int w, int h)
void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
if (w <= 0)
{
@@ -3930,26 +3664,29 @@ void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type,
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_copy_to_R32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_copy_to_R32G32B32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_copy_to_R32G32B32A32(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_copy_to_R16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_copy_to_R16G16B16(x, y, w, h, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_copy_to_R16G16B16A16(x, y, w, h, pixels); break;
- default: RLSW.errCode = SW_INVALID_ENUM; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_copy_to_GRAYALPHA(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_copy_to_R5G6B5(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_copy_to_R8G8B8(x, y, w, h, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_copy_to_R5G5B5A1(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_copy_to_R4G4B4A4(x, y, w, h, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_copy_to_R8G8B8A8(x, y, w, h, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ break;
}
}
void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels)
{
- sw_pixelformat_t pFormat = sw_get_pixel_format(format, type);
+ sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type);
if (wSrc <= 0)
{
@@ -3971,20 +3708,23 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr
switch (pFormat)
{
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32: sw_framebuffer_blit_to_R32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32: sw_framebuffer_blit_to_R32G32B32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: sw_framebuffer_blit_to_R32G32B32A32(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16: sw_framebuffer_blit_to_R16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16: sw_framebuffer_blit_to_R16G16B16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: sw_framebuffer_blit_to_R16G16B16A16(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, pixels); break;
- default: RLSW.errCode = SW_INVALID_ENUM; break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G6B5: sw_framebuffer_blit_to_R5G6B5(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8: sw_framebuffer_blit_to_R8G8B8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: sw_framebuffer_blit_to_R5G5B5A1(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: sw_framebuffer_blit_to_R4G4B4A4(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint16_t *)pixels); break;
+ case SW_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: sw_framebuffer_blit_to_R8G8B8A8(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break;
+ // Below: not implemented
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16:
+ case SW_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16:
+ default:
+ RLSW.errCode = SW_INVALID_ENUM;
+ break;
}
}
@@ -4392,7 +4132,7 @@ void swRotatef(float angle, float x, float y, float z)
float lengthSq = x*x + y*y + z*z;
- if (lengthSq != 1.0f && lengthSq != 0.0f)
+ if ((lengthSq != 1.0f) && (lengthSq != 0.0f))
{
float invLength = 1.0f/sqrtf(lengthSq);
x *= invLength;
@@ -4553,7 +4293,7 @@ void swBegin(SWdraw mode)
void swEnd(void)
{
- RLSW.drawMode = 0;
+ RLSW.drawMode = (SWdraw)0;
}
void swVertex2i(int x, int y)
@@ -4738,9 +4478,9 @@ void swBindArray(SWarray type, void *buffer)
{
switch (type)
{
- case SW_VERTEX_ARRAY: RLSW.array.positions = buffer; break;
- case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = buffer; break;
- case SW_COLOR_ARRAY: RLSW.array.colors = buffer; break;
+ case SW_VERTEX_ARRAY: RLSW.array.positions = (float *)buffer; break;
+ case SW_TEXTURE_COORD_ARRAY: RLSW.array.texcoords = (float *)buffer; break;
+ case SW_COLOR_ARRAY: RLSW.array.colors = (uint8_t *)buffer; break;
default: break;
}
}
@@ -4801,17 +4541,14 @@ void swDeleteTextures(int count, uint32_t *textures)
continue;
}
- if (RLSW.loadedTextures[textures[i]].copy)
- {
- SW_FREE(RLSW.loadedTextures[textures[i]].pixels.ptr);
- }
+ SW_FREE(RLSW.loadedTextures[textures[i]].pixels);
- RLSW.loadedTextures[textures[i]].pixels.cptr = NULL;
+ RLSW.loadedTextures[textures[i]].pixels = NULL;
RLSW.freeTextureIds[RLSW.freeTextureIdCount++] = textures[i];
}
}
-void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy, const void *data)
+void swTexImage2D(int width, int height, SWformat format, SWtype type, const void *data)
{
uint32_t id = RLSW.currentTexture;
@@ -4831,33 +4568,27 @@ void swTexImage2D(int width, int height, SWformat format, SWtype type, bool copy
sw_texture_t *texture = &RLSW.loadedTextures[id];
- if (copy)
+ int size = width*height;
+ texture->pixels = SW_MALLOC(4*size);
+
+ if (texture->pixels == NULL)
{
- int bytes = sw_get_pixel_bytes(pixelFormat);
- int size = bytes*width*height;
- texture->pixels.ptr = SW_MALLOC(size);
-
- if (texture->pixels.ptr == NULL)
- {
- RLSW.errCode = SW_STACK_OVERFLOW; // WARING: Out of memory...
- return;
- }
-
- for (int i = 0; i < size; i++)
- {
- ((uint8_t *)texture->pixels.ptr)[i] = ((uint8_t *)data)[i];
- }
+ RLSW.errCode = SW_STACK_OVERFLOW; // WARNING: Out of memory...
+ return;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ uint32_t *dst = &((uint32_t*)texture->pixels)[i];
+ sw_get_pixel((uint8_t*)dst, data, i, pixelFormat);
}
- else texture->pixels.cptr = data;
texture->width = width;
texture->height = height;
texture->wMinus1 = width - 1;
texture->hMinus1 = height - 1;
- texture->format = pixelFormat;
texture->tx = 1.0f/width;
texture->ty = 1.0f/height;
- texture->copy = copy;
}
void swTexParameteri(int param, int value)
@@ -4882,7 +4613,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->minFilter = value;
+ texture->minFilter = (SWfilter)value;
} break;
case SW_TEXTURE_MAG_FILTER:
{
@@ -4892,7 +4623,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->magFilter = value;
+ texture->magFilter = (SWfilter)value;
} break;
case SW_TEXTURE_WRAP_S:
{
@@ -4902,7 +4633,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->sWrap = value;
+ texture->sWrap = (SWwrap)value;
} break;
case SW_TEXTURE_WRAP_T:
{
@@ -4912,7 +4643,7 @@ void swTexParameteri(int param, int value)
return;
}
- texture->tWrap = value;
+ texture->tWrap = (SWwrap)value;
} break;
default: RLSW.errCode = SW_INVALID_ENUM; break;
}
@@ -4926,7 +4657,7 @@ void swBindTexture(uint32_t id)
return;
}
- if (RLSW.loadedTextures[id].pixels.cptr == NULL)
+ if (RLSW.loadedTextures[id].pixels == NULL)
{
RLSW.errCode = SW_INVALID_OPERATION;
return;
diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c
index 6ecc41888..47dcce32b 100644
--- a/src/platforms/rcore_android.c
+++ b/src/platforms/rcore_android.c
@@ -461,7 +461,7 @@ int GetCurrentMonitor(void)
if (display == NULL)
{
TRACELOG(LOG_ERROR, "GetCurrentMonitor() couldn't get the display object");
- }
+ }
else
{
jclass displayClass = (*env)->FindClass(env, "android/view/Display");
diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c
index 729ca308c..5dde1df67 100644
--- a/src/platforms/rcore_desktop_glfw.c
+++ b/src/platforms/rcore_desktop_glfw.c
@@ -1048,6 +1048,7 @@ Image GetClipboardImage(void)
void ShowCursor(void)
{
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
CORE.Input.Mouse.cursorHidden = false;
}
@@ -1055,6 +1056,7 @@ void ShowCursor(void)
void HideCursor(void)
{
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+
CORE.Input.Mouse.cursorHidden = true;
}
@@ -1075,13 +1077,10 @@ void EnableCursor(void)
void DisableCursor(void)
{
// Reset mouse position within the window area before disabling cursor
- SetMousePosition(CORE.Window.screen.width, CORE.Window.screen.height);
+ SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
glfwSetInputMode(platform.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- // Set cursor position in the middle
- SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
-
if (glfwRawMouseMotionSupported()) glfwSetInputMode(platform.handle, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
CORE.Input.Mouse.cursorLocked = true;
diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c
index 52ec6ac94..86842140d 100644
--- a/src/platforms/rcore_desktop_rgfw.c
+++ b/src/platforms/rcore_desktop_rgfw.c
@@ -80,7 +80,7 @@ void CloseWindow(void);
#define CloseWindow CloseWindow_win32
#define ShowCursor __imp_ShowCursor
#define _APISETSTRING_
-
+
#undef MAX_PATH
#if defined(__cplusplus)
@@ -262,7 +262,7 @@ static int RGFW_gpConvTable[18] = {
[RGFW_gamepadRight] = GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
[RGFW_gamepadDown] = GAMEPAD_BUTTON_LEFT_FACE_DOWN,
[RGFW_gamepadLeft] = GAMEPAD_BUTTON_LEFT_FACE_LEFT,
- [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
+ [RGFW_gamepadL3] = GAMEPAD_BUTTON_LEFT_THUMB,
[RGFW_gamepadR3] = GAMEPAD_BUTTON_RIGHT_THUMB,
};
@@ -933,7 +933,7 @@ void PollInputEvents(void)
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
#endif
-
+
// Reset keys/chars pressed registered
CORE.Input.Keyboard.keyPressedQueueCount = 0;
CORE.Input.Keyboard.charPressedQueueCount = 0;
@@ -1025,7 +1025,7 @@ void PollInputEvents(void)
CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event->droppedFiles[i]);
-
+
CORE.Window.dropFileCount++;
}
else if (CORE.Window.dropFileCount < 1024)
@@ -1229,7 +1229,7 @@ void PollInputEvents(void)
int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER)? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2;
int pressed = (value > 0.1f);
CORE.Input.Gamepad.currentButtonState[event->gamepad][button] = pressed;
-
+
if (pressed) CORE.Input.Gamepad.lastButtonPressed = button;
else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0;
}
@@ -1345,7 +1345,7 @@ int InitPlatform(void)
// TODO: Is this needed by raylib now?
// If so, rcore_desktop_sdl should be updated too
//SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height);
-
+
if (CORE.Window.flags & FLAG_VSYNC_HINT) RGFW_window_swapInterval(platform.window, 1);
RGFW_window_makeCurrent(platform.window);
diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c
index 6655db460..e135cd848 100644
--- a/src/platforms/rcore_desktop_sdl.c
+++ b/src/platforms/rcore_desktop_sdl.c
@@ -104,7 +104,6 @@ typedef struct {
SDL_GameController *gamepad[MAX_GAMEPADS];
SDL_JoystickID gamepadId[MAX_GAMEPADS]; // Joystick instance ids, they do not start from 0
SDL_Cursor *cursor;
- bool cursorRelative;
} PlatformData;
//----------------------------------------------------------------------------------
@@ -838,7 +837,11 @@ void SetWindowPosition(int x, int y)
void SetWindowMonitor(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
// NOTE:
// 1. SDL started supporting moving exclusive fullscreen windows between displays on SDL3,
@@ -962,7 +965,11 @@ int GetCurrentMonitor(void)
Vector2 GetMonitorPosition(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_Rect displayBounds;
@@ -986,7 +993,11 @@ int GetMonitorWidth(int monitor)
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1003,7 +1014,11 @@ int GetMonitorHeight(int monitor)
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1020,7 +1035,11 @@ int GetMonitorPhysicalWidth(int monitor)
int width = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
@@ -1040,7 +1059,11 @@ int GetMonitorPhysicalHeight(int monitor)
int height = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
float ddpi = 0.0f;
SDL_GetDisplayDPI(monitor, &ddpi, NULL, NULL);
@@ -1060,7 +1083,11 @@ int GetMonitorRefreshRate(int monitor)
int refresh = 0;
const int monitorCount = SDL_GetNumVideoDisplays();
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
if ((monitor >= 0) && (monitor < monitorCount))
+#endif
{
SDL_DisplayMode mode;
SDL_GetCurrentDisplayMode(monitor, &mode);
@@ -1076,7 +1103,14 @@ const char *GetMonitorName(int monitor)
{
const int monitorCount = SDL_GetNumVideoDisplays();
- if ((monitor >= 0) && (monitor < monitorCount)) return SDL_GetDisplayName(monitor);
+#if defined(USING_VERSION_SDL3) // SDL3 Migration: Monitor is an id instead of index now, returns 0 on failure
+ if ((monitor > 0) && (monitor <= monitorCount))
+#else
+ if ((monitor >= 0) && (monitor < monitorCount))
+#endif
+ {
+ return SDL_GetDisplayName(monitor);
+ }
else TRACELOG(LOG_WARNING, "SDL: Failed to find selected monitor");
return "";
@@ -1209,13 +1243,13 @@ void EnableCursor(void)
SDL_SetRelativeMouseMode(SDL_FALSE);
#if defined(USING_VERSION_SDL3)
- // SDL_ShowCursor() has been split into three functions: SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
+ // NOTE: SDL_ShowCursor() has been split into three functions:
+ // SDL_ShowCursor(), SDL_HideCursor(), and SDL_CursorVisible()
SDL_ShowCursor();
#else
SDL_ShowCursor(SDL_ENABLE);
#endif
- platform.cursorRelative = false;
CORE.Input.Mouse.cursorLocked = false;
}
@@ -1224,7 +1258,6 @@ void DisableCursor(void)
{
SDL_SetRelativeMouseMode(SDL_TRUE);
- platform.cursorRelative = true;
CORE.Input.Mouse.cursorLocked = true;
}
@@ -1332,7 +1365,7 @@ void PollInputEvents(void)
CORE.Input.Mouse.currentWheelMove.y = 0;
// Register previous mouse position
- if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
+ if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
// Reset last gamepad button/axis registered state
@@ -1634,7 +1667,7 @@ void PollInputEvents(void)
} break;
case SDL_MOUSEMOTION:
{
- if (platform.cursorRelative)
+ if (CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition.x = (float)event.motion.xrel;
CORE.Input.Mouse.currentPosition.y = (float)event.motion.yrel;
diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c
index 3ccd4d3bd..5b67c72b0 100644
--- a/src/platforms/rcore_desktop_win32.c
+++ b/src/platforms/rcore_desktop_win32.c
@@ -49,8 +49,6 @@
#define CloseWindow CloseWindowWin32
#define Rectangle RectangleWin32
#define ShowCursor ShowCursorWin32
-#define LoadImageA LoadImageAWin32
-#define LoadImageW LoadImageWin32
#define DrawTextA DrawTextAWin32
#define DrawTextW DrawTextWin32
#define DrawTextExA DrawTextExAWin32
@@ -63,8 +61,6 @@
#undef Rectangle // raylib symbol collision
#undef ShowCursor // raylib symbol collision
#undef LoadImage // raylib symbol collision
-#undef LoadImageA
-#undef LoadImageW
#undef DrawText // raylib symbol collision
#undef DrawTextA
#undef DrawTextW
@@ -84,29 +80,31 @@
// Types and Structures Definition
//----------------------------------------------------------------------------------
-// NOTE: appScreenSize is the last screen size requested by the app,
-// the backend must keep the client area this size (after DPI scaling is applied)
+// NOTE: appScreenSize is the last screen size requested by the app,
+// the backend must keep the client area this size (after DPI scaling is applied)
// when the window isn't fullscreen/maximized/minimized
typedef struct {
HWND hwnd; // Window handler
HDC hdc; // Graphic context handler
HGLRC glContext; // OpenGL context handler
+
// Software renderer variables
HDC hdcmem; // Memory graphic context handler
HBITMAP hbitmap; // GDI bitmap handler
unsigned int *pixels; // Pointer to pixel data buffer (BGRA format)
- LARGE_INTEGER timerFrequency;
unsigned int appScreenWidth;
unsigned int appScreenHeight;
unsigned int desiredFlags;
- bool cursorEnabled;
+
+ LARGE_INTEGER timerFrequency;
} PlatformData;
// Define WGL function pointer types (no wglext.h needed)
typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
typedef BOOL (WINAPI *PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC, const int *, const FLOAT *, UINT, int *, UINT *);
typedef BOOL (WINAPI *PFNWGLSWAPINTERVALEXTPROC)(int);
+typedef const char *(WINAPI *PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC hdc);
//----------------------------------------------------------------------------------
// Global Variables Definition
@@ -119,6 +117,7 @@ static PlatformData platform = { 0 }; // Platform specific data
static PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;
static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
+static PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = NULL;
// --------------------------------------------------------------------------------
// This part of the file contains pure functions that never access global state
@@ -133,12 +132,12 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
// Defines and Macros
//----------------------------------------------------------------------------------
#define A_TO_W_ALLOCA(outWstr, inAnsi) do { \
- size_t len = AToWLen(inAnsi); \
- outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(len + 1)); \
- AToWCopy(outWstr, len, inAnsi); \
- outWstr[len] = 0; \
+ size_t outLen = AToWLen(inAnsi); \
+ outWstr = (WCHAR *)alloca(sizeof(WCHAR)*(outLen + 1)); \
+ AToWCopy(inAnsi, outWstr, outLen); \
+ outWstr[outLen] = 0; \
} while (0)
-
+
#define STYLE_MASK_ALL 0xffffffff
#define STYLE_MASK_READONLY (WS_MINIMIZE | WS_MAXIMIZE)
#define STYLE_MASK_WRITABLE (~STYLE_MASK_READONLY)
@@ -150,7 +149,7 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
#define WINDOW_STYLE_EX 0
-#define CLASS_NAME L"RaylibWindow"
+#define CLASS_NAME L"raylibWindow"
#define FLAG_MASK_OPTIONAL (FLAG_VSYNC_HINT)
#define FLAG_MASK_REQUIRED ~(FLAG_MASK_OPTIONAL)
@@ -196,93 +195,86 @@ static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_ES_PROFILE_BIT_EXT 0x00000004
+#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
-typedef enum { MIZED_NONE, MIZED_MIN, MIZED_MAX } Mized;
-
+// Maximize-minimize request types
typedef enum {
- UPDATE_WINDOW_FIRST,
- UPDATE_WINDOW_NORMAL,
-} UpdateWindowKind;
-
-typedef enum {
- SANITIZE_FLAGS_FIRST,
- SANITIZE_FLAGS_NORMAL,
-} SanitizeFlagsKind;
-
-typedef struct {
- HMONITOR needle;
- int index;
- int matchIndex;
- RECT rect;
-} FindMonitorContext;
+ MIZED_NONE,
+ MIZED_MIN,
+ MIZED_MAX
+} Mized;
+// Flag operations
+// NOTE: Some ops need to be deferred
typedef struct {
DWORD set;
DWORD clear;
} FlagsOp;
+// Monitor info type
+typedef struct {
+ HMONITOR needle;
+ int index;
+ int matchIndex;
+ RECT rect;
+} MonitorInfo;
+
//----------------------------------------------------------------------------------
// Module Internal Functions Declaration
//----------------------------------------------------------------------------------
-static size_t AToWLen(const char *a)
+// Get ASCII to WCHAR length
+static size_t AToWLen(const char *ascii)
{
- int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, a, -1, NULL, 0);
-
- if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "Failed to calculate wide length, result=%d, error=%u", sizeNeeded, GetLastError());
+ int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, NULL, 0);
+
+ if (sizeNeeded < 0) TRACELOG(LOG_ERROR, "WIN32: Failed to calculate wide length [ERROR: %u]", GetLastError());
return sizeNeeded;
}
-static void AToWCopy(wchar_t *outPtr, size_t outLen, const char *a)
+
+// Copy ASCII to WCHAR string
+static void AToWCopy(const char *ascii, wchar_t *outPtr, size_t outLen)
{
- int size = MultiByteToWideChar(CP_UTF8, 0, a, -1, outPtr, (int)outLen);
- if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Convert %zu UTF-8 chars to WCHAR but converted %zu", outLen, size);
+ int size = MultiByteToWideChar(CP_UTF8, 0, ascii, -1, outPtr, (int)outLen);
+ if (size != outLen) TRACELOG(LOG_WARNING, "WIN32: Failed to convert %i UTF-8 chars to WCHAR, converted %i chars", outLen, size);
}
static bool DecoratedFromStyle(DWORD style)
{
if (style & STYLE_FLAGS_UNDECORATED_ON)
{
- if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x has both undecorated on/off flags", style);
+ if (style & STYLE_FLAGS_UNDECORATED_OFF) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x has both undecorated on/off flags", style);
return false; // Not decorated
}
DWORD masked = (style & STYLE_FLAGS_UNDECORATED_OFF);
- if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "FLAGS: Style 0x%x is missing these flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF);
+ if (STYLE_FLAGS_UNDECORATED_OFF != masked) TRACELOG(LOG_ERROR, "WIN32: FLAGS: Style 0x%x is missing flags 0x%x", masked, masked ^ STYLE_FLAGS_UNDECORATED_OFF);
return true; // Decorated
}
-static Mized MizedFromStyle(DWORD style)
-{
- // Minimized takes precedence over maximized
- if (style & WS_MINIMIZE) return MIZED_MIN;
- if (style & WS_MAXIMIZE) return MIZED_MAX;
- return MIZED_NONE;
-}
-
-static Mized MizedFromFlags(unsigned flags)
-{
- // minimized takes precedence over maximized
- if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) return MIZED_MIN;
- if (flags & FLAG_WINDOW_MAXIMIZED) return MIZED_MAX;
- return MIZED_NONE;
-}
-
+// Get window style from required flags
static DWORD MakeWindowStyle(unsigned flags)
{
- // we don't need this since we don't have any child windows, but I guess
+ // We don't need this since we don't have any child windows, but I guess
// it improves efficiency, plus, windows adds this flag automatically anyway
// so it keeps our flags in sync with the OS
- DWORD style = WS_CLIPSIBLINGS ;
-
+ DWORD style = WS_CLIPSIBLINGS;
+
style |= (flags & FLAG_WINDOW_HIDDEN)? 0 : WS_VISIBLE;
style |= (flags & FLAG_WINDOW_RESIZABLE)? STYLE_FLAGS_RESIZABLE : 0;
style |= (flags & FLAG_WINDOW_UNDECORATED)? STYLE_FLAGS_UNDECORATED_ON : STYLE_FLAGS_UNDECORATED_OFF;
- switch (MizedFromFlags(flags))
+ // Minimized takes precedence over maximized
+ int mized = MIZED_NONE;
+ if (FLAG_CHECK(flags, FLAG_WINDOW_MINIMIZED)) mized = MIZED_MIN;
+ if (flags & FLAG_WINDOW_MAXIMIZED) mized = MIZED_MAX;
+
+ switch (mized)
{
case MIZED_NONE: break;
case MIZED_MIN: style |= WS_MINIMIZE; break;
@@ -293,15 +285,13 @@ static DWORD MakeWindowStyle(unsigned flags)
return style;
}
-// Enforces that the actual window/platform state is in sync with raylib's flags
+// Check flags state, enforces that the actual window/platform state is in sync with raylib's flags
static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expectedStyle, DWORD styleCheckMask)
{
- //TRACELOG(LOG_INFO, "Verifying Flags 0x%x Style 0x%x Mask 0x%x", flags, expectedStyle & styleCheckMask, styleCheckMask);
-
DWORD styleFromFlags = MakeWindowStyle(flags);
if ((styleFromFlags & styleCheckMask) != (expectedStyle & styleCheckMask))
{
- TRACELOG(LOG_ERROR, "%s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: window flags (0x%x) produced style 0x%x which != expected 0x%x (diff=0x%x, mask=0x%x)",
context, flags, styleFromFlags & styleCheckMask, expectedStyle & styleCheckMask,
(styleFromFlags & styleCheckMask) ^ (expectedStyle & styleCheckMask), styleCheckMask);
}
@@ -310,7 +300,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
LONG actualStyle = (LONG)GetWindowLongPtrW(hwnd, GWL_STYLE);
if ((actualStyle & styleCheckMask) != (expectedStyle & styleCheckMask))
{
- TRACELOG(LOG_ERROR, "%s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s: expected style 0x%x but got 0x%x (diff=0x%x, mask=0x%x, lasterror=%lu)",
context, expectedStyle & styleCheckMask, actualStyle & styleCheckMask,
(expectedStyle & styleCheckMask) ^ (actualStyle & styleCheckMask),
styleCheckMask, GetLastError());
@@ -320,7 +310,7 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
{
bool isIconic = IsIconic(hwnd);
bool styleMinimized = !!(WS_MINIMIZE & actualStyle);
- if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
+ if (isIconic != styleMinimized) TRACELOG(LOG_ERROR, "WIN32: FLAGS: IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
}
if (styleCheckMask & WS_MAXIMIZE)
@@ -329,49 +319,32 @@ static void CheckFlags(const char *context, HWND hwnd, DWORD flags, DWORD expect
placement.length = sizeof(placement);
if (!GetWindowPlacement(hwnd, &placement))
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: %s failed, error=%lu", "GetWindowPlacement", GetLastError());
}
bool placementMaximized = (placement.showCmd == SW_SHOWMAXIMIZED);
bool styleMaximized = WS_MAXIMIZE & actualStyle;
if (placementMaximized != styleMaximized)
{
- TRACELOG(LOG_ERROR, "maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d",
+ TRACELOG(LOG_ERROR, "WIN32: FLAGS: Maximized state desync, placement maximized=%d (showCmd=%lu) style maximized=%d",
placementMaximized, placement.showCmd, styleMaximized);
}
}
}
-static SIZE PxFromPt2(float dpiScale, bool highdpiEnabled, int screenWidth, int screenHeight)
-{
- // Get size in pixels from points
- return (SIZE){
- highdpiEnabled? (int)((float)screenWidth*dpiScale) : screenWidth,
- highdpiEnabled? (int)((float)screenHeight*dpiScale) : screenHeight,
- };
-}
-
-static SIZE GetClientSize(HWND hwnd)
-{
- RECT rect = { 0 };
-
- if (GetClientRect(hwnd, &rect) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError());
-
- return (SIZE){ rect.right, rect.bottom };
-}
-
+// Calculate window size (with borders, title-bar...) from desired client size (framebuffer size)
static SIZE CalcWindowSize(UINT dpi, SIZE clientSize, DWORD style)
{
RECT rect = { 0, 0, clientSize.cx, clientSize.cy };
-
+
int result = AdjustWindowRectExForDpi(&rect, style, 0, WINDOW_STYLE_EX, dpi);
-
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "AdjustWindowRect", GetLastError());
+ if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to adjust window rect [ERROR: %lu]", GetLastError());
return (SIZE){ rect.right - rect.left, rect.bottom - rect.top };
}
-// returns true if the window size was updated, false otherwise
-static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int height, unsigned flags)
+// Update window size if required
+// NOTE: Returns true if the window size was updated, false otherwise
+static bool UpdateWindowSize(int mode, HWND hwnd, int width, int height, unsigned flags)
{
if (flags & FLAG_WINDOW_MINIMIZED) return false;
@@ -386,10 +359,10 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
MONITORINFO info = { 0 };
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError());
RECT windowRect = { 0 };
- if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowRect", GetLastError());
+ if (!GetWindowRect(hwnd, &windowRect)) TRACELOG(LOG_ERROR, "WIN32: Failed to get window rect [ERROR: %lu]", GetLastError());
if ((windowRect.left == info.rcMonitor.left) &&
(windowRect.top == info.rcMonitor.top) &&
@@ -402,33 +375,45 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
info.rcMonitor.bottom - info.rcMonitor.top,
SWP_NOOWNERZORDER))
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: Failed to set window position [ERROR: %lu]", GetLastError());
}
return true;
}
+ // Get size in pixels from points, considering high-dpi
UINT dpi = GetDpiForWindow(hwnd);
float dpiScale = ((float)dpi)/96.0f;
bool dpiScaling = flags & FLAG_WINDOW_HIGHDPI;
- SIZE desired = PxFromPt2(dpiScale, dpiScaling, width, height);
- SIZE actual = GetClientSize(hwnd);
- if ((actual.cx == desired.cx) || (actual.cy == desired.cy)) return false;
+ SIZE desiredSize = {
+ .cx = dpiScaling? (int)((float)width*dpiScale) : width,
+ .cy = dpiScaling? (int)((float)height*dpiScale) : height
+ };
- TRACELOG(LOG_INFO, "Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)",
- actual.cx, actual.cy, desired.cx, desired.cy, dpi, dpiScaling, width, height);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
- SIZE windowSize = CalcWindowSize(dpi, desired, MakeWindowStyle(flags));
- POINT windowPos = (POINT){ 0, 0 };
+ // If client size is alread desired size, no need to update
+ if ((clientSize.cx == desiredSize.cx) || (clientSize.cy == desiredSize.cy)) return false;
+
+ TRACELOG(LOG_INFO, "WIN32: Restoring client size from [%dx%d] to [%dx%d] (dpi:%lu dpiScaling:%d app:%ix%i)",
+ clientSize.cx, clientSize.cy, desiredSize.cx, desiredSize.cy, dpi, dpiScaling, width, height);
+
+ // Calculate window size from desired framebuffer size and window flags
+ SIZE windowSize = CalcWindowSize(dpi, desiredSize, MakeWindowStyle(flags));
+ POINT windowPos = { 0 };
UINT swpFlags = SWP_NOZORDER | SWP_FRAMECHANGED;
- if (kind == UPDATE_WINDOW_FIRST)
+
+ if (mode == 0) // UPDATE_WINDOW_FIRST
{
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
- if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError());
+ if (!monitor) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor from window [ERROR: %lu]", GetLastError());
- MONITORINFO info;
+ MONITORINFO info = { 0 };
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: Failed to get monitor info [ERROR: %lu]", GetLastError());
#define MAX(a,b) (((a)>(b))? (a):(b))
@@ -446,24 +431,19 @@ static bool UpdateWindowSize(UpdateWindowKind kind, HWND hwnd, int width, int he
//AdjustWindowRectEx(&rc, WS_OVERLAPPEDWINDOW, FALSE, 0);
//SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER);
- // Old code
- //if (!SetWindowPos(hwnd, NULL, windowPos.x, windowPos.y, windowSize.cx, windowSize.cy, swpFlags))
- //{
- // TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
- //}
-
return true;
}
+// Verify if we are running in Windows 10 version 1703 (Creators Update)
static BOOL IsWindows10Version1703OrGreaterWin32(void)
{
HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
-
- DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) =
+
+ DWORD (*Verify)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG) =
(DWORD (*)(RTL_OSVERSIONINFOEXW*, ULONG, ULONGLONG))GetProcAddress(ntdll, "RtlVerifyVersionInfo");
if (!Verify)
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetProcAddress 'RtlVerifyVersionInfo'", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: Failed to verify Windows version [ERROR: %lu]", GetLastError());
return 0;
}
@@ -472,11 +452,12 @@ static BOOL IsWindows10Version1703OrGreaterWin32(void)
osvi.dwMajorVersion = 10;
osvi.dwMinorVersion = 0;
osvi.dwBuildNumber = 15063; // Build 15063 corresponds to Windows 10 version 1703 (Creators Update)
+
DWORDLONG cond = 0;
VER_SET_CONDITION(cond, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(cond, VER_BUILDNUMBER, VER_GREATER_EQUAL);
-
+
return 0 == (*Verify)(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER, cond);
}
@@ -488,8 +469,8 @@ static void *WglGetProcAddress(const char *procname)
if ((proc == NULL) ||
// NOTE: Some GPU drivers could return following
// invalid sentinel values instead of NULL
- (proc == (void *)0x1) ||
- (proc == (void *)0x2) ||
+ (proc == (void *)0x1) ||
+ (proc == (void *)0x2) ||
(proc == (void *)0x3) ||
(proc == (void *)-1))
{
@@ -504,7 +485,8 @@ static void *WglGetProcAddress(const char *procname)
return proc;
}
-static KeyboardKey KeyFromWparam(WPARAM wparam)
+// Get key from wparam (mapping)
+static KeyboardKey GetKeyFromWparam(WPARAM wparam)
{
switch (wparam)
{
@@ -687,6 +669,7 @@ static KeyboardKey KeyFromWparam(WPARAM wparam)
}
}
+// Get cursor name
static LPCWSTR GetCursorName(int cursor)
{
LPCWSTR name = (LPCWSTR)IDC_ARROW;
@@ -710,37 +693,46 @@ static LPCWSTR GetCursorName(int cursor)
return name;
}
-static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam)
+// Count monitors process
+// NOTE: Required by GetMonitorCount()
+static BOOL CALLBACK CountMonitorsProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam)
{
int *count = (int *)lparam;
*count += 1;
+
// Always return TRUE to continue the loop, otherwise, the caller
// can't distinguish between stopping the loop and an error
return TRUE;
}
-static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC _, LPRECT rect, LPARAM lparam)
+// Find monitor process
+// NOTE: Required by GetCurrentMonitor()
+static BOOL CALLBACK FindMonitorProc(HMONITOR handle, HDC hdc, LPRECT rect, LPARAM lparam)
{
- FindMonitorContext *c = (FindMonitorContext*)lparam;
- if (handle == c->needle)
+ MonitorInfo *monitor = (MonitorInfo *)lparam;
+
+ if (handle == monitor->needle)
{
- c->matchIndex = c->index;
- c->rect = *rect;
+ monitor->matchIndex = monitor->index;
+ monitor->rect = *rect;
}
- c->index += 1;
+ monitor->index += 1;
+
// Always return TRUE to continue the loop, otherwise, the caller
// can't distinguish between stopping the loop and an error
return TRUE;
}
-static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsOp *deferredFlags)
+// Get style changed required operations flags
+// NOTE: Required for deferred operations
+static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *style, FlagsOp *deferredFlags)
{
// Check window resizable flag change
bool resizable = (coreWindowFlags & FLAG_WINDOW_RESIZABLE);
- bool resizableOld = ((ss->styleOld & STYLE_FLAGS_RESIZABLE) != 0);
- bool resizableNew = ((ss->styleNew & STYLE_FLAGS_RESIZABLE) != 0);
- if (resizable != resizableOld) TRACELOG(LOG_ERROR, "expected resizable %u but got %u", resizable, resizableOld);
+ bool resizableOld = ((style->styleOld & STYLE_FLAGS_RESIZABLE) != 0);
+ bool resizableNew = ((style->styleNew & STYLE_FLAGS_RESIZABLE) != 0);
+ if (resizable != resizableOld) TRACELOG(LOG_ERROR, "WIN32: Expected resizable %u but got %u", resizable, resizableOld);
if (resizableOld != resizableNew)
{
if (resizableNew) deferredFlags->set |= FLAG_WINDOW_RESIZABLE;
@@ -749,9 +741,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
// Check window decorated flag change
bool decorated = (0 == (coreWindowFlags & FLAG_WINDOW_UNDECORATED));
- bool decoratedOld = DecoratedFromStyle(ss->styleOld);
- bool decoratedNew = DecoratedFromStyle(ss->styleNew);
- if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "expected decorated %u but got %u", decorated, decoratedOld);
+ bool decoratedOld = DecoratedFromStyle(style->styleOld);
+ bool decoratedNew = DecoratedFromStyle(style->styleNew);
+ if (decorated != decoratedOld) TRACELOG(LOG_ERROR, "WIN32: Expected decorated %u but got %u", decorated, decoratedOld);
if (decoratedOld != decoratedNew)
{
if (decoratedNew) deferredFlags->clear |= FLAG_WINDOW_UNDECORATED;
@@ -760,9 +752,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
// Check window hidden flag change
bool hidden = (coreWindowFlags & FLAG_WINDOW_HIDDEN);
- bool hiddenOld = ((ss->styleOld & WS_VISIBLE) == 0);
- bool hiddenNew = ((ss->styleNew & WS_VISIBLE) == 0);
- if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "expected hidden %u but got %u", hidden, hiddenOld);
+ bool hiddenOld = ((style->styleOld & WS_VISIBLE) == 0);
+ bool hiddenNew = ((style->styleNew & WS_VISIBLE) == 0);
+ if (hidden != hiddenOld) TRACELOG(LOG_ERROR, "WIN32: Expected hidden %u but got %u", hidden, hiddenOld);
if (hiddenOld != hiddenNew)
{
if (hiddenNew) deferredFlags->set |= FLAG_WINDOW_HIDDEN;
@@ -770,7 +762,9 @@ static void GetStyleChangeFlagOps(DWORD coreWindowFlags, STYLESTRUCT *ss, FlagsO
}
}
-// Call when the window is rezised, returns true if the new window size should update the desired app size
+// Adopt window resize
+// NOTE: Call when the window is rezised, returns true
+// if the new window size should update the desired app size
static bool AdoptWindowResize(unsigned flags)
{
if (flags & FLAG_WINDOW_MINIMIZED) return false;
@@ -778,7 +772,7 @@ static bool AdoptWindowResize(unsigned flags)
if (flags & FLAG_FULLSCREEN_MODE) return false;
if (flags & FLAG_BORDERLESS_WINDOWED_MODE) return false;
if (!(flags & FLAG_WINDOW_RESIZABLE)) return false;
-
+
return true;
}
@@ -805,9 +799,12 @@ static void HandleRawInput(LPARAM lparam);
static void HandleWindowResize(HWND hwnd, int *width, int *height);
static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags);
-static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags);
+static unsigned SanitizeFlags(int mode, unsigned flags);
static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height); // Update window flags
+// Check if OpenGL extension is available
+static bool IsWglExtensionAvailable(HDC hdc, const char *extension);
+
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
@@ -826,20 +823,14 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
- TRACELOG(LOG_WARNING, "ToggleFullscreen not implemented");
+ TRACELOG(LOG_WARNING, "WIN32: Toggle full screen functionality not implemented");
}
// Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
- if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE)
- {
- ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
- }
- else
- {
- SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
- }
+ if (CORE.Window.flags & FLAG_BORDERLESS_WINDOWED_MODE) ClearWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
+ else SetWindowState(FLAG_BORDERLESS_WINDOWED_MODE);
}
// Set window state: maximized, if resizable
@@ -858,57 +849,123 @@ void MinimizeWindow(void)
void RestoreWindow(void)
{
if ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) &&
- (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)
- ) {
- ClearWindowState(FLAG_WINDOW_MINIMIZED);
- }
- else
- {
- ClearWindowState(FLAG_WINDOW_MINIMIZED|FLAG_WINDOW_MAXIMIZED);
- }
+ (CORE.Window.flags & FLAG_WINDOW_MINIMIZED)) ClearWindowState(FLAG_WINDOW_MINIMIZED);
+ else ClearWindowState(FLAG_WINDOW_MINIMIZED | FLAG_WINDOW_MAXIMIZED);
}
// Set window configuration state using flags
void SetWindowState(unsigned int flags)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags | flags);
+ platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags | flags);
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
}
// Clear window configuration state flags
void ClearWindowState(unsigned int flags)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_NORMAL, CORE.Window.flags & ~flags);
+ platform.desiredFlags = SanitizeFlags(1 /*SANITIZE_FLAGS_NORMAL*/, CORE.Window.flags & ~flags);
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
}
// Set icon for window
void SetWindowIcon(Image image)
{
- TRACELOG(LOG_WARNING, "SetWindowIcon not implemented");
+ if (!platform.hwnd || (image.data == NULL) || (image.width <= 0) || (image.height <= 0)) return;
+
+ HDC hdc = GetDC(platform.hwnd);
+
+ // Create 32-bit BGRA DIB for color
+ BITMAPV5HEADER bi = { 0 };
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bV5Size = sizeof(bi);
+ bi.bV5Width = image.width;
+ bi.bV5Height = -image.height; // Negative = top-down bitmap
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5RedMask = 0x00FF0000;
+ bi.bV5GreenMask = 0x0000FF00;
+ bi.bV5BlueMask = 0x000000FF;
+ bi.bV5AlphaMask = 0xFF000000;
+
+ unsigned char *targetBits = NULL;
+ HBITMAP hColorBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&targetBits, NULL, 0);
+ if (!hColorBitmap)
+ {
+ ReleaseDC(platform.hwnd, hdc);
+ return;
+ }
+
+ // Copy RGBA > BGRA (Win32 expects BGRA)
+ for (int y = 0; y < image.height; y++)
+ {
+ for (int x = 0; x < image.width; x++)
+ {
+ int i = (y*image.width + x)*4;
+ targetBits[i + 0] = ((unsigned char *)image.data)[i + 2]; // B
+ targetBits[i + 1] = ((unsigned char *)image.data)[i + 1]; // G
+ targetBits[i + 2] = ((unsigned char *)image.data)[i + 0]; // R
+ targetBits[i + 3] = ((unsigned char *)image.data)[i + 3]; // A
+ }
+ }
+
+ // Create mask bitmap (1-bit, all opaque)
+ HBITMAP hMaskBitmap = CreateBitmap(image.width, image.height, 1, 1, NULL);
+
+ // Build icon info
+ ICONINFO ii = { 0 };
+ ZeroMemory(&ii, sizeof(ii));
+ ii.fIcon = TRUE;
+ ii.hbmMask = hMaskBitmap;
+ ii.hbmColor = hColorBitmap;
+
+ HICON hIcon = CreateIconIndirect(&ii);
+
+ // Clean up GDI bitmaps (icon keeps copies internally)
+ DeleteObject(hColorBitmap);
+ DeleteObject(hMaskBitmap);
+ ReleaseDC(platform.hwnd, hdc);
+
+ if (hIcon)
+ {
+ // Set both large and small icons
+ SendMessage(platform.hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
+ SendMessage(platform.hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
+ }
}
// Set icon for window
void SetWindowIcons(Image *images, int count)
{
- TRACELOG(LOG_WARNING, "SetWindowIcons not implemented");
+ // TODO.
}
void SetWindowTitle(const char *title)
{
CORE.Window.title = title;
-
+
WCHAR *titleWide = NULL;
A_TO_W_ALLOCA(titleWide, CORE.Window.title);
-
+
int result = SetWindowTextW(platform.hwnd, titleWide);
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowText", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to set window title [ERROR: %lu]", GetLastError());
}
// Set window position on screen (windowed mode)
void SetWindowPosition(int x, int y)
{
- TRACELOG(LOG_WARNING, "SetWindowPosition not implemented");
+ if (platform.hwnd != NULL)
+ {
+ RECT rect = { 0 };
+ if (GetWindowRect(platform.hwnd, &rect))
+ {
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+
+ // Move the window to the new position (keeping size and z-order)
+ SetWindowPos(platform.hwnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ }
}
// Set monitor for the current window
@@ -962,7 +1019,7 @@ void *GetWindowHandle(void)
int GetMonitorCount(void)
{
int count = 0;
-
+
int result = EnumDisplayMonitors(NULL, NULL, CountMonitorsProc, (LPARAM)&count);
if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError());
@@ -975,15 +1032,15 @@ int GetCurrentMonitor(void)
HMONITOR monitor = MonitorFromWindow(platform.hwnd, MONITOR_DEFAULTTOPRIMARY);
if (!monitor) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "MonitorFromWindow", GetLastError());
- FindMonitorContext context;
- context.needle = monitor;
- context.index = 0;
- context.matchIndex = -1;
-
- int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&context);
+ MonitorInfo info = { 0 };
+ info.needle = monitor;
+ info.index = 0;
+ info.matchIndex = -1;
+
+ int result = EnumDisplayMonitors(NULL, NULL, FindMonitorProc, (LPARAM)&info);
if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "EnumDisplayMonitors", GetLastError());
- return context.matchIndex;
+ return info.matchIndex;
}
// Get selected monitor position
@@ -1066,7 +1123,7 @@ const char *GetClipboardText(void)
Image GetClipboardImage(void)
{
Image image = { 0 };
-
+
TRACELOG(LOG_WARNING, "GetClipboardText not implemented");
return image;
@@ -1075,26 +1132,25 @@ Image GetClipboardImage(void)
// Show mouse cursor
void ShowCursor(void)
{
- CORE.Input.Mouse.cursorHidden = false;
SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW));
+ CORE.Input.Mouse.cursorHidden = false;
}
// Hides mouse cursor
void HideCursor(void)
{
- // NOTE: we use SetCursor instead of ShowCursor because it makes it easy
- // to only hide the cursor while it's inside the client area
- CORE.Input.Mouse.cursorHidden = true;
+ // NOTE: We use SetCursor() instead of ShowCursor() because
+ // it makes it easy to only hide the cursor while it's inside the client area
SetCursor(NULL);
+ CORE.Input.Mouse.cursorHidden = true;
}
// Enables cursor (unlock cursor)
void EnableCursor(void)
{
- if (platform.cursorEnabled) TRACELOG(LOG_INFO, "EnableCursor: already enabled");
- else
+ if (CORE.Input.Mouse.cursorLocked)
{
- if (!ClipCursor(NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError());
+ if (!ClipCursor(NULL)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError());
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
@@ -1102,18 +1158,17 @@ void EnableCursor(void)
rid.dwFlags = RIDEV_REMOVE; // Add to this window even in background
rid.hwndTarget = NULL;
int result = RegisterRawInputDevices(&rid, 1, sizeof(rid));
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError());
ShowCursor();
- platform.cursorEnabled = true;
- TRACELOG(LOG_INFO, "EnableCursor: enabled");
+ CORE.Input.Mouse.cursorLocked = false;
}
}
// Disables cursor (lock cursor)
void DisableCursor(void)
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
RAWINPUTDEVICE rid = { 0 };
rid.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
@@ -1121,33 +1176,31 @@ void DisableCursor(void)
rid.dwFlags = RIDEV_INPUTSINK; // Add to this window even in background
rid.hwndTarget = platform.hwnd;
int result = RegisterRawInputDevices(&rid, 1, sizeof(rid));
- if (result == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterRawInputDevices", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Failed to register raw input devices [ERROR: %lu]", GetLastError());
RECT clientRect = { 0 };
- if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetClientRect", GetLastError());
+ if (!GetClientRect(platform.hwnd, &clientRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client rectangle [ERROR: %lu]", GetLastError());
POINT topleft = { clientRect.left, clientRect.top };
- if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClientToScreen", GetLastError());
+ if (!ClientToScreen(platform.hwnd, &topleft)) TRACELOG(LOG_WARNING, "WIN32: Failed to get client to screen size [ERROR: %lu]", GetLastError());
LONG width = clientRect.right - clientRect.left;
LONG height = clientRect.bottom - clientRect.top;
- TRACELOG(LOG_INFO, "ClipCursor client %d,%d %d,%d (topleft %d,%d)",
+ TRACELOG(LOG_INFO, "WIN32: Clip cursor client rect: [%d,%d %d,%d], top-left: (%d,%d)",
clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, topleft.x, topleft.y);
-
+
LONG centerX = topleft.x + width/2;
LONG centerY = topleft.y + height/2;
RECT clipRect = { centerX, centerY, centerX + 1, centerY + 1 };
- if (!ClipCursor(&clipRect)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ClipCursor", GetLastError());
+ if (!ClipCursor(&clipRect)) TRACELOG(LOG_WARNING, "WIN32: Failed to clip cursor [ERROR: %lu]", GetLastError());
CORE.Input.Mouse.previousPosition = (Vector2){ 0, 0 };
CORE.Input.Mouse.currentPosition = (Vector2){ 0, 0 };
HideCursor();
- platform.cursorEnabled = false;
- TRACELOG(LOG_INFO, "DisableCursor: disabled");
+ CORE.Input.Mouse.cursorLocked = true;
}
- else TRACELOG(LOG_INFO, "DisableCursor: already disabled");
}
// Swap back buffer with front buffer (screen drawing)
@@ -1163,8 +1216,8 @@ void SwapScreenBuffer(void)
InvalidateRect(platform.hwnd, NULL, FALSE);
UpdateWindow(platform.hwnd);
#else
- if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SwapBuffers", GetLastError());
- if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "ValidateRect", GetLastError());
+ if (!SwapBuffers(platform.hdc)) TRACELOG(LOG_ERROR, "WIN32: Failed to swap buffers [ERROR: %lu]", GetLastError());
+ if (!ValidateRect(platform.hwnd, NULL)) TRACELOG(LOG_ERROR, "WIN32: Failed to validate screen rect [ERROR: %lu]", GetLastError());
#endif
}
@@ -1216,7 +1269,7 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d
// Set mouse position XY
void SetMousePosition(int x, int y)
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
@@ -1230,7 +1283,7 @@ void SetMouseCursor(int cursor)
{
LPCWSTR cursorName = GetCursorName(cursor);
HCURSOR hcursor = LoadCursorW(NULL, cursorName);
- if (!hcursor) TRACELOG(LOG_ERROR, "LoadCursor %d (win32 %d) failed, error=%lu", cursor, (size_t)cursorName, GetLastError());
+ if (!hcursor) TRACELOG(LOG_ERROR, "WIN32: Failed to load requested cursor [ERROR: %lu]", GetLastError());
SetCursor(hcursor);
CORE.Input.Mouse.cursorHidden = false;
@@ -1289,7 +1342,7 @@ void PollInputEvents(void)
//----------------------------------------------------------------------------------
// Initialize modern OpenGL context
-// NOTE: We need to create a dummy context first to query requried extensions
+// NOTE: We need to create a dummy context first to query required extensions
HGLRC InitOpenGL(HWND hwnd, HDC hdc)
{
// First, create a dummy context to get WGL extensions
@@ -1319,6 +1372,7 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
// Setup modern pixel format if extension is available
if (wglChoosePixelFormatARB)
@@ -1353,10 +1407,52 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
HGLRC realContext = NULL;
if (wglCreateContextAttribsARB)
{
+ int glContextVersionMajor = 1;
+ int glContextVersionMinor = 1;
+ int glContextProfile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+
+ if (rlGetVersion() == RL_OPENGL_21) // Request OpenGL 2.1 context
+ {
+ glContextVersionMajor = 2;
+ glContextVersionMinor = 1;
+ }
+ else if (rlGetVersion() == RL_OPENGL_33) // Request OpenGL 3.3 context
+ {
+ glContextVersionMajor = 3;
+ glContextVersionMinor = 3;
+ }
+ else if (rlGetVersion() == RL_OPENGL_43) // Request OpenGL 4.3 context
+ {
+ glContextVersionMajor = 4;
+ glContextVersionMinor = 3;
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_20) // Request OpenGL ES 2.0 context
+ {
+ if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") ||
+ IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile"))
+ {
+ glContextVersionMajor = 2;
+ glContextVersionMinor = 0;
+ glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+ }
+ else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU");
+ }
+ else if (rlGetVersion() == RL_OPENGL_ES_30) // Request OpenGL ES 3.0 context
+ {
+ if (IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es_profile") ||
+ IsWglExtensionAvailable(platform.hdc, "WGL_EXT_create_context_es2_profile"))
+ {
+ glContextVersionMajor = 3;
+ glContextVersionMinor = 0;
+ glContextProfile = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+ }
+ else TRACELOG(LOG_WARNING, "GL: OpenGL ES context not supported by GPU");
+ }
+
int contextAttribs[] = {
- WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
- WGL_CONTEXT_MINOR_VERSION_ARB, 3,
- WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported)
+ WGL_CONTEXT_MAJOR_VERSION_ARB, glContextVersionMajor,
+ WGL_CONTEXT_MINOR_VERSION_ARB, glContextVersionMinor,
+ WGL_CONTEXT_PROFILE_MASK_ARB, glContextProfile, // WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_ES_PROFILE_BIT_EXT (if supported)
//WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB [glDebugMessageCallback()]
0 // Terminator
};
@@ -1387,9 +1483,11 @@ HGLRC InitOpenGL(HWND hwnd, HDC hdc)
// Initialize platform: graphics, inputs and more
int InitPlatform(void)
{
- platform.desiredFlags = SanitizeFlags(SANITIZE_FLAGS_FIRST, CORE.Window.flags);
+ int result = 0;
+
platform.appScreenWidth = CORE.Window.screen.width;
platform.appScreenHeight = CORE.Window.screen.height;
+ platform.desiredFlags = SanitizeFlags(0 /*SANITIZE_FLAGS_FIRST*/, CORE.Window.flags);
// NOTE: From this point CORE.Window.flags should always reflect the actual state of the window
CORE.Window.flags = FLAG_WINDOW_HIDDEN | (platform.desiredFlags & FLAG_MASK_NO_UPDATE);
@@ -1400,7 +1498,7 @@ int InitPlatform(void)
if (IsWindows10Version1703OrGreaterWin32())
{
TRACELOG(LOG_INFO, "DpiAware: >=Win10Creators");
- if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
+ if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
TRACELOG(LOG_ERROR, "%s failed, error %u", "SetProcessDpiAwarenessContext", GetLastError());
}
else
@@ -1411,37 +1509,56 @@ int InitPlatform(void)
}
*/
+ HINSTANCE hInstance = GetModuleHandleW(0);
+
+ // Define window class
WNDCLASSEXW windowClass = {
.cbSize = sizeof(WNDCLASSEXW),
.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
.lpfnWndProc = WndProc, // Custom procedure assigned
.cbWndExtra = sizeof(LONG_PTR), // extra space for the Tuple object ptr
- .hInstance = GetModuleHandleW(0),
+ .hInstance = hInstance,
.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW), // TODO: Audit if we want to set this since we're implementing WM_SETCURSOR
- .lpszClassName = CLASS_NAME //L"GLWindowClass";
+ .lpszClassName = CLASS_NAME // Class name: L"raylibWindow"
};
- // Register window class
- if (RegisterClassExW(&windowClass) == 0) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "RegisterClass", GetLastError());
+ // Load user-provided icon if available
+ // NOTE: raylib resource file defaults to GLFW_ICON id, so looking for same identifier
+ windowClass.hIcon = LoadImageW(hInstance, L"GLFW_ICON", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
+ if (!windowClass.hIcon) windowClass.hIcon = LoadImageW(NULL, (LPCWSTR)IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
-/*
- // TODO: Remove or move this code that sets the display size; should maybe go somewhere in WndProc?
+ // Register window class
+ result = (int)RegisterClassExW(&windowClass);
+ if (result == 0) TRACELOG(LOG_ERROR, "WIN32: Failed to register window class [ERROR: %lu]", GetLastError());
+
+ // Get primary monitor info
POINT primaryTopLeft = { 0 };
HMONITOR monitor = MonitorFromPoint(primaryTopLeft, MONITOR_DEFAULTTOPRIMARY);
if (monitor != NULL)
{
- MONITORINFO info;
+ MONITORINFO info = { 0 };
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_WARNING, "%s failed, error: %u", "GetMonitorInfo", GetLastError());
+ result = (int)GetMonitorInfoW(monitor, &info);
+
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get monitor info [ERROR: %u]", GetLastError());
else
{
CORE.Window.display.width = info.rcMonitor.right - info.rcMonitor.left;
CORE.Window.display.height = info.rcMonitor.bottom - info.rcMonitor.top;
}
}
- else TRACELOG(LOG_WARNING, "MonitorFromPoint, error: %s", GetLastError());
-*/
-
+ else TRACELOG(LOG_WARNING, "WIN32: DISPLAY: Failed to get primary monitor from point [ERROR: %u]", GetLastError());
+
+ // Adjust the window rectangle so the *client area* matches desired size
+ // NOTE: Window width/height includes borders and title-bar
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ RECT rect = { 0, 0, platform.appScreenWidth, platform.appScreenHeight };
+ AdjustWindowRect(&rect, style, FALSE);
+ //AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, WINDOW_STYLE_EX);
+ //AdjustWindowRectExForDpi(&rect, style, FALSE, WINDOW_STYLE_EX, dpi);
+ int windowWidth = rect.right - rect.left;
+ int windowHeight = rect.bottom - rect.top;
+
// Create window
// NOTE: Title string needs to be converted to WCHAR
WCHAR *titleWide = NULL;
@@ -1454,13 +1571,13 @@ int InitPlatform(void)
titleWide,
MakeWindowStyle(CORE.Window.flags), // WS_OVERLAPPEDWINDOW | WS_VISIBLE
CW_USEDEFAULT, CW_USEDEFAULT,
- platform.appScreenWidth, platform.appScreenHeight, // TODO: Window size [width, height], needs to be updated?
+ windowWidth, windowHeight, // TODO: Window size [width, height], needs to be updated?
NULL, NULL,
GetModuleHandleW(NULL), NULL);
if (!platform.hwnd)
{
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "CreateWindow", GetLastError());
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: Failed to create window [ERROR: %lu]", GetLastError());
return -1;
}
@@ -1475,11 +1592,11 @@ int InitPlatform(void)
// Initialize software framebuffer
BITMAPINFO bmi = { 0 };
ZeroMemory(&bmi, sizeof(bmi));
- bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmi.bmiHeader.biWidth = platform.appScreenWidth;
- bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap
- bmi.bmiHeader.biPlanes = 1;
- bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = platform.appScreenWidth;
+ bmi.bmiHeader.biHeight = -(int)(platform.appScreenHeight); // Top-down bitmap
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32; // 32-bit BGRA
bmi.bmiHeader.biCompression = BI_RGB;
platform.hdcmem = CreateCompatibleDC(platform.hdc);
@@ -1499,11 +1616,12 @@ int InitPlatform(void)
}
CORE.Window.ready = true;
-
- // TODO: Should this function be called before or after drawing context is created? --> After swInit() called!
- //UpdateWindowSize(UPDATE_WINDOW_FIRST, platform.hwnd, platform.appScreenWidth, platform.appScreenHeight, platform.desiredFlags);
+
+ // Update flags (in case of deferred state change required)
UpdateFlags(platform.hwnd, platform.desiredFlags, platform.appScreenWidth, platform.appScreenHeight);
+ CORE.Window.render.width = CORE.Window.screen.width;
+ CORE.Window.render.height = CORE.Window.screen.height;
CORE.Window.currentFbo.width = CORE.Window.render.width;
CORE.Window.currentFbo.height = CORE.Window.render.height;
TRACELOG(LOG_INFO, "DISPLAY: Device initialized successfully");
@@ -1512,20 +1630,32 @@ int InitPlatform(void)
TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height);
TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y);
- CORE.Storage.basePath = GetWorkingDirectory();
+ if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
+ {
+ TRACELOG(LOG_INFO, "GL: OpenGL device information:");
+ TRACELOG(LOG_INFO, " > Vendor: %s", "raylib");
+ TRACELOG(LOG_INFO, " > Renderer: %s", "rlsw - OpenGL 1.1 Software Renderer");
+ TRACELOG(LOG_INFO, " > Version: %s", "1.0");
+ TRACELOG(LOG_INFO, " > GLSL: %s", "NOT SUPPORTED");
+ }
+ // Initialize timming system
+ //----------------------------------------------------------------------------
LARGE_INTEGER time = { 0 };
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&platform.timerFrequency);
CORE.Time.base = time.QuadPart;
InitTimer();
-
- // TODO: Enable cursor? -> Use default value as 0
- platform.cursorEnabled = true;
+ //----------------------------------------------------------------------------
+
+ // Initialize storage system
+ //----------------------------------------------------------------------------
+ CORE.Storage.basePath = GetWorkingDirectory();
+ //----------------------------------------------------------------------------
TRACELOG(LOG_INFO, "PLATFORM: DESKTOP: WIN32: Initialized successfully");
-
+
return 0;
}
@@ -1535,7 +1665,7 @@ void ClosePlatform(void)
if (platform.hwnd)
{
int result = DestroyWindow(platform.hwnd);
- if (result == 0) TRACELOG(LOG_WARNING, "WIN32: Error on window destroy: %u", GetLastError());
+ if (result == 0) TRACELOG(LOG_WARNING, "WIN32: WINDOW: Failed on window destroy [ERROR: %u]", GetLastError());
platform.hwnd = NULL;
}
}
@@ -1556,7 +1686,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
FlagsOp flagsOp = { 0 };
FlagsOp *deferredFlags = &flagsOp;
-
+
// Message processing
//------------------------------------------------------------------------------------
switch (msg)
@@ -1572,13 +1702,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
// Clean up for window destruction
if (rlGetVersion() == RL_OPENGL_11_SOFTWARE) // Using software renderer
{
- if (platform.hdcmem)
+ if (platform.hdcmem)
{
DeleteDC(platform.hdcmem);
platform.hdcmem = NULL;
}
- if (platform.hbitmap)
+ if (platform.hbitmap)
{
DeleteObject(platform.hbitmap); // Clears platform.pixels data
platform.hbitmap = NULL;
@@ -1616,9 +1746,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
if (CORE.Window.flags & FLAG_WINDOW_RESIZABLE)
{
// TODO: Enforce min/max size
- }
- else TRACELOG(LOG_WARNING, "WINDOW: Trying to resize a non-resizable window");
-
+ }
+ else TRACELOG(LOG_WARNING, "WIN32: WINDOW: Trying to resize a non-resizable window");
+
result = TRUE;
} break;
case WM_STYLECHANGING:
@@ -1629,19 +1759,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
GetStyleChangeFlagOps(CORE.Window.flags, ss, deferredFlags);
UINT dpi = GetDpiForWindow(hwnd);
- SIZE clientSize = GetClientSize(hwnd);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
SIZE oldSize = CalcWindowSize(dpi, clientSize, ss->styleOld);
SIZE newSize = CalcWindowSize(dpi, clientSize, ss->styleNew);
-
+
if (oldSize.cx != newSize.cx || oldSize.cy != newSize.cy)
{
- TRACELOG(LOG_INFO, "resize from style change: %dx%d to %dx%d", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy);
-
+ TRACELOG(LOG_INFO, "WIN32: WINDOW: Resize from style change [%dx%d] to [%dx%d]", oldSize.cx, oldSize.cy, newSize.cx, newSize.cy);
+
if (CORE.Window.flags & FLAG_WINDOW_MAXIMIZED)
{
// looks like windows will automatically "unminimize" a window
// if a style changes modifies it's size
- TRACELOG(LOG_INFO, "style change modifed window size, removing maximized flag");
+ TRACELOG(LOG_INFO, "WIN32: WINDOW: Style change modifed window size, removing maximized flag");
deferredFlags->clear |= FLAG_WINDOW_MAXIMIZED;
}
}
@@ -1650,27 +1783,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS *pos = (WINDOWPOS *)lparam;
- if (pos->flags & SWP_SHOWWINDOW)
- {
- //if (pos->flags & SWP_HIDEWINDOW) abort();
- deferredFlags->clear |= FLAG_WINDOW_HIDDEN;
- }
- else if (pos->flags & SWP_HIDEWINDOW)
- {
- deferredFlags->set |= FLAG_WINDOW_HIDDEN;
- }
+ if (pos->flags & SWP_SHOWWINDOW) deferredFlags->clear |= FLAG_WINDOW_HIDDEN;
+ else if (pos->flags & SWP_HIDEWINDOW) deferredFlags->set |= FLAG_WINDOW_HIDDEN;
Mized mized = MIZED_NONE;
bool isIconic = IsIconic(hwnd);
bool styleMinimized = !!(WS_MINIMIZE & GetWindowLongPtrW(hwnd, GWL_STYLE));
- if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "IsIconic(%d) != WS_MINIMIZED(%d)", isIconic, styleMinimized);
-
+ if (isIconic != styleMinimized) TRACELOG(LOG_WARNING, "WIN32: IsIconic state different from WS_MINIMIZED state");
+
if (isIconic) mized = MIZED_MIN;
else
{
WINDOWPLACEMENT placement;
placement.length = sizeof(placement);
- if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetWindowPlacement", GetLastError());
+ if (!GetWindowPlacement(hwnd, &placement)) TRACELOG(LOG_ERROR, "WIN32: WINDOW: FAiled to get monitor placement [ERROR: %lu]", GetLastError());
if (placement.showCmd == SW_SHOWMAXIMIZED) mized = MIZED_MAX;
}
@@ -1683,19 +1809,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO info;
info.cbSize = sizeof(info);
- if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetMonitorInfo", GetLastError());
+ if (!GetMonitorInfoW(monitor, &info)) TRACELOG(LOG_ERROR, "WIN32: MONITOR: Failed to get monitor info [ERROR: %lu]", GetLastError());
if ((pos->x == info.rcMonitor.left) &&
(pos->y == info.rcMonitor.top) &&
(pos->cx == (info.rcMonitor.right - info.rcMonitor.left)) &&
- (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top)))
- {
- deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE;
- }
- else
- {
- deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE;
- }
+ (pos->cy == (info.rcMonitor.bottom - info.rcMonitor.top))) deferredFlags->set |= FLAG_BORDERLESS_WINDOWED_MODE;
+ else deferredFlags->clear |= FLAG_BORDERLESS_WINDOWED_MODE;
} break;
case MIZED_MIN:
@@ -1739,29 +1859,30 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
float dpiScale = ((float)newDpi)/96.0f;
bool dpiScaling = CORE.Window.flags & FLAG_WINDOW_HIGHDPI;
- SIZE desired = PxFromPt2(dpiScale, dpiScaling, platform.appScreenWidth, platform.appScreenHeight);
+ // Get size in pixels from points
+ SIZE desired = {
+ .cx = dpiScaling? (int)((float)platform.appScreenWidth*dpiScale) : platform.appScreenWidth,
+ .cy = dpiScaling? (int)((float)platform.appScreenHeight*dpiScale) : platform.appScreenHeight
+ };
inoutSize->cx = desired.cx;
inoutSize->cy = desired.cy;
-
+
result = TRUE;
} break;
case WM_DPICHANGED:
{
- RECT *suggestedRect = (RECT*)lparam;
+ RECT *suggestedRect = (RECT *)lparam;
+
// Never set the window size to anything other than the suggested rect here
// Doing so can cause a window to stutter between monitors when transitioning between them
- if (!SetWindowPos(hwnd, NULL,
- suggestedRect->left,
- suggestedRect->top,
- suggestedRect->right - suggestedRect->left,
- suggestedRect->bottom - suggestedRect->top,
- SWP_NOZORDER | SWP_NOACTIVATE))
- {
- TRACELOG(LOG_ERROR, "%s failed, error=%lu", "SetWindowPos", GetLastError());
- }
+ int result = (int)SetWindowPos(hwnd, NULL, suggestedRect->left, suggestedRect->top,
+ suggestedRect->right - suggestedRect->left, suggestedRect->bottom - suggestedRect->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ if (result == 0) TRACELOG(LOG_ERROR, "Failed to set window position [ERROR: %lu]", GetLastError());
+
} break;
case WM_SETCURSOR:
{
+ // Called when mouse moves, enters/leaves window...
if (LOWORD(lparam) == HTCLIENT)
{
SetCursor(CORE.Input.Mouse.cursorHidden? NULL : LoadCursorW(NULL, (LPCWSTR)IDC_ARROW));
@@ -1789,7 +1910,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
} break;
case WM_MOUSEMOVE:
{
- if (platform.cursorEnabled)
+ if (!CORE.Input.Mouse.cursorLocked)
{
CORE.Input.Mouse.currentPosition.x = (float)GET_X_LPARAM(lparam);
CORE.Input.Mouse.currentPosition.y = (float)GET_Y_LPARAM(lparam);
@@ -1804,7 +1925,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
case WM_RBUTTONUP : HandleMouseButton(MOUSE_BUTTON_RIGHT, 0); break;
case WM_MBUTTONDOWN: HandleMouseButton(MOUSE_BUTTON_MIDDLE, 1); break;
case WM_MBUTTONUP : HandleMouseButton(MOUSE_BUTTON_MIDDLE, 0); break;
- case WM_XBUTTONDOWN:
+ case WM_XBUTTONDOWN:
{
switch (HIWORD(wparam))
{
@@ -1833,37 +1954,29 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara
}
//------------------------------------------------------------------------------------
- // Sanity check
- if (platform.hwnd == hwnd)
- {
- CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask);
- }
+ // Sanity check for flags
+ if (platform.hwnd == hwnd) CheckFlags("After WndProc", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), mask);
// Operations to execute after the above check
- if (flagsOp.set & flagsOp.clear)
- {
- TRACELOG(LOG_ERROR, "the flags 0x%x were both set and cleared!", flagsOp.set & flagsOp.clear);
- }
+ if (flagsOp.set & flagsOp.clear) TRACELOG(LOG_WARNING, "WIN32: FLAGS: Flags 0x%x were both set and cleared", flagsOp.set & flagsOp.clear);
DWORD save = CORE.Window.flags;
CORE.Window.flags |= flagsOp.set;
CORE.Window.flags &= ~flagsOp.clear;
- if (save != CORE.Window.flags)
- {
- TRACELOG(LOG_DEBUG, "DeferredFlags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags);
- }
+ if (save != CORE.Window.flags) TRACELOG(LOG_DEBUG, "WIN32: FLAGS: Current deferred flags: 0x%x > 0x%x (diff 0x%x)", save, CORE.Window.flags, save ^ CORE.Window.flags);
return result;
}
+// Handle keyboard input event
static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
{
- KeyboardKey key = KeyFromWparam(wparam);
-
+ KeyboardKey key = GetKeyFromWparam(wparam);
+
// TODO: Use scancode?
//BYTE scancode = lparam >> 16;
//TRACELOG(LOG_INFO, "KEY key=%d vk=%lu scan=%u = %u", key, wparam, scancode, state);
-
+
if (key != KEY_NULL)
{
CORE.Input.Keyboard.currentKeyState[key] = state;
@@ -1875,22 +1988,25 @@ static void HandleKey(WPARAM wparam, LPARAM lparam, char state)
// TODO: Add key to the queue as well?
}
+// Handle mouse button input event
static void HandleMouseButton(int button, char state)
{
+ // Register current mouse button state
CORE.Input.Mouse.currentButtonState[button] = state;
CORE.Input.Touch.currentTouchState[button] = state;
}
+// Handle raw input event
static void HandleRawInput(LPARAM lparam)
{
RAWINPUT input = { 0 };
UINT inputSize = sizeof(input);
UINT size = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &input, &inputSize, sizeof(RAWINPUTHEADER));
-
- if (size == (UINT)-1) TRACELOG(LOG_ERROR, "%s failed, error=%lu", "GetRawInputData", GetLastError());
-
- if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "Unexpected WM_INPUT type %lu", input.header.dwType);
+
+ if (size == (UINT)-1) TRACELOG(LOG_ERROR, "WIN32: Failed to get raw input data [ERROR: %lu]", GetLastError());
+
+ if (input.header.dwType != RIM_TYPEMOUSE) TRACELOG(LOG_ERROR, "WIN32: Unexpected WM_INPUT type %lu", input.header.dwType);
if (input.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) TRACELOG(LOG_ERROR, "TODO: handle absolute mouse inputs!");
@@ -1904,16 +2020,19 @@ static void HandleRawInput(LPARAM lparam)
//if (CORE.Input.Mouse.currentPosition.y != 0) abort();
}
+// Handle window resizing event
static void HandleWindowResize(HWND hwnd, int *width, int *height)
{
if (CORE.Window.flags & FLAG_WINDOW_MINIMIZED) return;
- SIZE clientSize = GetClientSize(hwnd);
+ // Get client size (framebuffer inside the window)
+ RECT rect = { 0 };
+ GetClientRect(hwnd, &rect);
+ SIZE clientSize = { rect.right, rect.bottom };
- //TRACELOG(LOG_DEBUG, "WINDOW: New widow client size: [%lux%lu]", clientSize.cx, clientSize.cy);
-
- //CORE.Window.currentFbo.width = clientSize.cx;
- //CORE.Window.currentFbo.height = clientSize.cy;
+ // TODO: Update framebuffer on resize
+ CORE.Window.currentFbo.width = (int)clientSize.cx;
+ CORE.Window.currentFbo.height = (int)clientSize.cy;
//glViewport(0, 0, clientSize.cx, clientSize.cy);
//SetupFramebuffer(0, 0);
@@ -1925,18 +2044,16 @@ static void HandleWindowResize(HWND hwnd, int *width, int *height)
unsigned int screenHeight = highdpi? (unsigned int)(((float)clientSize.cy)/dpiScale) : clientSize.cy;
CORE.Window.screen.width = screenWidth;
CORE.Window.screen.height = screenHeight;
-
+
if (AdoptWindowResize(CORE.Window.flags))
{
- TRACELOG(LOG_DEBUG, "WINDOW: Updating app size to %ix%i from window resize", screenWidth, screenHeight);
+ TRACELOG(LOG_DEBUG, "WIN32: WINDOW: Updating app size to [%ix%i] from window resize", screenWidth, screenHeight);
*width = screenWidth;
*height = screenHeight;
}
- CORE.Window.screenScale = MatrixScale(
- (float)CORE.Window.render.width/CORE.Window.screen.width,
- (float)CORE.Window.render.height/CORE.Window.screen.height,
- 1.0f);
+ CORE.Window.screenScale = MatrixScale( (float)CORE.Window.render.width/CORE.Window.screen.width,
+ (float)CORE.Window.render.height/CORE.Window.screen.height, 1.0f);
}
// Update window style
@@ -1944,22 +2061,28 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags)
{
DWORD current = STYLE_MASK_WRITABLE & MakeWindowStyle(CORE.Window.flags);
DWORD desired = STYLE_MASK_WRITABLE & MakeWindowStyle(desiredFlags);
-
+
if (current != desired)
{
SetLastError(0);
DWORD previous = STYLE_MASK_WRITABLE & SetWindowLongPtrW(hwnd, GWL_STYLE, desired);
if (previous != current)
{
- TRACELOG(LOG_ERROR, "SetWindowLong returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)",
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: SetWindowLongPtr() returned writable flags 0x%x but expected 0x%x (diff=0x%x, error=%lu)",
previous, current, previous ^ current, GetLastError());
}
CheckFlags("UpdateWindowStyle", hwnd, desiredFlags, desired, STYLE_MASK_WRITABLE);
}
- Mized currentMized = MizedFromStyle(MakeWindowStyle(CORE.Window.flags));
- Mized desiredMized = MizedFromStyle(MakeWindowStyle(desiredFlags));
+ // Minimized takes precedence over maximized
+ Mized currentMized = MIZED_NONE;
+ Mized desiredMized = MIZED_NONE;
+ if (CORE.Window.flags & WS_MINIMIZE) currentMized = MIZED_MIN;
+ else if (CORE.Window.flags & WS_MAXIMIZE) currentMized = MIZED_MAX;
+ if (desiredFlags & WS_MINIMIZE) currentMized = MIZED_MIN;
+ else if (desiredFlags & WS_MAXIMIZE) currentMized = MIZED_MAX;
+
if (currentMized != desiredMized)
{
switch (desiredMized)
@@ -1972,24 +2095,21 @@ static void UpdateWindowStyle(HWND hwnd, unsigned desiredFlags)
}
// Sanitize flags
-static unsigned SanitizeFlags(SanitizeFlagsKind kind, unsigned flags)
+static unsigned SanitizeFlags(int mode, unsigned flags)
{
if ((flags & FLAG_WINDOW_MAXIMIZED) && (flags & FLAG_BORDERLESS_WINDOWED_MODE))
{
- TRACELOG(LOG_INFO, "borderless windows mode is overriding maximized");
+ TRACELOG(LOG_WARNING, "WIN32: WINDOW: Borderless windows mode overriding maximized window flag");
flags &= ~FLAG_WINDOW_MAXIMIZED;
}
- switch (kind)
+ if (mode == 1)
{
- case SANITIZE_FLAGS_FIRST: break;
- case SANITIZE_FLAGS_NORMAL:
- if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT)))
- {
- TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
- flags &= ~FLAG_MSAA_4X_HINT;
- }
- break;
+ if ((flags & FLAG_MSAA_4X_HINT) && (!(CORE.Window.flags & FLAG_MSAA_4X_HINT)))
+ {
+ TRACELOG(LOG_WARNING, "WIN32: WINDOW: MSAA can only be configured before window initialization");
+ flags &= ~FLAG_MSAA_4X_HINT;
+ }
}
return flags;
@@ -2018,16 +2138,15 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
CORE.Window.flags |= (desiredFlags & FLAG_MASK_NO_UPDATE);
int vsync = (CORE.Window.flags & FLAG_VSYNC_HINT)? 1 : 0;
- PFNWGLSWAPINTERVALEXTPROC wglSwapInterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
- if (wglSwapInterval)
+ if (wglSwapIntervalEXT)
{
- (*wglSwapInterval)(vsync);
+ (*wglSwapIntervalEXT)(vsync);
if (vsync) CORE.Window.flags |= FLAG_VSYNC_HINT;
else CORE.Window.flags &= ~FLAG_VSYNC_HINT;
}
// TODO: Review all this code...
- DWORD previousStyle;
+ DWORD previousStyle = 0;
for (unsigned attempt = 1; ; attempt++)
{
CheckFlags("UpdateFlags", hwnd, CORE.Window.flags, MakeWindowStyle(CORE.Window.flags), STYLE_MASK_ALL);
@@ -2035,15 +2154,14 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
bool windowSizeUpdated = false;
if (MakeWindowStyle(CORE.Window.flags) == MakeWindowStyle(desiredFlags))
{
- windowSizeUpdated = UpdateWindowSize(UPDATE_WINDOW_NORMAL, hwnd, width, height, desiredFlags);
+ windowSizeUpdated = UpdateWindowSize(1, hwnd, width, height, desiredFlags);
if ((FLAG_MASK_REQUIRED & desiredFlags) == (FLAG_MASK_REQUIRED & CORE.Window.flags)) break;
}
- if ((attempt > 1) &&
- (previousStyle == MakeWindowStyle(CORE.Window.flags)) &&
- !windowSizeUpdated)
+
+ if ((attempt > 1) && (previousStyle == MakeWindowStyle(CORE.Window.flags)) && !windowSizeUpdated)
{
- TRACELOG(LOG_ERROR, "WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)",
+ TRACELOG(LOG_ERROR, "WIN32: WINDOW: UpdateFlags() failed after %u attempt(s) wanted 0x%x but is 0x%x (diff=0x%x)",
attempt, desiredFlags, CORE.Window.flags, desiredFlags ^ CORE.Window.flags);
}
@@ -2051,3 +2169,21 @@ static void UpdateFlags(HWND hwnd, unsigned desiredFlags, int width, int height)
UpdateWindowStyle(hwnd, desiredFlags);
}
}
+
+// Check if OpenGL extension is available
+static bool IsWglExtensionAvailable(HDC hdc, const char *extension)
+{
+ bool result = false;
+
+ if (wglGetExtensionsStringARB != NULL)
+ {
+ const char *extList = wglGetExtensionsStringARB(hdc);
+ if (extList != NULL)
+ {
+ // Simple substring search (could use strtok or strstr)
+ if (strstr(extList, extension) != NULL) result = true;
+ }
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c
index 58e820af1..a08a76bce 100644
--- a/src/platforms/rcore_drm.c
+++ b/src/platforms/rcore_drm.c
@@ -864,7 +864,7 @@ void SwapScreenBuffer(void)
// Create framebuffer with the correct format
uint32_t fb = 0;
result = drmModeAddFB(platform.fd, width, height, depth, bpp, creq.pitch, creq.handle, &fb);
- if (result != 0)
+ if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeAddFB() failed with result: %d (%s)", result, strerror(errno));
struct drm_mode_destroy_dumb dreq = { 0 };
@@ -974,12 +974,12 @@ void SwapScreenBuffer(void)
// Set CRTC with better error handling
result = drmModeSetCrtc(platform.fd, crtcId, fb, 0, 0, &platform.connector->connector_id, 1, mode);
- if (result != 0)
+ if (result != 0)
{
TRACELOG(LOG_ERROR, "DISPLAY: drmModeSetCrtc() failed with result: %d (%s)", result, strerror(errno));
TRACELOG(LOG_ERROR, "DISPLAY: CRTC ID: %u, FB ID: %u, Connector ID: %u", crtcId, fb, platform.connector->connector_id);
TRACELOG(LOG_ERROR, "DISPLAY: Mode: %dx%d@%d", mode->hdisplay, mode->vdisplay, mode->vrefresh);
-
+
drmModeRmFB(platform.fd, fb);
struct drm_mode_destroy_dumb dreq = {0};
dreq.handle = creq.handle;
@@ -1229,7 +1229,7 @@ int InitPlatform(void)
}
TRACELOG(LOG_TRACE, "DISPLAY: Connector %i modes detected: %i", i, con->count_modes);
- TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
+ TRACELOG(LOG_TRACE, "DISPLAY: Connector %i status: %s", i,
(con->connection == DRM_MODE_CONNECTED) ? "CONNECTED" :
(con->connection == DRM_MODE_DISCONNECTED) ? "DISCONNECTED" :
(con->connection == DRM_MODE_UNKNOWNCONNECTION) ? "UNKNOWN" : "OTHER");
@@ -1357,10 +1357,10 @@ int InitPlatform(void)
platform.modeIndex = 0;
CORE.Window.display.width = platform.connector->modes[0].hdisplay;
CORE.Window.display.height = platform.connector->modes[0].vdisplay;
-
- TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
+
+ TRACELOG(LOG_INFO, "DISPLAY: Selected DRM connector mode %s (%ux%u%c@%u) for software rendering",
platform.connector->modes[0].name,
- platform.connector->modes[0].hdisplay,
+ platform.connector->modes[0].hdisplay,
platform.connector->modes[0].vdisplay,
(platform.connector->modes[0].flags & DRM_MODE_FLAG_INTERLACE) ? 'i' : 'p',
platform.connector->modes[0].vrefresh);
diff --git a/src/rcore.c b/src/rcore.c
index f87b68783..e4628e77c 100644
--- a/src/rcore.c
+++ b/src/rcore.c
@@ -26,7 +26,8 @@
* - Linux DRM subsystem (KMS mode)
* > PLATFORM_ANDROID:
* - Android (ARM, ARM64)
-*
+* > PLATFORM_DESKTOP_WIN32 (Native Win32):
+* - Windows (Win32, Win64)
* CONFIGURATION:
* #define SUPPORT_DEFAULT_FONT (default)
* Default font is loaded on window initialization to be available for the user to render simple text.
@@ -161,7 +162,10 @@
#endif
// Platform specific defines to handle GetApplicationDirectory()
-#if (defined(_WIN32) && !defined(PLATFORM_DESKTOP_RGFW)) || (defined(_MSC_VER) && defined(PLATFORM_DESKTOP_RGFW))
+#if defined(_WIN32)
+ #if !defined(MAX_PATH)
+ #define MAX_PATH 260
+ #endif
struct HINSTANCE__;
#if defined(__cplusplus)
@@ -679,12 +683,15 @@ void InitWindow(int width, int height, const char *title)
// Initialize window data
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
+ CORE.Window.currentFbo.width = CORE.Window.screen.width;
+ CORE.Window.currentFbo.height = CORE.Window.screen.height;
+
CORE.Window.eventWaiting = false;
- CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
+ CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
if ((title != NULL) && (title[0] != 0)) CORE.Window.title = title;
// Initialize global input state
- memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
+ memset(&CORE.Input, 0, sizeof(CORE.Input)); // Reset CORE.Input structure to 0
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
@@ -696,7 +703,7 @@ void InitWindow(int width, int height, const char *title)
if (result != 0)
{
- TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize Platform");
+ TRACELOG(LOG_WARNING, "SYSTEM: Failed to initialize platform");
return;
}
//--------------------------------------------------------------
@@ -2521,7 +2528,7 @@ int MakeDirectory(const char *dirPath)
// Create final directory
if (!DirectoryExists(pathcpy)) MKDIR(pathcpy);
RL_FREE(pathcpy);
-
+
// In case something failed and requested directory
// was not successfully created, return -1
if (!DirectoryExists(dirPath)) return -1;
@@ -3145,7 +3152,7 @@ unsigned int *ComputeSHA256(unsigned char *data, int dataSize)
unsigned char *block = buffer + (blockN*64);
unsigned int w[64];
for (int i = 0; i < 16; i++)
- {
+ {
w[i] =
((unsigned int)block[i*4 + 0] << 24) |
((unsigned int)block[i*4 + 1] << 16) |
diff --git a/src/rlgl.h b/src/rlgl.h
index f587d81a2..e6a1c9432 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -2329,6 +2329,16 @@ void rlglInit(int width, int height)
RLGL.State.currentMatrix = &RLGL.State.modelview;
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
+#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
+ // Initialize software renderer backend
+ int result = swInit(width, height);
+ if (result == 0)
+ {
+ TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!");
+ exit(-1);
+ }
+#endif
+
// Initialize OpenGL default states
//----------------------------------------------------------
// Init state: Depth test
@@ -2345,39 +2355,28 @@ void rlglInit(int width, int height)
glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
glEnable(GL_CULL_FACE); // Enable backface culling
- // Init state: Cubemap seamless
-#if defined(GRAPHICS_API_OPENGL_33)
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
-#endif
-
#if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
-
-#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
- int result = swInit(width, height); // Initialize software renderer backend
- if (result == 0)
- {
- TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!");
- exit(-1);
- }
+#if defined(GRAPHICS_API_OPENGL_33)
+ // Init state: Cubemap seamless
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0)
#endif
-
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Store screen size into global variables
RLGL.State.framebufferWidth = width;
RLGL.State.framebufferHeight = height;
-
- TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
- //----------------------------------------------------------
#endif
// Init state: Color/Depth buffers clear
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
+
+ TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully");
+ //----------------------------------------------------------
}
// Vertex Buffer Object deinitialization (memory free)
diff --git a/src/rshapes.c b/src/rshapes.c
index 55f7d7fb9..2b5854f86 100644
--- a/src/rshapes.c
+++ b/src/rshapes.c
@@ -1432,6 +1432,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
Rectangle shapeRect = GetShapesTextureRectangle();
rlBegin(RL_QUADS);
+ rlNormal3f(0.0f, 0.0f, 1.0f);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height);
@@ -1441,7 +1442,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlVertex2f(v2.x, v2.y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height);
- rlVertex2f(v2.x, v2.y);
+ rlVertex2f(v3.x, v3.y);
rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height);
rlVertex2f(v3.x, v3.y);
diff --git a/src/rtext.c b/src/rtext.c
index 9951dc66d..b4cd560ba 100644
--- a/src/rtext.c
+++ b/src/rtext.c
@@ -1701,9 +1701,9 @@ char *GetTextBetween(const char *text, const char *begin, const char *end)
char *TextReplace(const char *text, const char *search, const char *replacement)
{
char *result = NULL;
-
+
if (!text || !search) return NULL; // Sanity check
-
+
char *insertPoint = NULL; // Next insert point
char *temp = NULL; // Temp pointer
int searchLen = 0; // Search string length of (the string to remove)
@@ -1753,7 +1753,7 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c
char *result = NULL;
if (!text || !begin || !end) return NULL; // Sanity check
-
+
int beginIndex = TextFindIndex(text, begin);
if (beginIndex > -1)
diff --git a/tools/rexm/examples_report.md b/tools/rexm/examples_report.md
index e058e09a7..fcc1f8839 100644
--- a/tools/rexm/examples_report.md
+++ b/tools/rexm/examples_report.md
@@ -204,4 +204,6 @@ Example elements validated:
| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| core_text_file_loading | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| shaders_mandelbrot_set | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/examples_report_issues.md b/tools/rexm/examples_report_issues.md
index 3136c2709..5de76a17a 100644
--- a/tools/rexm/examples_report_issues.md
+++ b/tools/rexm/examples_report_issues.md
@@ -27,4 +27,4 @@ Example elements validated:
| easings_testbed | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| raylib_opengl_interop | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ |
| embedded_files_loading | ✔ | ❌ | ✔ | ✔ | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| web_basic_window | ✔ | ❌ | ✔ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| web_basic_window | ✔ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c
index 20fc1d5e5..d668655c8 100644
--- a/tools/rexm/rexm.c
+++ b/tools/rexm/rexm.c
@@ -239,7 +239,7 @@ int main(int argc, char *argv[])
// build : Build example for Desktop and Web platforms
// validate : Validate examples collection, generates report
// update : Validate and update examples collection, generates report
-
+
if (strcmp(argv[1], "create") == 0)
{
// Check for valid upcoming argument
@@ -394,8 +394,8 @@ int main(int argc, char *argv[])
{
// Support building not only individual examples but categories and "ALL"
if ((strcmp(argv[2], "ALL") == 0) || TextInList(argv[2], exCategories, REXM_MAX_EXAMPLE_CATEGORIES))
- {
- // Category/ALL rebuilt requested
+ {
+ // Category/ALL rebuilt requested
strcpy(exRebuildRequested, argv[2]);
}
else
@@ -2432,7 +2432,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath)
static bool TextInList(const char *text, const char **list, int listCount)
{
bool result = false;
-
+
for (int i = 0; i < listCount; i++)
{
if (TextIsEqual(text, list[i])) { result = true; break; }