Skip to content

[core][texture][text][shapes] Software renderer for 2D #1370

@raysan5

Description

@raysan5

raylib includes a set of ImageDraw*() functions that rely only on CPU memory (no GPU required). Those functions can be used to implement a basic 2d software rendered. Actually, those functions have been improved a lot in performance lately.

Here there are some notes about how it can be implemented, still under consideration:

  • New compilation flag: USE_SOFTWARE_RENDERER -> Some modules are not required any more: rlgl.h, models.h, camera.h
  • Texture2D (GPU) should fallback to Image (CPU)
  • Some modules require functions mapping: core.c, textures.c, text.c and shapes.c
  • Some functions won't be usable -> code should be commented or pre-processed

Here some design details:

/// core.c
void InitWindow();                   -> Create Image framebuffers (back + front) and NO_CONTEXT window (just for inputs)
void ClearBackground(Color color);   -> ImageClearBackground(Color color);
void BeginDrawing(void);             -> Just timing
void EndDrawing(void);               -> [rlglDraw(), SwapBuffers(), PollInputEvents(), Timming()]

void BeginMode2D(Camera2D camera);                          -> Setup Image transform (matrix/kernel?)
void EndMode2D(void);                                       -> Apply Image transform
void BeginMode3D(Camera3D camera);                          -> no 3d
void EndMode3D(void);                                       -> no 3d
void BeginTextureMode(RenderTexture2D target);              -> Replace internal framebuffer Image by custom one
void EndTextureMode(void);                                  -> Reset drawing to internal framebuffer
void BeginScissorMode(int x, int y, int width, int height); -> Define drawing rectangle (check before ImageDraw() on framebuffer)
void EndScissorMode(void);                                  -> Reset drawing rectangle

static bool InitGraphicsDevice(int width, int height);      -> Create Image framebuffer
static void SetupFramebuffer(int width, int height);        -> Setup Image framebuffer? -> Probably not required
static void SetupViewport(int width, int height);           -> Set Image drawing area?
static void SwapBuffers(void);                              -> Copy Image back buffer to front buffers -> ISSUE: SWAP to SCREEN!


/// textures.c
Texture2D LoadTexture(const char *fileName);                                 -> LoadImage()  
Texture2D LoadTextureFromImage(Image image);                                 -> ImageCopy()
TextureCubemap LoadTextureCubemap(Image image, int layoutType);              -> LoadImage()
RenderTexture2D LoadRenderTexture(int width, int height);                    -> LoadImage()
void UnloadTexture(Texture2D texture);                                       -> UnloadImage() 
void UnloadRenderTexture(RenderTexture2D target);                            -> UnloadImage()
void UpdateTexture(Texture2D texture, const void *pixels);                   -> ImageDraw()
void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); -> ImageDraw()
Image GetTextureData(Texture2D texture);                                     -> ImageCopy()
Image GetScreenData(void);                                                   -> ImageCopy() (internal framebuffer)

void GenTextureMipmaps(Texture2D *texture);                                  -> ImageMipmaps()
void SetTextureFilter(Texture2D texture, int filterMode);                    -> Set ImageResize() scale mode
void SetTextureWrap(Texture2D texture, int wrapMode);                        -> Set Image wrap mode -> out-of-scope?

void DrawTexture(Texture2D texture, int posX, int posY, Color tint);         -> ImageDraw()
void DrawTextureV(Texture2D texture, Vector2 position, Color tint);          -> ImageDraw()
void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint);       -> ImageDraw()
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint);              -> ImageDraw()
void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint);    -> ImageDraw()
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint);         -> ImageDraw()
void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint);    -> ImageDraw()

/// text.c
void DrawFPS(int posX, int posY);                                                   -> ImageDrawText()
void DrawText(const char *text, int posX, int posY, int fontSize, Color color);     -> ImageDrawText()
void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint);                  -> ImageDrawTextEx()
void DrawTextRec(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint);     -> no
void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint,
                   int selectStart, int selectLength, Color selectTint, Color selectBackTint);                              -> no
void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float scale, Color tint);                                -> ImageDrawTextEx()

/// shapes.c
void DrawPixel(int posX, int posY, Color color);                                    -> void ImageDrawPixel(Image *dst, int posX, int posY, Color color);
void DrawPixelV(Vector2 position, Color color);                                     -> void ImageDrawPixelV(Image *dst, Vector2 position, Color color);
void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); -> void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color);
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color);                      -> void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color);
void DrawCircle(int centerX, int centerY, float radius, Color color);               -> void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color);->
void DrawCircleV(Vector2 center, float radius, Color color);                        -> void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color);
void DrawRectangle(int posX, int posY, int width, int height, Color color);         -> void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color);
void DrawRectangleV(Vector2 position, Vector2 size, Color color);                   -> void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color);   
void DrawRectangleRec(Rectangle rec, Color color);                                  -> void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color);                  
void DrawRectangleLines(int posX, int posY, int width, int height, Color color);    -> void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color);
// Several shapes drawing functions not supported...

There is one big issue and actually the main stopper for this implementation: How to do the screen buffer display of our Image framebuffer?

Every platform would require a custom mechanism to push a bunch of pixels to the screen. GLFW has a long-time open issue where some mechanism was proposed: glfw/glfw#589

Two main concerns: how to integrate this in raylib (in a simple non-intrusive way) and how useful is this feature. Some answers:

  • Use preprocessor USE_SOFTWARE_RENDERER to completely separate default functions from software based ones. On textures.c, text.c and shapes.c seems feasible but core.c would require some careful tweaking and probably some functions reorganization or internal preprocessing.
  • Software renderer could be useful when targeting old devices (consoles), some low-end embedded devices or custom devices with a display attached (Arduino, FPGA-based...). But on those cases, maybe raylib is too high level and beter lower level options exist.

In any case, I opened the issue for reference and comments. Please, do not send a PR, it's still a feature under consideration.

Metadata

Metadata

Assignees

Labels

new featureThis is an addition to the library

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions