mirror of
https://github.com/nicbarker/clay.git
synced 2025-04-14 02:08:04 +00:00
Merge e5cf195d8a
into 06167b4f4b
This commit is contained in:
commit
89bae417d4
3
examples/allegro4-demo/README
Normal file
3
examples/allegro4-demo/README
Normal file
@ -0,0 +1,3 @@
|
||||
# Allegro 4 demo
|
||||
|
||||
To build this demo on your system of choice, include all source files in this directory, as well as in "renderers/alleg4" and link with a 4.x version of Allegro. It's probably easiest to go with a pre-built binary.
|
486
examples/allegro4-demo/main.c
Normal file
486
examples/allegro4-demo/main.c
Normal file
@ -0,0 +1,486 @@
|
||||
#include "renderers/alleg4/alleg4.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
// Locked 50 FPS
|
||||
#define TICKRATE_MS 20
|
||||
#define DEG_TO_RAD(x) ((x) / 180.0 * M_PI)
|
||||
|
||||
static volatile int pending_main_loop_update = 0;
|
||||
|
||||
void main_loop_ticker() {
|
||||
pending_main_loop_update = 1;
|
||||
}
|
||||
END_OF_FUNCTION(main_loop_ticker);
|
||||
|
||||
static const int FONT_ID_BODY_16 = 0;
|
||||
static const int FONT_ID_LARGE_TITLE = 1;
|
||||
static Clay_Color COLOR_BLACK = { 0, 0, 0, 255 };
|
||||
static Clay_Color COLOR_WHITE = { 255, 255, 255, 255 };
|
||||
static Clay_Color COLOR_RED = { 255, 0, 0, 255 };
|
||||
|
||||
#define EXPANDING_LAYOUT { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }
|
||||
|
||||
#define BORDER_DEPTH { .width = { 1, 2, 1, 2, 0 }, .color = COLOR_BLACK }
|
||||
|
||||
#define BEVELED(PADDING, BG, WIDTH, ...) \
|
||||
CLAY({ \
|
||||
.backgroundColor = BG, \
|
||||
.border = { .width = { 1, 0, 1, 0, 0 }, .color = COLOR_WHITE }, \
|
||||
.layout.sizing.height = CLAY_SIZING_GROW(0), \
|
||||
.layout.sizing.width = WIDTH > 0 ? CLAY_SIZING_FIXED(WIDTH) : WIDTH == 0 ? CLAY_SIZING_GROW() : CLAY_SIZING_FIT() \
|
||||
}) { \
|
||||
CLAY({ \
|
||||
.layout.padding.left = PADDING, \
|
||||
.layout.padding.right = PADDING, \
|
||||
.layout.sizing.width = CLAY_SIZING_GROW(), \
|
||||
.layout.sizing.height = CLAY_SIZING_GROW(), \
|
||||
.layout.childAlignment.x = CLAY_ALIGN_X_CENTER, \
|
||||
.layout.childAlignment.y = CLAY_ALIGN_Y_CENTER, \
|
||||
.border = { .width = { 0, 1, 0, 1, 0 }, .color = { 128, 128, 128, 255 }, } \
|
||||
}) { \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
}
|
||||
|
||||
static struct {
|
||||
BITMAP *lib_logo;
|
||||
BITMAP *environment_category;
|
||||
BITMAP *coral_reef;
|
||||
} R;
|
||||
|
||||
static void draw_bouncy_ball(BITMAP *buffer, Clay_BoundingBox box, void *user_data) {
|
||||
#define BALL_R 4
|
||||
#define BORDER 1
|
||||
static int x = BALL_R+BORDER, y = BALL_R+BORDER;
|
||||
static Clay_Vector2 dir = { 1, 1 };
|
||||
|
||||
circlefill(buffer, box.x + x, box.y + y, BALL_R, ALLEGCOLOR(COLOR_RED));
|
||||
|
||||
x += dir.x;
|
||||
y += dir.y;
|
||||
|
||||
if (x <= BALL_R+BORDER || x >= box.width - (BALL_R+BORDER)) {
|
||||
dir.x *= -1;
|
||||
}
|
||||
if (y <= BALL_R+BORDER || y >= box.height - (BALL_R+BORDER)) {
|
||||
dir.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
static Clay_String test_article;
|
||||
|
||||
typedef struct {
|
||||
intptr_t offset;
|
||||
intptr_t memory;
|
||||
} EncartaDemo_Arena;
|
||||
|
||||
typedef struct {
|
||||
EncartaDemo_Arena frameArena;
|
||||
unsigned int counter;
|
||||
} EncartaDemo_Data;
|
||||
|
||||
EncartaDemo_Data EncartaDemo_Initialize() {
|
||||
test_article = CLAY_STRING("A coral reef is an underwater ecosystem characterized by reef-building corals. Reefs are formed of colonies of coral polyps held together by calcium carbonate. Most coral reefs are built from stony corals, whose polyps cluster in groups.\n\nCoral belongs to the class Anthozoa in the animal phylum Cnidaria, which includes sea anemones and jellyfish. Unlike sea anemones, corals secrete hard carbonate exoskeletons that support and protect the coral. Most reefs grow best in warm, shallow, clear, sunny and agitated water. Coral reefs first appeared 485 million years ago, at the dawn of the Early Ordovician, displacing the microbial and sponge reefs of the Cambrian.\n\nSometimes called rainforests of the sea, shallow coral reefs form some of Earth's most diverse ecosystems. They occupy less than 0.1% of the world's ocean area, about half the area of France, yet they provide a home for at least 25% of all marine species, including fish, mollusks, worms, crustaceans, echinoderms, sponges, tunicates and other cnidarians. Coral reefs flourish in ocean waters that provide few nutrients. They are most commonly found at shallow depths in tropical waters, but deep water and cold water coral reefs exist on smaller scales in other areas.\n\nShallow tropical coral reefs have declined by 50% since 1950, partly because they are sensitive to water conditions. They are under threat from excess nutrients (nitrogen and phosphorus), rising ocean heat content and acidification, overfishing (e.g., from blast fishing, cyanide fishing, spearfishing on scuba), sunscreen use, and harmful land-use practices, including runoff and seeps (e.g., from injection wells and cesspools).\n\nCoral reefs deliver ecosystem services for tourism, fisheries and shoreline protection. The annual global economic value of coral reefs has been estimated at anywhere from US$30-375 billion (1997 and 2003 estimates) to US$2.7 trillion (a 2020 estimate) to US$9.9 trillion (a 2014 estimate).\n\nThough the shallow water tropical coral reefs are best known, there are also deeper water reef-forming corals, which live in colder water and in temperate seas.\n\n\n(( Material ))\n\nAs the name implies, coral reefs are made up of coral skeletons from mostly intact coral colonies. As other chemical elements present in corals become incorporated into the calcium carbonate deposits, aragonite is formed. However, shell fragments and the remains of coralline algae such as the green-segmented genus Halimeda can add to the reef's ability to withstand damage from storms and other threats. Such mixtures are visible in structures such as Eniwetok Atoll.");
|
||||
|
||||
EncartaDemo_Data data = {
|
||||
.frameArena = { .memory = (intptr_t)malloc(1024) },
|
||||
.counter = 0
|
||||
};
|
||||
return data;
|
||||
}
|
||||
|
||||
void BeveledButton(Clay_String text, int padding, int fixedWidth) {
|
||||
BEVELED(padding, Clay_Hovered() ? ((Clay_Color) { 224, 224, 224, 255 }) : ((Clay_Color) { 192, 192, 192, 255 }), fixedWidth, {
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.fontSize = 16,
|
||||
.textColor = COLOR_BLACK,
|
||||
.textAlignment = CLAY_TEXT_ALIGN_CENTER,
|
||||
.lineHeight = 12
|
||||
}));
|
||||
})
|
||||
}
|
||||
|
||||
static void menubar(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("menubar"),
|
||||
.backgroundColor = {64, 64, 64, 255 },
|
||||
.border = {
|
||||
.width = { 0, 0, 0, 1, 0 },
|
||||
.color = COLOR_BLACK
|
||||
},
|
||||
.layout = {
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_FIXED(24),
|
||||
.width = CLAY_SIZING_GROW(0)
|
||||
},
|
||||
}
|
||||
}) {
|
||||
BeveledButton(CLAY_STRING("Menu"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Contents"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Find"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Go Back"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Gallery"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Atlas"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Timeline"), 12, -1);
|
||||
BeveledButton(CLAY_STRING("Help"), 12, -1);
|
||||
BEVELED(0, ((Clay_Color) { 192, 192, 192, 255 }), 0, { });
|
||||
}
|
||||
}
|
||||
|
||||
static void largeArticleHeading(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("titlebar"),
|
||||
.layout = {
|
||||
.sizing.width = CLAY_SIZING_GROW(),
|
||||
.padding = { 8, 8, 8, 0 },
|
||||
}
|
||||
}) {
|
||||
CLAY({
|
||||
.backgroundColor = {255, 255, 128, 255 },
|
||||
.cornerRadius = { 12, 0, 0, 12 },
|
||||
.layout = {
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_GROW(),
|
||||
.width = CLAY_SIZING_GROW()
|
||||
},
|
||||
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }
|
||||
},
|
||||
.border = { .width = CLAY_BORDER_ALL(1), .color = COLOR_BLACK }
|
||||
}) {
|
||||
CLAY_TEXT(CLAY_STRING("Coral Reef"), CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_LARGE_TITLE,
|
||||
.textColor = COLOR_BLACK
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void demoTitleBox(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("DemoHeader"),
|
||||
.backgroundColor = COLOR_WHITE,
|
||||
.layout.sizing.width = CLAY_SIZING_FIXED(250),
|
||||
.layout.padding = CLAY_PADDING_ALL(5),
|
||||
.layout.childGap = 5,
|
||||
.border = BORDER_DEPTH,
|
||||
.cornerRadius = { 8, 8, 0, 0 }
|
||||
}) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("LibraryLogo"),
|
||||
.layout = { .sizing = CLAY_SIZING_FIXED(28) },
|
||||
.image = { .imageData = R.lib_logo, .sourceDimensions = {28, 28} },
|
||||
.backgroundColor = { 128+sin(DEG_TO_RAD(data->counter))*127, 0, 128+sin(DEG_TO_RAD(data->counter/2))*127, 128 }
|
||||
}) {}
|
||||
|
||||
CLAY_TEXT(CLAY_STRING("Clay Encarta 95:\nAllegro4 Demo"), CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.textColor = COLOR_BLACK
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
static void categoryBox(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("CategoryImage"),
|
||||
.backgroundColor = { 90, 90, 90, 255 },
|
||||
.layout = {
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_FIXED(250),
|
||||
.height = CLAY_SIZING_FIT()
|
||||
}
|
||||
},
|
||||
.border = BORDER_DEPTH
|
||||
}) {
|
||||
CLAY({
|
||||
.image = {
|
||||
.imageData = R.environment_category,
|
||||
.sourceDimensions = {250, 120}
|
||||
},
|
||||
.layout.sizing.height = CLAY_SIZING_FIXED(120),
|
||||
.layout.padding = CLAY_PADDING_ALL(6),
|
||||
.layout.childAlignment.y = CLAY_ALIGN_Y_BOTTOM
|
||||
}) {
|
||||
CLAY_TEXT(CLAY_STRING("Environment"), CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_LARGE_TITLE,
|
||||
.textColor = COLOR_BLACK
|
||||
}));
|
||||
}
|
||||
|
||||
CLAY({
|
||||
.backgroundColor = {64, 64, 64, 255 },
|
||||
.layout = {
|
||||
.padding = { 1, 2, 1, 2 },
|
||||
.sizing = {
|
||||
.width = CLAY_SIZING_GROW(),
|
||||
.height = CLAY_SIZING_FIT(32),
|
||||
}
|
||||
}
|
||||
}) {
|
||||
BeveledButton(CLAY_STRING("Show List"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("Change\nCategory"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("<"), 8, 28);
|
||||
BeveledButton(CLAY_STRING(">"), 8, 28);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void articleBox(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("ArticleImage"),
|
||||
.backgroundColor = { 90, 90, 90, 255 },
|
||||
.layout = {
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing.width = CLAY_SIZING_FIXED(250)
|
||||
},
|
||||
.border = BORDER_DEPTH
|
||||
}) {
|
||||
CLAY({
|
||||
.image = {
|
||||
.imageData = R.coral_reef,
|
||||
.sourceDimensions = {250, 230}
|
||||
},
|
||||
.layout.sizing.height = CLAY_SIZING_FIXED(230)
|
||||
}) {}
|
||||
|
||||
CLAY({
|
||||
.layout.sizing.height = CLAY_SIZING_FIXED(20),
|
||||
.layout.sizing.width = CLAY_SIZING_GROW(),
|
||||
.layout.padding = { 1, 1, 1, 0 },
|
||||
}) {
|
||||
BEVELED(0, ((Clay_Color) { 192, 192, 192, 255 }), 0, {
|
||||
CLAY_TEXT(CLAY_STRING("Biodiversity of a coral reef"), CLAY_TEXT_CONFIG({
|
||||
.fontId = -1,
|
||||
.textColor = COLOR_BLACK
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
CLAY({
|
||||
.backgroundColor = {64, 64, 64, 255 },
|
||||
.layout = {
|
||||
.padding = { 1, 2, 1, 2 },
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_FIT(32),
|
||||
.width = CLAY_SIZING_GROW()
|
||||
}
|
||||
}
|
||||
}) {
|
||||
BeveledButton(CLAY_STRING("Copy"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("Print"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("<"), 8, 28);
|
||||
BeveledButton(CLAY_STRING(">"), 8, 28);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sidebar(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("sidebar"),
|
||||
.layout = {
|
||||
.childGap = 8,
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing.width = CLAY_SIZING_FIT()
|
||||
}
|
||||
}) {
|
||||
demoTitleBox(data);
|
||||
categoryBox(data);
|
||||
articleBox(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void article(EncartaDemo_Data *data) {
|
||||
CLAY({
|
||||
.id = CLAY_ID("article"),
|
||||
.layout = {
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = EXPANDING_LAYOUT
|
||||
},
|
||||
.backgroundColor = COLOR_WHITE,
|
||||
.border = BORDER_DEPTH,
|
||||
.cornerRadius = { 8, 8, 0, 0 },
|
||||
}) {
|
||||
CLAY({
|
||||
.scroll.vertical = true,
|
||||
.layout.padding = CLAY_PADDING_ALL(8),
|
||||
}) {
|
||||
CLAY_TEXT(test_article, CLAY_TEXT_CONFIG({
|
||||
.fontId = FONT_ID_BODY_16,
|
||||
.textColor = COLOR_BLACK
|
||||
}));
|
||||
}
|
||||
|
||||
CLAY({
|
||||
.backgroundColor = {64, 64, 64, 255 },
|
||||
.layout = {
|
||||
.padding = { 1, 2, 1, 2 },
|
||||
.sizing = {
|
||||
.height = CLAY_SIZING_FIT(32),
|
||||
.width = CLAY_SIZING_GROW()
|
||||
}
|
||||
}
|
||||
}) {
|
||||
BeveledButton(CLAY_STRING("Outline"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("See Also"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("Copy"), 8, 0);
|
||||
BeveledButton(CLAY_STRING("Print"), 8, 0);
|
||||
BEVELED(0, ((Clay_Color) { 192, 192, 192, 255 }), 64, {
|
||||
alleg4_custom_element *ball_renderer = (alleg4_custom_element *)(data->frameArena.memory + data->frameArena.offset);
|
||||
data->frameArena.offset += sizeof(alleg4_custom_element);
|
||||
*ball_renderer = (alleg4_custom_element) {
|
||||
&draw_bouncy_ball, NULL
|
||||
};
|
||||
CLAY({
|
||||
.layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) } },
|
||||
.custom = { .customData = ball_renderer }
|
||||
}) { }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clay_RenderCommandArray EncartaDemo_CreateLayout(EncartaDemo_Data *data) {
|
||||
data->frameArena.offset = 0;
|
||||
|
||||
Clay_BeginLayout();
|
||||
|
||||
// Build UI here
|
||||
CLAY({
|
||||
.id = CLAY_ID("outer-container"),
|
||||
.backgroundColor = { 64, 64, 64, 255 },
|
||||
.layout = {
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||
.sizing = EXPANDING_LAYOUT
|
||||
}
|
||||
}) {
|
||||
menubar(data);
|
||||
largeArticleHeading(data);
|
||||
|
||||
CLAY({
|
||||
.id = CLAY_ID("lower-content"),
|
||||
.backgroundColor = { 64, 64, 64, 255 },
|
||||
.layout = {
|
||||
.sizing = EXPANDING_LAYOUT,
|
||||
.childGap = 8,
|
||||
.padding = CLAY_PADDING_ALL(8)
|
||||
}
|
||||
}) {
|
||||
sidebar(data);
|
||||
article(data);
|
||||
}
|
||||
}
|
||||
|
||||
return Clay_EndLayout();
|
||||
}
|
||||
|
||||
void HandleClayErrors(Clay_ErrorData errorData) {
|
||||
printf("%s", errorData.errorText.chars);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
EncartaDemo_Data demoData = EncartaDemo_Initialize();
|
||||
BITMAP *buffer;
|
||||
|
||||
if (allegro_init() != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
install_keyboard();
|
||||
install_mouse();
|
||||
install_timer();
|
||||
set_color_depth(16);
|
||||
|
||||
int driver = GFX_AUTODETECT;
|
||||
|
||||
#ifdef _WIN32
|
||||
driver = GFX_AUTODETECT_WINDOWED;
|
||||
#endif
|
||||
|
||||
set_window_title("Clay Encarta 95");
|
||||
|
||||
if (set_gfx_mode(driver, 800, 600, 0, 0) != 0) {
|
||||
if (set_gfx_mode(GFX_SAFE, 800, 600, 0, 0) != 0) {
|
||||
set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
|
||||
allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (install_int(main_loop_ticker, TICKRATE_MS) < 0) {
|
||||
allegro_message("Error installing interrupt\n%s\n", allegro_error);
|
||||
return 4;
|
||||
}
|
||||
|
||||
LOCK_VARIABLE(pending_main_loop_update);
|
||||
LOCK_FUNCTION(main_loop_ticker);
|
||||
|
||||
alleg4_init_fonts(2); /* Allocate space for 1 font */
|
||||
alleg4_set_font(FONT_ID_BODY_16, load_font("res/8x16.pcx", NULL, NULL));
|
||||
alleg4_set_font(FONT_ID_LARGE_TITLE, load_font("res/ex06.pcx", NULL, NULL));
|
||||
|
||||
buffer = create_bitmap(SCREEN_W, SCREEN_H);
|
||||
|
||||
R.lib_logo = load_bitmap("res/liblogo.pcx", NULL);
|
||||
R.environment_category = load_bitmap("res/env.pcx", NULL);
|
||||
R.coral_reef = load_bitmap("res/coral.pcx", NULL);
|
||||
|
||||
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
|
||||
|
||||
Clay_Initialize(clayMemory, (Clay_Dimensions) {
|
||||
(float)SCREEN_W, (float)SCREEN_H
|
||||
}, (Clay_ErrorHandler) {
|
||||
HandleClayErrors
|
||||
});
|
||||
Clay_SetMeasureTextFunction(alleg4_measure_text, NULL);
|
||||
|
||||
show_os_cursor(MOUSE_CURSOR_ARROW);
|
||||
enable_hardware_cursor();
|
||||
|
||||
int _mouse_w = mouse_w, _mouse_z = mouse_z;
|
||||
|
||||
while (!keypressed()) {
|
||||
if (!pending_main_loop_update) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pending_main_loop_update = false;
|
||||
|
||||
clear_to_color(buffer, makecol(0, 0, 0));
|
||||
|
||||
if (mouse_needs_poll()) {
|
||||
poll_mouse();
|
||||
}
|
||||
|
||||
Clay_SetLayoutDimensions((Clay_Dimensions) {
|
||||
(float)SCREEN_W, (float)SCREEN_H
|
||||
});
|
||||
Clay_SetPointerState((Clay_Vector2) {
|
||||
mouse_x, mouse_y
|
||||
}, mouse_b & 1);
|
||||
Clay_UpdateScrollContainers(true, (Clay_Vector2) {
|
||||
mouse_w - _mouse_w, mouse_z - _mouse_z
|
||||
}, (float)TICKRATE_MS / 1000.f);
|
||||
|
||||
_mouse_w = mouse_w;
|
||||
_mouse_z = mouse_z;
|
||||
|
||||
Clay_RenderCommandArray renderCommands = EncartaDemo_CreateLayout(&demoData);
|
||||
alleg4_render(buffer, renderCommands);
|
||||
|
||||
demoData.counter ++;
|
||||
|
||||
if (gfx_capabilities & GFX_HW_CURSOR) {
|
||||
blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
|
||||
} else {
|
||||
show_mouse(NULL);
|
||||
blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
|
||||
show_mouse(screen);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
END_OF_MAIN()
|
BIN
examples/allegro4-demo/res/8x16.pcx
Normal file
BIN
examples/allegro4-demo/res/8x16.pcx
Normal file
Binary file not shown.
BIN
examples/allegro4-demo/res/coral.pcx
Normal file
BIN
examples/allegro4-demo/res/coral.pcx
Normal file
Binary file not shown.
BIN
examples/allegro4-demo/res/env.pcx
Normal file
BIN
examples/allegro4-demo/res/env.pcx
Normal file
Binary file not shown.
BIN
examples/allegro4-demo/res/ex06.pcx
Normal file
BIN
examples/allegro4-demo/res/ex06.pcx
Normal file
Binary file not shown.
BIN
examples/allegro4-demo/res/liblogo.pcx
Normal file
BIN
examples/allegro4-demo/res/liblogo.pcx
Normal file
Binary file not shown.
306
renderers/alleg4/alleg4.c
Normal file
306
renderers/alleg4/alleg4.c
Normal file
@ -0,0 +1,306 @@
|
||||
#define CLAY_IMPLEMENTATION
|
||||
#include "alleg4.h"
|
||||
|
||||
#define CLIPPED_OPERATION(BUF, X, Y, W, H, CODE) { \
|
||||
int _X0, _Y0, _X1, _Y1; \
|
||||
get_clip_rect(BUF, &_X0, &_Y0, &_X1, &_Y1); \
|
||||
set_clip_rect(BUF, X, Y, X+W-1, Y+H-1); \
|
||||
CODE; \
|
||||
set_clip_rect(BUF, _X0, _Y0, _X1, _Y1); \
|
||||
}
|
||||
|
||||
typedef struct alleg4_font_store {
|
||||
size_t size;
|
||||
FONT *fonts[];
|
||||
} alleg4_font_store;
|
||||
|
||||
static alleg4_font_store *font_store = NULL;
|
||||
|
||||
void alleg4_init_fonts(size_t size) {
|
||||
font_store = malloc(sizeof(alleg4_font_store) + sizeof(FONT*[size]));
|
||||
font_store->size = size;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
font_store->fonts[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void alleg4_set_font(unsigned int font_id, FONT *font_object) {
|
||||
font_store->fonts[font_id] = font_object;
|
||||
}
|
||||
|
||||
static inline FONT* get_font(unsigned int font_id) {
|
||||
if (font_id >= 0 && font_id < font_store->size) {
|
||||
return font_store->fonts[font_id];
|
||||
} else {
|
||||
return font; /* Default built-in font */
|
||||
}
|
||||
}
|
||||
|
||||
static inline void arc_thickness(
|
||||
BITMAP *dst,
|
||||
int x,
|
||||
int y,
|
||||
fixed from,
|
||||
fixed to,
|
||||
int r,
|
||||
int color,
|
||||
int thickness
|
||||
) {
|
||||
do {
|
||||
arc(dst, x, y, from, to, r--, color);
|
||||
} while (--thickness);
|
||||
}
|
||||
|
||||
static inline void rectfill_wh(
|
||||
BITMAP *dst,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
int color
|
||||
) {
|
||||
// rectfill uses stard and end coordinates instead of size, so we'd have to -1 all over the place
|
||||
if (w == 1) { vline(dst, x, y, y+h-1, color); }
|
||||
else if (h == 1) { hline(dst, x, y, x+w-1, color); }
|
||||
else { rectfill(dst, x, y, x+w-1, y+h-1, color); }
|
||||
}
|
||||
|
||||
/* Radiuses array contains corner radiuses in clockwise order starting from top-left */
|
||||
static inline void roundrectfill(
|
||||
BITMAP *dst,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h,
|
||||
int color,
|
||||
int r[]
|
||||
) {
|
||||
int top = CLAY__MAX(r[0],r[1]);
|
||||
int bottom = CLAY__MAX(r[2],r[3]);
|
||||
int left = CLAY__MAX(r[0],r[3]);
|
||||
int right = CLAY__MAX(r[1],r[2]);
|
||||
|
||||
if (r[0]) {
|
||||
CLIPPED_OPERATION(dst, x, y, r[0], r[0], {
|
||||
circlefill(dst, x+r[0], y+r[0], r[0], color);
|
||||
});
|
||||
}
|
||||
|
||||
if (r[1]) {
|
||||
CLIPPED_OPERATION(dst, x+w-r[1], y, r[1], r[1], {
|
||||
circlefill(dst, x+w-1-r[1], y+r[1], r[1], color);
|
||||
});
|
||||
}
|
||||
|
||||
if (r[2]) {
|
||||
CLIPPED_OPERATION(dst, x+w-r[2], y+h-r[2], r[2], r[2], {
|
||||
circlefill(dst, x+w-1-r[2], y+h-1-r[2], r[2], color);
|
||||
});
|
||||
}
|
||||
|
||||
if (r[3]) {
|
||||
CLIPPED_OPERATION(dst, x, y+h-r[3], r[3], r[3], {
|
||||
circlefill(dst, x+r[3], y+h-1-r[3], r[3], color);
|
||||
});
|
||||
}
|
||||
|
||||
if (top) {
|
||||
rectfill_wh(dst, x+r[0], y, w-r[0]-r[1], top, color);
|
||||
}
|
||||
|
||||
if (bottom) {
|
||||
rectfill_wh(dst, x+r[3], y+h-bottom, w-r[2]-r[3], bottom, color);
|
||||
}
|
||||
|
||||
if (left) {
|
||||
rectfill_wh(dst, x, y+top, left, h-top-bottom, color);
|
||||
}
|
||||
|
||||
if (right) {
|
||||
rectfill_wh(dst, x+w-right, y+top, right, h-top-bottom, color);
|
||||
}
|
||||
|
||||
rectfill_wh(dst, x+left, y+top, w-left-right, h-top-bottom, color);
|
||||
}
|
||||
|
||||
void alleg4_render(
|
||||
BITMAP *buffer,
|
||||
Clay_RenderCommandArray renderCommands
|
||||
) {
|
||||
static int crx0, cry0, crx1, cry1;
|
||||
|
||||
for (uint32_t i = 0; i < renderCommands.length; i++) {
|
||||
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, i);
|
||||
Clay_BoundingBox box = renderCommand->boundingBox;
|
||||
|
||||
switch (renderCommand->commandType) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
Clay_RectangleRenderData *config = &renderCommand->renderData.rectangle;
|
||||
Clay_Color color = config->backgroundColor;
|
||||
|
||||
int radiuses[] = {
|
||||
config->cornerRadius.topLeft,
|
||||
config->cornerRadius.topRight,
|
||||
config->cornerRadius.bottomRight,
|
||||
config->cornerRadius.bottomLeft
|
||||
};
|
||||
|
||||
if (radiuses[0] + radiuses[1] + radiuses[2] + radiuses[3] > 0) {
|
||||
roundrectfill(buffer, box.x, box.y, box.width, box.height, ALLEGCOLOR(config->backgroundColor), radiuses);
|
||||
} else {
|
||||
rectfill_wh(buffer, box.x, box.y, box.width, box.height, ALLEGCOLOR(config->backgroundColor));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
Clay_TextRenderData *config = &renderCommand->renderData.text;
|
||||
char *slice = (char *)calloc(config->stringContents.length + 1, 1);
|
||||
memcpy(slice, config->stringContents.chars, config->stringContents.length);
|
||||
FONT *font_object = get_font(config->fontId);
|
||||
if (is_color_font(font_object)) {
|
||||
textout_ex(buffer, get_font(config->fontId), slice, box.x, box.y, -1, -1);
|
||||
} else {
|
||||
textout_ex(buffer, get_font(config->fontId), slice, box.x, box.y, ALLEGCOLOR(config->textColor), -1);
|
||||
}
|
||||
free(slice);
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
Clay_ImageRenderData *config = &renderCommand->renderData.image;
|
||||
Clay_Color tintColor = config->backgroundColor;
|
||||
BITMAP *image = (BITMAP *)config->imageData;
|
||||
if (tintColor.r + tintColor.g + tintColor.b == 0) {
|
||||
draw_sprite(buffer, image, box.x, box.y);
|
||||
} else {
|
||||
set_trans_blender(tintColor.r, tintColor.g, tintColor.b, 0);
|
||||
draw_lit_sprite(buffer, image, box.x, box.y, tintColor.a);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||
get_clip_rect(buffer, &crx0, &cry0, &crx1, &cry1); /* Save current clip rect coordinates */
|
||||
set_clip_rect(buffer, box.x, box.y, box.x + box.width, box.y + box.height);
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||
set_clip_rect(buffer, crx0, cry0, crx1, cry1);
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||
Clay_BorderRenderData *config = &renderCommand->renderData.border;
|
||||
|
||||
const float tl = config->cornerRadius.topLeft;
|
||||
const float tr = config->cornerRadius.topRight;
|
||||
const float bl = config->cornerRadius.bottomLeft;
|
||||
const float br = config->cornerRadius.bottomRight;
|
||||
|
||||
if (config->width.left > 0) {
|
||||
rectfill_wh(buffer, box.x, box.y + tl, config->width.left, box.height-tl-bl, ALLEGCOLOR(config->color));
|
||||
|
||||
/* Top-left half-arc */
|
||||
if (tl > 0) {
|
||||
CLIPPED_OPERATION(buffer, box.x, box.y+tl/2, tl, tl/2, {
|
||||
arc_thickness(buffer, box.x+tl, box.y+tl, itofix(64), itofix(128), tl, ALLEGCOLOR(config->color), config->width.left);
|
||||
});
|
||||
}
|
||||
|
||||
/* Bottom-left half-arc */
|
||||
if (bl > 0) {
|
||||
const int y = box.y+box.height-bl;
|
||||
CLIPPED_OPERATION(buffer, box.x, y, bl, bl/2, {
|
||||
arc_thickness(buffer, box.x+bl, y-1, itofix(128), itofix(192), bl, ALLEGCOLOR(config->color), config->width.left);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (config->width.right > 0) {
|
||||
rectfill_wh(buffer, box.x+box.width-config->width.right, box.y+tr, config->width.right, box.height-br-tr, ALLEGCOLOR(config->color));
|
||||
|
||||
/* Top-right half-arc */
|
||||
if (tr > 0) {
|
||||
const int x = box.x+box.width-tr;
|
||||
CLIPPED_OPERATION(buffer, x, box.y+tr/2, tr, tr/2, {
|
||||
arc_thickness(buffer, x-1, box.y+tr, itofix(0), itofix(64), tr, ALLEGCOLOR(config->color), config->width.right);
|
||||
});
|
||||
}
|
||||
|
||||
/* Bottom-right half-arc */
|
||||
if (br > 0) {
|
||||
const int y = box.y+box.height-br;
|
||||
const int x = box.x+box.width-br;
|
||||
CLIPPED_OPERATION(buffer, x, y, br, br/2, {
|
||||
arc_thickness(buffer, x-1, y-1, itofix(192), itofix(256), br, ALLEGCOLOR(config->color), config->width.right);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (config->width.top > 0) {
|
||||
rectfill_wh(buffer, box.x + tl, box.y, box.width - tr - tl, config->width.top, ALLEGCOLOR(config->color));
|
||||
|
||||
/* Top-left half-arc */
|
||||
if (tl > 0) {
|
||||
CLIPPED_OPERATION(buffer, box.x, box.y, tl, tl/2, {
|
||||
arc_thickness(buffer, box.x+tl, box.y+tl, itofix(64), itofix(128), tl, ALLEGCOLOR(config->color), config->width.top);
|
||||
});
|
||||
}
|
||||
|
||||
/* Top-right half-arc */
|
||||
if (tr > 0) {
|
||||
const int x = box.x+box.width-tr;
|
||||
CLIPPED_OPERATION(buffer, x, box.y, tr, tr/2, {
|
||||
arc_thickness(buffer, x-1, box.y+tr, itofix(0), itofix(64), tr, ALLEGCOLOR(config->color), config->width.top);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (config->width.bottom > 0) {
|
||||
rectfill_wh(buffer, box.x+bl, box.y+box.height-config->width.bottom, box.width-br-bl, config->width.bottom, ALLEGCOLOR(config->color));
|
||||
|
||||
/* Bottom-left half-arc */
|
||||
if (bl > 0) {
|
||||
const int y = box.y+box.height-bl;
|
||||
CLIPPED_OPERATION(buffer, box.x, y+bl/2, bl, bl/2, {
|
||||
arc_thickness(buffer, box.x+bl, y-1, itofix(128), itofix(192), bl, ALLEGCOLOR(config->color), config->width.bottom);
|
||||
});
|
||||
}
|
||||
|
||||
/* Bottom-right half-arc */
|
||||
if (br > 0) {
|
||||
const int y = box.y+box.height-br;
|
||||
const int x = box.x+box.width-br;
|
||||
CLIPPED_OPERATION(buffer, x, y+br/2, br, br/2, {
|
||||
arc_thickness(buffer, x-1, y-1, itofix(192), itofix(256), br, ALLEGCOLOR(config->color), config->width.bottom);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CLAY_RENDER_COMMAND_TYPE_CUSTOM: {
|
||||
Clay_CustomRenderData *config = &renderCommand->renderData.custom;
|
||||
alleg4_custom_element *callback_info = (alleg4_custom_element *)config->customData;
|
||||
callback_info->render(buffer, box, callback_info->user_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clay_Dimensions alleg4_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) {
|
||||
FONT *font_object = get_font(config->fontId);
|
||||
char *slice = (char *)calloc(text.length + 1, 1);
|
||||
memcpy(slice, text.chars, text.length);
|
||||
const Clay_Dimensions d = (Clay_Dimensions) {
|
||||
.width = text_length(font_object, slice),
|
||||
.height = text_height(font_object)
|
||||
};
|
||||
free(slice);
|
||||
return d;
|
||||
}
|
28
renderers/alleg4/alleg4.h
Normal file
28
renderers/alleg4/alleg4.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef CLAY_ALLEG4_HEADER
|
||||
#define CLAY_ALLEG4_HEADER
|
||||
|
||||
#include "clay.h"
|
||||
#include <allegro.h>
|
||||
|
||||
#define ALLEGCOLOR(COLOR) makecol(COLOR.r, COLOR.g, COLOR.b)
|
||||
|
||||
typedef struct {
|
||||
void (*render)(BITMAP *buffer, Clay_BoundingBox box, void *user_data);
|
||||
void *user_data;
|
||||
} alleg4_custom_element;
|
||||
|
||||
void alleg4_init_fonts(size_t);
|
||||
void alleg4_set_font(unsigned int, FONT *);
|
||||
|
||||
void alleg4_render(
|
||||
BITMAP *buffer,
|
||||
Clay_RenderCommandArray renderCommands
|
||||
);
|
||||
|
||||
Clay_Dimensions alleg4_measure_text(
|
||||
Clay_StringSlice text,
|
||||
Clay_TextElementConfig *config,
|
||||
void *userData
|
||||
);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user