Merge with origin/main

This commit is contained in:
jdflyer
2026-08-17 22:52:28 -07:00
133 changed files with 3076 additions and 886 deletions
+1 -1
View File
@@ -16,7 +16,7 @@
* of letting them corrupt memory.
*/
#define GAME_SERVICE_ID "dev.twilitrealm.dusklight.game"
#define GAME_SERVICE_MAJOR 1u
#define GAME_SERVICE_MAJOR 2u
#define GAME_SERVICE_MINOR 0u
typedef struct GameService {
+71 -3
View File
@@ -33,10 +33,68 @@
#define GFX_SERVICE_ID "dev.twilitrealm.dusklight.gfx"
#define GFX_SERVICE_MAJOR 1u
#define GFX_SERVICE_MINOR 1u
#define GFX_SERVICE_MINOR 2u
/* Maximum size for push_draw payload */
#define GFX_INLINE_DRAW_PAYLOAD_SIZE 128u
#define GFX_MAX_COLOR_ATTACHMENTS 8u
#define GFX_SCENE_COLOR_ATTACHMENT_INDEX 0u
typedef enum GfxAttachmentSemantic {
GFX_ATTACHMENT_SCENE_COLOR,
GFX_ATTACHMENT_NORMAL,
GFX_ATTACHMENT_AUXILIARY,
} GfxAttachmentSemantic;
typedef struct GfxColorAttachmentLayout {
GfxAttachmentSemantic semantic;
WGPUTextureFormat format;
uint32_t width;
uint32_t height;
} GfxColorAttachmentLayout;
typedef struct GfxRenderTargetLayout {
uint32_t struct_size;
uint64_t key;
/* At least one; scene color is at GFX_SCENE_COLOR_ATTACHMENT_INDEX. */
uint32_t color_attachment_count;
GfxColorAttachmentLayout color_attachments[GFX_MAX_COLOR_ATTACHMENTS];
WGPUTextureFormat depth_stencil_format;
uint32_t sample_count;
} GfxRenderTargetLayout;
#define GFX_RENDER_TARGET_LAYOUT_INIT \
{sizeof(GfxRenderTargetLayout), 0u, 0u, \
{{GFX_ATTACHMENT_AUXILIARY, WGPUTextureFormat_Undefined}}, WGPUTextureFormat_Undefined, \
1u}
/*
* Initializes pipeline color targets for a render-target layout. Only scene color is writable;
* callers that write another semantic should override that target afterward.
*/
static uint32_t gfx_init_color_target_states(const GfxRenderTargetLayout* layout,
WGPUColorTargetState targets[GFX_MAX_COLOR_ATTACHMENTS], const WGPUBlendState* scene_blend,
WGPUColorWriteMask scene_write_mask) {
if (layout == NULL || targets == NULL) {
return 0;
}
const uint32_t count = layout->color_attachment_count < GFX_MAX_COLOR_ATTACHMENTS ?
layout->color_attachment_count :
GFX_MAX_COLOR_ATTACHMENTS;
for (uint32_t i = 0; i < GFX_MAX_COLOR_ATTACHMENTS; ++i) {
WGPUColorTargetState target = WGPU_COLOR_TARGET_STATE_INIT;
if (i < count) {
target.format = layout->color_attachments[i].format;
target.writeMask = WGPUColorWriteMask_None;
}
targets[i] = target;
}
if (count != 0) {
targets[GFX_SCENE_COLOR_ATTACHMENT_INDEX].blend = scene_blend;
targets[GFX_SCENE_COLOR_ATTACHMENT_INDEX].writeMask = scene_write_mask;
}
return count;
}
/* 0 is never a valid handle. */
typedef uint64_t GfxDrawTypeHandle;
@@ -51,8 +109,8 @@ typedef struct GfxRange {
} GfxRange;
/*
* Device and scene pass configuration. Valid from mod_initialize onward and stable for the
* session. Offscreen passes from create_pass are always single-sample.
* Device and legacy primary scene-pass configuration. Use get_scene_target_layout when creating
* scene pipelines. Offscreen passes from create_pass are always single-sample.
*/
typedef struct GfxDeviceInfo {
uint32_t struct_size;
@@ -83,12 +141,18 @@ typedef struct GfxDrawContext {
WGPUBuffer index_buffer;
WGPUBuffer uniform_buffer;
WGPUBuffer storage_buffer;
/* deprecated: use layout.color_attachments[GFX_SCENE_COLOR_ATTACHMENT_INDEX].format */
WGPUTextureFormat color_format;
/* deprecated: use layout.depth_stencil_format */
WGPUTextureFormat depth_format;
/* deprecated: use layout.sample_count */
uint32_t sample_count;
/* deprecated: use layout.color_attachments[GFX_SCENE_COLOR_ATTACHMENT_INDEX].width */
uint32_t target_width;
/* deprecated: use layout.color_attachments[GFX_SCENE_COLOR_ATTACHMENT_INDEX].height */
uint32_t target_height;
bool uses_reversed_z;
GfxRenderTargetLayout layout; /* added in GfxService 1.2 */
} GfxDrawContext;
typedef void (*GfxDrawFn)(ModContext* ctx, const GfxDrawContext* draw_ctx, const void* payload,
@@ -269,6 +333,10 @@ typedef struct GfxService {
*/
ModResult (*push_present)(
ModContext* ctx, GfxPresentTargetHandle handle, const void* payload, size_t payload_size);
/* Minor version 2 */
ModResult (*get_scene_target_layout)(ModContext* ctx, GfxRenderTargetLayout* out_layout);
} GfxService;
MOD_DECLARE_SERVICE(GfxService, svc_gfx, GFX_SERVICE_ID, GFX_SERVICE_MAJOR, GFX_SERVICE_MINOR);
+94
View File
@@ -0,0 +1,94 @@
#pragma once
#include <mods/api.h>
#ifdef __cplusplus
#include <mods/service.hpp>
#endif
#define ITEM_SERVICE_ID "dev.twilitrealm.dusklight.item"
#define ITEM_SERVICE_MAJOR 2u
#define ITEM_SERVICE_MINOR 0u
/* 0 is never a valid handle. */
typedef uint64_t ItemCheckHandle;
typedef uint64_t ItemGiveHandle;
/*
* Item check resolution and inventory grants.
*
* Check names are case-sensitive. Resolvers must be free of side effects because the game may
* resolve a check more than once, including once for display and again when granting the item.
* Registrations and pending grants are removed when the calling mod is detached. Callbacks run
* on the game thread.
*/
/* Host-owned callback data, valid only for the duration of the callback. */
typedef struct ItemCheckInfo {
const char* name;
const void* giver_actor; /* fopAc_ac_c*, or NULL when unavailable */
uint8_t vanilla_item;
uint8_t current_item;
} ItemCheckInfo;
/* Return true and write out_item to replace current_item, or false to leave it unchanged. */
typedef bool (*ItemCheckResolveFn)(
ModContext* ctx, const ItemCheckInfo* info, uint8_t* out_item, void* user_data);
typedef enum ItemGiveOrigin {
ITEM_GIVE_ORIGIN_GAME = 0,
ITEM_GIVE_ORIGIN_QUEUE = 1,
ITEM_GIVE_ORIGIN_QUEUE_SILENT = 2,
} ItemGiveOrigin;
/* Host-owned callback data, valid only for the duration of the callback. */
typedef struct ItemGiveInfo {
const char* check_name; /* NULL when the grant is not attributed to a check */
const void* giver_actor; /* fopAc_ac_c*, or NULL when unavailable */
uint8_t item;
uint8_t origin; /* ItemGiveOrigin */
} ItemGiveInfo;
typedef void (*ItemGiveObserveFn)(ModContext* ctx, const ItemGiveInfo* info, void* user_data);
enum {
/* Apply the inventory change without a get-item demo. */
ITEM_GIVE_SILENT = 1u << 0,
/* Resolve item_no as the named check's vanilla item when the queue entry is dispatched. */
ITEM_GIVE_RESOLVE = 1u << 1,
};
typedef struct ItemService {
ServiceHeader header;
/* Set or replace the calling mod's fixed override for name. */
ModResult (*set_check_override)(ModContext* ctx, const char* name, uint8_t item_no);
ModResult (*clear_check_override)(ModContext* ctx, const char* name);
/* Register for name, or for every check when name is NULL. out_handle may be NULL. */
ModResult (*set_check_resolver)(ModContext* ctx, const char* name, ItemCheckResolveFn fn,
void* user_data, ItemCheckHandle* out_handle);
ModResult (*clear_check_resolver)(ModContext* ctx, ItemCheckHandle handle);
/* Resolve without granting an item or notifying give observers. */
ModResult (*resolve_check)(
ModContext* ctx, const char* name, uint8_t vanilla_item, uint8_t* out_item);
/*
* Add a grant to the global FIFO. check_name may be NULL unless ITEM_GIVE_RESOLVE is set.
* Returns MOD_UNAVAILABLE when the queue is full. Entries wait until gameplay is in a safe
* state and are cleared when the active save slot changes.
*/
ModResult (*give_item)(
ModContext* ctx, const char* check_name, uint8_t item_no, uint32_t flags);
/* Observe inventory grants. out_handle may be NULL. */
ModResult (*observe_gives)(
ModContext* ctx, ItemGiveObserveFn fn, void* user_data, ItemGiveHandle* out_handle);
ModResult (*unobserve_gives)(ModContext* ctx, ItemGiveHandle handle);
} ItemService;
MOD_DECLARE_SERVICE(ItemService, svc_item, ITEM_SERVICE_ID, ITEM_SERVICE_MAJOR, ITEM_SERVICE_MINOR);