Browse Source

Added rudimentary SVG support. (#2738)

* Added rudimentary SVG support. Added 2 functions ImageLoadSvg and ImageLoadSvgWithSize.

* Added an example on how to use ImageLoadSvgWithSize and adjusted Makefiles accordingly.

* Added actual correct example file.

* Reviewed the code to keep the raylib coding conventions in mind.
Moved the LoadImageSvg() code into LoadImage() guarded by SUPPORT_FILEFORMAT_SVG.
Renamed LoadImageSvgWithSize() to LoadImageSvg().
Added a LoadImageSvgFromString() function to parse the loaded SVG into an actual image. This does the bulk of the work.

* Fixed typo.

---------

Co-authored-by: Ray <raysan5@gmail.com>
pull/3284/head
bXi 1 year ago
committed by GitHub
parent
commit
c03ab03627
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 4700 additions and 17 deletions
  1. +2
    -1
      examples/Makefile
  2. +2
    -1
      examples/Makefile.Web
  3. +1
    -0
      examples/textures/resources/test.svg
  4. +72
    -0
      examples/textures/textures_svg_loading.c
  5. BIN
      examples/textures/textures_svg_loading.png
  6. +15
    -15
      src/config.h
  7. +3053
    -0
      src/external/nanosvg.h
  8. +1458
    -0
      src/external/nanosvgrast.h
  9. +2
    -0
      src/raylib.h
  10. +95
    -0
      src/rtextures.c

+ 2
- 1
examples/Makefile View File

@ -475,7 +475,8 @@ TEXTURES = \
textures/textures_draw_tiled \
textures/textures_polygon \
textures/textures_gif_player \
textures/textures_fog_of_war
textures/textures_fog_of_war \
textures/textures_svg_loading
TEXT = \
text/text_raylib_fonts \

+ 2
- 1
examples/Makefile.Web View File

@ -450,7 +450,8 @@ TEXTURES = \
textures/textures_draw_tiled \
textures/textures_polygon \
textures/textures_gif_player \
textures/textures_fog_of_war
textures/textures_fog_of_war \
textures/textures_svg_loading
TEXT = \
text/text_raylib_fonts \

+ 1
- 0
examples/textures/resources/test.svg
File diff suppressed because it is too large
View File


+ 72
- 0
examples/textures/textures_svg_loading.c View File

@ -0,0 +1,72 @@
/*******************************************************************************************
*
* raylib [textures] example - SVG loading and texture creation
*
* NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU memory (VRAM)
*
* Example originally created with raylib 4.2, last time updated with raylib 4.2
*
* 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) 2022 Dennis Meinen (@bixxy#4258 on Discord)
*
********************************************************************************************/
#include "raylib.h"
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [textures] example - svg loading");
// NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
Image image = LoadImageSvg("resources/test.svg", 400, 350); // Loaded in CPU memory (RAM)
Texture2D texture = LoadTextureFromImage(image); // Image converted to texture, GPU memory (VRAM)
UnloadImage(image); // Once image has been converted to texture and uploaded to VRAM, it can be unloaded from RAM
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
//----------------------------------------------------------------------------------
// TODO: Update your variables here
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
DrawTexture(texture, screenWidth/2 - texture.width/2, screenHeight/2 - texture.height/2, WHITE);
//Red border to illustrate how the SVG is centered within the specified dimensions
DrawRectangleLines((screenWidth / 2 - texture.width / 2) - 1, (screenHeight / 2 - texture.height / 2) - 1, texture.width + 2, texture.height + 2, RED);
DrawText("this IS a texture loaded from an SVG file!", 300, 410, 10, GRAY);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(texture); // Texture unloading
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

BIN
examples/textures/textures_svg_loading.png View File

Before After
Width: 800  |  Height: 450  |  Size: 14 KiB

+ 15
- 15
src/config.h View File

@ -141,22 +141,22 @@
//------------------------------------------------------------------------------------
// Module: rtextures - Configuration Flags
//------------------------------------------------------------------------------------
// Select the desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_QOI 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
cp">#define SUPPORT_FILEFORMAT_HDR 1
// Selecte desired fileformats to be supported for image data loading
#define SUPPORT_FILEFORMAT_PNG 1
//#define SUPPORT_FILEFORMAT_BMP 1
//#define SUPPORT_FILEFORMAT_TGA 1
//#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
#define SUPPORT_FILEFORMAT_QOI 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
o">//#define SUPPORT_FILEFORMAT_HDR 1
//#define SUPPORT_FILEFORMAT_PIC 1
//#define SUPPORT_FILEFORMAT_PNM 1
//#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
o">//#define SUPPORT_FILEFORMAT_PVR 1
//#define SUPPORT_FILEFORMAT_KTX 1
//#define SUPPORT_FILEFORMAT_ASTC 1
//#define SUPPORT_FILEFORMAT_PKM 1
//#define SUPPORT_FILEFORMAT_PVR 1
cp">#define SUPPORT_FILEFORMAT_SVG 1
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
#define SUPPORT_IMAGE_EXPORT 1

+ 3053
- 0
src/external/nanosvg.h
File diff suppressed because it is too large
View File


+ 1458
- 0
src/external/nanosvgrast.h
File diff suppressed because it is too large
View File


+ 2
- 0
src/raylib.h View File

@ -1245,6 +1245,8 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
// NOTE: These functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI Image LoadImageSvg(const char *fileName, int width, int height); // Load image from SVG file data with specified size
RLAPI Image LoadImageSvgFromString(const char *string, int width, int height); // Load an image from a SVG string with custom size
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data

+ 95
- 0
src/rtextures.c View File

@ -215,6 +215,14 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() [ImageResize()]
#if defined(SUPPORT_FILEFORMAT_SVG)
#define NANOSVG_IMPLEMENTATION // Expands implementation
#include "external/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "external/nanosvgrast.h"
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@ -310,6 +318,72 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
return image;
}
// Load an image from SVG file data with a custom size
Image LoadImageSvg(const char *fileName, int width, int height)
{
Image image = { 0 };
unsigned int dataSize = 0;
unsigned char *string = LoadFileData(fileName, &dataSize);
if (string != NULL)
{
image = LoadImageSvgFromString(string, width, height);
RL_FREE(string);
}
return image;
}
// Load an image from a SVG string with custom size
Image LoadImageSvgFromString(const char *string, int width, int height)
{
Image image = { 0 };
if (string != NULL)
{
struct NSVGimage *svgImage = nsvgParse(string, "px", 96.0f);
// Allocate memory for image
unsigned char *img = malloc(width*height*4);
// Calculate scales for both the width and the height
const float scaleWidth = width/svgImage->width;
const float scaleHeight = height/svgImage->height;
// Set the largest of the 2 scales to be the scale to use
const float scale = (scaleHeight > scaleWidth) ? scaleWidth : scaleHeight;
int offsetX = 0;
int offsetY = 0;
if (scaleHeight > scaleWidth)
{
offsetY = (height - svgImage->height*scale) / 2;
}
else
{
offsetX = (width - svgImage->width*scale) / 2;
}
// Rasterize
struct NSVGrasterizer* rast = nsvgCreateRasterizer();
nsvgRasterize(rast, svgImage, (int)offsetX, (int)offsetY, scale, img, width, height, width*4);
// Populate image struct with all data
image.data = img;
image.width = width;
image.height = height;
image.mipmaps = 1;
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
// Delete
nsvgDelete(svgImage);
}
return image;
}
// Load animated image data
// - Image.data buffer includes all frames: [image#0][image#1][image#2][...]
// - Number of frames is returned through 'frames' parameter
@ -470,6 +544,27 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
{
image.data = rl_load_astc_from_memory(fileData, dataSize, &image.width, &image.height, &image.format, &image.mipmaps);
}
#endif
#if defined(SUPPORT_FILEFORMAT_SVG)
else if (strcmp(fileType, ".svg") == 0)
{
if (fileData != NULL)
{
// Creating a duplicate svg to read sizes from due to nsvgParse modifiying the string buffer.
unsigned char *duplicate = (unsigned char*)RL_MALLOC(dataSize);
memcpy(duplicate, fileData, dataSize);
struct NSVGimage *svgImage = nsvgParse(duplicate, "px", 96.0f);
RL_FREE(duplicate);
const int width = (int)svgImage->width;
const int height = (int)svgImage->height;
// Delete
nsvgDelete(svgImage);
image = LoadImageSvgFromString(fileData, width, height);
}
}
#endif
else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");

Loading…
Cancel
Save