diff --git a/.gitmodules b/.gitmodules
index 0df9bf9e87..969a47316e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -82,3 +82,7 @@
path = project/lib/hashlink
url = https://github.com/HaxeFoundation/hashlink
shallow = true
+[submodule "project/lib/webp"]
+ path = project/lib/webp
+ url = https://github.com/webmproject/libwebp
+ shallow = true
diff --git a/NOTICE.md b/NOTICE.md
index a806789ebd..ee2998e83d 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -46,6 +46,9 @@ This product bundles pixman 0.32.8, which is available under an
This product bundles libpng 1.6.12, which is available under a
"zlib" (BSD-style) license. For details, see [project/lib/png/](project/lib).
+This product bundles libwebp 1.6.0, which is available under a
+BSD-3-Clause license. For details, see [project/lib/webp/](project/lib).
+
This product bundles SDL 2.0.12, which is available under a
"zlib" (BSD-style) license. For details, see [project/lib/sdl/](project/lib).
@@ -58,6 +61,7 @@ This product bundles libvorbis 1.3.3, which is available under a
This product bundles zlib 1.2.8, which is available under a
"zlib" (BSD-style) license. For details, see [project/lib/zlib/](project/lib).
+
-------
Modifications and source-repository versions of Haxe core files are included in the
diff --git a/project/Build.xml b/project/Build.xml
index d6f0d7c857..6a5854ba30 100755
--- a/project/Build.xml
+++ b/project/Build.xml
@@ -26,6 +26,7 @@
+
@@ -214,6 +215,13 @@
+
+
@@ -364,6 +372,7 @@
+
@@ -397,6 +406,7 @@
+
diff --git a/project/include/graphics/format/WEBP.h b/project/include/graphics/format/WEBP.h
new file mode 100644
index 0000000000..65c74cd4fb
--- /dev/null
+++ b/project/include/graphics/format/WEBP.h
@@ -0,0 +1,19 @@
+#ifndef LIME_GRAPHICS_FORMAT_WEBP_H
+#define LIME_GRAPHICS_FORMAT_WEBP_H
+
+#include
+#include
+#include
+
+namespace lime {
+
+ class WEBP {
+
+ public:
+ static bool Decode (Resource *resource, ImageBuffer *imageBuffer, bool decodeData = true);
+ static bool Encode (ImageBuffer *imageBuffer, Bytes *bytes, int quality);
+ };
+
+}
+
+#endif
diff --git a/project/lib/README.md b/project/lib/README.md
index 022e17030e..2accca8be9 100644
--- a/project/lib/README.md
+++ b/project/lib/README.md
@@ -18,6 +18,7 @@ Lime includes code from several other C/C++ libraries, listed below. Lime prefer
- [**OpenAL Soft**](https://openal-soft.org/) | [primary repo](https://github.com/kcat/openal-soft)
- [**Pixman**](http://pixman.org/) | [primary repo](https://gitlab.freedesktop.org/pixman/pixman) | [GitHub mirror](https://github.com/freedesktop/pixman)
- [**libpng**](http://www.libpng.org/pub/png/libpng.html) | [primary repo](https://sourceforge.net/p/libpng/code) | [GitHub mirror](https://github.com/glennrp/libpng)[^1]
+- [**libwebp**](https://developers.google.com/speed/webp) | [primary repo](https://chromium.googlesource.com/webm/libwebp) | [GitHub mirror](https://github.com/webmproject/libwebp)
- [**SDL**](https://www.libsdl.org/) | [primary repo](https://github.com/libsdl-org/SDL)
- [**tiny file dialogs**](https://sourceforge.net/projects/tinyfiledialogs/) | [primary repo](https://sourceforge.net/p/tinyfiledialogs/code) | [unofficial GitHub mirror](https://github.com/openfl/libtinyfiledialogs)[^1]
- [**Vorbis**](https://www.xiph.org/vorbis/) | [primary repo](https://github.com/xiph/vorbis)
diff --git a/project/lib/webp b/project/lib/webp
new file mode 160000
index 0000000000..4fa2191233
--- /dev/null
+++ b/project/lib/webp
@@ -0,0 +1 @@
+Subproject commit 4fa21912338357f89e4fd51cf2368325b59e9bd9
diff --git a/project/lib/webp-files.xml b/project/lib/webp-files.xml
new file mode 100644
index 0000000000..228330de11
--- /dev/null
+++ b/project/lib/webp-files.xml
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp
index 39ccdcf3d5..f4969600da 100644
--- a/project/src/ExternalInterface.cpp
+++ b/project/src/ExternalInterface.cpp
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1882,6 +1883,17 @@ namespace lime {
#endif
break;
+ case 2:
+
+ #ifdef LIME_WEBP
+ if (WEBP::Encode (&imageBuffer, &data, quality)) {
+
+ return data.Value (bytes);
+
+ }
+ #endif
+ break;
+
default: break;
}
@@ -1917,6 +1929,17 @@ namespace lime {
#endif
break;
+ case 2:
+
+ #ifdef LIME_WEBP
+ if (WEBP::Encode (buffer, bytes, quality)) {
+
+ return bytes;
+
+ }
+ #endif
+ break;
+
default: break;
}
@@ -1936,6 +1959,14 @@ namespace lime {
bytes.Set (data);
resource = Resource (&bytes);
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, &imageBuffer)) {
+
+ return imageBuffer.Value (buffer);
+
+ }
+ #endif
+
#ifdef LIME_PNG
if (PNG::Decode (&resource, &imageBuffer)) {
@@ -1961,6 +1992,14 @@ namespace lime {
Resource resource = Resource (data);
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, buffer)) {
+
+ return buffer;
+
+ }
+ #endif
+
#ifdef LIME_PNG
if (PNG::Decode (&resource, buffer)) {
@@ -1987,6 +2026,14 @@ namespace lime {
Resource resource = Resource (val_string (data));
ImageBuffer imageBuffer = ImageBuffer (buffer);
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, &imageBuffer)) {
+
+ return imageBuffer.Value (buffer);
+
+ }
+ #endif
+
#ifdef LIME_PNG
if (PNG::Decode (&resource, &imageBuffer)) {
@@ -2012,6 +2059,14 @@ namespace lime {
Resource resource = Resource (data);
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, buffer)) {
+
+ return buffer;
+
+ }
+ #endif
+
#ifdef LIME_PNG
if (PNG::Decode (&resource, buffer)) {
@@ -2033,6 +2088,77 @@ namespace lime {
}
+ value lime_webp_decode_bytes (value data, bool decodeData, value buffer) {
+
+ ImageBuffer imageBuffer (buffer);
+
+ Bytes bytes (data);
+ Resource resource = Resource (&bytes);
+
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, &imageBuffer, decodeData)) {
+
+ return imageBuffer.Value (buffer);
+
+ }
+ #endif
+
+ return alloc_null ();
+
+ }
+
+
+ HL_PRIM ImageBuffer* HL_NAME(hl_webp_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) {
+
+ Resource resource = Resource (data);
+
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, buffer, decodeData)) {
+
+ return buffer;
+
+ }
+ #endif
+
+ return 0;
+
+ }
+
+
+ value lime_webp_decode_file (HxString path, bool decodeData, value buffer) {
+
+ ImageBuffer imageBuffer (buffer);
+ Resource resource = Resource (hxs_utf8 (path, nullptr));
+
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, &imageBuffer, decodeData)) {
+
+ return imageBuffer.Value (buffer);
+
+ }
+ #endif
+
+ return alloc_null ();
+
+ }
+
+
+ HL_PRIM ImageBuffer* HL_NAME(hl_webp_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) {
+
+ Resource resource = Resource (path);
+
+ #ifdef LIME_WEBP
+ if (WEBP::Decode (&resource, buffer, decodeData)) {
+
+ return buffer;
+
+ }
+ #endif
+
+ return 0;
+
+ }
+
value lime_image_load (value data, value buffer) {
if (val_is_string (data)) {
@@ -4117,6 +4243,8 @@ namespace lime {
DEFINE_PRIME2v (lime_orientation_event_manager_register);
DEFINE_PRIME3 (lime_png_decode_bytes);
DEFINE_PRIME3 (lime_png_decode_file);
+ DEFINE_PRIME3 (lime_webp_decode_bytes);
+ DEFINE_PRIME3 (lime_webp_decode_file);
DEFINE_PRIME2v (lime_render_event_manager_register);
DEFINE_PRIME2v (lime_sensor_event_manager_register);
DEFINE_PRIME0 (lime_system_get_allow_screen_timeout);
@@ -4311,6 +4439,8 @@ namespace lime {
DEFINE_HL_PRIM (_VOID, hl_orientation_event_manager_register, _FUN (_VOID, _NO_ARG) _TORIENTATION_EVENT);
DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_bytes, _TBYTES _BOOL _TIMAGEBUFFER);
DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_file, _STRING _BOOL _TIMAGEBUFFER);
+ DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_webp_decode_bytes, _TBYTES _BOOL _TIMAGEBUFFER);
+ DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_webp_decode_file, _STRING _BOOL _TIMAGEBUFFER);
DEFINE_HL_PRIM (_VOID, hl_render_event_manager_register, _FUN (_VOID, _NO_ARG) _TRENDER_EVENT);
DEFINE_HL_PRIM (_VOID, hl_sensor_event_manager_register, _FUN (_VOID, _NO_ARG) _TSENSOR_EVENT);
DEFINE_HL_PRIM (_BOOL, hl_system_get_allow_screen_timeout, _NO_ARG);
diff --git a/project/src/graphics/format/WEBP.cpp b/project/src/graphics/format/WEBP.cpp
new file mode 100644
index 0000000000..70fbfc1457
--- /dev/null
+++ b/project/src/graphics/format/WEBP.cpp
@@ -0,0 +1,153 @@
+#ifdef LIME_WEBP
+
+extern "C" {
+ #include
+ #include
+}
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace lime {
+
+ static inline int clampi (int value, int min, int max) {
+ return value < min ? min : (value > max ? max : value);
+ }
+
+ static bool LoadResourceToMemory (Resource* resource, Bytes*& owned, const uint8_t*& src, size_t& len) {
+
+ owned = nullptr;
+ src = nullptr;
+ len = 0;
+
+ if (!resource) return false;
+
+ if (resource->path) {
+
+ FILE_HANDLE* file = lime::fopen (resource->path, "rb");
+ if (!file) return false;
+
+ unsigned char sig[12] = {0};
+ int readOK = lime::fread (&sig[0], 12, 1, file);
+ lime::fclose (file);
+
+ if (readOK != 1) return false;
+
+ const bool isRIFF = (sig[0]=='R' && sig[1]=='I' && sig[2]=='F' && sig[3]=='F');
+ const bool isWEBP = (sig[8]=='W' && sig[9]=='E' && sig[10]=='B' && sig[11]=='P');
+ if (!isRIFF || !isWEBP) return false;
+
+ Bytes* bytes = new Bytes ();
+ bytes->ReadFile (resource->path);
+ if (bytes->length <= 0) { delete bytes; return false; }
+
+ owned = bytes;
+ src = reinterpret_cast(bytes->b);
+ len = static_cast(bytes->length);
+ return true;
+
+ } else if (resource->data) {
+
+ src = reinterpret_cast(resource->data->b);
+ len = static_cast(resource->data->length);
+ if (len == 0) return false;
+
+ return true;
+
+ }
+
+ return false;
+ }
+
+
+ bool WEBP::Decode (Resource* resource, ImageBuffer* imageBuffer, bool decodeData) {
+
+ if (!resource || !imageBuffer) return false;
+
+ Bytes* owned = nullptr;
+ const uint8_t* src = nullptr;
+ size_t len = 0;
+
+ if (!LoadResourceToMemory (resource, owned, src, len)) {
+ return false;
+ }
+
+ int width = 0, height = 0;
+ if (!WebPGetInfo (src, len, &width, &height) || width <= 0 || height <= 0) {
+ if (owned) delete owned;
+ return false;
+ }
+
+ if (!decodeData) {
+ imageBuffer->width = width;
+ imageBuffer->height = height;
+ if (owned) delete owned;
+ return true;
+ }
+
+ imageBuffer->Resize (width, height, 32);
+ unsigned char* dst = imageBuffer->data && imageBuffer->data->buffer
+ ? imageBuffer->data->buffer->b : nullptr;
+ if (!dst) {
+ if (owned) delete owned;
+ return false;
+ }
+
+ const int stride = imageBuffer->Stride ();
+ const size_t dstSize = static_cast(height) * static_cast(stride);
+
+ uint8_t* ok = WebPDecodeRGBAInto (src, len, dst, dstSize, stride);
+ if (!ok) {
+ if (owned) delete owned;
+ return false;
+ }
+
+ if (owned) delete owned;
+ return true;
+ }
+
+
+
+ bool WEBP::Encode (ImageBuffer* imageBuffer, Bytes* bytes, int quality) {
+
+ if (!imageBuffer || !bytes) return false;
+
+ const int width = imageBuffer->width;
+ const int height = imageBuffer->height;
+ if (width <= 0 || height <= 0) return false;
+
+ const int stride = imageBuffer->Stride ();
+ const uint8_t* src = imageBuffer->data && imageBuffer->data->buffer
+ ? reinterpret_cast(imageBuffer->data->buffer->b) : nullptr;
+ if (!src) return false;
+
+
+ uint8_t* out = nullptr;
+ const float clampedQuality = static_cast(clampi (quality, 0, 100));
+ size_t out_size = WebPEncodeRGBA (src, width, height, stride, clampedQuality, &out);
+
+ if (!out || out_size == 0) {
+ if (out) WebPFree (out);
+ return false;
+ }
+
+ if (out_size > static_cast((std::numeric_limits::max)())) {
+ WebPFree (out);
+ return false;
+ }
+
+ bytes->Resize (static_cast(out_size));
+ std::memcpy (bytes->b, out, out_size);
+ WebPFree (out);
+
+ return true;
+ }
+
+} // namespace lime
+
+#endif // LIME_WEBP