mirror of
https://github.com/nicbarker/clay.git
synced 2026-08-03 05:39:09 +00:00
Merge 159cf2cb96 into e6cc36941a
This commit is contained in:
commit
c34386e50d
8 changed files with 598 additions and 0 deletions
|
|
@ -12,6 +12,7 @@ option(CLAY_INCLUDE_SDL3_EXAMPLES "Build SDL 3 examples" OFF)
|
|||
option(CLAY_INCLUDE_WIN32_GDI_EXAMPLES "Build Win32 GDI examples" OFF)
|
||||
option(CLAY_INCLUDE_SOKOL_EXAMPLES "Build Sokol examples" OFF)
|
||||
option(CLAY_INCLUDE_PLAYDATE_EXAMPLES "Build Playdate examples" OFF)
|
||||
option(CLAY_INCLUDE_TIGR_EXAMPLES "Build Tigr examples" OFF)
|
||||
|
||||
message(STATUS "CLAY_INCLUDE_DEMOS: ${CLAY_INCLUDE_DEMOS}")
|
||||
|
||||
|
|
@ -45,6 +46,10 @@ if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_SOKOL_EXAMPLES)
|
|||
add_subdirectory("examples/sokol-video-demo")
|
||||
add_subdirectory("examples/sokol-corner-radius")
|
||||
endif()
|
||||
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_TIGR_EXAMPLES)
|
||||
add_subdirectory("examples/tigr-demo")
|
||||
endif()
|
||||
|
||||
|
||||
# Playdate example not included in ALL because users need to install the playdate SDK first which requires a license agreement
|
||||
if(CLAY_INCLUDE_PLAYDATE_EXAMPLES)
|
||||
|
|
|
|||
52
examples/tigr-demo/CMakeLists.txt
Normal file
52
examples/tigr-demo/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(demo C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
# -----------------------------
|
||||
# EDIT ME WITH RELATIVE PATH TO:
|
||||
# tigr.c & tigr.h
|
||||
set(TIGR_DIR "../../../tigr")
|
||||
|
||||
add_executable(demo
|
||||
main.c
|
||||
${TIGR_DIR}/tigr.c
|
||||
../../renderers/tigr/tigr_utils.c
|
||||
../../renderers/tigr/clay_renderer_tigr.c
|
||||
)
|
||||
|
||||
target_include_directories(demo PRIVATE
|
||||
${TIGR_DIR}
|
||||
)
|
||||
|
||||
# Platform-specific libraries
|
||||
if(WIN32)
|
||||
target_link_libraries(demo PRIVATE
|
||||
opengl32
|
||||
gdi32
|
||||
)
|
||||
|
||||
elseif(APPLE)
|
||||
find_library(OPENGL_FRAMEWORK OpenGL)
|
||||
find_library(COCOA_FRAMEWORK Cocoa)
|
||||
|
||||
target_link_libraries(demo PRIVATE
|
||||
${OPENGL_FRAMEWORK}
|
||||
${COCOA_FRAMEWORK}
|
||||
)
|
||||
|
||||
elseif(UNIX)
|
||||
target_link_libraries(demo PRIVATE
|
||||
m
|
||||
GLU
|
||||
GL
|
||||
X11
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
$<TARGET_FILE_DIR:demo>/resources
|
||||
)
|
||||
121
examples/tigr-demo/main.c
Normal file
121
examples/tigr-demo/main.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* Simple example based off the Clay README
|
||||
*/
|
||||
#define CLAY_IMPLEMENTATION
|
||||
#include "../../clay.h"
|
||||
|
||||
#include "../../renderers/tigr/clay_renderer_tigr.h"
|
||||
|
||||
const Clay_Color COLOR_LIGHT = (Clay_Color) {224, 215, 210, 255};
|
||||
const Clay_Color COLOR_RED = (Clay_Color) {168, 66, 28, 255};
|
||||
const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255};
|
||||
|
||||
void HandleClayErrors(Clay_ErrorData errorData) {
|
||||
// See the Clay_ErrorData struct for more information
|
||||
printf("%s\n", errorData.errorText.chars);
|
||||
switch(errorData.errorType) {
|
||||
// etc
|
||||
}
|
||||
}
|
||||
|
||||
// Layout config is just a struct that can be declared statically, or inline
|
||||
Clay_ElementDeclaration sidebarItemConfig = (Clay_ElementDeclaration) {
|
||||
.layout = {
|
||||
.sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }
|
||||
},
|
||||
.backgroundColor = COLOR_ORANGE
|
||||
};
|
||||
|
||||
// Re-useable components are just normal functions
|
||||
void SidebarItemComponent(char* my_str, int number) {
|
||||
snprintf(my_str, 8, "Box #%02d", number);
|
||||
Clay_String box_txt = (Clay_String){.isStaticallyAllocated = false, .length = 8, .chars = my_str};
|
||||
CLAY_AUTO_ID(sidebarItemConfig) {
|
||||
CLAY_TEXT(box_txt, { .fontSize = 8, .textColor = {255, 255, 255, 255} });
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
|
||||
|
||||
int screenWidth = 1000;
|
||||
int screenHeight = 600;
|
||||
|
||||
int mousePositionX, mousePositionY, isMouseDown;
|
||||
float mouseWheelX, mouseWheelY;
|
||||
Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight }, (Clay_ErrorHandler) { HandleClayErrors });
|
||||
Clay_SetMeasureTextFunction(Clay_Tigr_MeasureText, NULL);
|
||||
|
||||
Tigr* win = tigrWindow(screenWidth, screenHeight, "Clay & Tigr", TIGR_AUTO);
|
||||
|
||||
/* 20 8 byte strings */
|
||||
char* my_str = calloc(20, 8);
|
||||
if(my_str == NULL) {
|
||||
printf("Failed to allocate memoery\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t frame_cnt = 0;
|
||||
while(!tigrClosed(win) && !tigrKeyDown(win, TK_ESCAPE)) {
|
||||
|
||||
int deltaTime = tigrTime(); // tigrTime return the time since it was last called
|
||||
tigrMouse(win, &mousePositionX, &mousePositionY, &isMouseDown);
|
||||
tigrScrollWheel(win, &mouseWheelX, &mouseWheelY);
|
||||
|
||||
screenWidth = win->w;
|
||||
screenHeight = win->h;
|
||||
Clay_SetLayoutDimensions((Clay_Dimensions) { screenWidth, screenHeight });
|
||||
Clay_SetPointerState((Clay_Vector2) { mousePositionX, mousePositionY }, isMouseDown);
|
||||
Clay_UpdateScrollContainers(true, (Clay_Vector2) { mouseWheelX, mouseWheelY }, deltaTime);
|
||||
|
||||
Clay_BeginLayout();
|
||||
|
||||
CLAY(CLAY_ID("OuterContainer"), {
|
||||
.layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)},
|
||||
.padding = CLAY_PADDING_ALL(16), .childGap = 16 },
|
||||
.backgroundColor = {41, 41, 61,255} }) {
|
||||
|
||||
CLAY(CLAY_ID("SideBarContainer"), {
|
||||
.layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = {CLAY_SIZING_FIXED(300), CLAY_SIZING_GROW(0)},
|
||||
.padding = CLAY_PADDING_ALL(16),
|
||||
.childGap = 16},
|
||||
.clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() },
|
||||
.backgroundColor = COLOR_LIGHT }) {
|
||||
|
||||
CLAY(CLAY_ID("ProfilePictureOuter"), {
|
||||
.layout = { .sizing = { .width = CLAY_SIZING_GROW(0) },
|
||||
.padding = CLAY_PADDING_ALL(16),
|
||||
.childGap = 16,
|
||||
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER } },
|
||||
.backgroundColor = COLOR_RED }) {
|
||||
|
||||
CLAY(CLAY_ID("ProfilePicture"), {
|
||||
.layout = { .sizing = { .width = CLAY_SIZING_FIXED(70), .height = CLAY_SIZING_FIXED(86) }},
|
||||
.image = { .imageData = "./resources/leroy.png" } }) {}
|
||||
|
||||
|
||||
CLAY_TEXT(CLAY_STRING("Clay & Tigr - UI Library"), { .fontSize = 16, .textColor = {255, 255, 255, 255} });
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
SidebarItemComponent(my_str + (8 * i), i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CLAY(CLAY_ID("MainContent"), {
|
||||
.layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) } },
|
||||
.backgroundColor = COLOR_LIGHT }) {}
|
||||
}
|
||||
|
||||
Clay_RenderCommandArray renderCommands = Clay_EndLayout(deltaTime);
|
||||
Clay_Tigr_Render(renderCommands, win);
|
||||
|
||||
tigrUpdate(win);
|
||||
}
|
||||
|
||||
free(my_str);
|
||||
tigrFree(win);
|
||||
}
|
||||
BIN
examples/tigr-demo/resources/leroy.png
Executable file
BIN
examples/tigr-demo/resources/leroy.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
106
renderers/tigr/clay_renderer_tigr.c
Normal file
106
renderers/tigr/clay_renderer_tigr.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "clay_renderer_tigr.h"
|
||||
|
||||
#define CLAY_TO_TPIXEL(color) (TPixel){color.r, color.g, color.b, color.a}
|
||||
|
||||
void Clay_Tigr_Render(Clay_RenderCommandArray commands, Tigr* ctx) {
|
||||
for(size_t i = 0; i < commands.length; i++) {
|
||||
Clay_RenderCommand *command = Clay_RenderCommandArray_Get(&commands, i);
|
||||
|
||||
switch(command->commandType) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
Clay_RectangleRenderData* config = &command->renderData.rectangle;
|
||||
Clay_BoundingBox bb = command->boundingBox;
|
||||
|
||||
int box_radius = config->cornerRadius.topLeft; // only take take top left radius
|
||||
|
||||
tigrFillArcRect(ctx, bb.x, bb.y, bb.width, bb.height, box_radius, CLAY_TO_TPIXEL(config->backgroundColor));
|
||||
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
Clay_TextRenderData* config = &command->renderData.text;
|
||||
Clay_String toTerminate = (Clay_String){ .chars = config->stringContents.chars, .length = config->stringContents.length, .isStaticallyAllocated = false };
|
||||
char* text = Clay_to_Cstr(&toTerminate);
|
||||
|
||||
Clay_BoundingBox bb = command->boundingBox;
|
||||
Clay_Color color = config->textColor;
|
||||
|
||||
float scale = config->fontSize / 8.0f; // tfont is roughly 8px high
|
||||
|
||||
Tigr* temp = tigrBitmap(
|
||||
tigrTextWidth(tfont, text),
|
||||
tfont->glyphs->h
|
||||
);
|
||||
|
||||
tigrClear(temp, tigrRGBA(0,0,0,0));
|
||||
tigrPrint(temp, tfont, 0, 0, CLAY_TO_TPIXEL(color), text);
|
||||
|
||||
tigrBlitScale(ctx, temp, bb.x, bb.y, 0, 0, temp->w, temp->h, temp->w * scale, temp->h * scale);
|
||||
|
||||
tigrFree(temp);
|
||||
free(text);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||
Clay_BorderRenderData* config = &command->renderData.border;
|
||||
Clay_BoundingBox bb = command->boundingBox;
|
||||
|
||||
int box_radius = config->cornerRadius.topLeft;
|
||||
|
||||
tigrArcRect(ctx, bb.x, bb.y, bb.width, bb.height, box_radius, CLAY_TO_TPIXEL(config->color));
|
||||
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
Clay_ImageRenderData *config = &command->renderData.image;
|
||||
Clay_BoundingBox bb = command->boundingBox;
|
||||
|
||||
char* path = config->imageData;
|
||||
|
||||
Tigr* img = tigrLoadImage(path);
|
||||
|
||||
double image_w = img->w;
|
||||
double image_h = img->h;
|
||||
|
||||
/* Calculate the scaling factor to fit within the bounding box while preserving aspect ratio */
|
||||
double scale_w = bb.width / image_w;
|
||||
double scale_h = bb.height / image_h;
|
||||
double scale = (scale_w < scale_h) ? scale_w : scale_h; // Use the smaller scaling factor
|
||||
|
||||
/* Apply the same scale to both dimensions to preserve aspect ratio */
|
||||
double scale_x = scale;
|
||||
double scale_y = scale;
|
||||
|
||||
/* Calculate the scaled image dimensions */
|
||||
double scaled_w = image_w * scale_x;
|
||||
double scaled_h = image_h * scale_y;
|
||||
|
||||
/* Adjust the x and y coordinates to center the scaled image within the bounding box */
|
||||
double centered_x = bb.x + (bb.width - scaled_w) / 2.0;
|
||||
double centered_y = bb.y + (bb.height - scaled_h) / 2.0;
|
||||
|
||||
/* Blit the scaled and centered image */
|
||||
tigrBlit(ctx, img, centered_x, centered_y, 0, 0, scaled_w, scaled_h);
|
||||
|
||||
/* Clean up the source surface */
|
||||
tigrFree(img);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||
Clay_BoundingBox bb = command->boundingBox;
|
||||
tigrClip(ctx, bb.x, bb.y, bb.width, bb.height);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||
tigrClip(ctx, 0, 0, -1, -1);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_CUSTOM: {
|
||||
// Slot your custom elements in here.
|
||||
}
|
||||
default: {
|
||||
fprintf(stderr, "Unknown command type %d\n", (int) command->commandType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
renderers/tigr/clay_renderer_tigr.h
Normal file
75
renderers/tigr/clay_renderer_tigr.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright (c) 2026 Noah Arthur Breedy
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the
|
||||
// use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software in a
|
||||
// product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not
|
||||
// be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
#ifndef __CLAY_TIGR_RENDERER_H__
|
||||
#define __CLAY_TIGR_RENDERER_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "../../clay.h"
|
||||
#include "tigr.h"
|
||||
#include "tigr_utils.h" // for our rounded borders
|
||||
|
||||
|
||||
#define CLAY_TO_TPIXEL(color) (TPixel){color.r, color.g, color.b, color.a}
|
||||
|
||||
/* Render the command queue to the `Tigr*` instance provided */
|
||||
void Clay_Tigr_Render(Clay_RenderCommandArray commands, Tigr* ctx);
|
||||
|
||||
/* Return a null-terminated copy of Clay_String `str`
|
||||
* caller is required to free
|
||||
* */
|
||||
static inline char *Clay_to_Cstr(Clay_String *str) {
|
||||
char* copy = (char*) malloc(str->length + 1);
|
||||
if (!copy) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
memcpy(copy, str->chars, str->length);
|
||||
copy[str->length] = '\0';
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* Measure text using built-in Tigr functions */
|
||||
static inline Clay_Dimensions Clay_Tigr_MeasureText(Clay_StringSlice str, Clay_TextElementConfig *config, void *userData) {
|
||||
|
||||
Clay_String toTerminate = (Clay_String){ .chars = str.chars, .length = str.length, .isStaticallyAllocated = false };
|
||||
|
||||
char* cstr = Clay_to_Cstr(&toTerminate);
|
||||
|
||||
int text_width = tigrTextWidth(tfont, cstr) * (config->fontSize/8);
|
||||
int text_height = tigrTextHeight(tfont, cstr) * (config->fontSize/8);
|
||||
|
||||
free(cstr);
|
||||
|
||||
// Return dimensions
|
||||
return (Clay_Dimensions){
|
||||
.width = (float)text_width,
|
||||
.height = (float)text_height
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __CLAY_TIGR_RENDERER_H__ */
|
||||
208
renderers/tigr/tigr_utils.c
Normal file
208
renderers/tigr/tigr_utils.c
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
#include "tigr_utils.h"
|
||||
|
||||
enum ARC_STATES {
|
||||
NOT_DRAWN,
|
||||
STARTS_HERE,
|
||||
ALL_DRAWN,
|
||||
ENDS_HERE,
|
||||
STARTS_ENDS_HERE
|
||||
};
|
||||
|
||||
/* Radian to degree conversion value */
|
||||
#define R_TO_D 57.29578
|
||||
|
||||
/* global memory for our arc renderer */
|
||||
int arc_sector[9];
|
||||
|
||||
void PositiveSectorPoint(Tigr* ctx, int x, int y, int s, int sp, int ep, TPixel col) {
|
||||
|
||||
if (arc_sector[s] == NOT_DRAWN) return;
|
||||
|
||||
/* Draw all points of this sector */
|
||||
if (arc_sector[s] == ALL_DRAWN) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
return;
|
||||
}
|
||||
|
||||
/* draw all points flowing to right */
|
||||
if (arc_sector[s] == STARTS_HERE) {
|
||||
if (x >=sp) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* draw all points flowing from left */
|
||||
if (arc_sector[s] == ENDS_HERE) {
|
||||
if (x <= ep) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill only sections of this sector if ((x >= sp) && (x <= ep)) pixel (x, y); */
|
||||
if (arc_sector[s] == STARTS_ENDS_HERE) {
|
||||
}
|
||||
}
|
||||
|
||||
void NegativeSectorPoint(Tigr* ctx, int x, int y, int s, int sp, int ep, TPixel col) {
|
||||
|
||||
if (arc_sector[s] == NOT_DRAWN) return;
|
||||
|
||||
/* Draw all points in this sector */
|
||||
if (arc_sector[s] == ALL_DRAWN) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Draw all points flowing to the left */
|
||||
if (arc_sector[s] == STARTS_HERE) {
|
||||
if (x <= sp) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw all points flowing from the right if (x >= ep) {plot(x, y); return; } */
|
||||
if (arc_sector[s] == ENDS_HERE) {
|
||||
}
|
||||
|
||||
/* fill only sections of this sector */
|
||||
if (arc_sector[s] == STARTS_ENDS_HERE) {
|
||||
if ((x >= ep) && (x <= sp)) {
|
||||
tigrPlot(ctx, x, y, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tigrArc(Tigr* ctx, int xc, int yc, int sa, int ea, int r, TPixel col) {
|
||||
|
||||
int start_sector, end_sector;
|
||||
|
||||
int i;
|
||||
int x, y;
|
||||
int ep, sp, d;
|
||||
|
||||
/* Clear all the arc sector flags */
|
||||
for(i = 0; i < 8; i++) {
|
||||
arc_sector[i] = NOT_DRAWN;
|
||||
}
|
||||
|
||||
/* Calculate start and end arc sectors */
|
||||
start_sector = sa / 45;
|
||||
end_sector = ea / 45;
|
||||
|
||||
if(start_sector == end_sector) {
|
||||
arc_sector[start_sector] = STARTS_ENDS_HERE;
|
||||
}else {
|
||||
/* Set all of the possible drawn sector flags */
|
||||
for(i = start_sector; i < end_sector; i++) {
|
||||
arc_sector[i] = ALL_DRAWN;
|
||||
}
|
||||
arc_sector[start_sector] = STARTS_HERE;
|
||||
arc_sector[end_sector] = ENDS_HERE;
|
||||
}
|
||||
|
||||
/* Calculate the Start and End points */
|
||||
x = 0;
|
||||
y = r;
|
||||
|
||||
sp = ((double)xc + (double)r * cos((double)sa/R_TO_D));
|
||||
ep = ((double)xc + (double)r * cos((double)ea/R_TO_D));
|
||||
d = 2 * (1 - r);
|
||||
|
||||
while(y > x) {
|
||||
NegativeSectorPoint(ctx, xc + y, yc + x, 0, sp, ep, col);
|
||||
NegativeSectorPoint(ctx, xc + x, yc + y, 1, sp, ep, col);
|
||||
NegativeSectorPoint(ctx, xc - x, yc + y, 2, sp, ep, col);
|
||||
NegativeSectorPoint(ctx, xc - y, yc + x, 3, sp, ep, col);
|
||||
PositiveSectorPoint(ctx, xc - y, yc - x, 4, sp, ep, col);
|
||||
PositiveSectorPoint(ctx, xc - x, yc - y, 5, sp, ep, col);
|
||||
PositiveSectorPoint(ctx, xc + x, yc - y, 6, sp, ep, col);
|
||||
PositiveSectorPoint(ctx, xc + y, yc - x, 7, sp, ep, col);
|
||||
if (d + y > 0) {
|
||||
y = y - 1;
|
||||
d = d - 2 * y + 1;
|
||||
}
|
||||
else {
|
||||
if (x > d) {
|
||||
x = x + 1;
|
||||
d = d + 2 * x + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void tigrArcRect(Tigr* ctx, int x, int y, int w, int h, int r, TPixel col) {
|
||||
|
||||
tigrArc(ctx, x + r, y, 180, 270, r, col); // top left
|
||||
tigrArc(ctx, x - r + w, y, 270, 360, r, col); // top right
|
||||
tigrArc(ctx, x - r + w, y + h, 0, 90, r, col); // bottom right
|
||||
tigrArc(ctx, x + r, y + h, 90, 180, r, col); // bottom left
|
||||
|
||||
/* These are the connecting in lines */
|
||||
tigrLine(ctx, x + r, y - r, x + w - r, y - r, col); // top
|
||||
tigrLine(ctx, x + r, y + h + r, x + w - r, y + h + r, col); // bottom
|
||||
tigrLine(ctx, x, y, x, y + h, col); // left
|
||||
tigrLine(ctx, x + w, y, x + w, y + h, col); // right
|
||||
|
||||
}
|
||||
|
||||
/* The reason I dont call the tigrArcRect function is to save on draw calls */
|
||||
void tigrFillArcRect(Tigr* ctx, int x, int y, int w, int h, int r, TPixel col) {
|
||||
|
||||
/* Build the base frame */
|
||||
tigrFillRect(ctx, x - 1, y, w + 3, h, col);
|
||||
tigrFillRect(ctx, x + r, y - r - 1, w - (r * 2) , h + (r * 2) + 3, col);
|
||||
|
||||
/* Draw the corners */
|
||||
tigrArc(ctx, x + r, y, 180, 270, r, col); // top left
|
||||
tigrArc(ctx, x - r + w, y, 270, 360, r, col); // top right
|
||||
tigrArc(ctx, x - r + w, y + h, 0, 90, r, col); // bottom right
|
||||
tigrArc(ctx, x + r, y + h, 90, 180, r, col); // bottom left
|
||||
|
||||
/* Fill in the gaps */
|
||||
tigrFillCircle(ctx, x + r, y, r, col); // top left
|
||||
tigrFillCircle(ctx, x + w - r, y, r, col); // top right
|
||||
tigrFillCircle(ctx, x + w - r, y + h, r, col); // bottom right
|
||||
tigrFillCircle(ctx, x + r, y + h, r, col); // bottom left
|
||||
|
||||
}
|
||||
|
||||
/* ChatGPT generated blitScale function */
|
||||
void tigrBlitScale(Tigr* dst, Tigr* src, int dx, int dy, int sx, int sy, int sw, int sh, int dw, int dh) {
|
||||
for(int y = 0; y < dh; y++)
|
||||
{
|
||||
int srcY = sy + (y * sh) / dh;
|
||||
|
||||
if(srcY < 0 || srcY >= src->h)
|
||||
continue;
|
||||
|
||||
int dstY = dy + y;
|
||||
|
||||
if(dstY < 0 || dstY >= dst->h)
|
||||
continue;
|
||||
|
||||
for(int x = 0; x < dw; x++)
|
||||
{
|
||||
int srcX = sx + (x * sw) / dw;
|
||||
|
||||
if(srcX < 0 || srcX >= src->w)
|
||||
continue;
|
||||
|
||||
int dstX = dx + x;
|
||||
|
||||
if(dstX < 0 || dstX >= dst->w)
|
||||
continue;
|
||||
|
||||
TPixel p = src->pix[srcY * src->w + srcX];
|
||||
|
||||
/* Skip transparent pixels */
|
||||
if(p.a == 0)
|
||||
continue;
|
||||
|
||||
tigrPlot(dst, dstX, dstY, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
renderers/tigr/tigr_utils.h
Normal file
31
renderers/tigr/tigr_utils.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef __TIGR_UTILS_H__
|
||||
#define __TIGR_UTILS_H__
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "tigr.h"
|
||||
|
||||
/* Fast arc drawing algorithm based on Bressenham Circle Routine
|
||||
*
|
||||
* taken from --> https://www.scattergood.io/arc-drawing-algorithm/
|
||||
*/
|
||||
void tigrArc(Tigr* ctx, int xc, int yc, int sa, int ea, int r, TPixel col);
|
||||
|
||||
/* Function to draw rectangles with arches in the angles of them
|
||||
* makes use of the tigrArc function
|
||||
*
|
||||
* This is the wire frame one
|
||||
*/
|
||||
void tigrArcRect(Tigr* ctx, int x, int y, int w, int h, int r, TPixel col);
|
||||
|
||||
/* Function to draw rectangles with arches in the angles of them
|
||||
* makes use of the tigrArc function
|
||||
*
|
||||
* This is the filled one
|
||||
*/
|
||||
void tigrFillArcRect(Tigr* ctx, int x, int y, int w, int h, int r, TPixel col);
|
||||
|
||||
/* ChatGPT generated blitScale function */
|
||||
void tigrBlitScale(Tigr* dst, Tigr* src, int dx, int dy, int sx, int sy, int sw, int sh, int dw, int dh);
|
||||
|
||||
#endif /* __TIGR_UTILS_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue