mirror of
				https://github.com/nicbarker/clay.git
				synced 2025-11-04 00:26:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "stdint.h"
 | 
						|
#include "string.h"
 | 
						|
#include "stdio.h"
 | 
						|
#include "stdlib.h"
 | 
						|
 | 
						|
#ifdef CLAY_OVERFLOW_TRAP
 | 
						|
#include "signal.h"
 | 
						|
#endif
 | 
						|
 | 
						|
static inline void Console_MoveCursor(int x, int y) {
 | 
						|
    printf("\033[%d;%dH", y + 1, x + 1);
 | 
						|
}
 | 
						|
 | 
						|
bool Clay_PointIsInsideRect(Clay_Vector2 point, Clay_BoundingBox rect) {
 | 
						|
    // TODO this function is a copy of Clay__PointIsInsideRect but that one is internal, I don't know if we want
 | 
						|
    // TODO to expose Clay__PointIsInsideRect
 | 
						|
    return point.x >= rect.x && point.x < rect.x + rect.width && point.y >= rect.y && point.y < rect.y + rect.height;
 | 
						|
}
 | 
						|
 | 
						|
static inline void Console_DrawRectangle(int x0, int y0, int width, int height, Clay_Color color,
 | 
						|
                                         Clay_BoundingBox scissorBox) {
 | 
						|
    float average = (color.r + color.g + color.b + color.a) / 4 / 255;
 | 
						|
 | 
						|
    for (int y = y0; y < height + y0; y++) {
 | 
						|
        for (int x = x0; x < width + x0; x++) {
 | 
						|
            if (!Clay_PointIsInsideRect((Clay_Vector2) {.x = x, .y = y}, scissorBox)) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
 | 
						|
            Console_MoveCursor(x, y);
 | 
						|
            // TODO this should be replaced by a better logarithmic scale if we're doing black and white
 | 
						|
            if (average > 0.75) {
 | 
						|
                printf("█");
 | 
						|
            } else if (average > 0.5) {
 | 
						|
                printf("▓");
 | 
						|
            } else if (average > 0.25) {
 | 
						|
                printf("▒");
 | 
						|
            } else {
 | 
						|
                printf("░");
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static inline Clay_Dimensions
 | 
						|
Console_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) {
 | 
						|
    Clay_Dimensions textSize = {0};
 | 
						|
    int columnWidth = *(int *) userData;
 | 
						|
 | 
						|
    // TODO this function is very wrong, it measures in characters, I have no idea what is the size in pixels
 | 
						|
 | 
						|
    float maxTextWidth = 0.0f;
 | 
						|
    float lineTextWidth = 0;
 | 
						|
 | 
						|
    float textHeight = 1;
 | 
						|
 | 
						|
    for (int i = 0; i < text.length; ++i) {
 | 
						|
        if (text.chars[i] == '\n') {
 | 
						|
            maxTextWidth = maxTextWidth > lineTextWidth ? maxTextWidth : lineTextWidth;
 | 
						|
            lineTextWidth = 0;
 | 
						|
            textHeight++;
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
        lineTextWidth++;
 | 
						|
    }
 | 
						|
 | 
						|
    maxTextWidth = maxTextWidth > lineTextWidth ? maxTextWidth : lineTextWidth;
 | 
						|
 | 
						|
    textSize.width = maxTextWidth * columnWidth;
 | 
						|
    textSize.height = textHeight * columnWidth;
 | 
						|
 | 
						|
    return textSize;
 | 
						|
}
 | 
						|
 | 
						|
void Clay_Terminal_Render(Clay_RenderCommandArray renderCommands, int width, int height, int columnWidth) {
 | 
						|
    printf("\033[H\033[J"); // Clear
 | 
						|
 | 
						|
    const Clay_BoundingBox fullWindow = {
 | 
						|
            .x = 0,
 | 
						|
            .y = 0,
 | 
						|
            .width = (float) width,
 | 
						|
            .height = (float) height,
 | 
						|
    };
 | 
						|
 | 
						|
    Clay_BoundingBox scissorBox = fullWindow;
 | 
						|
 | 
						|
    for (int j = 0; j < renderCommands.length; j++) {
 | 
						|
        Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, j);
 | 
						|
        Clay_BoundingBox boundingBox = (Clay_BoundingBox) {
 | 
						|
                .x = (int)((renderCommand->boundingBox.x / columnWidth) + 0.5),
 | 
						|
                .y = (int)((renderCommand->boundingBox.y / columnWidth) + 0.5),
 | 
						|
                .width = (int)((renderCommand->boundingBox.width / columnWidth) + 0.5),
 | 
						|
                .height = (int)((renderCommand->boundingBox.height / columnWidth) + 0.5),
 | 
						|
        };
 | 
						|
        switch (renderCommand->commandType) {
 | 
						|
            case CLAY_RENDER_COMMAND_TYPE_TEXT: {
 | 
						|
                Clay_TextRenderData data = renderCommand->renderData.text;
 | 
						|
                Clay_StringSlice text = data.stringContents;
 | 
						|
                int y = 0;
 | 
						|
                for (int x = 0; x < text.length; x++) {
 | 
						|
                    if (text.chars[x] == '\n') {
 | 
						|
                        y++;
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
 | 
						|
                    int cursorX = (int) boundingBox.x + x;
 | 
						|
                    int cursorY = (int) boundingBox.y + y;
 | 
						|
                    if (cursorY > scissorBox.y + scissorBox.height) {
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                    if (!Clay_PointIsInsideRect((Clay_Vector2) {.x = cursorX, .y = cursorY}, scissorBox)) {
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
 | 
						|
                    Console_MoveCursor(cursorX, cursorY);
 | 
						|
                    printf("%c", text.chars[x]);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
 | 
						|
                scissorBox = boundingBox;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
 | 
						|
                scissorBox = fullWindow;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
 | 
						|
                Clay_RectangleRenderData data = renderCommand->renderData.rectangle;
 | 
						|
                Console_DrawRectangle(
 | 
						|
                        (int) boundingBox.x,
 | 
						|
                        (int) boundingBox.y,
 | 
						|
                        (int) boundingBox.width,
 | 
						|
                        (int) boundingBox.height,
 | 
						|
                        data.backgroundColor,
 | 
						|
                        scissorBox);
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            case CLAY_RENDER_COMMAND_TYPE_BORDER: {
 | 
						|
                Clay_BorderRenderData data = renderCommand->renderData.border;
 | 
						|
                // Left border
 | 
						|
                if (data.width.left > 0) {
 | 
						|
                    Console_DrawRectangle(
 | 
						|
                            (int) (boundingBox.x),
 | 
						|
                            (int) (boundingBox.y + data.cornerRadius.topLeft),
 | 
						|
                            (int) data.width.left,
 | 
						|
                            (int) (boundingBox.height - data.cornerRadius.topLeft - data.cornerRadius.bottomLeft),
 | 
						|
                            data.color,
 | 
						|
                            scissorBox);
 | 
						|
                }
 | 
						|
                // Right border
 | 
						|
                if (data.width.right > 0) {
 | 
						|
                    Console_DrawRectangle(
 | 
						|
                            (int) (boundingBox.x + boundingBox.width - data.width.right),
 | 
						|
                            (int) (boundingBox.y + data.cornerRadius.topRight),
 | 
						|
                            (int) data.width.right,
 | 
						|
                            (int) (boundingBox.height - data.cornerRadius.topRight - data.cornerRadius.bottomRight),
 | 
						|
                            data.color,
 | 
						|
                            scissorBox);
 | 
						|
                }
 | 
						|
                // Top border
 | 
						|
                if (data.width.top > 0) {
 | 
						|
                    Console_DrawRectangle(
 | 
						|
                            (int) (boundingBox.x + data.cornerRadius.topLeft),
 | 
						|
                            (int) (boundingBox.y),
 | 
						|
                            (int) (boundingBox.width - data.cornerRadius.topLeft - data.cornerRadius.topRight),
 | 
						|
                            (int) data.width.top,
 | 
						|
                            data.color,
 | 
						|
                            scissorBox);
 | 
						|
                }
 | 
						|
                // Bottom border
 | 
						|
                if (data.width.bottom > 0) {
 | 
						|
                    Console_DrawRectangle(
 | 
						|
                            (int) (boundingBox.x + data.cornerRadius.bottomLeft),
 | 
						|
                            (int) (boundingBox.y + boundingBox.height - data.width.bottom),
 | 
						|
                            (int) (boundingBox.width - data.cornerRadius.bottomLeft - data.cornerRadius.bottomRight),
 | 
						|
                            (int) data.width.bottom,
 | 
						|
                            data.color,
 | 
						|
                            scissorBox);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            default: {
 | 
						|
                printf("Error: unhandled render command.");
 | 
						|
#ifdef CLAY_OVERFLOW_TRAP
 | 
						|
                raise(SIGTRAP);
 | 
						|
#endif
 | 
						|
                exit(1);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    Console_MoveCursor(-1, -1);  // TODO make the user not be able to write
 | 
						|
}
 |