mirror of
https://github.com/nicbarker/clay.git
synced 2025-04-15 10:48:04 +00:00
Merge ef950c43d4
into 8efa855e8c
This commit is contained in:
commit
26f737dce9
@ -13,4 +13,7 @@ if(NOT MSVC)
|
||||
add_subdirectory("examples/clay-official-website")
|
||||
add_subdirectory("examples/introducing-clay-video-demo")
|
||||
add_subdirectory("examples/SDL2-video-demo")
|
||||
add_subdirectory("examples/SDL2-video-demo")
|
||||
add_subdirectory("examples/RSGL_rendering/GLFW_windowing")
|
||||
add_subdirectory("examples/RSGL_rendering/RGFW_windowing")
|
||||
endif()
|
||||
|
25
examples/RSGL_rendering/GLFW_windowing/CMakeLists.txt
Normal file
25
examples/RSGL_rendering/GLFW_windowing/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(GLFWExample)
|
||||
|
||||
set(SRC main.c)
|
||||
|
||||
# Set libraries and extensions based on OS
|
||||
if(WIN32)
|
||||
set(LIBS -lglfw3 -lgdi32 -lopengl32)
|
||||
elseif(APPLE)
|
||||
set(LIBS -lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo)
|
||||
elseif(UNIX)
|
||||
set(LIBS -lglfw -lGL -lm -ldl -lpthread)
|
||||
endif()
|
||||
|
||||
# Include directories
|
||||
include_directories(${CMAKE_SOURCE_DIR})
|
||||
|
||||
# Add executable
|
||||
add_executable(main${EXT} ${SRC})
|
||||
|
||||
# Link libraries
|
||||
target_include_directories(main PRIVATE ../../../renderers/RSGL)
|
||||
target_include_directories(main PRIVATE ../../../)
|
||||
target_link_libraries(main${EXT} ${LIBS})
|
86
examples/RSGL_rendering/GLFW_windowing/clay_backend_glfw.c
Normal file
86
examples/RSGL_rendering/GLFW_windowing/clay_backend_glfw.c
Normal file
@ -0,0 +1,86 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#define GLFW_UNUSED(x) (void)(x);
|
||||
|
||||
Clay_Vector2 GLFW_mousePosition;
|
||||
|
||||
u32 GLFW_mouseLeft = 0;
|
||||
|
||||
GLFWkeyfun GLFW_old_key = NULL;
|
||||
GLFWcharfun GLFW_old_char = NULL;
|
||||
GLFWwindowsizefun GLFW_old_resize = NULL;
|
||||
GLFWmousebuttonfun GLFW_old_button = NULL;
|
||||
GLFWcursorposfun GLFW_old_cursor = NULL;
|
||||
GLFWscrollfun GLFW_old_scroll = NULL;
|
||||
|
||||
|
||||
void windowSizeCallback(GLFWwindow *window, int width, int height) {
|
||||
GLFW_UNUSED(window)
|
||||
Clay_SetLayoutDimensions((Clay_Dimensions) { (float)width, (float)height });
|
||||
|
||||
if (GLFW_old_resize != NULL)
|
||||
GLFW_old_resize(window, width, height);
|
||||
}
|
||||
|
||||
static void charCallback(GLFWwindow *window, unsigned int codepoint) {
|
||||
GLFW_UNUSED(window)
|
||||
|
||||
if (GLFW_old_char != NULL)
|
||||
GLFW_old_char(window, codepoint);
|
||||
}
|
||||
|
||||
|
||||
static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
GLFW_UNUSED(window)
|
||||
GLFW_UNUSED(mods)
|
||||
GLFW_UNUSED(scancode)
|
||||
|
||||
|
||||
if (GLFW_old_key != NULL)
|
||||
GLFW_old_key(window, key, scancode, action, mods);
|
||||
|
||||
}
|
||||
|
||||
static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
|
||||
GLFW_UNUSED(window)
|
||||
GLFW_UNUSED(mods)
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT)
|
||||
GLFW_mouseLeft = action == GLFW_PRESS ? 1 : 0;
|
||||
|
||||
Clay_SetPointerState(GLFW_mousePosition, GLFW_mouseLeft);
|
||||
if (GLFW_old_cursor != NULL)
|
||||
GLFW_old_button(window, button, action, mods);
|
||||
}
|
||||
|
||||
static void mouseCursorPosCallback(GLFWwindow *window, double x, double y) {
|
||||
GLFW_UNUSED(window);
|
||||
|
||||
GLFW_mousePosition = (Clay_Vector2){ (float)x, (float)y };
|
||||
Clay_SetPointerState(GLFW_mousePosition, GLFW_mouseLeft);
|
||||
if (GLFW_old_cursor != NULL)
|
||||
GLFW_old_cursor(window, x, y);
|
||||
}
|
||||
|
||||
static void mouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset) {
|
||||
GLFW_UNUSED(window)
|
||||
|
||||
Clay_UpdateScrollContainers(
|
||||
false,
|
||||
(Clay_Vector2) { xoffset, yoffset },
|
||||
0
|
||||
);
|
||||
|
||||
if (GLFW_old_scroll != NULL)
|
||||
GLFW_old_scroll(window, xoffset, yoffset);
|
||||
}
|
||||
|
||||
void clay_GLFW_callbackInit(GLFWwindow* window) {
|
||||
GLFW_old_key = glfwSetKeyCallback(window, keyCallback);
|
||||
GLFW_old_char = glfwSetCharCallback(window, charCallback);
|
||||
GLFW_old_resize = glfwSetWindowSizeCallback(window, windowSizeCallback);
|
||||
GLFW_old_button = glfwSetMouseButtonCallback(window, mouseButtonCallback);
|
||||
GLFW_old_cursor = glfwSetCursorPosCallback(window, mouseCursorPosCallback);
|
||||
GLFW_old_scroll = glfwSetScrollCallback(window, mouseScrollCallback);
|
||||
}
|
324
examples/RSGL_rendering/GLFW_windowing/main.c
Normal file
324
examples/RSGL_rendering/GLFW_windowing/main.c
Normal file
@ -0,0 +1,324 @@
|
||||
#define CLAY_IMPLEMENTATION
|
||||
#define RSGL_IMPLEMENTATION
|
||||
#include "clay_renderer_RSGL.c"
|
||||
#include "clay_backend_glfw.c"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int FONT_ID_BODY_16 = 0;
|
||||
Clay_Color COLOR_WHITE = { 255, 255, 255, 255};
|
||||
|
||||
void RenderHeaderButton(Clay_String text) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT({ .padding = { 16, 8 }}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 140, 140, 140, 255 },
|
||||
.cornerRadius = 5
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDropdownMenuItem(Clay_String text) {
|
||||
CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) {
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Clay_String title;
|
||||
Clay_String contents;
|
||||
} Document;
|
||||
|
||||
typedef struct {
|
||||
Document *documents;
|
||||
uint32_t length;
|
||||
} DocumentArray;
|
||||
|
||||
DocumentArray documents = {
|
||||
.documents = NULL,
|
||||
.length = 5
|
||||
};
|
||||
|
||||
uint32_t selectedDocumentIndex = 0;
|
||||
|
||||
void HandleSidebarInteraction(
|
||||
Clay_ElementId elementId,
|
||||
Clay_PointerData pointerData,
|
||||
intptr_t userData
|
||||
) {
|
||||
// If this button was clicked
|
||||
if (pointerData.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
|
||||
if (userData >= 0 && userData < documents.length) {
|
||||
// Select the corresponding document
|
||||
selectedDocumentIndex = userData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Clay_RenderCommandArray CreateLayout() {
|
||||
Clay_BeginLayout();
|
||||
Clay_Sizing layoutExpand = {
|
||||
.width = CLAY_SIZING_GROW(),
|
||||
.height = CLAY_SIZING_GROW()
|
||||
};
|
||||
|
||||
Clay_RectangleElementConfig contentBackgroundConfig = {
|
||||
.color = { 90, 90, 90, 255 },
|
||||
.cornerRadius = 8
|
||||
};
|
||||
|
||||
Clay_BeginLayout();
|
||||
// Build UI here
|
||||
CLAY(
|
||||
CLAY_ID("OuterContainer"),
|
||||
CLAY_RECTANGLE({ .color = { 43, 41, 51, 255 } }),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = layoutExpand,
|
||||
.padding = { 16, 16 },
|
||||
.childGap = 16
|
||||
})
|
||||
) {
|
||||
// Child elements go inside braces
|
||||
CLAY(
|
||||
CLAY_ID("HeaderBar"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_LAYOUT({
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_FIXED(60),
|
||||
.width = CLAY_SIZING_GROW()
|
||||
},
|
||||
.padding = { 16 },
|
||||
.childGap = 16,
|
||||
.childAlignment = {
|
||||
.y = CLAY_ALIGN_Y_CENTER
|
||||
}
|
||||
})
|
||||
) {
|
||||
// Header buttons go here
|
||||
CLAY(
|
||||
CLAY_ID("FileButton"),
|
||||
CLAY_LAYOUT({ .padding = { 16, 8 }}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 140, 140, 140, 255 },
|
||||
.cornerRadius = 5
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(CLAY_STRING("File"), CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
|
||||
bool fileMenuVisible =
|
||||
Clay_PointerOver(Clay_GetElementId(CLAY_STRING("FileButton")))
|
||||
||
|
||||
Clay_PointerOver(Clay_GetElementId(CLAY_STRING("FileMenu")));
|
||||
|
||||
if (fileMenuVisible) { // Below has been changed slightly to fix the small bug where the menu would dismiss when mousing over the top gap
|
||||
CLAY(
|
||||
CLAY_ID("FileMenu"),
|
||||
CLAY_FLOATING({
|
||||
.attachment = {
|
||||
.parent = CLAY_ATTACH_POINT_LEFT_BOTTOM
|
||||
},
|
||||
}),
|
||||
CLAY_LAYOUT({
|
||||
.padding = {0, 8 }
|
||||
})
|
||||
) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_FIXED(200)
|
||||
},
|
||||
}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 40, 40, 40, 255 },
|
||||
.cornerRadius = 8
|
||||
})
|
||||
) {
|
||||
// Render dropdown items here
|
||||
RenderDropdownMenuItem(CLAY_STRING("New"));
|
||||
RenderDropdownMenuItem(CLAY_STRING("Open"));
|
||||
RenderDropdownMenuItem(CLAY_STRING("Close"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderHeaderButton(CLAY_STRING("Edit"));
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {}
|
||||
RenderHeaderButton(CLAY_STRING("Upload"));
|
||||
RenderHeaderButton(CLAY_STRING("Media"));
|
||||
RenderHeaderButton(CLAY_STRING("Support"));
|
||||
}
|
||||
|
||||
CLAY(
|
||||
CLAY_ID("LowerContent"),
|
||||
CLAY_LAYOUT({ .sizing = layoutExpand, .childGap = 16 })
|
||||
) {
|
||||
CLAY(
|
||||
CLAY_ID("Sidebar"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.padding = { 16, 16 },
|
||||
.childGap = 8,
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_FIXED(250),
|
||||
.height = CLAY_SIZING_GROW()
|
||||
}
|
||||
})
|
||||
) {
|
||||
for (int i = 0; i < documents.length; i++) {
|
||||
Document document = documents.documents[i];
|
||||
Clay_LayoutConfig sidebarButtonLayout = {
|
||||
.sizing = { .width = CLAY_SIZING_GROW() },
|
||||
.padding = { 16, 16 }
|
||||
};
|
||||
|
||||
if (i == selectedDocumentIndex) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT(sidebarButtonLayout),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 120, 120, 120, 255 },
|
||||
.cornerRadius = 8,
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 20,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
CLAY(
|
||||
CLAY_LAYOUT(sidebarButtonLayout),
|
||||
Clay_OnHover(HandleSidebarInteraction, i),
|
||||
Clay_Hovered()
|
||||
? CLAY_RECTANGLE({
|
||||
.color = { 120, 120, 120, 120 },
|
||||
.cornerRadius = 8
|
||||
})
|
||||
: 0
|
||||
) {
|
||||
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 20,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLAY(
|
||||
CLAY_ID("MainContent"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_SCROLL({ .vertical = true }),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.childGap = 16,
|
||||
.padding = { 16, 16 },
|
||||
.sizing = layoutExpand
|
||||
})
|
||||
) {
|
||||
Document selectedDocument = documents.documents[selectedDocumentIndex];
|
||||
CLAY_TEXT(selectedDocument.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 24,
|
||||
.textColor = COLOR_WHITE
|
||||
}));
|
||||
CLAY_TEXT(selectedDocument.contents, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 24,
|
||||
.textColor = COLOR_WHITE
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Clay_EndLayout();
|
||||
}
|
||||
|
||||
void HandleClayErrors(Clay_ErrorData errorData) {
|
||||
printf("%s", errorData.errorText.chars);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
documents.documents = (Document[]) {
|
||||
{ .title = CLAY_STRING("Squirrels"), .contents = CLAY_STRING("The Secret Life of Squirrels: Nature's Clever Acrobats\n""Squirrels are often overlooked creatures, dismissed as mere park inhabitants or backyard nuisances. Yet, beneath their fluffy tails and twitching noses lies an intricate world of cunning, agility, and survival tactics that are nothing short of fascinating. As one of the most common mammals in North America, squirrels have adapted to a wide range of environments from bustling urban centers to tranquil forests and have developed a variety of unique behaviors that continue to intrigue scientists and nature enthusiasts alike.\n""\n""Master Tree Climbers\n""At the heart of a squirrel's skill set is its impressive ability to navigate trees with ease. Whether they're darting from branch to branch or leaping across wide gaps, squirrels possess an innate talent for acrobatics. Their powerful hind legs, which are longer than their front legs, give them remarkable jumping power. With a tail that acts as a counterbalance, squirrels can leap distances of up to ten times the length of their body, making them some of the best aerial acrobats in the animal kingdom.\n""But it's not just their agility that makes them exceptional climbers. Squirrels' sharp, curved claws allow them to grip tree bark with precision, while the soft pads on their feet provide traction on slippery surfaces. Their ability to run at high speeds and scale vertical trunks with ease is a testament to the evolutionary adaptations that have made them so successful in their arboreal habitats.\n""\n""Food Hoarders Extraordinaire\n""Squirrels are often seen frantically gathering nuts, seeds, and even fungi in preparation for winter. While this behavior may seem like instinctual hoarding, it is actually a survival strategy that has been honed over millions of years. Known as \"scatter hoarding,\" squirrels store their food in a variety of hidden locations, often burying it deep in the soil or stashing it in hollowed-out tree trunks.\n""Interestingly, squirrels have an incredible memory for the locations of their caches. Research has shown that they can remember thousands of hiding spots, often returning to them months later when food is scarce. However, they don't always recover every stash some forgotten caches eventually sprout into new trees, contributing to forest regeneration. This unintentional role as forest gardeners highlights the ecological importance of squirrels in their ecosystems.\n""\n""The Great Squirrel Debate: Urban vs. Wild\n""While squirrels are most commonly associated with rural or wooded areas, their adaptability has allowed them to thrive in urban environments as well. In cities, squirrels have become adept at finding food sources in places like parks, streets, and even garbage cans. However, their urban counterparts face unique challenges, including traffic, predators, and the lack of natural shelters. Despite these obstacles, squirrels in urban areas are often observed using human infrastructure such as buildings, bridges, and power lines as highways for their acrobatic escapades.\n""There is, however, a growing concern regarding the impact of urban life on squirrel populations. Pollution, deforestation, and the loss of natural habitats are making it more difficult for squirrels to find adequate food and shelter. As a result, conservationists are focusing on creating squirrel-friendly spaces within cities, with the goal of ensuring these resourceful creatures continue to thrive in both rural and urban landscapes.\n""\n""A Symbol of Resilience\n""In many cultures, squirrels are symbols of resourcefulness, adaptability, and preparation. Their ability to thrive in a variety of environments while navigating challenges with agility and grace serves as a reminder of the resilience inherent in nature. Whether you encounter them in a quiet forest, a city park, or your own backyard, squirrels are creatures that never fail to amaze with their endless energy and ingenuity.\n""In the end, squirrels may be small, but they are mighty in their ability to survive and thrive in a world that is constantly changing. So next time you spot one hopping across a branch or darting across your lawn, take a moment to appreciate the remarkable acrobat at work a true marvel of the natural world.\n") },
|
||||
{ .title = CLAY_STRING("Lorem Ipsum"), .contents = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") },
|
||||
{ .title = CLAY_STRING("Vacuum Instructions"), .contents = CLAY_STRING("Chapter 3: Getting Started - Unpacking and Setup\n""\n""Congratulations on your new SuperClean Pro 5000 vacuum cleaner! In this section, we will guide you through the simple steps to get your vacuum up and running. Before you begin, please ensure that you have all the components listed in the \"Package Contents\" section on page 2.\n""\n""1. Unboxing Your Vacuum\n""Carefully remove the vacuum cleaner from the box. Avoid using sharp objects that could damage the product. Once removed, place the unit on a flat, stable surface to proceed with the setup. Inside the box, you should find:\n""\n"" The main vacuum unit\n"" A telescoping extension wand\n"" A set of specialized cleaning tools (crevice tool, upholstery brush, etc.)\n"" A reusable dust bag (if applicable)\n"" A power cord with a 3-prong plug\n"" A set of quick-start instructions\n""\n""2. Assembling Your Vacuum\n""Begin by attaching the extension wand to the main body of the vacuum cleaner. Line up the connectors and twist the wand into place until you hear a click. Next, select the desired cleaning tool and firmly attach it to the wand's end, ensuring it is securely locked in.\n""\n""For models that require a dust bag, slide the bag into the compartment at the back of the vacuum, making sure it is properly aligned with the internal mechanism. If your vacuum uses a bagless system, ensure the dust container is correctly seated and locked in place before use.\n""\n""3. Powering On\n""To start the vacuum, plug the power cord into a grounded electrical outlet. Once plugged in, locate the power switch, usually positioned on the side of the handle or body of the unit, depending on your model. Press the switch to the \"On\" position, and you should hear the motor begin to hum. If the vacuum does not power on, check that the power cord is securely plugged in, and ensure there are no blockages in the power switch.\n""\n""Note: Before first use, ensure that the vacuum filter (if your model has one) is properly installed. If unsure, refer to \"Section 5: Maintenance\" for filter installation instructions.") },
|
||||
{ .title = CLAY_STRING("Article 4"), .contents = CLAY_STRING("Article 4") },
|
||||
{ .title = CLAY_STRING("Article 5"), .contents = CLAY_STRING("Article 5") },
|
||||
};
|
||||
|
||||
if (!glfwInit())
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
const int width = 640;
|
||||
const int height = 480;
|
||||
|
||||
GLFWwindow* window = glfwCreateWindow(width, height, "Clay | RSGL-GLFW", NULL, NULL);
|
||||
glfwMakeContextCurrent(window);
|
||||
|
||||
glfwSwapInterval(1);
|
||||
|
||||
RSGL_init((RSGL_area){width, height}, glfwGetProcAddress);
|
||||
|
||||
FONT_ID_BODY_16 = RSGL_loadFont("resources/Roboto-Regular.ttf");
|
||||
RSGL_setFont(FONT_ID_BODY_16);
|
||||
|
||||
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
|
||||
|
||||
Clay_SetMeasureTextFunction(RSGL_MeasureText);
|
||||
|
||||
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)width, (float)height }, (Clay_ErrorHandler) { HandleClayErrors });
|
||||
u32 NOW = glfwGetTime();
|
||||
u32 LAST = 0;
|
||||
double deltaTime = 0;
|
||||
|
||||
clay_GLFW_callbackInit(window);
|
||||
|
||||
while (glfwWindowShouldClose(window) == false) {
|
||||
LAST = NOW;
|
||||
NOW = glfwGetTime();
|
||||
deltaTime = NOW - LAST;
|
||||
|
||||
glfwPollEvents();
|
||||
|
||||
RSGL_clear(RSGL_RGB(0, 0, 0));
|
||||
Clay_RenderCommandArray renderCommands = CreateLayout();
|
||||
Clay_RSGL_Render(renderCommands);
|
||||
RSGL_draw();
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
RSGL_free();
|
||||
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
Binary file not shown.
38
examples/RSGL_rendering/RGFW_windowing/CMakeLists.txt
Normal file
38
examples/RSGL_rendering/RGFW_windowing/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(MyProject)
|
||||
|
||||
set(SRC main.c)
|
||||
|
||||
# Detect OS
|
||||
if(WIN32)
|
||||
set(LIBS -ggdb -lshell32 -lwinmm -lgdi32 -lopengl32)
|
||||
set(EXT ".exe")
|
||||
elseif(APPLE)
|
||||
set(LIBS -lm -framework Foundation -framework AppKit -framework IOKit -framework OpenGL)
|
||||
set(EXT "")
|
||||
elseif(UNIX)
|
||||
set(LIBS -lXrandr -lX11 -lm -lGL -ldl -lpthread)
|
||||
set(EXT "")
|
||||
else()
|
||||
set(detected_OS "Unknown")
|
||||
endif()
|
||||
|
||||
# Settings for emcc
|
||||
if(CMAKE_C_COMPILER MATCHES "emcc")
|
||||
set(EXPORTED_JS "-s EXPORTED_RUNTIME_METHODS=['stringToNewUTF8']")
|
||||
set(LIBS "-s FULL_ES3 -s WASM=1 -s ASYNCIFY -s USE_WEBGL2=1 -s GL_SUPPORT_EXPLICIT_SWAP_CONTROL=1 ${EXPORTED_JS}")
|
||||
set(LIBS "${LIBS} -s EXPORTED_FUNCTIONS=['_malloc', '_main']")
|
||||
set(EXT ".js")
|
||||
set(CMAKE_C_COMPILER "emcc")
|
||||
set(LIBS "${LIBS} --preload-file ./")
|
||||
endif()
|
||||
|
||||
# Include directories
|
||||
include_directories(../../../ ../../../renderers/RSGL)
|
||||
|
||||
# Add executable
|
||||
add_executable(main${EXT} ${SRC})
|
||||
|
||||
# Link libraries
|
||||
target_link_libraries(main${EXT} ${LIBS})
|
9664
examples/RSGL_rendering/RGFW_windowing/RGFW.h
Normal file
9664
examples/RSGL_rendering/RGFW_windowing/RGFW.h
Normal file
File diff suppressed because it is too large
Load Diff
37
examples/RSGL_rendering/RGFW_windowing/clay_backend_rgfw.c
Normal file
37
examples/RSGL_rendering/RGFW_windowing/clay_backend_rgfw.c
Normal file
@ -0,0 +1,37 @@
|
||||
Clay_Vector2 mousePosition;
|
||||
|
||||
void clay_RGFW_update(RGFW_window* win, double deltaTime) {
|
||||
|
||||
|
||||
RGFW_Event ev = win->event;
|
||||
switch (ev.type) {
|
||||
case RGFW_mouseButtonPressed: {
|
||||
switch (ev.button) {
|
||||
case RGFW_mouseScrollUp:
|
||||
case RGFW_mouseScrollDown:
|
||||
Clay_UpdateScrollContainers(
|
||||
false,
|
||||
(Clay_Vector2) { 0, ev.scroll },
|
||||
0
|
||||
);
|
||||
break;
|
||||
default:
|
||||
Clay_SetPointerState(mousePosition, RGFW_isMousePressed(win, RGFW_mouseLeft));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RGFW_mouseButtonReleased:
|
||||
Clay_SetPointerState(mousePosition, RGFW_isMousePressed(win, RGFW_mouseLeft));
|
||||
break;
|
||||
case RGFW_mousePosChanged:
|
||||
mousePosition = (Clay_Vector2){ (float)ev.point.x, (float)ev.point.y };
|
||||
Clay_SetPointerState(mousePosition, RGFW_isMousePressed(win, RGFW_mouseLeft));
|
||||
break;
|
||||
|
||||
case RGFW_windowResized:
|
||||
Clay_SetLayoutDimensions((Clay_Dimensions) { (float)win->r.w, (float)win->r.h });
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
313
examples/RSGL_rendering/RGFW_windowing/main.c
Normal file
313
examples/RSGL_rendering/RGFW_windowing/main.c
Normal file
@ -0,0 +1,313 @@
|
||||
#define RGFW_IMPLEMENTATION
|
||||
#include "RGFW.h"
|
||||
|
||||
#define CLAY_IMPLEMENTATION
|
||||
#define RSGL_IMPLEMENTATION
|
||||
#include "clay_renderer_RSGL.c"
|
||||
#include "clay_backend_rgfw.c"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
int FONT_ID_BODY_16 = 0;
|
||||
Clay_Color COLOR_WHITE = { 255, 255, 255, 255};
|
||||
|
||||
void RenderHeaderButton(Clay_String text) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT({ .padding = { 16, 8 }}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 140, 140, 140, 255 },
|
||||
.cornerRadius = 5
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderDropdownMenuItem(Clay_String text) {
|
||||
CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) {
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Clay_String title;
|
||||
Clay_String contents;
|
||||
} Document;
|
||||
|
||||
typedef struct {
|
||||
Document *documents;
|
||||
uint32_t length;
|
||||
} DocumentArray;
|
||||
|
||||
DocumentArray documents = {
|
||||
.documents = NULL,
|
||||
.length = 5
|
||||
};
|
||||
|
||||
uint32_t selectedDocumentIndex = 0;
|
||||
|
||||
void HandleSidebarInteraction(
|
||||
Clay_ElementId elementId,
|
||||
Clay_PointerData pointerData,
|
||||
intptr_t userData
|
||||
) {
|
||||
// If this button was clicked
|
||||
if (pointerData.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
|
||||
if (userData >= 0 && userData < documents.length) {
|
||||
// Select the corresponding document
|
||||
selectedDocumentIndex = userData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Clay_RenderCommandArray CreateLayout() {
|
||||
Clay_BeginLayout();
|
||||
Clay_Sizing layoutExpand = {
|
||||
.width = CLAY_SIZING_GROW(),
|
||||
.height = CLAY_SIZING_GROW()
|
||||
};
|
||||
|
||||
Clay_RectangleElementConfig contentBackgroundConfig = {
|
||||
.color = { 90, 90, 90, 255 },
|
||||
.cornerRadius = 8
|
||||
};
|
||||
|
||||
Clay_BeginLayout();
|
||||
// Build UI here
|
||||
CLAY(
|
||||
CLAY_ID("OuterContainer"),
|
||||
CLAY_RECTANGLE({ .color = { 43, 41, 51, 255 } }),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = layoutExpand,
|
||||
.padding = { 16, 16 },
|
||||
.childGap = 16
|
||||
})
|
||||
) {
|
||||
// Child elements go inside braces
|
||||
CLAY(
|
||||
CLAY_ID("HeaderBar"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_LAYOUT({
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_FIXED(60),
|
||||
.width = CLAY_SIZING_GROW()
|
||||
},
|
||||
.padding = { 16 },
|
||||
.childGap = 16,
|
||||
.childAlignment = {
|
||||
.y = CLAY_ALIGN_Y_CENTER
|
||||
}
|
||||
})
|
||||
) {
|
||||
// Header buttons go here
|
||||
CLAY(
|
||||
CLAY_ID("FileButton"),
|
||||
CLAY_LAYOUT({ .padding = { 16, 8 }}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 140, 140, 140, 255 },
|
||||
.cornerRadius = 5
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(CLAY_STRING("File"), CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
|
||||
bool fileMenuVisible =
|
||||
Clay_PointerOver(Clay_GetElementId(CLAY_STRING("FileButton")))
|
||||
||
|
||||
Clay_PointerOver(Clay_GetElementId(CLAY_STRING("FileMenu")));
|
||||
|
||||
if (fileMenuVisible) { // Below has been changed slightly to fix the small bug where the menu would dismiss when mousing over the top gap
|
||||
CLAY(
|
||||
CLAY_ID("FileMenu"),
|
||||
CLAY_FLOATING({
|
||||
.attachment = {
|
||||
.parent = CLAY_ATTACH_POINT_LEFT_BOTTOM
|
||||
},
|
||||
}),
|
||||
CLAY_LAYOUT({
|
||||
.padding = {0, 8 }
|
||||
})
|
||||
) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_FIXED(200)
|
||||
},
|
||||
}),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 40, 40, 40, 255 },
|
||||
.cornerRadius = 8
|
||||
})
|
||||
) {
|
||||
// Render dropdown items here
|
||||
RenderDropdownMenuItem(CLAY_STRING("New"));
|
||||
RenderDropdownMenuItem(CLAY_STRING("Open"));
|
||||
RenderDropdownMenuItem(CLAY_STRING("Close"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderHeaderButton(CLAY_STRING("Edit"));
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {}
|
||||
RenderHeaderButton(CLAY_STRING("Upload"));
|
||||
RenderHeaderButton(CLAY_STRING("Media"));
|
||||
RenderHeaderButton(CLAY_STRING("Support"));
|
||||
}
|
||||
|
||||
CLAY(
|
||||
CLAY_ID("LowerContent"),
|
||||
CLAY_LAYOUT({ .sizing = layoutExpand, .childGap = 16 })
|
||||
) {
|
||||
CLAY(
|
||||
CLAY_ID("Sidebar"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.padding = { 16, 16 },
|
||||
.childGap = 8,
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_FIXED(250),
|
||||
.height = CLAY_SIZING_GROW()
|
||||
}
|
||||
})
|
||||
) {
|
||||
for (int i = 0; i < documents.length; i++) {
|
||||
Document document = documents.documents[i];
|
||||
Clay_LayoutConfig sidebarButtonLayout = {
|
||||
.sizing = { .width = CLAY_SIZING_GROW() },
|
||||
.padding = { 16, 16 }
|
||||
};
|
||||
|
||||
if (i == selectedDocumentIndex) {
|
||||
CLAY(
|
||||
CLAY_LAYOUT(sidebarButtonLayout),
|
||||
CLAY_RECTANGLE({
|
||||
.color = { 120, 120, 120, 255 },
|
||||
.cornerRadius = 8,
|
||||
})
|
||||
) {
|
||||
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 20,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
CLAY(
|
||||
CLAY_LAYOUT(sidebarButtonLayout),
|
||||
Clay_OnHover(HandleSidebarInteraction, i),
|
||||
Clay_Hovered()
|
||||
? CLAY_RECTANGLE({
|
||||
.color = { 120, 120, 120, 120 },
|
||||
.cornerRadius = 8
|
||||
})
|
||||
: 0
|
||||
) {
|
||||
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 20,
|
||||
.textColor = { 255, 255, 255, 255 }
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLAY(
|
||||
CLAY_ID("MainContent"),
|
||||
CLAY_RECTANGLE(contentBackgroundConfig),
|
||||
CLAY_SCROLL({ .vertical = true }),
|
||||
CLAY_LAYOUT({
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.childGap = 16,
|
||||
.padding = { 16, 16 },
|
||||
.sizing = layoutExpand
|
||||
})
|
||||
) {
|
||||
Document selectedDocument = documents.documents[selectedDocumentIndex];
|
||||
CLAY_TEXT(selectedDocument.title, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 24,
|
||||
.textColor = COLOR_WHITE
|
||||
}));
|
||||
CLAY_TEXT(selectedDocument.contents, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 24,
|
||||
.textColor = COLOR_WHITE
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Clay_EndLayout();
|
||||
}
|
||||
|
||||
void HandleClayErrors(Clay_ErrorData errorData) {
|
||||
printf("%s", errorData.errorText.chars);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
documents.documents = (Document[]) {
|
||||
{ .title = CLAY_STRING("Squirrels"), .contents = CLAY_STRING("The Secret Life of Squirrels: Nature's Clever Acrobats\n""Squirrels are often overlooked creatures, dismissed as mere park inhabitants or backyard nuisances. Yet, beneath their fluffy tails and twitching noses lies an intricate world of cunning, agility, and survival tactics that are nothing short of fascinating. As one of the most common mammals in North America, squirrels have adapted to a wide range of environments from bustling urban centers to tranquil forests and have developed a variety of unique behaviors that continue to intrigue scientists and nature enthusiasts alike.\n""\n""Master Tree Climbers\n""At the heart of a squirrel's skill set is its impressive ability to navigate trees with ease. Whether they're darting from branch to branch or leaping across wide gaps, squirrels possess an innate talent for acrobatics. Their powerful hind legs, which are longer than their front legs, give them remarkable jumping power. With a tail that acts as a counterbalance, squirrels can leap distances of up to ten times the length of their body, making them some of the best aerial acrobats in the animal kingdom.\n""But it's not just their agility that makes them exceptional climbers. Squirrels' sharp, curved claws allow them to grip tree bark with precision, while the soft pads on their feet provide traction on slippery surfaces. Their ability to run at high speeds and scale vertical trunks with ease is a testament to the evolutionary adaptations that have made them so successful in their arboreal habitats.\n""\n""Food Hoarders Extraordinaire\n""Squirrels are often seen frantically gathering nuts, seeds, and even fungi in preparation for winter. While this behavior may seem like instinctual hoarding, it is actually a survival strategy that has been honed over millions of years. Known as \"scatter hoarding,\" squirrels store their food in a variety of hidden locations, often burying it deep in the soil or stashing it in hollowed-out tree trunks.\n""Interestingly, squirrels have an incredible memory for the locations of their caches. Research has shown that they can remember thousands of hiding spots, often returning to them months later when food is scarce. However, they don't always recover every stash some forgotten caches eventually sprout into new trees, contributing to forest regeneration. This unintentional role as forest gardeners highlights the ecological importance of squirrels in their ecosystems.\n""\n""The Great Squirrel Debate: Urban vs. Wild\n""While squirrels are most commonly associated with rural or wooded areas, their adaptability has allowed them to thrive in urban environments as well. In cities, squirrels have become adept at finding food sources in places like parks, streets, and even garbage cans. However, their urban counterparts face unique challenges, including traffic, predators, and the lack of natural shelters. Despite these obstacles, squirrels in urban areas are often observed using human infrastructure such as buildings, bridges, and power lines as highways for their acrobatic escapades.\n""There is, however, a growing concern regarding the impact of urban life on squirrel populations. Pollution, deforestation, and the loss of natural habitats are making it more difficult for squirrels to find adequate food and shelter. As a result, conservationists are focusing on creating squirrel-friendly spaces within cities, with the goal of ensuring these resourceful creatures continue to thrive in both rural and urban landscapes.\n""\n""A Symbol of Resilience\n""In many cultures, squirrels are symbols of resourcefulness, adaptability, and preparation. Their ability to thrive in a variety of environments while navigating challenges with agility and grace serves as a reminder of the resilience inherent in nature. Whether you encounter them in a quiet forest, a city park, or your own backyard, squirrels are creatures that never fail to amaze with their endless energy and ingenuity.\n""In the end, squirrels may be small, but they are mighty in their ability to survive and thrive in a world that is constantly changing. So next time you spot one hopping across a branch or darting across your lawn, take a moment to appreciate the remarkable acrobat at work a true marvel of the natural world.\n") },
|
||||
{ .title = CLAY_STRING("Lorem Ipsum"), .contents = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") },
|
||||
{ .title = CLAY_STRING("Vacuum Instructions"), .contents = CLAY_STRING("Chapter 3: Getting Started - Unpacking and Setup\n""\n""Congratulations on your new SuperClean Pro 5000 vacuum cleaner! In this section, we will guide you through the simple steps to get your vacuum up and running. Before you begin, please ensure that you have all the components listed in the \"Package Contents\" section on page 2.\n""\n""1. Unboxing Your Vacuum\n""Carefully remove the vacuum cleaner from the box. Avoid using sharp objects that could damage the product. Once removed, place the unit on a flat, stable surface to proceed with the setup. Inside the box, you should find:\n""\n"" The main vacuum unit\n"" A telescoping extension wand\n"" A set of specialized cleaning tools (crevice tool, upholstery brush, etc.)\n"" A reusable dust bag (if applicable)\n"" A power cord with a 3-prong plug\n"" A set of quick-start instructions\n""\n""2. Assembling Your Vacuum\n""Begin by attaching the extension wand to the main body of the vacuum cleaner. Line up the connectors and twist the wand into place until you hear a click. Next, select the desired cleaning tool and firmly attach it to the wand's end, ensuring it is securely locked in.\n""\n""For models that require a dust bag, slide the bag into the compartment at the back of the vacuum, making sure it is properly aligned with the internal mechanism. If your vacuum uses a bagless system, ensure the dust container is correctly seated and locked in place before use.\n""\n""3. Powering On\n""To start the vacuum, plug the power cord into a grounded electrical outlet. Once plugged in, locate the power switch, usually positioned on the side of the handle or body of the unit, depending on your model. Press the switch to the \"On\" position, and you should hear the motor begin to hum. If the vacuum does not power on, check that the power cord is securely plugged in, and ensure there are no blockages in the power switch.\n""\n""Note: Before first use, ensure that the vacuum filter (if your model has one) is properly installed. If unsure, refer to \"Section 5: Maintenance\" for filter installation instructions.") },
|
||||
{ .title = CLAY_STRING("Article 4"), .contents = CLAY_STRING("Article 4") },
|
||||
{ .title = CLAY_STRING("Article 5"), .contents = CLAY_STRING("Article 5") },
|
||||
};
|
||||
|
||||
RGFW_window* win = RGFW_createWindow("RSGL-RGFW Clay", (RGFW_rect){0, 0, 800, 600}, RGFW_CENTER);
|
||||
|
||||
RSGL_init(RSGL_AREA(win->r.w, win->r.h), RGFW_getProcAddress);
|
||||
|
||||
FONT_ID_BODY_16 = RSGL_loadFont("resources/Roboto-Regular.ttf");
|
||||
RSGL_setFont(FONT_ID_BODY_16);
|
||||
|
||||
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
|
||||
|
||||
Clay_SetMeasureTextFunction(RSGL_MeasureText);
|
||||
|
||||
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)win->r.w, (float)win->r.h }, (Clay_ErrorHandler) { HandleClayErrors });
|
||||
u32 NOW = RGFW_getTime();
|
||||
u32 LAST = 0;
|
||||
double deltaTime = 0;
|
||||
|
||||
while (RGFW_window_shouldClose(win) == false) {
|
||||
LAST = NOW;
|
||||
NOW = RGFW_getTimeNS();
|
||||
deltaTime = NOW - LAST;
|
||||
|
||||
Clay_Vector2 scrollDelta = {};
|
||||
while (RGFW_window_checkEvent(win)) {
|
||||
clay_RGFW_update(win, deltaTime);
|
||||
}
|
||||
|
||||
RSGL_clear(RSGL_RGB(0, 0, 0));
|
||||
Clay_RenderCommandArray renderCommands = CreateLayout();
|
||||
Clay_RSGL_Render(renderCommands);
|
||||
RSGL_draw();
|
||||
|
||||
RGFW_window_swapBuffers(win);
|
||||
}
|
||||
|
||||
RGFW_window_close(win);
|
||||
RSGL_free();
|
||||
return 0;
|
||||
}
|
Binary file not shown.
1577
renderers/RSGL/RSGL.h
Normal file
1577
renderers/RSGL/RSGL.h
Normal file
File diff suppressed because it is too large
Load Diff
868
renderers/RSGL/RSGL_gl.h
Normal file
868
renderers/RSGL/RSGL_gl.h
Normal file
@ -0,0 +1,868 @@
|
||||
#ifdef RSGL_CUSTOM_RENDER
|
||||
#define RSGL_IMPLEMENTATION
|
||||
#include "RSGL.h"
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <GL/gl.h>
|
||||
#else
|
||||
#include <OpenGL/gl.h>
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define RSGL_OPENGL_ES2
|
||||
#define RSGL_NO_GL_LOADER
|
||||
#include <GLES3/gl3.h>
|
||||
#endif
|
||||
|
||||
#if !defined(RSGL_RENDER_LEGACY)
|
||||
#define RSGL_MODERN_OPENGL
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_33) && !defined(RSGL_OPENGL_43) && !defined(RSGL_OPENGL_ES2)
|
||||
#define RSGL_OPENGL_33
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32) && !defined(__linux__) && !defined(GL_VERTEX_SHADER)
|
||||
typedef char GLchar;
|
||||
typedef int GLsizei;
|
||||
typedef ptrdiff_t GLintptr;
|
||||
typedef uintptr_t GLsizeiptr;
|
||||
|
||||
#define GL_VERTEX_SHADER 0x8B31
|
||||
#define GL_FRAGMENT_SHADER 0x8B30
|
||||
#define GL_ARRAY_BUFFER 0x8892
|
||||
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
|
||||
#define GL_STATIC_DRAW 0x88E4
|
||||
#define GL_DYNAMIC_DRAW 0x88E8
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#endif
|
||||
|
||||
#if !defined(RSGL_NO_GL_LOADER) && defined(RSGL_MODERN_OPENGL)
|
||||
#define RSGL_PROC_DEF(proc, name) name##SRC = (name##PROC)proc(#name)
|
||||
|
||||
typedef void (*RSGLapiproc)(void);
|
||||
typedef RSGLapiproc (*RSGLloadfunc)(const char *name);
|
||||
|
||||
typedef void (*glShaderSourcePROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);
|
||||
typedef GLuint (*glCreateShaderPROC) (GLenum type);
|
||||
typedef void (*glCompileShaderPROC) (GLuint shader);
|
||||
typedef GLuint (*glCreateProgramPROC) (void);
|
||||
typedef void (*glAttachShaderPROC) (GLuint program, GLuint shader);
|
||||
typedef void (*glBindAttribLocationPROC) (GLuint program, GLuint index, const GLchar *name);
|
||||
typedef void (*glLinkProgramPROC) (GLuint program);
|
||||
typedef void (*glBindBufferPROC) (GLenum target, GLuint buffer);
|
||||
typedef void (*glBufferDataPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
|
||||
typedef void (*glEnableVertexAttribArrayPROC) (GLuint index);
|
||||
typedef void (*glVertexAttribPointerPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
typedef void (*glDisableVertexAttribArrayPROC) (GLuint index);
|
||||
typedef void (*glDeleteBuffersPROC) (GLsizei n, const GLuint *buffers);
|
||||
typedef void (*glDeleteVertexArraysPROC) (GLsizei n, const GLuint *arrays);
|
||||
typedef void (*glUseProgramPROC) (GLuint program);
|
||||
typedef void (*glDetachShaderPROC) (GLuint program, GLuint shader);
|
||||
typedef void (*glDeleteShaderPROC) (GLuint shader);
|
||||
typedef void (*glDeleteProgramPROC) (GLuint program);
|
||||
typedef void (*glBufferSubDataPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
|
||||
typedef void (*glGetShaderivPROC)(GLuint shader, GLenum pname, GLint *params);
|
||||
typedef void (*glGetShaderInfoLogPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (*glGetProgramivPROC)(GLuint program, GLenum pname, GLint *params);
|
||||
typedef void (*glGetProgramInfoLogPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
|
||||
typedef void (*glGenVertexArraysPROC)(GLsizei n, GLuint *arrays);
|
||||
typedef void (*glGenBuffersPROC)(GLsizei n, GLuint *buffers);
|
||||
typedef void (*glBindVertexArrayPROC)(GLuint array);
|
||||
typedef GLint (*glGetUniformLocationPROC)(GLuint program, const GLchar *name);
|
||||
typedef void (*glUniformMatrix4fvPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
|
||||
typedef void (*glTexImage2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
typedef void (*glActiveTexturePROC) (GLenum texture);
|
||||
typedef void (*glUniform1fPROC) (GLint location, GLfloat v0);
|
||||
typedef void (*glUniform2fPROC) (GLint location, GLfloat v0, GLfloat v1);
|
||||
typedef void (*glUniform3fPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
|
||||
typedef void (*glUniform4fPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
|
||||
|
||||
glShaderSourcePROC glShaderSourceSRC = NULL;
|
||||
glCreateShaderPROC glCreateShaderSRC = NULL;
|
||||
glCompileShaderPROC glCompileShaderSRC = NULL;
|
||||
glCreateProgramPROC glCreateProgramSRC = NULL;
|
||||
glAttachShaderPROC glAttachShaderSRC = NULL;
|
||||
glBindAttribLocationPROC glBindAttribLocationSRC = NULL;
|
||||
glLinkProgramPROC glLinkProgramSRC = NULL;
|
||||
glBindBufferPROC glBindBufferSRC = NULL;
|
||||
glBufferDataPROC glBufferDataSRC = NULL;
|
||||
glEnableVertexAttribArrayPROC glEnableVertexAttribArraySRC = NULL;
|
||||
glVertexAttribPointerPROC glVertexAttribPointerSRC = NULL;
|
||||
glDisableVertexAttribArrayPROC glDisableVertexAttribArraySRC = NULL;
|
||||
glDeleteBuffersPROC glDeleteBuffersSRC = NULL;
|
||||
glUseProgramPROC glUseProgramSRC = NULL;
|
||||
glDetachShaderPROC glDetachShaderSRC = NULL;
|
||||
glDeleteShaderPROC glDeleteShaderSRC = NULL;
|
||||
glDeleteProgramPROC glDeleteProgramSRC = NULL;
|
||||
glBufferSubDataPROC glBufferSubDataSRC = NULL;
|
||||
glGetShaderivPROC glGetShaderivSRC = NULL;
|
||||
glGetShaderInfoLogPROC glGetShaderInfoLogSRC = NULL;
|
||||
glGetProgramivPROC glGetProgramivSRC = NULL;
|
||||
glGetProgramInfoLogPROC glGetProgramInfoLogSRC = NULL;
|
||||
glGenBuffersPROC glGenBuffersSRC = NULL;
|
||||
glGetUniformLocationPROC glGetUniformLocationSRC = NULL;
|
||||
glUniformMatrix4fvPROC glUniformMatrix4fvSRC = NULL;
|
||||
glActiveTexturePROC glActiveTextureSRC = NULL;
|
||||
glUniform1fPROC glUniform1fSRC = NULL;
|
||||
glUniform2fPROC glUniform2fSRC = NULL;
|
||||
glUniform3fPROC glUniform3fSRC = NULL;
|
||||
glUniform4fPROC glUniform4fSRC = NULL;
|
||||
|
||||
#if defined(RSGL_OPENGL_ES2) && !defined(RSGL_OPENGL_ES3)
|
||||
typedef void (* PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
|
||||
typedef void (* PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
|
||||
typedef void (* PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
|
||||
|
||||
static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysSRC = NULL;
|
||||
static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArraySRC = NULL;
|
||||
static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysSRC = NULL;
|
||||
#else
|
||||
glGenVertexArraysPROC glGenVertexArraysSRC = NULL;
|
||||
glBindVertexArrayPROC glBindVertexArraySRC = NULL;
|
||||
glDeleteVertexArraysPROC glDeleteVertexArraysSRC = NULL;
|
||||
#endif
|
||||
|
||||
#define glUniform1f glUniform1fSRC
|
||||
#define glUniform2f glUniform2fSRC
|
||||
#define glUniform3f glUniform3fSRC
|
||||
#define glUniform4f glUniform4fSRC
|
||||
#define glActiveTexture glActiveTextureSRC
|
||||
#define glShaderSource glShaderSourceSRC
|
||||
#define glCreateShader glCreateShaderSRC
|
||||
#define glCompileShader glCompileShaderSRC
|
||||
#define glCreateProgram glCreateProgramSRC
|
||||
#define glAttachShader glAttachShaderSRC
|
||||
#define glBindAttribLocation glBindAttribLocationSRC
|
||||
#define glLinkProgram glLinkProgramSRC
|
||||
#define glBindBuffer glBindBufferSRC
|
||||
#define glBufferData glBufferDataSRC
|
||||
#define glEnableVertexAttribArray glEnableVertexAttribArraySRC
|
||||
#define glVertexAttribPointer glVertexAttribPointerSRC
|
||||
#define glDisableVertexAttribArray glDisableVertexAttribArraySRC
|
||||
#define glDeleteBuffers glDeleteBuffersSRC
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysSRC
|
||||
#define glUseProgram glUseProgramSRC
|
||||
#define glDetachShader glDetachShaderSRC
|
||||
#define glDeleteShader glDeleteShaderSRC
|
||||
#define glDeleteProgram glDeleteProgramSRC
|
||||
#define glBufferSubData glBufferSubDataSRC
|
||||
#define glGetShaderiv glGetShaderivSRC
|
||||
#define glGetShaderInfoLog glGetShaderInfoLogSRC
|
||||
#define glGetProgramiv glGetProgramivSRC
|
||||
#define glGetProgramInfoLog glGetProgramInfoLogSRC
|
||||
#define glGenVertexArrays glGenVertexArraysSRC
|
||||
#define glGenBuffers glGenBuffersSRC
|
||||
#define glBindVertexArray glBindVertexArraySRC
|
||||
#define glGetUniformLocation glGetUniformLocationSRC
|
||||
#define glUniformMatrix4fv glUniformMatrix4fvSRC
|
||||
|
||||
extern int RSGL_loadGLModern(RSGLloadfunc proc);
|
||||
#endif
|
||||
|
||||
#define RSGL_MULTILINE_STR(...) #__VA_ARGS__
|
||||
|
||||
typedef struct RSGL_INFO {
|
||||
RSGL_programInfo program; /* Default shader program id, supports vertex color and diffuse texture*/
|
||||
u32 defaultTex;
|
||||
|
||||
u32 vao, vbo, tbo, cbo; /* array object and array buffers */
|
||||
} RSGL_INFO;
|
||||
|
||||
RSGL_INFO RSGL_gl;
|
||||
|
||||
void RSGL_renderDeleteTexture(RSGL_texture tex) { glDeleteTextures(1, (u32*)&tex); }
|
||||
void RSGL_renderViewport(i32 x, i32 y, i32 w, i32 h) { glViewport(x, y, w ,h); }
|
||||
|
||||
void RSGL_renderClear(float r, float g, float b, float a) {
|
||||
glClearColor(r, g, b, a);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void RSGL_renderInit(void* proc, RSGL_RENDER_INFO* info) {
|
||||
RSGL_UNUSED(info);
|
||||
|
||||
#ifdef RSGL_MODERN_OPENGL
|
||||
#ifndef __EMSCRIPTEN__
|
||||
if (RSGL_loadGLModern((RSGLloadfunc)proc)) {
|
||||
RSGL_args.legacy = 2;
|
||||
#ifdef RSGL_DEBUG
|
||||
printf("Failed to load an OpenGL 3.3 Context, reverting to OpenGL Legacy\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#else
|
||||
RSGL_UNUSED(proc);
|
||||
#endif
|
||||
|
||||
static const char *defaultVShaderCode = RSGL_MULTILINE_STR(
|
||||
#if defined(RSGL_OPENGL_21)
|
||||
\x23version 120 \n
|
||||
attribute vec3 vertexPosition; \n
|
||||
attribute vec2 vertexTexCoord; \n
|
||||
attribute vec4 vertexColor; \n
|
||||
varying vec2 fragTexCoord; \n
|
||||
varying vec4 fragColor; \n
|
||||
#elif defined(RSGL_OPENGL_33)
|
||||
\x23version 330 \n
|
||||
in vec3 vertexPosition; \n
|
||||
in vec2 vertexTexCoord; \n
|
||||
in vec4 vertexColor; \n
|
||||
out vec2 fragTexCoord; \n
|
||||
out vec4 fragColor; \n
|
||||
#endif
|
||||
#if defined(RSGL_OPENGL_ES2)
|
||||
\x23version 100 \n
|
||||
precision mediump float; \n
|
||||
attribute vec3 vertexPosition; \n
|
||||
attribute vec2 vertexTexCoord; \n
|
||||
attribute vec4 vertexColor; \n
|
||||
varying vec2 fragTexCoord; \n
|
||||
varying vec4 fragColor; \n
|
||||
#endif
|
||||
void main() {
|
||||
fragTexCoord = vertexTexCoord;
|
||||
fragColor = vertexColor;
|
||||
gl_Position = vec4(vertexPosition, 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
static const char* defaultFShaderCode = RSGL_MULTILINE_STR(
|
||||
#if defined(RSGL_OPENGL_21)
|
||||
\x23version 120 \n
|
||||
varying vec2 fragTexCoord;
|
||||
varying vec4 fragColor;
|
||||
#elif defined(RSGL_OPENGL_33)
|
||||
\x23version 330 \n
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
out vec4 finalColor;
|
||||
#endif
|
||||
#if defined(RSGL_OPENGL_ES2)
|
||||
\x23version 100 \n
|
||||
precision mediump float; \n
|
||||
varying vec2 fragTexCoord; \n
|
||||
varying vec4 fragColor; \n
|
||||
#endif
|
||||
uniform sampler2D texture0;
|
||||
void main() {
|
||||
#ifdef RSGL_OPENGL_33
|
||||
finalColor = texture(texture0, fragTexCoord) * fragColor;
|
||||
#else
|
||||
gl_FragColor = texture2D(texture0, fragTexCoord) * fragColor;
|
||||
#endif
|
||||
}
|
||||
);
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glGenVertexArrays(1, &RSGL_gl.vao);
|
||||
glBindVertexArray(RSGL_gl.vao);
|
||||
#endif
|
||||
|
||||
glGenBuffers(1, &RSGL_gl.vbo);
|
||||
glGenBuffers(1, &RSGL_gl.tbo);
|
||||
glGenBuffers(1, &RSGL_gl.cbo);
|
||||
|
||||
RSGL_gl.program = RSGL_renderCreateProgram(defaultVShaderCode, defaultFShaderCode, "vertexPosition", "vertexTexCoord", "vertexColor");
|
||||
|
||||
/* Init default vertex arrays buffers */
|
||||
/* Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) */
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glBindVertexArray(RSGL_gl.vao);
|
||||
#endif
|
||||
|
||||
/* Quads - Vertex buffers binding and attributes enable */
|
||||
/* Vertex position buffer (shader-location = 0) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, RSGL_MAX_VERTS * 3 * 4 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
|
||||
|
||||
/* Vertex texcoord buffer (shader-location = 1) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.tbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, RSGL_MAX_VERTS * 2 * 4 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
|
||||
|
||||
/* Vertex color buffer (shader-location = 3) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.cbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, RSGL_MAX_VERTS * 4 * sizeof(float), NULL, GL_DYNAMIC_DRAW);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_TRUE, 0, 0);
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
/* Unbind the current VAO */
|
||||
if (RSGL_gl.vao)
|
||||
glBindVertexArray(0);
|
||||
#endif
|
||||
|
||||
/* load default texture */
|
||||
u8 white[4] = {255, 255, 255, 255};
|
||||
RSGL_gl.defaultTex = RSGL_renderCreateTexture(white, RSGL_AREA(1, 1), 4);
|
||||
|
||||
#else
|
||||
RSGL_UNUSED(proc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RSGL_renderFree(void) {
|
||||
#ifdef RSGL_MODERN_OPENGL
|
||||
if (RSGL_args.legacy == 2)
|
||||
return;
|
||||
|
||||
/* Unbind everything */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
/* Unload all vertex buffers data */
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glBindVertexArray(RSGL_gl.vao);
|
||||
glDisableVertexAttribArray(0);
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(2);
|
||||
glDisableVertexAttribArray(3);
|
||||
glBindVertexArray(0);
|
||||
#endif
|
||||
|
||||
/* Delete VBOs from GPU (VRAM) */
|
||||
glDeleteBuffers(1, &RSGL_gl.vbo);
|
||||
glDeleteBuffers(1, &RSGL_gl.tbo);
|
||||
glDeleteBuffers(1, &RSGL_gl.cbo);
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glDeleteVertexArrays(1, &RSGL_gl.vao);
|
||||
#endif
|
||||
|
||||
RSGL_renderDeleteProgram(RSGL_gl.program);
|
||||
|
||||
glDeleteTextures(1, (u32*)&RSGL_gl.defaultTex); /* Unload default texture */
|
||||
#endif
|
||||
}
|
||||
|
||||
void RSGL_renderBatch(RSGL_RENDER_INFO* info) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#ifdef RSGL_MODERN_OPENGL
|
||||
if (info->vert_len > 0 && RSGL_args.legacy == 0) {
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glBindVertexArray(RSGL_gl.vao);
|
||||
#endif
|
||||
|
||||
/* Vertex positions buffer */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.vbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, info->vert_len * 3 * sizeof(float), info->verts);
|
||||
|
||||
/* Texture coordinates buffer */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.tbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, info->vert_len * 2 * sizeof(float), info->texCoords);
|
||||
|
||||
/* Colors buffer */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.cbo);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, info->vert_len * 4 * sizeof(float), info->colors);
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glBindVertexArray(0);
|
||||
#endif
|
||||
|
||||
/* Set current shader */
|
||||
if (RSGL_args.program)
|
||||
glUseProgram(RSGL_args.program);
|
||||
else
|
||||
glUseProgram(RSGL_gl.program.program);
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glBindVertexArray(RSGL_gl.vao);
|
||||
#endif
|
||||
|
||||
/* Bind vertex attrib: position (shader-location = 0) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.vbo);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
/* Bind vertex attrib: texcoord (shader-location = 1) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.tbo);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
/* Bind vertex attrib: color (shader-location = 3) */
|
||||
glBindBuffer(GL_ARRAY_BUFFER, RSGL_gl.cbo);
|
||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_TRUE, 0, 0);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < info->len; i++) {
|
||||
GLenum mode = info->batches[i].type;
|
||||
|
||||
if (mode > 0x0100) {
|
||||
mode -= 0x0100;
|
||||
}
|
||||
|
||||
if (mode > 0x0010) {
|
||||
mode -= 0x0010;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
/* Bind current draw call texture, activated as GL_TEXTURE0 and Bound to sampler2D texture0 by default */
|
||||
if (info->batches[i].tex == 0)
|
||||
info->batches[i].tex = RSGL_gl.defaultTex;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, info->batches[i].tex);
|
||||
glLineWidth(info->batches[i].lineWidth);
|
||||
|
||||
if (RSGL_args.program)
|
||||
glUseProgram(RSGL_args.program);
|
||||
else
|
||||
glUseProgram(RSGL_gl.program.program);
|
||||
|
||||
glDrawArrays(mode, info->batches[i].start, info->batches[i].len);
|
||||
|
||||
if (info->batches[i].type > 0x0010) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!RSGL_gl.vao) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0); /* Unbind textures */
|
||||
|
||||
if (RSGL_gl.vao)
|
||||
glBindVertexArray(0); /* Unbind VAO */
|
||||
|
||||
glUseProgram(0); /* Unbind shader program */
|
||||
}
|
||||
|
||||
else if (RSGL_args.legacy)
|
||||
#endif
|
||||
#ifndef RSGL_GL_NO_LEGACY
|
||||
{
|
||||
size_t i, j;
|
||||
size_t tIndex = 0, cIndex = 0, vIndex = 0;
|
||||
for (i = 0; i < info->len; i++) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, info->batches[i].tex);
|
||||
glLineWidth(info->batches[i].lineWidth);
|
||||
|
||||
u32 mode = info->batches[i].type;
|
||||
if (mode > 0x0100) {
|
||||
glEnable(GL_BLEND);
|
||||
mode -= 0x0100;
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
if (mode > 0x0010) {
|
||||
mode -= 0x0010;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
else {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
glBegin(mode);
|
||||
|
||||
for (j = info->batches[i].start; j < info->batches[i].len; j++) {
|
||||
glTexCoord2f(info->texCoords[tIndex], info->texCoords[tIndex + 1]);
|
||||
glColor4f(info->colors[cIndex], info->colors[cIndex + 1], info->colors[cIndex + 2], info->colors[cIndex + 3]);
|
||||
glVertex3f(info->verts[vIndex], info->verts[vIndex + 1], info->verts[vIndex + 2]);
|
||||
|
||||
tIndex += 2;
|
||||
vIndex += 3;
|
||||
cIndex += 4;
|
||||
}
|
||||
|
||||
glEnd();
|
||||
|
||||
if (info->batches[i].type > 0x0010)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
info->len = 0;
|
||||
info->vert_len = 0;
|
||||
}
|
||||
|
||||
void RSGL_renderScissorStart(RSGL_rectF scissor) {
|
||||
RSGL_draw();
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glScissor(scissor.x, RSGL_args.currentRect.h - (scissor.y + scissor.h), scissor.w, scissor.h);
|
||||
glScissor(scissor.x, scissor.y, scissor.w, scissor.h);
|
||||
}
|
||||
|
||||
void RSGL_renderScissorEnd(void) {
|
||||
RSGL_draw();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
#ifndef GL_RG
|
||||
#define GL_RG 0x8227
|
||||
#endif
|
||||
|
||||
/* textures / images */
|
||||
RSGL_texture RSGL_renderCreateTexture(u8* bitmap, RSGL_area memsize, u8 channels) {
|
||||
unsigned int id = 0;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, memsize.w);
|
||||
|
||||
unsigned int c = 0;
|
||||
|
||||
switch (channels) {
|
||||
case 1: c = GL_RED; break;
|
||||
case 2: c = GL_RG; break;
|
||||
case 3: c = GL_RGB; break;
|
||||
case 4: c = GL_RGBA; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, c, memsize.w, memsize.h, 0, c, GL_UNSIGNED_BYTE, bitmap);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void RSGL_renderUpdateTexture(RSGL_texture texture, u8* bitmap, RSGL_area memsize, u8 channels) {
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, memsize.w);
|
||||
|
||||
u16 c = 0;
|
||||
switch (channels) {
|
||||
case 1: c = GL_RED; break;
|
||||
case 2: c = GL_RG; break;
|
||||
case 3: c = GL_RGB; break;
|
||||
case 4: c = GL_RGBA; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, c, memsize.w, memsize.h, 0, c, GL_UNSIGNED_BYTE, bitmap);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
#ifdef RSGL_MODERN_OPENGL
|
||||
|
||||
#ifndef GL_DEBUG_TYPE_ERROR
|
||||
#define GL_DEBUG_TYPE_ERROR 0x824C
|
||||
#define GL_DEBUG_OUTPUT 0x92E0
|
||||
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
|
||||
#define GL_COMPILE_STATUS 0x8B81
|
||||
#define GL_LINK_STATUS 0x8B82
|
||||
#define GL_INFO_LOG_LENGTH 0x8B84
|
||||
#endif
|
||||
|
||||
void RSGL_opengl_getError(void) {
|
||||
GLenum err;
|
||||
while ((err = glGetError()) != GL_NO_ERROR) {
|
||||
switch (err) {
|
||||
case GL_INVALID_ENUM:
|
||||
printf("OpenGL error: GL_INVALID_ENUM\n");
|
||||
break;
|
||||
case GL_INVALID_VALUE:
|
||||
printf("OpenGL error: GL_INVALID_VALUE\n");
|
||||
break;
|
||||
case GL_INVALID_OPERATION:
|
||||
printf("OpenGL error: GL_INVALID_OPERATION\n");
|
||||
break;
|
||||
case GL_STACK_OVERFLOW:
|
||||
printf("OpenGL error: GL_STACK_OVERFLOW\n");
|
||||
break;
|
||||
case GL_STACK_UNDERFLOW:
|
||||
printf("OpenGL error: GL_STACK_UNDERFLOW\n");
|
||||
break;
|
||||
default:
|
||||
printf("OpenGL error: Unknown error code 0x%x\n", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RSGL_debug_shader(u32 src, const char *shader, const char *action) {
|
||||
GLint status;
|
||||
if (action[0] == 'l')
|
||||
glGetProgramiv(src, GL_LINK_STATUS, &status);
|
||||
else
|
||||
glGetShaderiv(src, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (status == GL_TRUE)
|
||||
printf("%s Shader %s successfully.\n", shader, action);
|
||||
else {
|
||||
printf("%s Shader failed to %s.\n", shader, action);
|
||||
|
||||
if (action[0] == 'c') {
|
||||
GLint infoLogLength;
|
||||
glGetShaderiv(src, GL_INFO_LOG_LENGTH, &infoLogLength);
|
||||
|
||||
if (infoLogLength > 0) {
|
||||
GLchar *infoLog = (GLchar *)RSGL_MALLOC(infoLogLength);
|
||||
glGetShaderInfoLog(src, infoLogLength, NULL, infoLog);
|
||||
printf("%s Shader info log:\n%s\n", shader, infoLog);
|
||||
free(infoLog);
|
||||
}
|
||||
}
|
||||
|
||||
RSGL_opengl_getError();
|
||||
}
|
||||
}
|
||||
|
||||
RSGL_programInfo RSGL_renderCreateProgram(const char* VShaderCode, const char* FShaderCode, char* posName, char* texName, char* colorName) {
|
||||
RSGL_programInfo program;
|
||||
|
||||
/* compile vertex shader */
|
||||
program.vShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(program.vShader, 1, &VShaderCode, NULL);
|
||||
glCompileShader(program.vShader);
|
||||
|
||||
RSGL_debug_shader(program.vShader, "Vertex", "compile");
|
||||
|
||||
/* compile fragment shader */
|
||||
program.fShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(program.fShader, 1, &FShaderCode, NULL);
|
||||
glCompileShader(program.fShader);
|
||||
|
||||
RSGL_debug_shader(program.fShader, "Fragment", "compile");
|
||||
|
||||
/* create program and link vertex and fragment shaders */
|
||||
program.program = glCreateProgram();
|
||||
|
||||
glAttachShader(program.program, program.vShader);
|
||||
glAttachShader(program.program, program.fShader);
|
||||
|
||||
glBindAttribLocation(program.program, 0, posName);
|
||||
glBindAttribLocation(program.program, 1, texName);
|
||||
glBindAttribLocation(program.program, 2, colorName);
|
||||
|
||||
glLinkProgram(program.program);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
void RSGL_renderDeleteProgram(RSGL_programInfo program) {
|
||||
glUseProgram(0);
|
||||
|
||||
glDetachShader(program.program, program.vShader);
|
||||
glDetachShader(program.program, program.fShader);
|
||||
glDeleteShader(program.vShader);
|
||||
glDeleteShader(program.fShader);
|
||||
|
||||
glDeleteProgram(program.program);
|
||||
}
|
||||
|
||||
void RSGL_renderSetShaderValue(u32 program, char* var, float value[], u8 len) {
|
||||
glUseProgram(program);
|
||||
int loc = glGetUniformLocation(program, var);
|
||||
|
||||
switch (len) {
|
||||
case 1: glUniform1f(loc, value[0]); break;
|
||||
case 2: glUniform2f(loc, value[0], value[1]); break;
|
||||
case 3: glUniform3f(loc, value[0], value[1], value[2]); break;
|
||||
case 4: glUniform4f(loc, value[0], value[1], value[2], value[3]); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef GL_PERSPECTIVE_CORRECTION_HINT
|
||||
#define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50
|
||||
#endif
|
||||
|
||||
#ifndef GL_TEXTURE_SWIZZLE_RGBA
|
||||
#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
|
||||
#endif
|
||||
|
||||
#ifndef GL_TEXTURE0
|
||||
#define GL_TEXTURE0 0x84C0
|
||||
#endif
|
||||
|
||||
#ifndef GL_CLAMP_TO_EDGE
|
||||
#define GL_CLAMP_TO_EDGE 0x812F
|
||||
#endif
|
||||
|
||||
RFont_texture RFont_create_atlas(u32 atlasWidth, u32 atlasHeight) {
|
||||
#if defined(RFONT_DEBUG) && !defined(RFONT_RENDER_LEGACY)
|
||||
glEnable(GL_DEBUG_OUTPUT);
|
||||
#endif
|
||||
|
||||
u32 id = 0;
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glGenTextures(1, &id);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
u8* data = (u8*)calloc(atlasWidth * atlasHeight * 4, sizeof(u8));
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, atlasWidth, atlasHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
|
||||
free(data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
static GLint swizzleRgbaParams[4] = {GL_ONE, GL_ONE, GL_ONE, GL_RED};
|
||||
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleRgbaParams);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
#ifndef GL_UNPACK_ROW_LENGTH
|
||||
#define GL_UNPACK_ROW_LENGTH 0x0CF2
|
||||
#define GL_UNPACK_SKIP_PIXELS 0x0CF4
|
||||
#define GL_UNPACK_SKIP_ROWS 0x0CF3
|
||||
#endif
|
||||
|
||||
|
||||
void RFont_push_pixel_values(GLint alignment, GLint rowLength, GLint skipPixels, GLint skipRows);
|
||||
void RFont_push_pixel_values(GLint alignment, GLint rowLength, GLint skipPixels, GLint skipRows) {
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, rowLength);
|
||||
glPixelStorei(GL_UNPACK_SKIP_PIXELS, skipPixels);
|
||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, skipRows);
|
||||
}
|
||||
|
||||
void RFont_bitmap_to_atlas(RFont_texture atlas, u8* bitmap, float x, float y, float w, float h) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
GLint alignment, rowLength, skipPixels, skipRows;
|
||||
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
|
||||
glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowLength);
|
||||
glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skipPixels);
|
||||
glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skipRows);
|
||||
|
||||
#if !defined(RFONT_RENDER_LEGACY)
|
||||
glActiveTexture(GL_TEXTURE0 + atlas - 1);
|
||||
#endif
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, atlas);
|
||||
|
||||
RFont_push_pixel_values(1, w, 0, 0);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RED, GL_UNSIGNED_BYTE, bitmap);
|
||||
|
||||
RFont_push_pixel_values(alignment, rowLength, skipPixels, skipRows);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
#ifdef RSGL_MODERN_OPENGL
|
||||
|
||||
#ifndef RSGL_NO_GL_LOADER
|
||||
int RSGL_loadGLModern(RSGLloadfunc proc) {
|
||||
RSGL_PROC_DEF(proc, glShaderSource);
|
||||
RSGL_PROC_DEF(proc, glCreateShader);
|
||||
RSGL_PROC_DEF(proc, glCompileShader);
|
||||
RSGL_PROC_DEF(proc, glCreateProgram);
|
||||
RSGL_PROC_DEF(proc, glAttachShader);
|
||||
RSGL_PROC_DEF(proc, glBindAttribLocation);
|
||||
RSGL_PROC_DEF(proc, glLinkProgram);
|
||||
RSGL_PROC_DEF(proc, glBindBuffer);
|
||||
RSGL_PROC_DEF(proc, glBufferData);
|
||||
RSGL_PROC_DEF(proc, glEnableVertexAttribArray);
|
||||
RSGL_PROC_DEF(proc, glVertexAttribPointer);
|
||||
RSGL_PROC_DEF(proc, glDisableVertexAttribArray);
|
||||
RSGL_PROC_DEF(proc, glDeleteBuffers);
|
||||
RSGL_PROC_DEF(proc, glUseProgram);
|
||||
RSGL_PROC_DEF(proc, glDetachShader);
|
||||
RSGL_PROC_DEF(proc, glDeleteShader);
|
||||
RSGL_PROC_DEF(proc, glDeleteProgram);
|
||||
RSGL_PROC_DEF(proc, glBufferSubData);
|
||||
RSGL_PROC_DEF(proc, glGetShaderiv);
|
||||
RSGL_PROC_DEF(proc, glGetShaderInfoLog);
|
||||
RSGL_PROC_DEF(proc, glGetProgramiv);
|
||||
RSGL_PROC_DEF(proc, glGetProgramInfoLog);
|
||||
RSGL_PROC_DEF(proc, glGenBuffers);
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2) && !defined(RSGL_OPENGL_ES3)
|
||||
RSGL_PROC_DEF(proc, glBindVertexArray);
|
||||
RSGL_PROC_DEF(proc, glGenVertexArrays);
|
||||
RSGL_PROC_DEF(proc, glDeleteVertexArrays);
|
||||
#endif
|
||||
RSGL_PROC_DEF(proc, glGetUniformLocation);
|
||||
RSGL_PROC_DEF(proc, glUniformMatrix4fv);
|
||||
RSGL_PROC_DEF(proc, glActiveTexture);
|
||||
RSGL_PROC_DEF(proc, glUniform1f);
|
||||
RSGL_PROC_DEF(proc, glUniform2f);
|
||||
RSGL_PROC_DEF(proc, glUniform3f);
|
||||
RSGL_PROC_DEF(proc, glUniform4f);
|
||||
|
||||
#if defined(RSGL_OPENGL_ES2) && !defined(RSGL_OPENGL_ES3)
|
||||
glGenVertexArraysSRC = (PFNGLGENVERTEXARRAYSOESPROC)((RSGLloadfunc)loader)("glGenVertexArraysOES");
|
||||
glBindVertexArraySRC = (PFNGLBINDVERTEXARRAYOESPROC)((RSGLloadfunc)loader)("glBindVertexArrayOES");
|
||||
glDeleteVertexArraysSRC = (PFNGLDELETEVERTEXARRAYSOESPROC)((RSGLloadfunc)loader)("glDeleteVertexArraysOES");
|
||||
#endif
|
||||
|
||||
if (
|
||||
glShaderSourceSRC == NULL ||
|
||||
glCreateShaderSRC == NULL ||
|
||||
glCompileShaderSRC == NULL ||
|
||||
glCreateProgramSRC == NULL ||
|
||||
glAttachShaderSRC == NULL ||
|
||||
glBindAttribLocationSRC == NULL ||
|
||||
glLinkProgramSRC == NULL ||
|
||||
glBindBufferSRC == NULL ||
|
||||
glBufferDataSRC == NULL ||
|
||||
glVertexAttribPointerSRC == NULL ||
|
||||
glDisableVertexAttribArraySRC == NULL ||
|
||||
glDeleteBuffersSRC == NULL ||
|
||||
glUseProgramSRC == NULL ||
|
||||
glDetachShaderSRC == NULL ||
|
||||
glDeleteShaderSRC == NULL ||
|
||||
glDeleteProgramSRC == NULL ||
|
||||
glBufferSubDataSRC == NULL ||
|
||||
glGetShaderivSRC == NULL ||
|
||||
glGetShaderInfoLogSRC == NULL ||
|
||||
glGetProgramivSRC == NULL ||
|
||||
glGetProgramInfoLogSRC == NULL ||
|
||||
glGenBuffersSRC == NULL ||
|
||||
glGetUniformLocationSRC == NULL ||
|
||||
glUniformMatrix4fvSRC == NULL
|
||||
)
|
||||
return 1;
|
||||
|
||||
#if !defined(RSGL_OPENGL_21)
|
||||
GLuint vao;
|
||||
glGenVertexArraysSRC(1, &vao);
|
||||
|
||||
if (vao == 0)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#if !defined(RSGL_OPENGL_21) && !defined(RSGL_OPENGL_ES2)
|
||||
glDeleteVertexArraysSRC(1, &vao);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RSGL_MODERN_OPENGL */
|
104
renderers/RSGL/clay_renderer_RSGL.c
Normal file
104
renderers/RSGL/clay_renderer_RSGL.c
Normal file
@ -0,0 +1,104 @@
|
||||
#include "RSGL.h"
|
||||
#include "clay.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define RFONT_FONT_SCALE 1
|
||||
|
||||
#define CLAY_COLOR_TO_RSGL_COLOR(color) \
|
||||
RSGL_RGBA((unsigned char)roundf(color.r), (unsigned char)roundf(color.g), (unsigned char)roundf(color.b), (unsigned char)roundf(color.a))
|
||||
|
||||
static Clay_Dimensions RSGL_MeasureText(Clay_String *text, Clay_TextElementConfig *config)
|
||||
{
|
||||
RSGL_area area = RSGL_textArea(text->chars, config->fontSize / RFONT_FONT_SCALE, text->length);
|
||||
return (Clay_Dimensions) {
|
||||
.width = (float)area.w,
|
||||
.height = (float)area.h,
|
||||
};
|
||||
}
|
||||
|
||||
static void Clay_RSGL_Render(Clay_RenderCommandArray renderCommands)
|
||||
{
|
||||
for (uint32_t i = 0; i < renderCommands.length; i++)
|
||||
{
|
||||
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, i);
|
||||
RSGL_rectF boundingBox = RSGL_RECTF(renderCommand->boundingBox.x,
|
||||
renderCommand->boundingBox.y,
|
||||
renderCommand->boundingBox.width,
|
||||
renderCommand->boundingBox.height);
|
||||
|
||||
switch (renderCommand->commandType)
|
||||
{
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
Clay_RectangleElementConfig *config = renderCommand->config.rectangleElementConfig;
|
||||
RSGL_drawRectF(boundingBox, CLAY_COLOR_TO_RSGL_COLOR(config->color));
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
Clay_TextElementConfig *config = renderCommand->config.textElementConfig;
|
||||
Clay_String text = renderCommand->text;
|
||||
RSGL_setFont(config->fontId);
|
||||
|
||||
RSGL_color color = RSGL_RGBA( (u8)(config->textColor.r),
|
||||
(u8)(config->textColor.g),
|
||||
(u8)(config->textColor.b),
|
||||
(u8)(config->textColor.a));
|
||||
|
||||
RSGL_circle destination = RSGL_CIRCLE(
|
||||
boundingBox.x,
|
||||
boundingBox.y,
|
||||
config->fontSize / RFONT_FONT_SCALE);
|
||||
RSGL_drawText_pro(text.chars, text.length, config->letterSpacing, destination, color);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE:
|
||||
Clay_ImageElementConfig* config = renderCommand->config.imageElementConfig;
|
||||
RSGL_setTexture((RSGL_texture)config->imageData);
|
||||
RSGL_drawRectF(boundingBox, RSGL_RGBA(255, 255, 255, 255));
|
||||
break;
|
||||
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||
Clay_BorderElementConfig *config = renderCommand->config.borderElementConfig;
|
||||
if (config->left.width > 0) {
|
||||
RSGL_drawRectF(RSGL_RECTF(boundingBox.x,
|
||||
boundingBox.y + config->cornerRadius.topLeft,
|
||||
config->left.width,
|
||||
boundingBox.h - config->cornerRadius.topLeft - config->cornerRadius.bottomLeft),
|
||||
CLAY_COLOR_TO_RSGL_COLOR(config->left.color));
|
||||
}
|
||||
if (config->right.width > 0) {
|
||||
RSGL_drawRectF(RSGL_RECTF(boundingBox.x + boundingBox.w - config->right.width,
|
||||
boundingBox.y + config->cornerRadius.topRight,
|
||||
config->right.width,
|
||||
boundingBox.h - config->cornerRadius.topRight - config->cornerRadius.bottomRight),
|
||||
CLAY_COLOR_TO_RSGL_COLOR(config->right.color));
|
||||
}
|
||||
if (config->top.width > 0) {RSGL_drawRectF(RSGL_RECTF(boundingBox.x + config->cornerRadius.topLeft, boundingBox.y,
|
||||
boundingBox.w - config->cornerRadius.topLeft - config->cornerRadius.topRight,
|
||||
config->top.width),
|
||||
CLAY_COLOR_TO_RSGL_COLOR(config->top.color));
|
||||
}
|
||||
if (config->bottom.width > 0) {RSGL_drawRectF(RSGL_RECTF(boundingBox.x + config->cornerRadius.bottomLeft, \
|
||||
boundingBox.y + boundingBox.h - config->bottom.width,
|
||||
boundingBox.w - config->cornerRadius.bottomLeft - config->cornerRadius.bottomRight,
|
||||
config->bottom.width),
|
||||
CLAY_COLOR_TO_RSGL_COLOR(config->bottom.color));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||
RSGL_renderScissorStart(boundingBox);
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||
RSGL_renderScissorEnd();
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_CUSTOM:
|
||||
printf("Custom render commands have not been implemented yet\n");
|
||||
break;
|
||||
default: {
|
||||
fprintf(stderr, "Error: unhandled render command: %d\n", renderCommand->commandType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3732
renderers/RSGL/deps/RFont.h
Normal file
3732
renderers/RSGL/deps/RFont.h
Normal file
File diff suppressed because it is too large
Load Diff
7898
renderers/RSGL/deps/stb_image.h
Normal file
7898
renderers/RSGL/deps/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user