Merge branch 'master' into master

This commit is contained in:
Jeroen van Rijn
2022-07-28 16:01:18 +02:00
committed by GitHub
619 changed files with 122592 additions and 30625 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
package ENet
when ODIN_OS == "windows" {
when ODIN_ARCH == "amd64" {
when ODIN_OS == .Windows {
when ODIN_ARCH == .amd64 {
foreign import ENet {
"lib/enet64.lib",
"system:Ws2_32.lib",
+3 -3
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package ENet
// When we implement the appropriate bindings for Unix, the section separated
@@ -14,7 +14,7 @@ import "core:c"
@(private="file") FD_ZERO :: #force_inline proc(s: ^fd_set) {
for i := size_of(fd_set) / size_of(c.long); i != 0; i -= 1 {
s.fds_bits[i] = 0;
s.fds_bits[i] = 0
}
}
@@ -56,4 +56,4 @@ SOCKETSET_REMOVE :: #force_inline proc(sockset: ^SocketSet, socket: Socket) {
SOCKSET_CHECK :: #force_inline proc(sockset: ^SocketSet, socket: Socket) -> bool {
return FD_ISSET(i32(socket), cast(^fd_set)sockset)
}
}
+11
View File
@@ -0,0 +1,11 @@
Copyright (c) Contributors to the OpenEXR Project. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Binary file not shown.
+397
View File
@@ -0,0 +1,397 @@
package vendor_openexr
import "core:c"
// Enum declaring allowed values for \c u8 value stored in built-in compression type.
compression_t :: enum c.int {
NONE = 0,
RLE = 1,
ZIPS = 2,
ZIP = 3,
PIZ = 4,
PXR24 = 5,
B44 = 6,
B44A = 7,
DWAA = 8,
DWAB = 9,
}
// Enum declaring allowed values for \c u8 value stored in built-in env map type.
envmap_t :: enum c.int {
LATLONG = 0,
CUBE = 1,
}
// Enum declaring allowed values for \c u8 value stored in \c lineOrder type.
lineorder_t :: enum c.int {
INCREASING_Y = 0,
DECREASING_Y = 1,
RANDOM_Y = 2,
}
// Enum declaring allowed values for part type.
storage_t :: enum c.int {
SCANLINE = 0, // Corresponds to type of \c scanlineimage.
TILED, // Corresponds to type of \c tiledimage.
DEEP_SCANLINE, // Corresponds to type of \c deepscanline.
DEEP_TILED, // Corresponds to type of \c deeptile.
}
// @brief Enum representing what type of tile information is contained.
tile_level_mode_t :: enum c.int {
ONE_LEVEL = 0, // Single level of image data.
MIPMAP_LEVELS = 1, // Mipmapped image data.
RIPMAP_LEVELS = 2, // Ripmapped image data.
}
/** @brief Enum representing how to scale positions between levels. */
tile_round_mode_t :: enum c.int {
DOWN = 0,
UP = 1,
}
/** @brief Enum capturing the underlying data type on a channel. */
pixel_type_t :: enum c.int {
UINT = 0,
HALF = 1,
FLOAT = 2,
}
/* /////////////////////////////////////// */
/* First set of structs are data where we can read directly with no allocation needed... */
/** @brief Struct to hold color chromaticities to interpret the tristimulus color values in the image data. */
attr_chromaticities_t :: struct #packed {
red_x: f32,
red_y: f32,
green_x: f32,
green_y: f32,
blue_x: f32,
blue_y: f32,
white_x: f32,
white_y: f32,
}
/** @brief Struct to hold keycode information. */
attr_keycode_t :: struct #packed {
film_mfc_code: i32,
film_type: i32,
prefix: i32,
count: i32,
perf_offset: i32,
perfs_per_frame: i32,
perfs_per_count: i32,
}
/** @brief struct to hold a 32-bit floating-point 3x3 matrix. */
attr_m33f_t :: struct #packed {
m: [9]f32,
}
/** @brief struct to hold a 64-bit floating-point 3x3 matrix. */
attr_m33d_t :: struct #packed {
m: [9]f64,
}
/** @brief Struct to hold a 32-bit floating-point 4x4 matrix. */
attr_m44f_t :: struct #packed {
m: [16]f32,
}
/** @brief Struct to hold a 64-bit floating-point 4x4 matrix. */
attr_m44d_t :: struct #packed {
m: [16]f64,
}
/** @brief Struct to hold an integer ratio value. */
attr_rational_t :: struct #packed {
num: i32,
denom: u32,
}
/** @brief Struct to hold timecode information. */
attr_timecode_t :: struct #packed {
time_and_flags: u32,
user_data: u32,
}
/** @brief Struct to hold a 2-element integer vector. */
attr_v2i_t :: distinct [2]i32
/** @brief Struct to hold a 2-element 32-bit float vector. */
attr_v2f_t :: distinct [2]f32
/** @brief Struct to hold a 2-element 64-bit float vector. */
attr_v2d_t :: distinct [2]f64
/** @brief Struct to hold a 3-element integer vector. */
attr_v3i_t :: distinct [3]i32
/** @brief Struct to hold a 3-element 32-bit float vector. */
attr_v3f_t :: distinct [3]f32
/** @brief Struct to hold a 3-element 64-bit float vector. */
attr_v3d_t :: distinct [3]f64
/** @brief Struct to hold an integer box/region definition. */
attr_box2i_t :: struct #packed {
min: attr_v2i_t,
max: attr_v2i_t,
}
/** @brief Struct to hold a floating-point box/region definition. */
attr_box2f_t:: struct #packed {
min: attr_v2f_t,
max: attr_v2f_t,
}
/** @brief Struct holding base tiledesc attribute type defined in spec
*
* NB: This is in a tightly packed area so it can be read directly, be
* careful it doesn't become padded to the next \c uint32_t boundary.
*/
attr_tiledesc_t :: struct #packed {
x_size: u32,
y_size: u32,
level_and_round: u8,
}
/** @brief Macro to access type of tiling from packed structure. */
GET_TILE_LEVEL_MODE :: #force_inline proc "c" (tiledesc: attr_tiledesc_t) -> tile_level_mode_t {
return tile_level_mode_t(tiledesc.level_and_round & 0xf)
}
/** @brief Macro to access the rounding mode of tiling from packed structure. */
GET_TILE_ROUND_MODE :: #force_inline proc "c" (tiledesc: attr_tiledesc_t) -> tile_round_mode_t {
return tile_round_mode_t((tiledesc.level_and_round >> 4) & 0xf)
}
/** @brief Macro to pack the tiling type and rounding mode into packed structure. */
PACK_TILE_LEVEL_ROUND :: #force_inline proc "c" (lvl: tile_level_mode_t, mode: tile_round_mode_t) -> u8 {
return ((u8(mode) & 0xf) << 4) | (u8(lvl) & 0xf)
}
/* /////////////////////////////////////// */
/* Now structs that involve heap allocation to store data. */
/** Storage for a string. */
attr_string_t :: struct {
length: i32,
/** If this is non-zero, the string owns the data, if 0, is a const ref to a static string. */
alloc_size: i32,
str: cstring,
}
/** Storage for a string vector. */
attr_string_vector_t :: struct {
n_strings: i32,
/** If this is non-zero, the string vector owns the data, if 0, is a const ref. */
alloc_size: i32,
strings: [^]attr_string_t,
}
/** Float vector storage struct. */
attr_float_vector_t :: struct {
length: i32,
/** If this is non-zero, the float vector owns the data, if 0, is a const ref. */
alloc_size: i32,
arr: [^]f32,
}
/** Hint for lossy compression methods about how to treat values
* (logarithmic or linear), meaning a human sees values like R, G, B,
* luminance difference between 0.1 and 0.2 as about the same as 1.0
* to 2.0 (logarithmic), where chroma coordinates are closer to linear
* (0.1 and 0.2 is about the same difference as 1.0 and 1.1).
*/
perceptual_treatment_t :: enum c.int {
LOGARITHMIC = 0,
LINEAR = 1,
}
/** Individual channel information. */
attr_chlist_entry_t :: struct {
name: attr_string_t,
/** Data representation for these pixels: uint, half, float. */
pixel_type: pixel_type_t,
/** Possible values are 0 and 1 per docs perceptual_treatment_t. */
p_linear: u8,
reserved: [3]u8,
x_sampling: i32,
y_sampling: i32,
}
/** List of channel information (sorted alphabetically). */
attr_chlist_t :: struct {
num_channels: c.int,
num_alloced: c.int,
entries: [^]attr_chlist_entry_t,
}
/** @brief Struct to define attributes of an embedded preview image. */
attr_preview_t :: struct {
width: u32,
height: u32,
/** If this is non-zero, the preview owns the data, if 0, is a const ref. */
alloc_size: c.size_t,
rgba: [^]u8,
}
/** Custom storage structure for opaque data.
*
* Handlers for opaque types can be registered, then when a
* non-builtin type is encountered with a registered handler, the
* function pointers to unpack/pack it will be set up.
*
* @sa register_attr_type_handler
*/
attr_opaquedata_t :: struct {
size: i32,
unpacked_size: i32,
/** If this is non-zero, the struct owns the data, if 0, is a const ref. */
packed_alloc_size: i32,
pad: [4]u8,
packed_data: rawptr,
/** When an application wants to have custom data, they can store
* an unpacked form here which will be requested to be destroyed
* upon destruction of the attribute.
*/
unpacked_data: rawptr,
/** An application can register an attribute handler which then
* fills in these function pointers. This allows a user to delay
* the expansion of the custom type until access is desired, and
* similarly, to delay the packing of the data until write time.
*/
unpack_func_ptr: proc "c" (
ctxt: context_t,
data: rawptr,
attrsize: i32,
outsize: ^i32,
outbuffer: ^rawptr) -> result_t,
pack_func_ptr: proc "c" (
ctxt: context_t,
data: rawptr,
datasize: i32,
outsize: ^i32,
outbuffer: rawptr) -> result_t,
destroy_unpacked_func_ptr: proc "c" (
ctxt: context_t, data: rawptr, attrsize: i32),
}
/* /////////////////////////////////////// */
/** @brief Built-in/native attribute type enum.
*
* This will enable us to do a tagged type struct to generically store
* attributes.
*/
attribute_type_t :: enum c.int {
UNKNOWN = 0, // Type indicating an error or uninitialized attribute.
BOX2I, // Integer region definition. @see attr_box2i_t.
BOX2F, // Float region definition. @see attr_box2f_t.
CHLIST, // Definition of channels in file @see chlist_entry.
CHROMATICITIES, // Values to specify color space of colors in file @see attr_chromaticities_t.
COMPRESSION, // ``u8`` declaring compression present.
DOUBLE, // Double precision floating point number.
ENVMAP, // ``u8`` declaring environment map type.
FLOAT, // Normal (4 byte) precision floating point number.
FLOAT_VECTOR, // List of normal (4 byte) precision floating point numbers.
INT, // 32-bit signed integer value.
KEYCODE, // Struct recording keycode @see attr_keycode_t.
LINEORDER, // ``u8`` declaring scanline ordering.
M33F, // 9 32-bit floats representing a 3x3 matrix.
M33D, // 9 64-bit floats representing a 3x3 matrix.
M44F, // 16 32-bit floats representing a 4x4 matrix.
M44D, // 16 64-bit floats representing a 4x4 matrix.
PREVIEW, // 2 ``unsigned ints`` followed by 4 x w x h ``u8`` image.
RATIONAL, // \c int followed by ``unsigned int``
STRING, // ``int`` (length) followed by char string data.
STRING_VECTOR, // 0 or more text strings (int + string). number is based on attribute size.
TILEDESC, // 2 ``unsigned ints`` ``xSize``, ``ySize`` followed by mode.
TIMECODE, // 2 ``unsigned ints`` time and flags, user data.
V2I, // Pair of 32-bit integers.
V2F, // Pair of 32-bit floats.
V2D, // Pair of 64-bit floats.
V3I, // Set of 3 32-bit integers.
V3F, // Set of 3 32-bit floats.
V3D, // Set of 3 64-bit floats.
OPAQUE, // User/unknown provided type.
}
/** @brief Storage, name and type information for an attribute.
*
* Attributes (metadata) for the file cause a surprising amount of
* overhead. It is not uncommon for a production-grade EXR to have
* many attributes. As such, the attribute struct is designed in a
* slightly more complicated manner. It is optimized to have the
* storage for that attribute: the struct itself, the name, the type,
* and the data all allocated as one block. Further, the type and
* standard names may use a static string to avoid allocating space
* for those as necessary with the pointers pointing to static strings
* (not to be freed). Finally, small values are optimized for.
*/
attribute_t :: struct {
/** Name of the attribute. */
name: cstring,
/** String type name of the attribute. */
type_name: cstring,
/** Length of name string (short flag is 31 max, long allows 255). */
name_length: u8,
/** Length of type string (short flag is 31 max, long allows 255). */
type_name_length: u8,
pad: [2]u8,
/** Enum of the attribute type. */
type: attribute_type_t,
/** Union of pointers of different types that can be used to type
* pun to an appropriate type for builtins. Do note that while
* this looks like a big thing, it is only the size of a single
* pointer. These are all pointers into some other data block
* storing the value you want, with the exception of the pod types
* which are just put in place (i.e. small value optimization).
*
* The attribute type \c type should directly correlate to one
* of these entries.
*/
using _: struct #raw_union {
// NB: not pointers for POD types
uc: u8,
d: f64,
f: f32,
i: i32,
box2i: ^attr_box2i_t,
box2f: ^attr_box2f_t,
chlist: ^attr_chlist_t,
chromaticities: ^attr_chromaticities_t,
keycode: ^attr_keycode_t,
floatvector: ^attr_float_vector_t,
m33f: ^attr_m33f_t,
m33d: ^attr_m33d_t,
m44f: ^attr_m44f_t,
m44d: ^attr_m44d_t,
preview: ^attr_preview_t,
rational: ^attr_rational_t,
string: ^attr_string_t,
stringvector: ^attr_string_vector_t,
tiledesc: ^attr_tiledesc_t,
timecode: ^attr_timecode_t,
v2i: ^attr_v2i_t,
v2f: ^attr_v2f_t,
v2d: ^attr_v2d_t,
v3i: ^attr_v3i_t,
v3f: ^attr_v3f_t,
v3d: ^attr_v3d_t,
opaque: ^attr_opaquedata_t,
rawptr: ^u8,
},
}
+174
View File
@@ -0,0 +1,174 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
/** @brief Function pointer used to hold a malloc-like routine.
*
* Providing these to a context will override what memory is used to
* allocate the context itself, as well as any allocations which
* happen during processing of a file or stream. This can be used by
* systems which provide rich malloc tracking routines to override the
* internal allocations performed by the library.
*
* This function is expected to allocate and return a new memory
* handle, or `NULL` if allocation failed (which the library will then
* handle and return an out-of-memory error).
*
* If one is provided, both should be provided.
* @sa exr_memory_free_func_t
*/
memory_allocation_func_t :: proc "c" (bytes: c.size_t) -> rawptr
/** @brief Function pointer used to hold a free-like routine.
*
* Providing these to a context will override what memory is used to
* allocate the context itself, as well as any allocations which
* happen during processing of a file or stream. This can be used by
* systems which provide rich malloc tracking routines to override the
* internal allocations performed by the library.
*
* This function is expected to return memory to the system, ala free
* from the C library.
*
* If providing one, probably need to provide both routines.
* @sa exr_memory_allocation_func_t
*/
memory_free_func_t :: proc "c" (ptr: rawptr)
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** @brief Retrieve the current library version. The @p extra string is for
* custom installs, and is a static string, do not free the returned
* pointer.
*/
get_library_version :: proc(maj, min, patch: ^c.int, extra: ^cstring) ---
/** @brief Limit the size of image allowed to be parsed or created by
* the library.
*
* This is used as a safety check against corrupt files, but can also
* serve to avoid potential issues on machines which have very
* constrained RAM.
*
* These values are among the only globals in the core layer of
* OpenEXR. The intended use is for applications to define a global
* default, which will be combined with the values provided to the
* individual context creation routine. The values are used to check
* against parsed header values. This adds some level of safety from
* memory overruns where a corrupt file given to the system may cause
* a large allocation to happen, enabling buffer overruns or other
* potential security issue.
*
* These global values are combined with the values in
* \ref exr_context_initializer_t using the following rules:
*
* 1. negative values are ignored.
*
* 2. if either value has a positive (non-zero) value, and the other
* has 0, the positive value is preferred.
*
* 3. If both are positive (non-zero), the minimum value is used.
*
* 4. If both values are 0, this disables the constrained size checks.
*
* This function does not fail.
*/
set_default_maximum_image_size :: proc(w, h: c.int) ---
/** @brief Retrieve the global default maximum image size.
*
* This function does not fail.
*/
get_default_maximum_image_size :: proc(w, h: ^c.int) ---
/** @brief Limit the size of an image tile allowed to be parsed or
* created by the library.
*
* Similar to image size, this places constraints on the maximum tile
* size as a safety check against bad file data
*
* This is used as a safety check against corrupt files, but can also
* serve to avoid potential issues on machines which have very
* constrained RAM
*
* These values are among the only globals in the core layer of
* OpenEXR. The intended use is for applications to define a global
* default, which will be combined with the values provided to the
* individual context creation routine. The values are used to check
* against parsed header values. This adds some level of safety from
* memory overruns where a corrupt file given to the system may cause
* a large allocation to happen, enabling buffer overruns or other
* potential security issue.
*
* These global values are combined with the values in
* \ref exr_context_initializer_t using the following rules:
*
* 1. negative values are ignored.
*
* 2. if either value has a positive (non-zero) value, and the other
* has 0, the positive value is preferred.
*
* 3. If both are positive (non-zero), the minimum value is used.
*
* 4. If both values are 0, this disables the constrained size checks.
*
* This function does not fail.
*/
set_default_maximum_tile_size :: proc(w, h: c.int) ---
/** @brief Retrieve the global maximum tile size.
*
* This function does not fail.
*/
get_default_maximum_tile_size :: proc(w, h: ^c.int) ---
/** @} */
/**
* @defgroup CompressionDefaults Provides default compression settings
* @{
*/
/** @brief Assigns a default zip compression level.
*
* This value may be controlled separately on each part, but this
* global control determines the initial value.
*/
set_default_zip_compression_level :: proc(l: c.int) ---
/** @brief Retrieve the global default zip compression value
*/
get_default_zip_compression_level :: proc(l: ^c.int) ---
/** @brief Assigns a default DWA compression quality level.
*
* This value may be controlled separately on each part, but this
* global control determines the initial value.
*/
set_default_dwa_compression_quality :: proc(q: f32) ---
/** @brief Retrieve the global default dwa compression quality
*/
get_default_dwa_compression_quality :: proc(q: ^f32) ---
/** @brief Allow the user to override default allocator used internal
* allocations necessary for files, attributes, and other temporary
* memory.
*
* These routines may be overridden when creating a specific context,
* however this provides global defaults such that the default can be
* applied.
*
* If either pointer is 0, the appropriate malloc/free routine will be
* substituted.
*
* This function does not fail.
*/
set_default_memory_routines :: proc(alloc_func: memory_allocation_func_t, free_func: memory_free_func_t) ---
}
+147
View File
@@ -0,0 +1,147 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
/**
* Struct describing raw data information about a chunk.
*
* A chunk is the generic term for a pixel data block in an EXR file,
* as described in the OpenEXR File Layout documentation. This is
* common between all different forms of data that can be stored.
*/
chunk_info_t :: struct {
idx: i32,
/** For tiles, this is the tilex; for scans it is the x. */
start_x: i32,
/** For tiles, this is the tiley; for scans it is the scanline y. */
start_y: i32,
height: i32, /**< For this chunk. */
width: i32, /**< For this chunk. */
level_x: u8, /**< For tiled files. */
level_y: u8, /**< For tiled files. */
type: u8,
compression: u8,
data_offset: u64,
packed_size: u64,
unpacked_size: u64,
sample_count_data_offset: u64,
sample_count_table_size: u64,
}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
read_scanline_chunk_info :: proc(ctxt: const_context_t, part_index: c.int, y: c.int, cinfo: ^chunk_info_t) -> result_t ---
read_tile_chunk_info :: proc(
ctxt: const_context_t,
part_index: c.int,
tilex: c.int,
tiley: c.int,
levelx: c.int,
levely: c.int,
cinfo: ^chunk_info_t) -> result_t ---
/** Read the packed data block for a chunk.
*
* This assumes that the buffer pointed to by @p packed_data is
* large enough to hold the chunk block info packed_size bytes.
*/
read_chunk :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
packed_data: rawptr) -> result_t ---
/**
* Read chunk for deep data.
*
* This allows one to read the packed data, the sample count data, or both.
* \c exr_read_chunk also works to read deep data packed data,
* but this is a routine to get the sample count table and the packed
* data in one go, or if you want to pre-read the sample count data,
* you can get just that buffer.
*/
read_deep_chunk :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
packed_data: rawptr,
sample_data: rawptr) -> result_t ---
/**************************************/
/** Initialize a \c chunk_info_t structure when encoding scanline
* data (similar to read but does not do anything with a chunk
* table).
*/
write_scanline_chunk_info :: proc(ctxt: context_t, part_index: c.int, y: c.int, cinfo: ^chunk_info_t) -> result_t ---
/** Initialize a \c chunk_info_t structure when encoding tiled data
* (similar to read but does not do anything with a chunk table).
*/
write_tile_chunk_info :: proc(
ctxt: context_t,
part_index: c.int,
tilex: c.int,
tiley: c.int,
levelx: c.int,
levely: c.int,
cinfo: ^chunk_info_t) -> result_t ---
/**
* @p y must the appropriate starting y for the specified chunk.
*/
write_scanline_chunk :: proc(
ctxt: context_t,
part_index: int,
y: int,
packed_data: rawptr,
packed_size: u64) -> result_t ---
/**
* @p y must the appropriate starting y for the specified chunk.
*/
write_deep_scanline_chunk :: proc(
ctxt: context_t,
part_index: c.int,
y: c.int,
packed_data: rawptr,
packed_size: u64,
unpacked_size: u64,
sample_data: rawptr,
sample_data_size: u64) -> result_t ---
write_tile_chunk :: proc(
ctxt: context_t,
part_index: c.int,
tilex: c.int,
tiley: c.int,
levelx: c.int,
levely: c.int,
packed_data: rawptr,
packed_size: u64) -> result_t ---
write_deep_tile_chunk :: proc(
ctxt: context_t,
part_index: c.int,
tilex: c.int,
tiley: c.int,
levelx: c.int,
levely: c.int,
packed_data: rawptr,
packed_size: u64,
unpacked_size: u64,
sample_data: rawptr,
sample_data_size: u64) -> result_t ---
}
+119
View File
@@ -0,0 +1,119 @@
package vendor_openexr
import "core:c"
/**
* Enum for use in a custom allocator in the encode/decode pipelines
* (that is, so the implementor knows whether to allocate on which
* device based on the buffer disposition).
*/
transcoding_pipeline_buffer_id_t :: enum c.int {
PACKED,
UNPACKED,
COMPRESSED,
SCRATCH1,
SCRATCH2,
PACKED_SAMPLES,
SAMPLES,
}
/** @brief Struct for negotiating buffers when decoding/encoding
* chunks of data.
*
* This is generic and meant to negotiate exr data bi-directionally,
* in that the same structure is used for both decoding and encoding
* chunks for read and write, respectively.
*
* The first half of the structure will be filled by the library, and
* the caller is expected to fill the second half appropriately.
*/
coding_channel_info_t :: struct {
/**************************************************
* Elements below are populated by the library when
* decoding is initialized/updated and must be left
* untouched when using the default decoder routines.
**************************************************/
/** Channel name.
*
* This is provided as a convenient reference. Do not free, this
* refers to the internal data structure in the context.
*/
channel_name: cstring,
/** Number of lines for this channel in this chunk.
*
* May be 0 or less than overall image height based on sampling
* (i.e. when in 4:2:0 type sampling)
*/
height: i32,
/** Width in pixel count.
*
* May be 0 or less than overall image width based on sampling
* (i.e. 4:2:2 will have some channels have fewer values).
*/
width: i32,
/** Horizontal subsampling information. */
x_samples: i32,
/** Vertical subsampling information. */
y_samples: i32,
/** Linear flag from channel definition (used by b44). */
p_linear: u8,
/** How many bytes per pixel this channel consumes (2 for float16,
* 4 for float32/uint32).
*/
bytes_per_element: i8,
/** Small form of exr_pixel_type_t enum (EXR_PIXEL_UINT/HALF/FLOAT). */
data_type: u16,
/**************************************************
* Elements below must be edited by the caller
* to control encoding/decoding.
**************************************************/
/** How many bytes per pixel the input is or output should be
* (2 for float16, 4 for float32/uint32). Defaults to same
* size as input.
*/
user_bytes_per_element: i16,
/** Small form of exr_pixel_type_t enum
* (EXR_PIXEL_UINT/HALF/FLOAT). Defaults to same type as input.
*/
user_data_type: u16,
/** Increment to get to next pixel.
*
* This is in bytes. Must be specified when the decode pointer is
* specified (and always for encode).
*
* This is useful for implementing transcoding generically of
* planar or interleaved data. For planar data, where the layout
* is RRRRRGGGGGBBBBB, you can pass in 1 * bytes per component.
*/
user_pixel_stride: i32,
/** When \c lines > 1 for a chunk, this is the increment used to get
* from beginning of line to beginning of next line.
*
* This is in bytes. Must be specified when the decode pointer is
* specified (and always for encode).
*/
user_line_stride: i32,
/** This data member has different requirements reading vs
* writing. When reading, if this is left as `NULL`, the channel
* will be skipped during read and not filled in. During a write
* operation, this pointer is considered const and not
* modified. To make this more clear, a union is used here.
*/
using _: struct #raw_union {
decode_to_ptr: ^u8,
encode_from_ptr: ^u8,
},
}
+489
View File
@@ -0,0 +1,489 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
#assert(size_of(c.int) == size_of(b32))
context_t :: distinct rawptr
const_context_t :: context_t
/**
* @defgroup ContextFunctions OpenEXR Context Stream/File Functions
*
* @brief These are a group of function interfaces used to customize
* the error handling, memory allocations, or I/O behavior of an
* OpenEXR context.
*
* @{
*/
/** @brief Stream error notifier
*
* This function pointer is provided to the stream functions by the
* library such that they can provide a nice error message to the
* user during stream operations.
*/
stream_error_func_ptr_t :: proc "c" (ctxt: const_context_t, code: result_t, fmt: cstring, #c_vararg args: ..any) -> result_t
/** @brief Error callback function
*
* Because a file can be read from using many threads at once, it is
* difficult to store an error message for later retrieval. As such,
* when a file is constructed, a callback function can be provided
* which delivers an error message for the calling application to
* handle. This will then be delivered on the same thread causing the
* error.
*/
error_handler_cb_t :: proc "c" (ctxt: const_context_t, code: result_t, msg: cstring)
/** Destroy custom stream function pointer
*
* Generic callback to clean up user data for custom streams.
* This is called when the file is closed and expected not to
* error.
*
* @param failed Indicates the write operation failed, the
* implementor may wish to cleanup temporary files
*/
destroy_stream_func_ptr_t :: proc "c" (ctxt: const_context_t, userdata: rawptr, failed: c.int)
/** Query stream size function pointer
*
* Used to query the size of the file, or amount of data representing
* the openexr file in the data stream.
*
* This is used to validate requests against the file. If the size is
* unavailable, return -1, which will disable these validation steps
* for this file, although appropriate memory safeguards must be in
* place in the calling application.
*/
query_size_func_ptr_t :: proc "c" (ctxt: const_context_t, userdata: rawptr) -> i64
/** @brief Read custom function pointer
*
* Used to read data from a custom output. Expects similar semantics to
* pread or ReadFile with overlapped data under win32.
*
* It is required that this provides thread-safe concurrent access to
* the same file. If the stream/input layer you are providing does
* not have this guarantee, your are responsible for providing
* appropriate serialization of requests.
*
* A file should be expected to be accessed in the following pattern:
* - upon open, the header and part information attributes will be read
* - upon the first image read request, the offset tables will be read
* multiple threads accessing this concurrently may actually read
* these values at the same time
* - chunks can then be read in any order as preferred by the
* application
*
* While this should mean that the header will be read in 'stream'
* order (no seeks required), no guarantee is made beyond that to
* retrieve image/deep data in order. So if the backing file is
* truly a stream, it is up to the provider to implement appropriate
* caching of data to give the appearance of being able to seek/read
* atomically.
*/
read_func_ptr_t :: proc "c" (
ctxt: const_context_t,
userdata: rawptr,
buffer: rawptr,
sz: u64,
offset: u64,
error_cb: stream_error_func_ptr_t) -> i64
/** Write custom function pointer
*
* Used to write data to a custom output. Expects similar semantics to
* pwrite or WriteFile with overlapped data under win32.
*
* It is required that this provides thread-safe concurrent access to
* the same file. While it is unlikely that multiple threads will
* be used to write data for compressed forms, it is possible.
*
* A file should be expected to be accessed in the following pattern:
* - upon open, the header and part information attributes is constructed.
*
* - when the write_header routine is called, the header becomes immutable
* and is written to the file. This computes the space to store the chunk
* offsets, but does not yet write the values.
*
* - Image chunks are written to the file, and appear in the order
* they are written, not in the ordering that is required by the
* chunk offset table (unless written in that order). This may vary
* slightly if the size of the chunks is not directly known and
* tight packing of data is necessary.
*
* - at file close, the chunk offset tables are written to the file.
*/
write_func_ptr_t :: proc "c" (
ctxt: const_context_t,
userdata: rawptr,
buffer: rawptr,
sz: u64,
offset: u64,
error_cb: stream_error_func_ptr_t) -> i64
/** @brief Struct used to pass function pointers into the context
* initialization routines.
*
* This partly exists to avoid the chicken and egg issue around
* creating the storage needed for the context on systems which want
* to override the malloc/free routines.
*
* However, it also serves to make a tidier/simpler set of functions
* to create and start processing exr files.
*
* The size member is required for version portability.
*
* It can be initialized using \c EXR_DEFAULT_CONTEXT_INITIALIZER.
*
* \code{.c}
* exr_context_initializer_t myctxtinit = DEFAULT_CONTEXT_INITIALIZER;
* myctxtinit.error_cb = &my_super_cool_error_callback_function;
* ...
* \endcode
*
*/
context_initializer_t :: struct {
/** @brief Size member to tag initializer for version stability.
*
* This should be initialized to the size of the current
* structure. This allows EXR to add functions or other
* initializers in the future, and retain version compatibility
*/
size: c.size_t,
/** @brief Error callback function pointer
*
* The error callback is allowed to be `NULL`, and will use a
* default print which outputs to \c stderr.
*
* @sa exr_error_handler_cb_t
*/
error_handler_fn: error_handler_cb_t,
/** Custom allocator, if `NULL`, will use malloc. @sa memory_allocation_func_t */
alloc_fn: memory_allocation_func_t,
/** Custom deallocator, if `NULL`, will use free. @sa memory_free_func_t */
free_fn: memory_free_func_t,
/** Blind data passed to custom read, size, write, destroy
* functions below. Up to user to manage this pointer.
*/
user_data: rawptr,
/** @brief Custom read routine.
*
* This is only used during read or update contexts. If this is
* provided, it is expected that the caller has previously made
* the stream available, and placed whatever stream/file data
* into \c user_data above.
*
* If this is `NULL`, and the context requested is for reading an
* exr file, an internal implementation is provided for reading
* from normal filesystem files, and the filename provided is
* attempted to be opened as such.
*
* Expected to be `NULL` for a write-only operation, but is ignored
* if it is provided.
*
* For update contexts, both read and write functions must be
* provided if either is.
*
* @sa exr_read_func_ptr_t
*/
read_fn: read_func_ptr_t,
/** @brief Custom size query routine.
*
* Used to provide validation when reading header values. If this
* is not provided, but a custom read routine is provided, this
* will disable some of the validation checks when parsing the
* image header.
*
* Expected to be `NULL` for a write-only operation, but is ignored
* if it is provided.
*
* @sa exr_query_size_func_ptr_t
*/
size_fn: query_size_func_ptr_t,
/** @brief Custom write routine.
*
* This is only used during write or update contexts. If this is
* provided, it is expected that the caller has previously made
* the stream available, and placed whatever stream/file data
* into \c user_data above.
*
* If this is `NULL`, and the context requested is for writing an
* exr file, an internal implementation is provided for reading
* from normal filesystem files, and the filename provided is
* attempted to be opened as such.
*
* For update contexts, both read and write functions must be
* provided if either is.
*
* @sa exr_write_func_ptr_t
*/
write_fn: write_func_ptr_t,
/** @brief Optional function to destroy the user data block of a custom stream.
*
* Allows one to free any user allocated data, and close any handles.
*
* @sa exr_destroy_stream_func_ptr_t
* */
destroy_fn: destroy_stream_func_ptr_t,
/** Initialize a field specifying what the maximum image width
* allowed by the context is. See exr_set_default_maximum_image_size() to
* understand how this interacts with global defaults.
*/
max_image_width: c.int,
/** Initialize a field specifying what the maximum image height
* allowed by the context is. See exr_set_default_maximum_image_size() to
* understand how this interacts with global defaults.
*/
max_image_height: c.int,
/** Initialize a field specifying what the maximum tile width
* allowed by the context is. See exr_set_default_maximum_tile_size() to
* understand how this interacts with global defaults.
*/
max_tile_width: c.int,
/** Initialize a field specifying what the maximum tile height
* allowed by the context is. See exr_set_default_maximum_tile_size() to
* understand how this interacts with global defaults.
*/
max_tile_height: c.int,
/** Initialize a field specifying what the default zip compression level should be
* for this context. See exr_set_default_zip_compresion_level() to
* set it for all contexts.
*/
zip_level: c.int,
/** Initialize the default dwa compression quality. See
* exr_set_default_dwa_compression_quality() to set the default
* for all contexts.
*/
dwa_quality: f32,
/** Initialize with a bitwise or of the various context flags
*/
flags: c.int,
}
/** @brief context flag which will enforce strict header validation
* checks and may prevent reading of files which could otherwise be
* processed.
*/
CONTEXT_FLAG_STRICT_HEADER :: (1 << 0)
/** @brief Disables error messages while parsing headers
*
* The return values will remain the same, but error reporting will be
* skipped. This is only valid for reading contexts
*/
CONTEXT_FLAG_SILENT_HEADER_PARSE :: (1 << 1)
/** @brief Disables reconstruction logic upon corrupt / missing data chunks
*
* This will disable the reconstruction logic that searches through an
* incomplete file, and will instead just return errors at read
* time. This is only valid for reading contexts
*/
CONTEXT_FLAG_DISABLE_CHUNK_RECONSTRUCTION :: (1 << 2)
/** @brief Simple macro to initialize the context initializer with default values. */
DEFAULT_CONTEXT_INITIALIZER :: context_initializer_t{zip_level = -2, dwa_quality = -1}
/** @} */ /* context function pointer declarations */
/** @brief Enum describing how default files are handled during write. */
default_write_mode_t :: enum c.int {
WRITE_FILE_DIRECTLY = 0, /**< Overwrite filename provided directly, deleted upon error. */
INTERMEDIATE_TEMP_FILE = 1, /**< Create a temporary file, renaming it upon successful write, leaving original upon error */
}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** @brief Check the magic number of the file and report
* `EXR_ERR_SUCCESS` if the file appears to be a valid file (or at least
* has the correct magic number and can be read).
*/
test_file_header :: proc(filename: cstring, ctxtdata: ^context_initializer_t) -> result_t ---
/** @brief Close and free any internally allocated memory,
* calling any provided destroy function for custom streams.
*
* If the file was opened for write, first save the chunk offsets
* or any other unwritten data.
*/
finish :: proc(ctxt: ^context_t) -> result_t ---
/** @brief Create and initialize a read-only exr read context.
*
* If a custom read function is provided, the filename is for
* informational purposes only, the system assumes the user has
* previously opened a stream, file, or whatever and placed relevant
* data in userdata to access that.
*
* One notable attribute of the context is that once it has been
* created and returned a successful code, it has parsed all the
* header data. This is done as one step such that it is easier to
* provide a safe context for multiple threads to request data from
* the same context concurrently.
*
* Once finished reading data, use exr_finish() to clean up
* the context.
*
* If you have custom I/O requirements, see the initializer context
* documentation \ref exr_context_initializer_t. The @p ctxtdata parameter
* is optional, if `NULL`, default values will be used.
*/
start_read :: proc(
ctxt: ^context_t,
filename: cstring,
ctxtdata: ^context_initializer_t) -> result_t ---
/** @brief Create and initialize a write-only context.
*
* If a custom write function is provided, the filename is for
* informational purposes only, and the @p default_mode parameter will be
* ignored. As such, the system assumes the user has previously opened
* a stream, file, or whatever and placed relevant data in userdata to
* access that.
*
* Multi-Threading: To avoid issues with creating multi-part EXR
* files, the library approaches writing as a multi-step process, so
* the same concurrent guarantees can not be made for writing a
* file. The steps are:
*
* 1. Context creation (this function)
*
* 2. Part definition (required attributes and additional metadata)
*
* 3. Transition to writing data (this "commits" the part definitions,
* any changes requested after will result in an error)
*
* 4. Write part data in sequential order of parts (part<sub>0</sub>
* -> part<sub>N-1</sub>).
*
* 5. Within each part, multiple threads can be encoding and writing
* data concurrently. For some EXR part definitions, this may be able
* to write data concurrently when it can predict the chunk sizes, or
* data is allowed to be padded. For others, it may need to
* temporarily cache chunks until the data is received to flush in
* order. The concurrency around this is handled by the library
*
* 6. Once finished writing data, use exr_finish() to clean
* up the context, which will flush any unwritten data such as the
* final chunk offset tables, and handle the temporary file flags.
*
* If you have custom I/O requirements, see the initializer context
* documentation \ref exr_context_initializer_t. The @p ctxtdata
* parameter is optional, if `NULL`, default values will be used.
*/
start_write :: proc(
ctxt: ^context_t,
filename: cstring,
default_mode: default_write_mode_t,
ctxtdata: ^context_initializer_t) -> result_t ---
/** @brief Create a new context for updating an exr file in place.
*
* This is a custom mode that allows one to modify the value of a
* metadata entry, although not to change the size of the header, or
* any of the image data.
*
* If you have custom I/O requirements, see the initializer context
* documentation \ref exr_context_initializer_t. The @p ctxtdata parameter
* is optional, if `NULL`, default values will be used.
*/
start_inplace_header_update :: proc(
ctxt: ^context_t,
filename: cstring,
ctxtdata: ^context_initializer_t) -> result_t ---
/** @brief Retrieve the file name the context is for as provided
* during the start routine.
*
* Do not free the resulting string.
*/
get_file_name :: proc(ctxt: const_context_t, name: ^cstring) -> result_t ---
/** @brief Query the user data the context was constructed with. This
* is perhaps useful in the error handler callback to jump back into
* an object the user controls.
*/
get_user_data :: proc(ctxt: const_context_t, userdata: ^rawptr) -> result_t ---
/** Any opaque attribute data entry of the specified type is tagged
* with these functions enabling downstream users to unpack (or pack)
* the data.
*
* The library handles the memory packed data internally, but the
* handler is expected to allocate and manage memory for the
* *unpacked* buffer (the library will call the destroy function).
*
* NB: the pack function will be called twice (unless there is a
* memory failure), the first with a `NULL` buffer, requesting the
* maximum size (or exact size if known) for the packed buffer, then
* the second to fill the output packed buffer, at which point the
* size can be re-updated to have the final, precise size to put into
* the file.
*/
register_attr_type_handler :: proc(
ctxt: context_t,
type: cstring,
unpack_func_ptr: proc "c" (
ctxt: context_t,
data: rawptr,
attrsize: i32,
outsize: ^i32,
outbuffer: ^rawptr) -> result_t,
pack_func_ptr: proc "c" (
ctxt: context_t,
data: rawptr,
datasize: i32,
outsize: ^i32,
outbuffer: rawptr) -> result_t,
destroy_unpacked_func_ptr: proc "c" (
ctxt: context_t, data: rawptr, datasize: i32),
) -> result_t ---
/** @brief Enable long name support in the output context */
set_longname_support :: proc(ctxt: context_t, onoff: b32) -> result_t ---
/** @brief Write the header data.
*
* Opening a new output file has a small initialization state problem
* compared to opening for read/update: we need to enable the user
* to specify an arbitrary set of metadata across an arbitrary number
* of parts. To avoid having to create the list of parts and entire
* metadata up front, prior to calling the above exr_start_write(),
* allow the data to be set, then once this is called, it switches
* into a mode where the library assumes the data is now valid.
*
* It will recompute the number of chunks that will be written, and
* reset the chunk offsets. If you modify file attributes or part
* information after a call to this, it will error.
*/
write_header :: proc(ctxt: context_t) -> result_t ---
}
+12
View File
@@ -0,0 +1,12 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
print_context_info :: proc(c: const_context_t, verbose: b32) -> result_t ---
}
+292
View File
@@ -0,0 +1,292 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the sample count table should be decoded to a an
* individual sample count list (n, m, o, ...), with an extra int at
* the end containing the total samples.
*
* Without this (i.e. a value of 0 in that bit), indicates the sample
* count table should be decoded to a cumulative list (n, n+m, n+m+o,
* ...), which is the on-disk representation.
*/
DECODE_SAMPLE_COUNTS_AS_INDIVIDUAL :: u16(1 << 0)
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the data in the channel pointers to decode to is not
* a direct pointer, but instead is a pointer-to-pointers. In this
* mode, the user_pixel_stride and user_line_stride are used to
* advance the pointer offsets for each pixel in the output, but the
* user_bytes_per_element and user_data_type are used to put
* (successive) entries into each destination pointer (if not `NULL`).
*
* So each channel pointer must then point to an array of
* chunk.width * chunk.height pointers.
*
* With this, you can only extract desired pixels (although all the
* pixels must be initially decompressed) to handle such operations
* like proxying where you might want to read every other pixel.
*
* If this is NOT set (0), the default unpacking routine assumes the
* data will be planar and contiguous (each channel is a separate
* memory block), ignoring user_line_stride and user_pixel_stride.
*/
DECODE_NON_IMAGE_DATA_AS_POINTERS :: u16(1 << 1)
/**
* When reading non-image data (i.e. deep), only read the sample table.
*/
DECODE_SAMPLE_DATA_ONLY :: u16(1 << 2)
/**
* Struct meant to be used on a per-thread basis for reading exr data
*
* As should be obvious, this structure is NOT thread safe, but rather
* meant to be used by separate threads, which can all be accessing
* the same context concurrently.
*/
decode_pipeline_t :: struct {
/** The output channel information for this chunk.
*
* User is expected to fill the channel pointers for the desired
* output channels (any that are `NULL` will be skipped) if you are
* going to use exr_decoding_choose_default_routines(). If all that is
* desired is to read and decompress the data, this can be left
* uninitialized.
*
* Describes the channel information. This information is
* allocated dynamically during exr_decoding_initialize().
*/
channels: [^]coding_channel_info_t,
channel_count: i16,
/** Decode flags to control the behavior. */
decode_flags: u16,
/** Copy of the parameters given to the initialize/update for
* convenience.
*/
part_index: c.int,
ctx: const_context_t,
chunk: chunk_info_t,
/** Can be used by the user to pass custom context data through
* the decode pipeline.
*/
decoding_user_data: rawptr,
/** The (compressed) buffer.
*
* If `NULL`, will be allocated during the run of the pipeline.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
packed_buffer: rawptr,
/** Used when re-using the same decode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
packed_alloc_size: c.size_t,
/** The decompressed buffer (unpacked_size from the chunk block
* info), but still packed into storage order, only needed for
* compressed files.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
unpacked_buffer: rawptr,
/** Used when re-using the same decode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
unpacked_alloc_size: c.size_t,
/** For deep or other non-image data: packed sample table
* (compressed, raw on disk representation).
*/
packed_sample_count_table: rawptr,
packed_sample_count_alloc_size: c.size_t,
/** Usable, native sample count table. Depending on the flag set
* above, will be decoded to either a cumulative list (n, n+m,
* n+m+o, ...), or an individual table (n, m, o, ...). As an
* optimization, if the latter individual count table is chosen,
* an extra int32_t will be allocated at the end of the table to
* contain the total count of samples, so the table will be n+1
* samples in size.
*/
sample_count_table: [^]i32,
sample_count_alloc_size: c.size_t,
/** A scratch buffer of unpacked_size for intermediate results.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
scratch_buffer_1: rawptr,
/** Used when re-using the same decode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
scratch_alloc_size_1: c.size_t,
/** Some decompression routines may need a second scratch buffer (zlib).
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
scratch_buffer_2: rawptr,
/** Used when re-using the same decode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
scratch_alloc_size_2: c.size_t,
/** Enable a custom allocator for the different buffers (if
* decoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
alloc_fn: proc "c" (transcoding_pipeline_buffer_id_t, c.size_t) -> rawptr,
/** Enable a custom allocator for the different buffers (if
* decoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
free_fn: proc "c" (transcoding_pipeline_buffer_id_t, rawptr),
/** Function chosen to read chunk data from the context.
*
* Initialized to a default generic read routine, may be updated
* based on channel information when
* exr_decoding_choose_default_routines() is called. This is done such that
* if the file is uncompressed and the output channel data is
* planar and the same type, the read function can read straight
* into the output channels, getting closer to a zero-copy
* operation. Otherwise a more traditional read, decompress, then
* unpack pipeline will be used with a default reader.
*
* This is allowed to be overridden, but probably is not necessary
* in most scenarios.
*/
read_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t,
/** Function chosen based on the compression type of the part to
* decompress data.
*
* If the user has a custom decompression method for the
* compression on this part, this can be changed after
* initialization.
*
* If only compressed data is desired, then assign this to `NULL`
* after initialization.
*/
decompress_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t,
/** Function which can be provided if you have bespoke handling for
* non-image data and need to re-allocate the data to handle the
* about-to-be unpacked data.
*
* If left `NULL`, will assume the memory pointed to by the channel
* pointers is sufficient.
*/
realloc_nonimage_data_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t,
/** Function chosen based on the output layout of the channels of the part to
* decompress data.
*
* This will be `NULL` after initialization, until the user
* specifies a custom routine, or initializes the channel data and
* calls exr_decoding_choose_default_routines().
*
* If only compressed data is desired, then leave or assign this
* to `NULL` after initialization.
*/
unpack_and_convert_fn: proc "c" (pipeline: ^decode_pipeline_t) -> result_t,
/** Small stash of channel info values. This is faster than calling
* malloc when the channel count in the part is small (RGBAZ),
* which is super common, however if there are a large number of
* channels, it will allocate space for that, so do not rely on
* this being used.
*/
_quick_chan_store: [5]coding_channel_info_t,
}
DECODE_PIPELINE_INITIALIZER :: decode_pipeline_t{}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** Initialize the decoding pipeline structure with the channel info
* for the specified part, and the first block to be read.
*
* NB: The decode->unpack_and_convert_fn field will be `NULL` after this. If that
* stage is desired, initialize the channel output information and
* call exr_decoding_choose_default_routines().
*/
decoding_initialize :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
decode: ^decode_pipeline_t) -> result_t ---
/** Given an initialized decode pipeline, find appropriate functions
* to read and shuffle/convert data into the defined channel outputs.
*
* Calling this is not required if custom routines will be used, or if
* just the raw compressed data is desired. Although in that scenario,
* it is probably easier to just read the chunk directly using
* exr_read_chunk().
*/
decoding_choose_default_routines :: proc(
ctxt: const_context_t, part_index: c.int, decode: ^decode_pipeline_t) -> result_t ---
/** Given a decode pipeline previously initialized, update it for the
* new chunk to be read.
*
* In this manner, memory buffers can be re-used to avoid continual
* malloc/free calls. Further, it allows the previous choices for
* the various functions to be quickly re-used.
*/
decoding_update :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
decode: ^decode_pipeline_t) -> result_t ---
/** Execute the decoding pipeline. */
decoding_run :: proc(
ctxt: const_context_t, part_index: c.int, decode: ^decode_pipeline_t) -> result_t ---
/** Free any intermediate memory in the decoding pipeline.
*
* This does *not* free any pointers referred to in the channel info
* areas, but rather only the intermediate buffers and memory needed
* for the structure itself.
*/
decoding_destroy :: proc(ctxt: const_context_t, decode: ^decode_pipeline_t) -> result_t ---
}
+323
View File
@@ -0,0 +1,323 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the sample count table should be encoded from an
* individual sample count list (n, m, o, ...), meaning it will have
* to compute the cumulative counts on the fly.
*
* Without this (i.e. a value of 0 in that bit), indicates the sample
* count table is already a cumulative list (n, n+m, n+m+o, ...),
* which is the on-disk representation.
*/
ENCODE_DATA_SAMPLE_COUNTS_ARE_INDIVIDUAL :: u16(1 << 0)
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the data in the channel pointers to encode from is not
* a direct pointer, but instead is a pointer-to-pointers. In this
* mode, the user_pixel_stride and user_line_stride are used to
* advance the pointer offsets for each pixel in the output, but the
* user_bytes_per_element and user_data_type are used to put
* (successive) entries into each destination.
*
* So each channel pointer must then point to an array of
* chunk.width * chunk.height pointers. If an entry is
* `NULL`, 0 samples will be placed in the output.
*
* If this is NOT set (0), the default packing routine assumes the
* data will be planar and contiguous (each channel is a separate
* memory block), ignoring user_line_stride and user_pixel_stride and
* advancing only by the sample counts and bytes per element.
*/
ENCODE_NON_IMAGE_DATA_AS_POINTERS :: u16(1 << 1)
/** Struct meant to be used on a per-thread basis for writing exr data.
*
* As should be obvious, this structure is NOT thread safe, but rather
* meant to be used by separate threads, which can all be accessing
* the same context concurrently.
*/
encode_pipeline_t :: struct {
/** The output channel information for this chunk.
*
* User is expected to fill the channel pointers for the input
* channels. For writing, all channels must be initialized prior
* to using exr_encoding_choose_default_routines(). If a custom pack routine
* is written, that is up to the implementor.
*
* Describes the channel information. This information is
* allocated dynamically during exr_encoding_initialize().
*/
channels: [^]coding_channel_info_t,
channel_count: i16,
/** Encode flags to control the behavior. */
encode_flags: u16,
/** Copy of the parameters given to the initialize/update for convenience. */
part_index: c.int,
ctx: const_context_t,
chunk: chunk_info_t,
/** Can be used by the user to pass custom context data through
* the encode pipeline.
*/
encoding_user_data: rawptr,
/** The packed buffer where individual channels have been put into here.
*
* If `NULL`, will be allocated during the run of the pipeline.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
packed_buffer: rawptr,
/** Differing from the allocation size, the number of actual bytes */
packed_bytes: u64,
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough
*
* If `NULL`, will be allocated during the run of the pipeline.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
packed_alloc_size: c.size_t,
/** For deep data. NB: the members NOT const because we need to
* temporarily swap it to xdr order and restore it (to avoid a
* duplicate buffer allocation).
*
* Depending on the flag set above, will be treated either as a
* cumulative list (n, n+m, n+m+o, ...), or an individual table
* (n, m, o, ...). */
sample_count_table: [^]i32,
/** Allocated table size (to avoid re-allocations). Number of
* samples must always be width * height for the chunk.
*/
sample_count_alloc_size: c.size_t,
/** Packed sample table (compressed, raw on disk representation)
* for deep or other non-image data.
*/
packed_sample_count_table: rawptr,
/** Number of bytes to write (actual size) for the
* packed_sample_count_table.
*/
packed_sample_count_bytes: c.size_t,
/** Allocated size (to avoid re-allocations) for the
* packed_sample_count_table.
*/
packed_sample_count_alloc_size: c.size_t,
/** The compressed buffer, only needed for compressed files.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
compressed_buffer: rawptr,
/** Must be filled in as the pipeline runs to inform the writing
* software about the compressed size of the chunk (if it is an
* uncompressed file or the compression would make the file
* larger, it is expected to be the packed_buffer)
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to zero here. Be cognizant of any
* custom allocators.
*/
compressed_bytes: c.size_t,
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to zero here. Be cognizant of any
* custom allocators.
*/
compressed_alloc_size: c.size_t,
/** A scratch buffer for intermediate results.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
scratch_buffer_1: rawptr,
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
scratch_alloc_size_1: c.size_t,
/** Some compression routines may need a second scratch buffer.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
scratch_buffer_2: rawptr,
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
scratch_alloc_size_2: c.size_t,
/** Enable a custom allocator for the different buffers (if
* encoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
alloc_fn: proc "c" (transcoding_pipeline_buffer_id_t, c.size_t) -> rawptr,
/** Enable a custom allocator for the different buffers (if
* encoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
free_fn: proc "c" (transcoding_pipeline_buffer_id_t, rawptr),
/** Function chosen based on the output layout of the channels of the part to
* decompress data.
*
* If the user has a custom method for the
* compression on this part, this can be changed after
* initialization.
*/
convert_and_pack_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t,
/** Function chosen based on the compression type of the part to
* compress data.
*
* If the user has a custom compression method for the compression
* type on this part, this can be changed after initialization.
*/
compress_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t,
/** This routine is used when waiting for other threads to finish
* writing previous chunks such that this thread can write this
* chunk. This is used for parts which have a specified chunk
* ordering (increasing/decreasing y) and the chunks can not be
* written randomly (as could be true for uncompressed).
*
* This enables the calling application to contribute thread time
* to other computation as needed, or just use something like
* pthread_yield().
*
* By default, this routine will be assigned to a function which
* returns an error, failing the encode immediately. In this way,
* it assumes that there is only one thread being used for
* writing.
*
* It is up to the user to provide an appropriate routine if
* performing multi-threaded writing.
*/
yield_until_ready_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t,
/** Function chosen to write chunk data to the context.
*
* This is allowed to be overridden, but probably is not necessary
* in most scenarios.
*/
write_fn: proc "c" (pipeline: ^encode_pipeline_t) -> result_t,
/** Small stash of channel info values. This is faster than calling
* malloc when the channel count in the part is small (RGBAZ),
* which is super common, however if there are a large number of
* channels, it will allocate space for that, so do not rely on
* this being used.
*/
_quick_chan_store: [5]coding_channel_info_t,
}
ENCODE_PIPELINE_INITIALIZER :: encode_pipeline_t{}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** Initialize the encoding pipeline structure with the channel info
* for the specified part based on the chunk to be written.
*
* NB: The encode_pipe->pack_and_convert_fn field will be `NULL` after this. If that
* stage is desired, initialize the channel output information and
* call exr_encoding_choose_default_routines().
*/
encoding_initialize :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
encode_pipe: ^encode_pipeline_t) -> result_t ---
/** Given an initialized encode pipeline, find an appropriate
* function to shuffle and convert data into the defined channel
* outputs.
*
* Calling this is not required if a custom routine will be used, or
* if just the raw decompressed data is desired.
*/
encoding_choose_default_routines :: proc(
ctxt: const_context_t,
part_index: c.int,
encode_pipe: ^encode_pipeline_t) -> result_t ---
/** Given a encode pipeline previously initialized, update it for the
* new chunk to be written.
*
* In this manner, memory buffers can be re-used to avoid continual
* malloc/free calls. Further, it allows the previous choices for
* the various functions to be quickly re-used.
*/
encoding_update :: proc(
ctxt: const_context_t,
part_index: c.int,
cinfo: ^chunk_info_t,
encode_pipe: ^encode_pipeline_t) -> result_t ---
/** Execute the encoding pipeline. */
encoding_run :: proc(
ctxt: const_context_t,
part_index: c.int,
encode_pipe: ^encode_pipeline_t) -> result_t ---
/** Free any intermediate memory in the encoding pipeline.
*
* This does NOT free any pointers referred to in the channel info
* areas, but rather only the intermediate buffers and memory needed
* for the structure itself.
*/
encoding_destroy :: proc(ctxt: const_context_t, encode_pipe: ^encode_pipeline_t) -> result_t ---
}
+67
View File
@@ -0,0 +1,67 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
#assert(size_of(c.int) == size_of(i32))
/** Error codes that may be returned by various functions. */
/** Return type for all functions. */
result_t :: enum i32 {
SUCCESS = 0,
OUT_OF_MEMORY,
MISSING_CONTEXT_ARG,
INVALID_ARGUMENT,
ARGUMENT_OUT_OF_RANGE,
FILE_ACCESS,
FILE_BAD_HEADER,
NOT_OPEN_READ,
NOT_OPEN_WRITE,
HEADER_NOT_WRITTEN,
READ_IO,
WRITE_IO,
NAME_TOO_LONG,
MISSING_REQ_ATTR,
INVALID_ATTR,
NO_ATTR_BY_NAME,
ATTR_TYPE_MISMATCH,
ATTR_SIZE_MISMATCH,
SCAN_TILE_MIXEDAPI,
TILE_SCAN_MIXEDAPI,
MODIFY_SIZE_CHANGE,
ALREADY_WROTE_ATTRS,
BAD_CHUNK_LEADER,
CORRUPT_CHUNK,
INCORRECT_PART,
INCORRECT_CHUNK,
USE_SCAN_DEEP_WRITE,
USE_TILE_DEEP_WRITE,
USE_SCAN_NONDEEP_WRITE,
USE_TILE_NONDEEP_WRITE,
INVALID_SAMPLE_DATA,
FEATURE_NOT_IMPLEMENTED,
UNKNOWN,
}
error_code_t :: result_t
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** @brief Return a static string corresponding to the specified error code.
*
* The string should not be freed (it is compiled into the binary).
*/
get_default_error_message :: proc(code: result_t) -> cstring ---
/** @brief Return a static string corresponding to the specified error code.
*
* The string should not be freed (it is compiled into the binary).
*/
get_error_code_as_string :: proc(code: result_t) -> cstring ---
}
+737
View File
@@ -0,0 +1,737 @@
package vendor_openexr
when ODIN_OS == .Windows {
foreign import lib "OpenEXRCore-3_1.lib"
} else {
foreign import lib "system:OpenEXRCore-3_1"
}
import "core:c"
attr_list_access_mode_t :: enum c.int {
FILE_ORDER, /**< Order they appear in the file */
SORTED_ORDER, /**< Alphabetically sorted */
}
@(link_prefix="exr_", default_calling_convention="c")
foreign lib {
/** @brief Query how many parts are in the file. */
get_count :: proc (ctxt: const_context_t, count: ^c.int) -> result_t ---
/** @brief Query the part name for the specified part.
*
* NB: If this file is a single part file and name has not been set, this
* will return `NULL`.
*/
get_name :: proc(ctxt: const_context_t, part_index: c.int, out: ^cstring) -> result_t ---
/** @brief Query the storage type for the specified part. */
get_storage :: proc(ctxt: const_context_t, part_index: c.int, out: ^storage_t) -> result_t ---
/** @brief Define a new part in the file. */
add_part :: proc(
ctxt: context_t,
partname: rawptr,
type: storage_t,
new_index: ^c.int) -> result_t ---
/** @brief Query how many levels are in the specified part.
*
* If the part is a tiled part, fill in how many tile levels are present.
*
* Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the part
* is not tiled).
*
* It is valid to pass `NULL` to either of the @p levelsx or @p levelsy
* arguments, which enables testing if this part is a tiled part, or
* if you don't need both (i.e. in the case of a mip-level tiled
* image)
*/
get_tile_levels :: proc(
ctxt: const_context_t,
part_index: c.int,
levelsx: ^i32,
levelsy: ^i32) -> result_t ---
/** @brief Query the tile size for a particular level in the specified part.
*
* If the part is a tiled part, fill in the tile size for the
* specified part/level.
*
* Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the
* part is not tiled).
*
* It is valid to pass `NULL` to either of the @p tilew or @p tileh
* arguments, which enables testing if this part is a tiled part, or
* if you don't need both (i.e. in the case of a mip-level tiled
* image)
*/
get_tile_sizes :: proc(
ctxt: const_context_t,
part_index: c.int,
levelx: c.int,
levely: c.int,
tilew: ^i32,
tileh: ^i32) -> result_t ---
/** @brief Query the data sizes for a particular level in the specified part.
*
* If the part is a tiled part, fill in the width/height for the
* specified levels.
*
* Return `ERR_SUCCESS` on success, an error otherwise (i.e. if the part
* is not tiled).
*
* It is valid to pass `NULL` to either of the @p levw or @p levh
* arguments, which enables testing if this part is a tiled part, or
* if you don't need both for some reason.
*/
get_level_sizes :: proc(
ctxt: const_context_t,
part_index: c.int,
levelx: c.int,
levely: c.int,
levw: ^i32,
levh: ^i32) -> result_t ---
/** Return the number of chunks contained in this part of the file.
*
* As in the technical documentation for OpenEXR, the chunk is the
* generic term for a pixel data block. This is the atomic unit that
* this library uses to negotiate data to and from a context.
*
* This should be used as a basis for splitting up how a file is
* processed. Depending on the compression, a different number of
* scanlines are encoded in each chunk, and since those need to be
* encoded/decoded as a block, the chunk should be the basis for I/O
* as well.
*/
get_chunk_count :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t ---
/** Return the number of scanlines chunks for this file part.
*
* When iterating over a scanline file, this may be an easier metric
* for multi-threading or other access than only negotiating chunk
* counts, and so is provided as a utility.
*/
get_scanlines_per_chunk :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t ---
/** Return the maximum unpacked size of a chunk for the file part.
*
* This may be used ahead of any actual reading of data, so can be
* used to pre-allocate buffers for multiple threads in one block or
* whatever your application may require.
*/
get_chunk_unpacked_size :: proc(ctxt: const_context_t, part_index: c.int, out: ^u64) -> result_t ---
/** @brief Retrieve the zip compression level used for the specified part.
*
* This only applies when the compression method involves using zip
* compression (zip, zips, some modes of DWAA/DWAB).
*
* This value is NOT persisted in the file, and only exists for the
* lifetime of the context, so will be at the default value when just
* reading a file.
*/
get_zip_compression_level :: proc(ctxt: const_context_t, part_index: c.int, level: ^c.int) -> result_t ---
/** @brief Set the zip compression method used for the specified part.
*
* This only applies when the compression method involves using zip
* compression (zip, zips, some modes of DWAA/DWAB).
*
* This value is NOT persisted in the file, and only exists for the
* lifetime of the context, so this value will be ignored when
* reading a file.
*/
set_zip_compression_level :: proc(ctxt: context_t, part_index: c.int, level: c.int) -> result_t ---
/** @brief Retrieve the dwa compression level used for the specified part.
*
* This only applies when the compression method is DWAA/DWAB.
*
* This value is NOT persisted in the file, and only exists for the
* lifetime of the context, so will be at the default value when just
* reading a file.
*/
get_dwa_compression_level :: proc(ctxt: const_context_t, part_index: c.int, level: ^f32) -> result_t ---
/** @brief Set the dwa compression method used for the specified part.
*
* This only applies when the compression method is DWAA/DWAB.
*
* This value is NOT persisted in the file, and only exists for the
* lifetime of the context, so this value will be ignored when
* reading a file.
*/
set_dwa_compression_level :: proc(ctxt: context_t, part_index: c.int, level: f32) -> result_t ---
/**************************************/
/** @defgroup PartMetadata Functions to get and set metadata for a particular part.
* @{
*
*/
/** @brief Query the count of attributes in a part. */
get_attribute_count :: proc(ctxt: const_context_t, part_index: c.int, count: ^i32) -> result_t ---
/** @brief Query a particular attribute by index. */
get_attribute_by_index :: proc(
ctxt: const_context_t,
part_index: c.int,
mode: attr_list_access_mode_t,
idx: i32,
outattr: ^^attribute_t) -> result_t ---
/** @brief Query a particular attribute by name. */
get_attribute_by_name :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
outattr: ^^attribute_t) -> result_t ---
/** @brief Query the list of attributes in a part.
*
* This retrieves a list of attributes currently defined in a part.
*
* If outlist is `NULL`, this function still succeeds, filling only the
* count. In this manner, the user can allocate memory for the list of
* attributes, then re-call this function to get the full list.
*/
get_attribute_list :: proc(
ctxt: const_context_t,
part_index: c.int,
mode: attr_list_access_mode_t,
count: ^i32,
outlist: ^[^]attribute_t) -> result_t ---
/** Declare an attribute within the specified part.
*
* Only valid when a file is opened for write.
*/
attr_declare_by_type :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
type: cstring,
newattr: ^^attribute_t) -> result_t ---
/** @brief Declare an attribute within the specified part.
*
* Only valid when a file is opened for write.
*/
attr_declare :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
type: attribute_type_t,
newattr: ^^attribute_t) -> result_t ---
/**
* @defgroup RequiredAttributeHelpers Required Attribute Utililities
*
* @brief These are a group of functions for attributes that are
* required to be in every part of every file.
*
* @{
*/
/** @brief Initialize all required attributes for all files.
*
* NB: other file types do require other attributes, such as the tile
* description for a tiled file.
*/
initialize_required_attr :: proc(
ctxt: context_t,
part_index: c.int,
displayWindow: ^attr_box2i_t,
dataWindow: ^attr_box2i_t,
pixelaspectratio: f32,
screenWindowCenter: attr_v2f_t,
screenWindowWidth: f32,
lineorder: lineorder_t,
ctype: compression_t) -> result_t ---
/** @brief Initialize all required attributes to default values:
*
* - `displayWindow` is set to (0, 0 -> @p width - 1, @p height - 1)
* - `dataWindow` is set to (0, 0 -> @p width - 1, @p height - 1)
* - `pixelAspectRatio` is set to 1.0
* - `screenWindowCenter` is set to 0.f, 0.f
* - `screenWindowWidth` is set to 1.f
* - `lineorder` is set to `INCREASING_Y`
* - `compression` is set to @p ctype
*/
initialize_required_attr_simple :: proc(
ctxt: context_t,
part_index: c.int,
width: i32,
height: i32,
ctype: compression_t) -> result_t ---
/** @brief Copy the attributes from one part to another.
*
* This allows one to quickly unassigned attributes from one source to another.
*
* If an attribute in the source part has not been yet set in the
* destination part, the item will be copied over.
*
* For example, when you add a part, the storage type and name
* attributes are required arguments to the definition of a new part,
* but channels has not yet been assigned. So by calling this with an
* input file as the source, you can copy the channel definitions (and
* any other unassigned attributes from the source).
*/
copy_unset_attributes :: proc(
ctxt: context_t,
part_index: c.int,
source: const_context_t,
src_part_index: c.int) -> result_t ---
/** @brief Retrieve the list of channels. */
get_channels :: proc(ctxt: const_context_t, part_index: c.int, chlist: ^^attr_chlist_t) -> result_t ---
/** @brief Define a new channel to the output file part.
*
* The @p percept parameter is used for lossy compression techniques
* to indicate that the value represented is closer to linear (1) or
* closer to logarithmic (0). For r, g, b, luminance, this is normally
* 0.
*/
add_channel :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
ptype: pixel_type_t,
percept: perceptual_treatment_t,
xsamp: i32,
ysamp: i32) -> c.int ---
/** @brief Copy the channels from another source.
*
* Useful if you are manually constructing the list or simply copying
* from an input file.
*/
set_channels :: proc(ctxt: context_t, part_index: c.int, channels: ^attr_chlist_t) -> result_t ---
/** @brief Retrieve the compression method used for the specified part. */
get_compression :: proc(ctxt: const_context_t, part_index: c.int, compression: ^compression_t) -> result_t ---
/** @brief Set the compression method used for the specified part. */
set_compression :: proc(ctxt: context_t, part_index: c.int, ctype: compression_t) -> result_t ---
/** @brief Retrieve the data window for the specified part. */
get_data_window :: proc(ctxt: const_context_t, part_index: c.int, out: ^attr_box2i_t) -> result_t ---
/** @brief Set the data window for the specified part. */
set_data_window :: proc(ctxt: context_t, part_index: c.int, dw: ^attr_box2i_t) -> c.int ---
/** @brief Retrieve the display window for the specified part. */
get_display_window :: proc(ctxt: const_context_t, part_index: c.int, out: ^attr_box2i_t) -> result_t ---
/** @brief Set the display window for the specified part. */
set_display_window :: proc(ctxt: context_t, part_index: c.int, dw: ^attr_box2i_t) -> c.int ---
/** @brief Retrieve the line order for storing data in the specified part (use 0 for single part images). */
get_lineorder :: proc(ctxt: const_context_t, part_index: c.int, out: ^lineorder_t) -> result_t ---
/** @brief Set the line order for storing data in the specified part (use 0 for single part images). */
set_lineorder :: proc(ctxt: context_t, part_index: c.int, lo: lineorder_t) -> result_t ---
/** @brief Retrieve the pixel aspect ratio for the specified part (use 0 for single part images). */
get_pixel_aspect_ratio :: proc(ctxt: const_context_t, part_index: c.int, par: ^f32) -> result_t ---
/** @brief Set the pixel aspect ratio for the specified part (use 0 for single part images). */
set_pixel_aspect_ratio :: proc(ctxt: context_t, part_index: c.int, par: f32) -> result_t ---
/** @brief Retrieve the screen oriented window center for the specified part (use 0 for single part images). */
get_screen_window_center :: proc(ctxt: const_context_t, part_index: c.int, wc: ^attr_v2f_t) -> result_t ---
/** @brief Set the screen oriented window center for the specified part (use 0 for single part images). */
set_screen_window_center :: proc(ctxt: context_t, part_index: c.int, wc: ^attr_v2f_t) -> c.int ---
/** @brief Retrieve the screen oriented window width for the specified part (use 0 for single part images). */
get_screen_window_width :: proc(ctxt: const_context_t, part_index: c.int, out: ^f32) -> result_t ---
/** @brief Set the screen oriented window width for the specified part (use 0 for single part images). */
set_screen_window_width :: proc(ctxt: context_t, part_index: c.int, ssw: f32) -> result_t ---
/** @brief Retrieve the tiling info for a tiled part (use 0 for single part images). */
get_tile_descriptor :: proc(
ctxt: const_context_t,
part_index: c.int,
xsize: ^u32,
ysize: ^u32,
level: ^tile_level_mode_t,
round: ^tile_round_mode_t) -> result_t ---
/** @brief Set the tiling info for a tiled part (use 0 for single part images). */
set_tile_descriptor :: proc(
ctxt: context_t,
part_index: c.int,
x_size: u32,
y_size: u32,
level_mode: tile_level_mode_t,
round_mode: tile_round_mode_t) -> result_t ---
set_name :: proc(ctxt: context_t, part_index: c.int, val: cstring) -> result_t ---
get_version :: proc(ctxt: const_context_t, part_index: c.int, out: ^i32) -> result_t ---
set_version :: proc(ctxt: context_t, part_index: c.int, val: i32) -> result_t ---
set_chunk_count :: proc(ctxt: context_t, part_index: c.int, val: i32) -> result_t ---
/** @} */ /* required attr group. */
/**
* @defgroup BuiltinAttributeHelpers Attribute utilities for builtin types
*
* @brief These are a group of functions for attributes that use the builtin types.
*
* @{
*/
attr_get_box2i :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
outval: ^attr_box2i_t) -> result_t ---
attr_set_box2i :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
val: ^attr_box2i_t) -> result_t ---
attr_get_box2f :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
outval: ^attr_box2f_t) -> result_t ---
attr_set_box2f :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
val: ^attr_box2f_t) -> result_t ---
/** @brief Zero-copy query of channel data.
*
* Do not free or manipulate the @p chlist data, or use
* after the lifetime of the context.
*/
attr_get_channels :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
chlist: ^^attr_chlist_t) -> result_t ---
/** @brief This allows one to quickly copy the channels from one file
* to another.
*/
attr_set_channels :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
channels: ^attr_chlist_t) -> result_t ---
attr_get_chromaticities :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
chroma: ^attr_chromaticities_t) -> result_t ---
attr_set_chromaticities :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
chroma: ^attr_chromaticities_t) -> result_t ---
attr_get_compression :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^compression_t) -> result_t ---
attr_set_compression :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
comp: compression_t) -> result_t ---
attr_get_double :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: f64) -> result_t ---
attr_set_double :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: f64) -> result_t ---
attr_get_envmap :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^envmap_t) -> result_t ---
attr_set_envmap :: proc(ctxt: context_t, part_index: c.int, name: cstring, emap: envmap_t) -> result_t ---
attr_get_float :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: ^f32) -> result_t ---
attr_set_float :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: f32) -> result_t ---
/** @brief Zero-copy query of float data.
*
* Do not free or manipulate the @p out data, or use after the
* lifetime of the context.
*/
attr_get_float_vector :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
sz: ^i32,
out: ^[^]f32) -> result_t ---
attr_set_float_vector :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
sz: i32,
vals: [^]f32) -> result_t ---
attr_get_int :: proc(ctxt: const_context_t, part_index: c.int, name: cstring, out: ^i32) -> result_t ---
attr_set_int :: proc(ctxt: context_t, part_index: c.int, name: cstring, val: i32) -> result_t ---
attr_get_keycode :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_keycode_t) -> result_t ---
attr_set_keycode :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
kc: ^attr_keycode_t) -> result_t ---
attr_get_lineorder :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^lineorder_t) -> result_t ---
attr_set_lineorder :: proc(ctxt: context_t, part_index: c.int, name: cstring, lo: lineorder_t) -> result_t ---
attr_get_m33f :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_m33f_t) -> result_t ---
attr_set_m33f :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
m: ^attr_m33f_t) -> result_t ---
attr_get_m33d :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_m33d_t) -> result_t ---
attr_set_m33d :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
m: ^attr_m33d_t) -> result_t ---
attr_get_m44f :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_m44f_t) -> result_t ---
attr_set_m44f :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
m: ^attr_m44f_t) -> result_t ---
attr_get_m44d :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_m44d_t) -> result_t ---
attr_set_m44d :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
m: ^attr_m44d_t) -> result_t ---
attr_get_preview :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_preview_t) -> result_t ---
attr_set_preview :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
p: ^attr_preview_t) -> result_t ---
attr_get_rational :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_rational_t) -> result_t ---
attr_set_rational :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
r: ^attr_rational_t) -> result_t ---
/** @brief Zero-copy query of string value.
*
* Do not modify the string pointed to by @p out, and do not use
* after the lifetime of the context.
*/
attr_get_string :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
length: ^i32,
out: ^cstring) -> result_t ---
attr_set_string :: proc(ctxt: context_t, part_index: c.int, name: cstring, s: cstring) -> result_t ---
/** @brief Zero-copy query of string data.
*
* Do not free the strings pointed to by the array.
*
* Must provide @p size.
*
* \p out must be a ``^cstring`` array large enough to hold
* the string pointers for the string vector when provided.
*/
attr_get_string_vector :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
size: ^i32,
out: ^cstring) -> result_t ---
attr_set_string_vector :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
size: i32,
sv: ^cstring) -> result_t ---
attr_get_tiledesc :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_tiledesc_t) -> result_t ---
attr_set_tiledesc :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
td: ^attr_tiledesc_t) -> result_t ---
attr_get_timecode :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_timecode_t) -> result_t ---
attr_set_timecode :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
tc: ^attr_timecode_t) -> result_t ---
attr_get_v2i :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v2i_t) -> result_t ---
attr_set_v2i :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v2i_t) -> result_t ---
attr_get_v2f :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v2f_t) -> result_t ---
attr_set_v2f :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v2f_t) -> result_t ---
attr_get_v2d :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v2d_t) -> result_t ---
attr_set_v2d :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v2d_t) -> result_t ---
attr_get_v3i :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v3i_t) -> result_t ---
attr_set_v3i :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v3i_t) -> result_t ---
attr_get_v3f :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v3f_t) -> result_t ---
attr_set_v3f :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v3f_t) -> result_t ---
attr_get_v3d :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
out: ^attr_v3d_t) -> result_t ---
attr_set_v3d :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
v: ^attr_v3d_t) -> result_t ---
attr_get_user :: proc(
ctxt: const_context_t,
part_index: c.int,
name: cstring,
type: ^cstring,
size: ^i32,
out: ^rawptr) -> result_t ---
attr_set_user :: proc(
ctxt: context_t,
part_index: c.int,
name: cstring,
type: cstring,
size: i32,
out: rawptr) -> result_t ---
}
+2 -1
View File
@@ -5,6 +5,7 @@ package odin_gl
import "core:os"
import "core:fmt"
import "core:strings"
_ :: fmt
Shader_Type :: enum i32 {
NONE = 0x0000,
@@ -188,7 +189,7 @@ load_shaders_source :: proc(vs_source, fs_source: string, binary_retrievable :=
load_shaders :: proc{load_shaders_file}
when ODIN_OS == "windows" {
when ODIN_OS == .Windows {
update_shader_if_changed :: proc(
vertex_name, fragment_name: string,
program: u32,
+48 -4
View File
@@ -199,7 +199,7 @@ load_1_1 :: proc(set_proc_address: Set_Proc_Address_Type) {
// VERSION_1_2
impl_DrawRangeElements: proc "c" (mode: u32, start: u32, end: u32, count: i32, type: u32, indices: rawptr)
impl_TexImage3D: proc "c" (target: u32, level: i32, internalformat: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, type: u32, pixels: rawptr)
impl_TexImage3D: proc "c" (target: u32, level: i32, internalformat: i32, width: i32, height: i32, depth: i32, border: i32, format: u32, type: u32, data: rawptr)
impl_TexSubImage3D: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, width: i32, height: i32, depth: i32, format: u32, type: u32, pixels: rawptr)
impl_CopyTexSubImage3D: proc "c" (target: u32, level: i32, xoffset: i32, yoffset: i32, zoffset: i32, x: i32, y: i32, width: i32, height: i32)
@@ -947,6 +947,13 @@ impl_DrawTransformFeedbackStream: proc "c" (mode: u32, id: u32, stream: u32)
impl_BeginQueryIndexed: proc "c" (target: u32, index: u32, id: u32)
impl_EndQueryIndexed: proc "c" (target: u32, index: u32)
impl_GetQueryIndexediv: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32)
impl_GetTextureHandleARB: proc "c" (texture: u32) -> u64
impl_GetTextureSamplerHandleARB: proc "c" (texture, sampler: u32) -> u64
impl_GetImageHandleARB: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64
impl_MakeTextureHandleResidentARB: proc "c" (handle: u64)
impl_MakeImageHandleResidentARB: proc "c" (handle: u64, access: u32)
impl_MakeTextureHandleNonResidentARB:proc "c" (handle: u64)
impl_MakeImageHandleNonResidentARB: proc "c" (handle: u64)
load_4_0 :: proc(set_proc_address: Set_Proc_Address_Type) {
set_proc_address(&impl_MinSampleShading, "glMinSampleShading")
@@ -995,6 +1002,42 @@ load_4_0 :: proc(set_proc_address: Set_Proc_Address_Type) {
set_proc_address(&impl_BeginQueryIndexed, "glBeginQueryIndexed")
set_proc_address(&impl_EndQueryIndexed, "glEndQueryIndexed")
set_proc_address(&impl_GetQueryIndexediv, "glGetQueryIndexediv")
// Load ARB (architecture review board, vendor specific) extensions that might be available
set_proc_address(&impl_GetTextureHandleARB, "glGetTextureHandleARB")
if impl_GetTextureHandleARB == nil {
set_proc_address(&impl_GetTextureHandleARB, "glGetTextureHandleNV")
}
set_proc_address(&impl_GetTextureSamplerHandleARB, "glGetTextureSamplerHandleARB")
if impl_GetTextureSamplerHandleARB == nil {
set_proc_address(&impl_GetTextureSamplerHandleARB, "glGetTextureSamplerHandleNV")
}
set_proc_address(&impl_GetImageHandleARB, "glGetImageHandleARB")
if impl_GetImageHandleARB == nil {
set_proc_address(&impl_GetImageHandleARB, "glGetImageHandleNV")
}
set_proc_address(&impl_MakeTextureHandleResidentARB, "glMakeTextureHandleResidentARB")
if impl_MakeTextureHandleResidentARB == nil {
set_proc_address(&impl_MakeTextureHandleResidentARB, "glMakeTextureHandleResidentNV")
}
set_proc_address(&impl_MakeImageHandleResidentARB, "glMakeImageHandleResidentARB")
if impl_MakeImageHandleResidentARB == nil {
set_proc_address(&impl_MakeImageHandleResidentARB, "glMakeImageHandleResidentNV")
}
set_proc_address(&impl_MakeTextureHandleNonResidentARB, "glMakeTextureHandleNonResidentARB")
if impl_MakeTextureHandleNonResidentARB == nil {
set_proc_address(&impl_MakeTextureHandleNonResidentARB, "glMakeTextureHandleNonResidentNV")
}
set_proc_address(&impl_MakeImageHandleNonResidentARB, "glMakeImageHandleNonResidentARB")
if impl_MakeImageHandleNonResidentARB == nil {
set_proc_address(&impl_MakeImageHandleNonResidentARB, "glMakeImageHandleNonResidentNV")
}
}
@@ -1250,14 +1293,14 @@ impl_VertexAttribLFormat: proc "c" (attribindex: u32, size: i32, typ
impl_VertexAttribBinding: proc "c" (attribindex: u32, bindingindex: u32)
impl_VertexBindingDivisor: proc "c" (bindingindex: u32, divisor: u32)
impl_DebugMessageControl: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool)
impl_DebugMessageInsert: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: [^]u8)
impl_DebugMessageInsert: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring)
impl_DebugMessageCallback: proc "c" (callback: debug_proc_t, userParam: rawptr)
impl_GetDebugMessageLog: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32
impl_PushDebugGroup: proc "c" (source: u32, id: u32, length: i32, message: cstring)
impl_PopDebugGroup: proc "c" ()
impl_ObjectLabel: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8)
impl_ObjectLabel: proc "c" (identifier: u32, name: u32, length: i32, label: cstring)
impl_GetObjectLabel: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8)
impl_ObjectPtrLabel: proc "c" (ptr: rawptr, length: i32, label: [^]u8)
impl_ObjectPtrLabel: proc "c" (ptr: rawptr, length: i32, label: cstring)
impl_GetObjectPtrLabel: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8)
load_4_3 :: proc(set_proc_address: Set_Proc_Address_Type) {
@@ -1594,3 +1637,4 @@ load_4_6 :: proc(set_proc_address: Set_Proc_Address_Type) {
set_proc_address(&impl_MultiDrawElementsIndirectCount, "glMultiDrawElementsIndirectCount")
set_proc_address(&impl_PolygonOffsetClamp, "glPolygonOffsetClamp")
}
+37 -7
View File
@@ -70,7 +70,7 @@ when !ODIN_DEBUG {
// VERSION_1_2
DrawRangeElements :: proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr) { impl_DrawRangeElements(mode, start, end, count, type, indices) }
TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels) }
TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, data: rawptr) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, data) }
TexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) }
CopyTexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height) }
@@ -449,6 +449,20 @@ when !ODIN_DEBUG {
BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32) { impl_BeginQueryIndexed(target, index, id) }
EndQueryIndexed :: proc "c" (target: u32, index: u32) { impl_EndQueryIndexed(target, index) }
GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32) { impl_GetQueryIndexediv(target, index, pname, params) }
GetTextureHandleARB :: proc "c" (texture: u32) -> u64
{ return impl_GetTextureHandleARB(texture) }
GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32) -> u64
{ return impl_GetTextureSamplerHandleARB(texture, sampler) }
GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32) -> u64
{ return impl_GetImageHandleARB(texture, level, layered, layer, format) }
MakeTextureHandleResidentARB :: proc "c" (handle: u64)
{ impl_MakeTextureHandleResidentARB(handle) }
MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32)
{ impl_MakeImageHandleResidentARB(handle, access) }
MakeTextureHandleNonResidentARB:: proc "c" (handle: u64)
{ impl_MakeTextureHandleNonResidentARB(handle) }
MakeImageHandleNonResidentARB :: proc "c" (handle: u64)
{ impl_MakeImageHandleNonResidentARB(handle) }
// VERSION_4_1
ReleaseShaderCompiler :: proc "c" () { impl_ReleaseShaderCompiler() }
@@ -589,14 +603,14 @@ when !ODIN_DEBUG {
VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32) { impl_VertexAttribBinding(attribindex, bindingindex) }
VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32) { impl_VertexBindingDivisor(bindingindex, divisor) }
DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool) { impl_DebugMessageControl(source, type, severity, count, ids, enabled) }
DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8) { impl_DebugMessageInsert(source, type, id, severity, length, buf) }
DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring) { impl_DebugMessageInsert(source, type, id, severity, length, message) }
DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr) { impl_DebugMessageCallback(callback, userParam) }
GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret }
PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring) { impl_PushDebugGroup(source, id, length, message) }
PopDebugGroup :: proc "c" () { impl_PopDebugGroup() }
ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8) { impl_ObjectLabel(identifier, name, length, label) }
ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: cstring) { impl_ObjectLabel(identifier, name, length, label) }
GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectLabel(identifier, name, bufSize, length, label) }
ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8) { impl_ObjectPtrLabel(ptr, length, label) }
ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: cstring) { impl_ObjectPtrLabel(ptr, length, label) }
GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8) { impl_GetObjectPtrLabel(ptr, bufSize, length, label) }
// VERSION_4_4
@@ -1249,6 +1263,22 @@ when !ODIN_DEBUG {
BeginQueryIndexed :: proc "c" (target: u32, index: u32, id: u32, loc := #caller_location) { impl_BeginQueryIndexed(target, index, id); debug_helper(loc, 0, target, index, id) }
EndQueryIndexed :: proc "c" (target: u32, index: u32, loc := #caller_location) { impl_EndQueryIndexed(target, index); debug_helper(loc, 0, target, index) }
GetQueryIndexediv :: proc "c" (target: u32, index: u32, pname: u32, params: [^]i32, loc := #caller_location) { impl_GetQueryIndexediv(target, index, pname, params); debug_helper(loc, 0, target, index, pname, params) }
GetTextureHandleARB :: proc "c" (target: u32, loc := #caller_location) -> u64
{ ret := impl_GetTextureHandleARB(target); debug_helper(loc, 0, target); return ret }
GetTextureSamplerHandleARB :: proc "c" (texture, sampler: u32, loc := #caller_location) -> u64
{ ret := impl_GetTextureSamplerHandleARB(texture, sampler); debug_helper(loc, 0, texture, sampler); return ret }
GetImageHandleARB :: proc "c" (texture: u32, level: i32, layered: bool, layer: i32, format: u32, loc := #caller_location) -> u64
{ ret := impl_GetImageHandleARB(texture, level, layered, layer, format); debug_helper(loc, 0, texture, level, layered, layer, format); return ret }
MakeTextureHandleResidentARB :: proc "c" (handle: u64, loc := #caller_location)
{ impl_MakeTextureHandleResidentARB(handle); debug_helper(loc, 0, handle) }
MakeImageHandleResidentARB :: proc "c" (handle: u64, access: u32, loc := #caller_location)
{ impl_MakeImageHandleResidentARB(handle, access); debug_helper(loc, 0, handle, access) }
MakeTextureHandleNonResidentARB:: proc "c" (handle: u64, loc := #caller_location)
{ impl_MakeTextureHandleNonResidentARB(handle); debug_helper(loc, 0, handle) }
MakeImageHandleNonResidentARB :: proc "c" (handle: u64, loc := #caller_location)
{ impl_MakeImageHandleNonResidentARB(handle); debug_helper(loc, 0, handle) }
// VERSION_4_1
ReleaseShaderCompiler :: proc "c" (loc := #caller_location) { impl_ReleaseShaderCompiler(); debug_helper(loc, 0) }
@@ -1389,14 +1419,14 @@ when !ODIN_DEBUG {
VertexAttribBinding :: proc "c" (attribindex: u32, bindingindex: u32, loc := #caller_location) { impl_VertexAttribBinding(attribindex, bindingindex); debug_helper(loc, 0, attribindex, bindingindex) }
VertexBindingDivisor :: proc "c" (bindingindex: u32, divisor: u32, loc := #caller_location) { impl_VertexBindingDivisor(bindingindex, divisor); debug_helper(loc, 0, bindingindex, divisor) }
DebugMessageControl :: proc "c" (source: u32, type: u32, severity: u32, count: i32, ids: [^]u32, enabled: bool, loc := #caller_location) { impl_DebugMessageControl(source, type, severity, count, ids, enabled); debug_helper(loc, 0, source, type, severity, count, ids, enabled) }
DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, buf: ^u8, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, buf); debug_helper(loc, 0, source, type, id, severity, length, buf) }
DebugMessageInsert :: proc "c" (source: u32, type: u32, id: u32, severity: u32, length: i32, message: cstring, loc := #caller_location) { impl_DebugMessageInsert(source, type, id, severity, length, message); debug_helper(loc, 0, source, type, id, severity, length, message) }
DebugMessageCallback :: proc "c" (callback: debug_proc_t, userParam: rawptr, loc := #caller_location) { impl_DebugMessageCallback(callback, userParam); debug_helper(loc, 0, callback, userParam) }
GetDebugMessageLog :: proc "c" (count: u32, bufSize: i32, sources: [^]u32, types: [^]u32, ids: [^]u32, severities: [^]u32, lengths: [^]i32, messageLog: [^]u8, loc := #caller_location) -> u32 { ret := impl_GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog); debug_helper(loc, 1, ret, count, bufSize, sources, types, ids, severities, lengths, messageLog); return ret }
PushDebugGroup :: proc "c" (source: u32, id: u32, length: i32, message: cstring, loc := #caller_location) { impl_PushDebugGroup(source, id, length, message); debug_helper(loc, 0, source, id, length, message) }
PopDebugGroup :: proc "c" (loc := #caller_location) { impl_PopDebugGroup(); debug_helper(loc, 0) }
ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) }
ObjectLabel :: proc "c" (identifier: u32, name: u32, length: i32, label: cstring, loc := #caller_location) { impl_ObjectLabel(identifier, name, length, label); debug_helper(loc, 0, identifier, name, length, label) }
GetObjectLabel :: proc "c" (identifier: u32, name: u32, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectLabel(identifier, name, bufSize, length, label); debug_helper(loc, 0, identifier, name, bufSize, length, label) }
ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: [^]u8, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) }
ObjectPtrLabel :: proc "c" (ptr: rawptr, length: i32, label: cstring, loc := #caller_location) { impl_ObjectPtrLabel(ptr, length, label); debug_helper(loc, 0, ptr, length, label) }
GetObjectPtrLabel :: proc "c" (ptr: rawptr, bufSize: i32, length: ^i32, label: [^]u8, loc := #caller_location) { impl_GetObjectPtrLabel(ptr, bufSize, length, label); debug_helper(loc, 0, ptr, bufSize, length, label) }
// VERSION_4_4
+8
View File
@@ -119,6 +119,14 @@ See also LICENSE.txt in the `portmidi` directory itself.
See also LICENSE in the `ENet` directory itself.
## GGPO
[GGPO](https://www.ggpo.net/) GGPO Rollback Networking SDK.
Zero-input latency networking library for peer-to-peer games.
See also LICENSE in the `GGPO` directory itself.
## Botan
[Botan](https://botan.randombit.net/) Crypto and TLS library.
+7 -5
View File
@@ -99,6 +99,10 @@ MAC_HMAC_SHA_384 :: "HMAC(SHA-384)"
MAC_HMAC_SHA_512 :: "HMAC(SHA-512)"
MAC_HMAC_MD5 :: "HMAC(MD5)"
MAC_SIPHASH_1_3 :: "SipHash(1,3)"
MAC_SIPHASH_2_4 :: "SipHash(2,4)"
MAC_SIPHASH_4_8 :: "SipHash(4,8)"
hash_struct :: struct{}
hash_t :: ^hash_struct
rng_struct :: struct{}
@@ -136,11 +140,9 @@ totp_t :: ^totp_struct
fpe_struct :: struct{}
fpe_t :: ^fpe_struct
when ODIN_OS == "windows" {
when ODIN_OS == .Windows {
foreign import botan_lib "botan.lib"
} else when ODIN_OS == "linux" {
foreign import botan_lib "system:botan-2"
} else when ODIN_OS == "darwin" {
} else {
foreign import botan_lib "system:botan-2"
}
@@ -467,4 +469,4 @@ foreign botan_lib {
fpe_destroy :: proc(fpe: fpe_t) -> c.int ---
fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_160 will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+4 -4
View File
@@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
@@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
@@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
@@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
+4 -4
View File
@@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
@@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
@@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
@@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
+2 -2
View File
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_128 will hash the given input and write the
@@ -124,7 +124,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
+253
View File
@@ -0,0 +1,253 @@
package siphash
/*
Copyright 2022 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog: Initial implementation.
Interface for the SipHash hashing algorithm.
The hash will be computed via bindings to the Botan crypto library
Use the specific procedures for a certain setup. The generic procdedures will default to Siphash 2-4
*/
import "core:crypto"
import "core:crypto/util"
import botan "../bindings"
KEY_SIZE :: 16
DIGEST_SIZE :: 8
// sum_string_1_3 will hash the given message with the key and return
// the computed hash as a u64
sum_string_1_3 :: proc(msg, key: string) -> u64 {
return sum_bytes_1_3(transmute([]byte)(msg), transmute([]byte)(key))
}
// sum_bytes_1_3 will hash the given message with the key and return
// the computed hash as a u64
sum_bytes_1_3 :: proc (msg, key: []byte) -> u64 {
dst: [8]byte
ctx: botan.mac_t
init(&ctx, key[:], 1, 3)
update(&ctx, msg[:])
final(&ctx, dst[:])
return util.U64_LE(dst[:])
}
// sum_string_to_buffer_1_3 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_string_to_buffer_1_3 :: proc(msg, key: string, dst: []byte) {
sum_bytes_to_buffer_1_3(transmute([]byte)(msg), transmute([]byte)(key), dst)
}
// sum_bytes_to_buffer_1_3 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_bytes_to_buffer_1_3 :: proc(msg, key, dst: []byte) {
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
ctx: botan.mac_t
init(&ctx, key[:], 1, 3)
update(&ctx, msg[:])
final(&ctx, dst[:])
}
sum_1_3 :: proc {
sum_string_1_3,
sum_bytes_1_3,
sum_string_to_buffer_1_3,
sum_bytes_to_buffer_1_3,
}
// verify_u64_1_3 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_u64_1_3 :: proc (tag: u64 msg, key: []byte) -> bool {
return sum_bytes_1_3(msg, key) == tag
}
// verify_bytes_1_3 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_bytes_1_3 :: proc (tag, msg, key: []byte) -> bool {
derived_tag: [8]byte
sum_bytes_to_buffer_1_3(msg, key, derived_tag[:])
return crypto.compare_constant_time(derived_tag[:], tag) == 1
}
verify_1_3 :: proc {
verify_bytes_1_3,
verify_u64_1_3,
}
// sum_string_2_4 will hash the given message with the key and return
// the computed hash as a u64
sum_string_2_4 :: proc(msg, key: string) -> u64 {
return sum_bytes_2_4(transmute([]byte)(msg), transmute([]byte)(key))
}
// sum_bytes_2_4 will hash the given message with the key and return
// the computed hash as a u64
sum_bytes_2_4 :: proc (msg, key: []byte) -> u64 {
dst: [8]byte
ctx: botan.mac_t
init(&ctx, key[:])
update(&ctx, msg[:])
final(&ctx, dst[:])
return util.U64_LE(dst[:])
}
// sum_string_to_buffer_2_4 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_string_to_buffer_2_4 :: proc(msg, key: string, dst: []byte) {
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
}
// sum_bytes_to_buffer_2_4 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_bytes_to_buffer_2_4 :: proc(msg, key, dst: []byte) {
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
ctx: botan.mac_t
init(&ctx, key[:])
update(&ctx, msg[:])
final(&ctx, dst[:])
}
sum_2_4 :: proc {
sum_string_2_4,
sum_bytes_2_4,
sum_string_to_buffer_2_4,
sum_bytes_to_buffer_2_4,
}
sum_string :: sum_string_2_4
sum_bytes :: sum_bytes_2_4
sum_string_to_buffer :: sum_string_to_buffer_2_4
sum_bytes_to_buffer :: sum_bytes_to_buffer_2_4
sum :: proc {
sum_string,
sum_bytes,
sum_string_to_buffer,
sum_bytes_to_buffer,
}
// verify_u64_2_4 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_u64_2_4 :: proc (tag: u64 msg, key: []byte) -> bool {
return sum_bytes_2_4(msg, key) == tag
}
// verify_bytes_2_4 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_bytes_2_4 :: proc (tag, msg, key: []byte) -> bool {
derived_tag: [8]byte
sum_bytes_to_buffer_2_4(msg, key, derived_tag[:])
return crypto.compare_constant_time(derived_tag[:], tag) == 1
}
verify_2_4 :: proc {
verify_bytes_2_4,
verify_u64_2_4,
}
verify_bytes :: verify_bytes_2_4
verify_u64 :: verify_u64_2_4
verify :: proc {
verify_bytes,
verify_u64,
}
// sum_string_4_8 will hash the given message with the key and return
// the computed hash as a u64
sum_string_4_8 :: proc(msg, key: string) -> u64 {
return sum_bytes_4_8(transmute([]byte)(msg), transmute([]byte)(key))
}
// sum_bytes_4_8 will hash the given message with the key and return
// the computed hash as a u64
sum_bytes_4_8 :: proc (msg, key: []byte) -> u64 {
dst: [8]byte
ctx: botan.mac_t
init(&ctx, key[:], 4, 8)
update(&ctx, msg[:])
final(&ctx, dst[:])
return util.U64_LE(dst[:])
}
// sum_string_to_buffer_4_8 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_string_to_buffer_4_8 :: proc(msg, key: string, dst: []byte) {
sum_bytes_to_buffer_2_4(transmute([]byte)(msg), transmute([]byte)(key), dst)
}
// sum_bytes_to_buffer_4_8 will hash the given message with the key and write
// the computed hash into the provided destination buffer
sum_bytes_to_buffer_4_8 :: proc(msg, key, dst: []byte) {
assert(len(dst) >= DIGEST_SIZE, "vendor/botan: Destination buffer needs to be at least of size 8")
ctx: botan.mac_t
init(&ctx, key[:], 4, 8)
update(&ctx, msg[:])
final(&ctx, dst[:])
}
sum_4_8 :: proc {
sum_string_4_8,
sum_bytes_4_8,
sum_string_to_buffer_4_8,
sum_bytes_to_buffer_4_8,
}
// verify_u64_4_8 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_u64_4_8 :: proc (tag: u64 msg, key: []byte) -> bool {
return sum_bytes_4_8(msg, key) == tag
}
// verify_bytes_4_8 will check if the supplied tag matches with the output you
// will get from the provided message and key
verify_bytes_4_8 :: proc (tag, msg, key: []byte) -> bool {
derived_tag: [8]byte
sum_bytes_to_buffer_4_8(msg, key, derived_tag[:])
return crypto.compare_constant_time(derived_tag[:], tag) == 1
}
verify_4_8 :: proc {
verify_bytes_4_8,
verify_u64_4_8,
}
/*
Low level API
*/
Context :: botan.mac_t
init :: proc(ctx: ^botan.mac_t, key: []byte, c_rounds := 2, d_rounds := 4) {
assert(len(key) == KEY_SIZE, "vendor/botan: Invalid key size, want 16")
is_valid_setting := (c_rounds == 1 && d_rounds == 3) ||
(c_rounds == 2 && d_rounds == 4) ||
(c_rounds == 4 && d_rounds == 8)
assert(is_valid_setting, "vendor/botan: Incorrect rounds set up. Valid pairs are (1,3), (2,4) and (4,8)")
if c_rounds == 1 && d_rounds == 3 {
botan.mac_init(ctx, botan.MAC_SIPHASH_1_3, 0)
} else if c_rounds == 2 && d_rounds == 4 {
botan.mac_init(ctx, botan.MAC_SIPHASH_2_4, 0)
} else if c_rounds == 4 && d_rounds == 8 {
botan.mac_init(ctx, botan.MAC_SIPHASH_4_8, 0)
}
botan.mac_set_key(ctx^, len(key) == 0 ? nil : &key[0], uint(len(key)))
}
update :: proc "contextless" (ctx: ^botan.mac_t, data: []byte) {
botan.mac_update(ctx^, len(data) == 0 ? nil : &data[0], uint(len(data)))
}
final :: proc(ctx: ^botan.mac_t, dst: []byte) {
botan.mac_final(ctx^, &dst[0])
reset(ctx)
}
reset :: proc(ctx: ^botan.mac_t) {
botan.mac_destroy(ctx^)
}
+3 -3
View File
@@ -47,7 +47,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
@@ -126,7 +126,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
@@ -205,7 +205,7 @@ hash_bytes_slice :: proc(data: []byte, bit_size: int, allocator := context.alloc
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_slice :: proc(data: string, hash: []byte, bit_size: int, allocator := context.allocator) {
hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator);
hash_bytes_to_buffer_slice(transmute([]byte)(data), hash, bit_size, allocator)
}
// hash_bytes_to_buffer_slice will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+2 -2
View File
@@ -45,7 +45,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
@@ -124,7 +124,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
+3 -3
View File
@@ -46,7 +46,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_128 will hash the given input and write the
@@ -125,7 +125,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_160 will hash the given input and write the
@@ -204,7 +204,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_192(transmute([]byte)(data), hash);
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_192 will hash the given input and write the
+1 -1
View File
@@ -44,7 +44,7 @@ hash_bytes :: proc "contextless" (data: []byte) -> [DIGEST_SIZE]byte {
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash);
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
+95
View File
@@ -0,0 +1,95 @@
package objc_Foundation
import "core:intrinsics"
ActivationPolicy :: enum UInteger {
Regular = 0,
Accessory = 1,
Prohibited = 2,
}
ApplicationDelegate :: struct {
willFinishLaunching: proc "c" (self: ^ApplicationDelegate, notification: ^Notification),
didFinishLaunching: proc "c" (self: ^ApplicationDelegate, notification: ^Notification),
shouldTerminateAfterLastWindowClosed: proc "c" (self: ^ApplicationDelegate, sender: ^Application),
user_data: rawptr,
}
@(objc_class="NSApplication")
Application :: struct {using _: Object}
@(objc_type=Application, objc_name="sharedApplication", objc_is_class_method=true)
Application_sharedApplication :: proc() -> ^Application {
return msgSend(^Application, Application, "sharedApplication")
}
@(objc_type=Application, objc_name="setDelegate")
Application_setDelegate :: proc(self: ^Application, delegate: ^ApplicationDelegate) {
willFinishLaunching :: proc "c" (self: ^Value, _: SEL, notification: ^Notification) {
del := (^ApplicationDelegate)(self->pointerValue())
del->willFinishLaunching(notification)
}
didFinishLaunching :: proc "c" (self: ^Value, _: SEL, notification: ^Notification) {
del := (^ApplicationDelegate)(self->pointerValue())
del->didFinishLaunching(notification)
}
shouldTerminateAfterLastWindowClosed :: proc "c" (self: ^Value, _: SEL, application: ^Application) {
del := (^ApplicationDelegate)(self->pointerValue())
del->shouldTerminateAfterLastWindowClosed(application)
}
wrapper := Value.valueWithPointer(delegate)
class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationWillFinishLaunching:"), auto_cast willFinishLaunching, "v@:@")
class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationDidFinishLaunching:"), auto_cast didFinishLaunching, "v@:@")
class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("applicationShouldTerminateAfterLastWindowClosed:"), auto_cast shouldTerminateAfterLastWindowClosed, "B@:@")
msgSend(nil, self, "setDelegate:", wrapper)
}
@(objc_type=Application, objc_name="setActivationPolicy")
Application_setActivationPolicy :: proc(self: ^Application, activationPolicy: ActivationPolicy) -> BOOL {
return msgSend(BOOL, self, "setActivationPolicy:", activationPolicy)
}
@(objc_type=Application, objc_name="activateIgnoringOtherApps")
Application_activateIgnoringOtherApps :: proc(self: ^Application, ignoreOtherApps: BOOL) {
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
}
@(objc_type=Application, objc_name="setMainMenu")
Application_setMainMenu :: proc(self: ^Application, menu: ^Menu) {
msgSend(nil, self, "setMainMenu:", menu)
}
@(objc_type=Application, objc_name="windows")
Application_windows :: proc(self: ^Application) -> ^Array {
return msgSend(^Array, self, "windows")
}
@(objc_type=Application, objc_name="run")
Application_run :: proc(self: ^Application) {
msgSend(nil, self, "run")
}
@(objc_type=Application, objc_name="terminate")
Application_terminate :: proc(self: ^Application, sender: ^Object) {
msgSend(nil, self, "terminate:", sender)
}
@(objc_class="NSRunningApplication")
RunningApplication :: struct {using _: Object}
@(objc_type=RunningApplication, objc_name="currentApplication", objc_is_class_method=true)
RunningApplication_currentApplication :: proc() -> ^RunningApplication {
return msgSend(^RunningApplication, RunningApplication, "currentApplication")
}
@(objc_type=RunningApplication, objc_name="localizedName")
RunningApplication_localizedName :: proc(self: ^RunningApplication) -> ^String {
return msgSend(^String, self, "localizedName")
}
+42
View File
@@ -0,0 +1,42 @@
package objc_Foundation
import "core:intrinsics"
@(objc_class="NSArray")
Array :: struct {
using _: Copying(Array),
}
@(objc_type=Array, objc_name="alloc", objc_is_class_method=true)
Array_alloc :: proc() -> ^Array {
return msgSend(^Array, Array, "alloc")
}
@(objc_type=Array, objc_name="init")
Array_init :: proc(self: ^Array) -> ^Array {
return msgSend(^Array, self, "init")
}
@(objc_type=Array, objc_name="initWithObjects")
Array_initWithObjects :: proc(self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array {
return msgSend(^Array, self, "initWithObjects:count:", objects, count)
}
@(objc_type=Array, objc_name="initWithCoder")
Array_initWithCoder :: proc(self: ^Array, coder: ^Coder) -> ^Array {
return msgSend(^Array, self, "initWithCoder:", coder)
}
@(objc_type=Array, objc_name="object")
Array_object :: proc(self: ^Array, index: UInteger) -> ^Object {
return msgSend(^Object, self, "objectAtIndex:", index)
}
@(objc_type=Array, objc_name="objectAs")
Array_objectAs :: proc(self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
return (T)(Array_object(self, index))
}
@(objc_type=Array, objc_name="count")
Array_count :: proc(self: ^Array) -> UInteger {
return msgSend(UInteger, self, "count")
}
+33
View File
@@ -0,0 +1,33 @@
package objc_Foundation
@(objc_class="NSAutoreleasePool")
AutoreleasePool :: struct {using _: Object}
@(objc_type=AutoreleasePool, objc_name="alloc", objc_is_class_method=true)
AutoreleasePool_alloc :: proc() -> ^AutoreleasePool {
return msgSend(^AutoreleasePool, AutoreleasePool, "alloc")
}
@(objc_type=AutoreleasePool, objc_name="init")
AutoreleasePool_init :: proc(self: ^AutoreleasePool) -> ^AutoreleasePool {
return msgSend(^AutoreleasePool, self, "init")
}
@(objc_type=AutoreleasePool, objc_name="drain")
AutoreleasePool_drain :: proc(self: ^AutoreleasePool) {
msgSend(nil, self, "drain")
}
@(objc_type=AutoreleasePool, objc_name="addObject")
AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) {
msgSend(nil, self, "addObject:", obj)
}
@(objc_type=AutoreleasePool, objc_name="showPools")
AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) {
msgSend(nil, self, "showPools")
}
@(deferred_out=AutoreleasePool_drain)
scoped_autoreleasepool :: proc() -> ^AutoreleasePool {
return AutoreleasePool.alloc()->init()
}
+81
View File
@@ -0,0 +1,81 @@
package objc_Foundation
import "core:intrinsics"
@(objc_class="NSConcreteGlobalBlock")
Block :: struct {using _: Object}
@(objc_type=Block, objc_name="createGlobal", objc_is_class_method=true)
Block_createGlobal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
return Block_createInternal(true, user_data, user_proc)
}
@(objc_type=Block, objc_name="createLocal", objc_is_class_method=true)
Block_createLocal :: proc "c" (user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
return Block_createInternal(false, user_data, user_proc)
}
@(private)
Internal_Block_Literal_Base :: struct {
isa: ^intrinsics.objc_class,
flags: u32,
reserved: u32,
invoke: proc "c" (^Internal_Block_Literal),
descriptor: ^Block_Descriptor,
}
@(private)
Internal_Block_Literal :: struct {
using base: Internal_Block_Literal_Base,
// Imported Variables
user_proc: proc "c" (user_data: rawptr),
user_data: rawptr,
}
@(private)
Block_Descriptor :: struct {
reserved: uint,
size: uint,
copy_helper: proc "c" (dst, src: rawptr),
dispose_helper: proc "c" (src: rawptr),
signature: cstring,
}
@(private)
global_block_descriptor := Block_Descriptor{
reserved = 0,
size = size_of(Internal_Block_Literal),
}
@(private="file")
Block_createInternal :: proc "c" (is_global: bool, user_data: rawptr, user_proc: proc "c" (user_data: rawptr)) -> ^Block {
// Set to true on blocks that have captures (and thus are not true
// global blocks) but are known not to escape for various other
// reasons. For backward compatibility with old runtimes, whenever
// BLOCK_IS_NOESCAPE is set, BLOCK_IS_GLOBAL is set too. Copying a
// non-escaping block returns the original block and releasing such a
// block is a no-op, which is exactly how global blocks are handled.
BLOCK_IS_NOESCAPE :: (1 << 23)|BLOCK_IS_GLOBAL
BLOCK_HAS_COPY_DISPOSE :: 1 << 25
BLOCK_HAS_CTOR :: 1 << 26 // helpers have C++ code
BLOCK_IS_GLOBAL :: 1 << 28
BLOCK_HAS_STRET :: 1 << 29 // IFF BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE :: 1 << 30
extraBytes :: size_of(Internal_Block_Literal) - size_of(Internal_Block_Literal_Base)
cls := intrinsics.objc_find_class("NSConcreteGlobalBlock")
bl := (^Internal_Block_Literal)(AllocateObject(cls, extraBytes, nil))
bl.isa = cls
bl.flags = BLOCK_IS_GLOBAL if is_global else 0
bl.invoke = proc "c" (bl: ^Internal_Block_Literal) {
bl.user_proc(bl.user_data)
}
bl.descriptor = &global_block_descriptor
bl.user_proc = user_proc
bl.user_data = user_data
return auto_cast bl
}
+191
View File
@@ -0,0 +1,191 @@
package objc_Foundation
@(objc_class="NSBundle")
Bundle :: struct { using _: Object }
@(objc_type=Bundle, objc_name="mainBundle", objc_is_class_method=true)
Bundle_mainBundle :: proc() -> ^Bundle {
return msgSend(^Bundle, Bundle, "mainBundle")
}
@(objc_type=Bundle, objc_name="bundleWithPath", objc_is_class_method=true)
Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle {
return msgSend(^Bundle, Bundle, "bundleWithPath:", path)
}
@(objc_type=Bundle, objc_name="bundleWithURL", objc_is_class_method=true)
Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle {
return msgSend(^Bundle, Bundle, "bundleWithUrl:", url)
}
@(objc_type=Bundle, objc_name="alloc", objc_is_class_method=true)
Bundle_alloc :: proc() -> ^Bundle {
return msgSend(^Bundle, Bundle, "alloc")
}
@(objc_type=Bundle, objc_name="init")
Bundle_init :: proc(self: ^Bundle) -> ^Bundle {
return msgSend(^Bundle, self, "init")
}
@(objc_type=Bundle, objc_name="initWithPath")
Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle {
return msgSend(^Bundle, self, "initWithPath:", path)
}
@(objc_type=Bundle, objc_name="initWithURL")
Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle {
return msgSend(^Bundle, self, "initWithUrl:", url)
}
@(objc_type=Bundle, objc_name="allBundles")
Bundle_allBundles :: proc() -> (all: ^Array) {
return msgSend(type_of(all), Bundle, "allBundles")
}
@(objc_type=Bundle, objc_name="allFrameworks")
Bundle_allFrameworks :: proc() -> (all: ^Array) {
return msgSend(type_of(all), Bundle, "allFrameworks")
}
@(objc_type=Bundle, objc_name="load")
Bundle_load :: proc(self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "load")
}
@(objc_type=Bundle, objc_name="unload")
Bundle_unload :: proc(self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "unload")
}
@(objc_type=Bundle, objc_name="isLoaded")
Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL {
return msgSend(BOOL, self, "isLoaded")
}
@(objc_type=Bundle, objc_name="preflightAndReturnError")
Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
ok = msgSend(BOOL, self, "preflightAndReturnError:", &error)
return
}
@(objc_type=Bundle, objc_name="loadAndReturnError")
Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
ok = msgSend(BOOL, self, "loadAndReturnError:", &error)
return
}
@(objc_type=Bundle, objc_name="bundleURL")
Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "bundleURL")
}
@(objc_type=Bundle, objc_name="resourceURL")
Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "resourceURL")
}
@(objc_type=Bundle, objc_name="executableURL")
Bundle_executableURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "executableURL")
}
@(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable")
Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL {
return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName)
}
@(objc_type=Bundle, objc_name="privateFrameworksURL")
Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "privateFrameworksURL")
}
@(objc_type=Bundle, objc_name="sharedFrameworksURL")
Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "sharedFrameworksURL")
}
@(objc_type=Bundle, objc_name="sharedSupportURL")
Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "sharedSupportURL")
}
@(objc_type=Bundle, objc_name="builtInPlugInsURL")
Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "builtInPlugInsURL")
}
@(objc_type=Bundle, objc_name="appStoreReceiptURL")
Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL {
return msgSend(^URL, self, "appStoreReceiptURL")
}
@(objc_type=Bundle, objc_name="bundlePath")
Bundle_bundlePath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "bundlePath")
}
@(objc_type=Bundle, objc_name="resourcePath")
Bundle_resourcePath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "resourcePath")
}
@(objc_type=Bundle, objc_name="executablePath")
Bundle_executablePath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "executablePath")
}
@(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable")
Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String {
return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName)
}
@(objc_type=Bundle, objc_name="privateFrameworksPath")
Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "privateFrameworksPath")
}
@(objc_type=Bundle, objc_name="sharedFrameworksPath")
Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "sharedFrameworksPath")
}
@(objc_type=Bundle, objc_name="sharedSupportPath")
Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "sharedSupportPath")
}
@(objc_type=Bundle, objc_name="builtInPlugInsPath")
Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "builtInPlugInsPath")
}
@(objc_type=Bundle, objc_name="appStoreReceiptPath")
Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "appStoreReceiptPath")
}
@(objc_type=Bundle, objc_name="bundleIdentifier")
Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String {
return msgSend(^String, self, "bundleIdentifier")
}
@(objc_type=Bundle, objc_name="infoDictionary")
Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
return msgSend(^Dictionary, self, "infoDictionary")
}
@(objc_type=Bundle, objc_name="localizedInfoDictionary")
Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
return msgSend(^Dictionary, self, "localizedInfoDictionary")
}
@(objc_type=Bundle, objc_name="objectForInfoDictionaryKey")
Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object {
return msgSend(^Object, self, "objectForInfoDictionaryKey:", key)
}
@(objc_type=Bundle, objc_name="localizedStringForKey")
Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String {
return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName)
}
+24
View File
@@ -0,0 +1,24 @@
package objc_Foundation
@(objc_class="NSData")
Data :: struct {using _: Copying(Data)}
@(objc_type=Data, objc_name="alloc", objc_is_class_method=true)
Data_alloc :: proc() -> ^Data {
return msgSend(^Data, Data, "alloc")
}
@(objc_type=Data, objc_name="init")
Data_init :: proc(self: ^Data) -> ^Data {
return msgSend(^Data, self, "init")
}
@(objc_type=Data, objc_name="mutableBytes")
Data_mutableBytes :: proc(self: ^Data) -> rawptr {
return msgSend(rawptr, self, "mutableBytes")
}
@(objc_type=Data, objc_name="length")
Data_length :: proc(self: ^Data) -> UInteger {
return msgSend(UInteger, self, "length")
}
+19
View File
@@ -0,0 +1,19 @@
package objc_Foundation
@(objc_class="NSDate")
Date :: struct {using _: Copying(Date)}
@(objc_type=Date, objc_name="alloc", objc_is_class_method=true)
Date_alloc :: proc() -> ^Date {
return msgSend(^Date, Date, "alloc")
}
@(objc_type=Date, objc_name="init")
Date_init :: proc(self: ^Date) -> ^Date {
return msgSend(^Date, self, "init")
}
@(objc_type=Date, objc_name="dateWithTimeIntervalSinceNow")
Date_dateWithTimeIntervalSinceNow :: proc(secs: TimeInterval) -> ^Date {
return msgSend(^Date, Date, "dateWithTimeIntervalSinceNow:", secs)
}
+50
View File
@@ -0,0 +1,50 @@
package objc_Foundation
@(objc_class="NSDictionary")
Dictionary :: struct {using _: Copying(Dictionary)}
@(objc_type=Dictionary, objc_name="dictionary", objc_is_class_method=true)
Dictionary_dictionary :: proc() -> ^Dictionary {
return msgSend(^Dictionary, Dictionary, "dictionary")
}
@(objc_type=Dictionary, objc_name="dictionaryWithObject", objc_is_class_method=true)
Dictionary_dictionaryWithObject :: proc(object: ^Object, forKey: ^Object) -> ^Dictionary {
return msgSend(^Dictionary, Dictionary, "dictionaryWithObject:forKey:", object, forKey)
}
@(objc_type=Dictionary, objc_name="dictionaryWithObjects", objc_is_class_method=true)
Dictionary_dictionaryWithObjects :: proc(objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary {
return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count)
}
@(objc_type=Dictionary, objc_name="alloc", objc_is_class_method=true)
Dictionary_alloc :: proc() -> ^Dictionary {
return msgSend(^Dictionary, Dictionary, "alloc")
}
@(objc_type=Dictionary, objc_name="init")
Dictionary_init :: proc(self: ^Dictionary) -> ^Dictionary {
return msgSend(^Dictionary, self, "init")
}
@(objc_type=Dictionary, objc_name="initWithObjects")
Dictionary_initWithObjects :: proc(self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary {
return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count)
}
@(objc_type=Dictionary, objc_name="objectForKey")
Dictionary_objectForKey :: proc(self: ^Dictionary, key: ^Object) -> ^Object {
return msgSend(^Dictionary, self, "objectForKey:", key)
}
@(objc_type=Dictionary, objc_name="count")
Dictionary_count :: proc(self: ^Dictionary) -> UInteger {
return msgSend(UInteger, self, "count")
}
@(objc_type=Dictionary, objc_name="keyEnumerator")
Dictionary_keyEnumerator :: proc(self: ^Dictionary, $KeyType: typeid) -> (enumerator: ^Enumerator(KeyType)) {
return msgSend(type_of(enumerator), self, "keyEnumerator")
}
+50
View File
@@ -0,0 +1,50 @@
package objc_Foundation
import "core:c"
import "core:intrinsics"
FastEnumerationState :: struct #packed {
state: c.ulong,
itemsPtr: [^]^Object,
mutationsPtr: [^]c.ulong,
extra: [5]c.ulong,
}
@(objc_class="NSFastEnumeration")
FastEnumeration :: struct {using _: Object}
@(objc_class="NSEnumerator")
Enumerator :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
using _: FastEnumeration,
}
@(objc_type=FastEnumeration, objc_name="alloc", objc_is_class_method=true)
FastEnumeration_alloc :: proc() -> ^FastEnumeration {
return msgSend(^FastEnumeration, FastEnumeration, "alloc")
}
@(objc_type=FastEnumeration, objc_name="init")
FastEnumeration_init :: proc(self: ^FastEnumeration) -> ^FastEnumeration {
return msgSend(^FastEnumeration, self, "init")
}
@(objc_type=FastEnumeration, objc_name="countByEnumerating")
FastEnumeration_countByEnumerating :: proc(self: ^FastEnumeration, state: ^FastEnumerationState, buffer: [^]^Object, len: UInteger) -> UInteger {
return msgSend(UInteger, self, "countByEnumeratingWithState:objects:count:", state, buffer, len)
}
Enumerator_nextObject :: proc(self: ^$E/Enumerator($T)) -> T {
return msgSend(T, self, "nextObject")
}
Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: ^Array) {
return msgSend(type_of(all), self, "allObjects")
}
Enumerator_iterator :: proc(self: ^$E/Enumerator($T)) -> (obj: T, ok: bool) {
obj = msgSend(T, self, "nextObject")
ok = obj != nil
return
}
+88
View File
@@ -0,0 +1,88 @@
package objc_Foundation
foreign import "system:Foundation.framework"
ErrorDomain :: ^String
foreign Foundation {
@(linkage="weak") CocoaErrorDomain: ErrorDomain
@(linkage="weak") POSIXErrorDomain: ErrorDomain
@(linkage="weak") OSStatusErrorDomain: ErrorDomain
@(linkage="weak") MachErrorDomain: ErrorDomain
}
ErrorUserInfoKey :: ^String
foreign Foundation {
@(linkage="weak") UnderlyingErrorKey: ErrorUserInfoKey
@(linkage="weak") LocalizedDescriptionKey: ErrorUserInfoKey
@(linkage="weak") LocalizedFailureReasonErrorKey: ErrorUserInfoKey
@(linkage="weak") LocalizedRecoverySuggestionErrorKey: ErrorUserInfoKey
@(linkage="weak") LocalizedRecoveryOptionsErrorKey: ErrorUserInfoKey
@(linkage="weak") RecoveryAttempterErrorKey: ErrorUserInfoKey
@(linkage="weak") HelpAnchorErrorKey: ErrorUserInfoKey
@(linkage="weak") DebugDescriptionErrorKey: ErrorUserInfoKey
@(linkage="weak") LocalizedFailureErrorKey: ErrorUserInfoKey
@(linkage="weak") StringEncodingErrorKey: ErrorUserInfoKey
@(linkage="weak") URLErrorKey: ErrorUserInfoKey
@(linkage="weak") FilePathErrorKey: ErrorUserInfoKey
}
@(objc_class="NSError")
Error :: struct { using _: Copying(Error) }
@(objc_type=Error, objc_name="alloc", objc_is_class_method=true)
Error_alloc :: proc() -> ^Error {
return msgSend(^Error, Error, "alloc")
}
@(objc_type=Error, objc_name="init")
Error_init :: proc(self: ^Error) -> ^Error {
return msgSend(^Error, self, "init")
}
@(objc_type=Error, objc_name="errorWithDomain", objc_is_class_method=true)
Error_errorWithDomain :: proc(domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error {
return msgSend(^Error, Error, "errorWithDomain:code:userInfo:", domain, code, userInfo)
}
@(objc_type=Error, objc_name="initWithDomain")
Error_initWithDomain :: proc(self: ^Error, domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error {
return msgSend(^Error, self, "initWithDomain:code:userInfo:", domain, code, userInfo)
}
@(objc_type=Error, objc_name="code")
Error_code :: proc(self: ^Error) -> Integer {
return msgSend(Integer, self, "code")
}
@(objc_type=Error, objc_name="domain")
Error_domain :: proc(self: ^Error) -> ErrorDomain {
return msgSend(ErrorDomain, self, "domain")
}
@(objc_type=Error, objc_name="userInfo")
Error_userInfo :: proc(self: ^Error) -> ^Dictionary {
return msgSend(^Dictionary, self, "userInfo")
}
@(objc_type=Error, objc_name="localizedDescription")
Error_localizedDescription :: proc(self: ^Error) -> ^String {
return msgSend(^String, self, "localizedDescription")
}
@(objc_type=Error, objc_name="localizedRecoveryOptions")
Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array) {
return msgSend(type_of(options), self, "localizedRecoveryOptions")
}
@(objc_type=Error, objc_name="localizedRecoverySuggestion")
Error_localizedRecoverySuggestion :: proc(self: ^Error) -> ^String {
return msgSend(^String, self, "localizedRecoverySuggestion")
}
@(objc_type=Error, objc_name="localizedFailureReason")
Error_localizedFailureReason :: proc(self: ^Error) -> ^String {
return msgSend(^String, self, "localizedFailureReason")
}
+53
View File
@@ -0,0 +1,53 @@
package objc_Foundation
Locking :: struct($T: typeid) {using _: Object}
Locking_lock :: proc(self: ^Locking($T)) {
msgSend(nil, self, "lock")
}
Locking_unlock :: proc(self: ^Locking($T)) {
msgSend(nil, self, "unlock")
}
@(objc_class="NSCondition")
Condition :: struct {using _: Locking(Condition) }
@(objc_type=Condition, objc_name="alloc", objc_is_class_method=true)
Condition_alloc :: proc() -> ^Condition {
return msgSend(^Condition, Condition, "alloc")
}
@(objc_type=Condition, objc_name="init")
Condition_init :: proc(self: ^Condition) -> ^Condition {
return msgSend(^Condition, self, "init")
}
@(objc_type=Condition, objc_name="wait")
Condition_wait :: proc(self: ^Condition) {
msgSend(nil, self, "wait")
}
@(objc_type=Condition, objc_name="waitUntilDate")
Condition_waitUntilDate :: proc(self: ^Condition, limit: ^Date) -> BOOL {
return msgSend(BOOL, self, "waitUntilDate:", limit)
}
@(objc_type=Condition, objc_name="signal")
Condition_signal :: proc(self: ^Condition) {
msgSend(nil, self, "signal")
}
@(objc_type=Condition, objc_name="broadcast")
Condition_broadcast :: proc(self: ^Condition) {
msgSend(nil, self, "broadcast")
}
@(objc_type=Condition, objc_name="lock")
Condition_lock :: proc(self: ^Condition) {
msgSend(nil, self, "lock")
}
@(objc_type=Condition, objc_name="unlock")
Condition_unlock :: proc(self: ^Condition) {
msgSend(nil, self, "unlock")
}
+103
View File
@@ -0,0 +1,103 @@
package objc_Foundation
import "core:builtin"
import "core:intrinsics"
KeyEquivalentModifierFlag :: enum UInteger {
CapsLock = 16, // Set if Caps Lock key is pressed.
Shift = 17, // Set if Shift key is pressed.
Control = 18, // Set if Control key is pressed.
Option = 19, // Set if Option or Alternate key is pressed.
Command = 20, // Set if Command key is pressed.
NumericPad = 21, // Set if any key in the numeric keypad is pressed.
Help = 22, // Set if the Help key is pressed.
Function = 23, // Set if any function key is pressed.
}
KeyEquivalentModifierMask :: distinct bit_set[KeyEquivalentModifierFlag; UInteger]
// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information.
KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask
@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000)
MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object)
@(objc_class="NSMenuItem")
MenuItem :: struct {using _: Object}
@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true)
MenuItem_alloc :: proc() -> ^MenuItem {
return msgSend(^MenuItem, MenuItem, "alloc")
}
@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true)
MenuItem_registerActionCallback :: proc(name: cstring, callback: MenuItemCallback) -> SEL {
s := string(name)
n := len(s)
sel: SEL
if n > 0 && s[n-1] != ':' {
col_name := intrinsics.alloca(n+2, 1)
builtin.copy(col_name[:n], s)
col_name[n] = ':'
col_name[n+1] = 0
sel = sel_registerName(cstring(col_name))
} else {
sel = sel_registerName(name)
}
if callback != nil {
class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@")
}
return sel
}
@(objc_type=MenuItem, objc_name="init")
MenuItem_init :: proc(self: ^MenuItem) -> ^MenuItem {
return msgSend(^MenuItem, self, "init")
}
@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask")
MenuItem_setKeyEquivalentModifierMask :: proc(self: ^MenuItem, modifierMask: KeyEquivalentModifierMask) {
msgSend(nil, self, "setKeyEquivalentModifierMask:", modifierMask)
}
@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask")
MenuItem_keyEquivalentModifierMask :: proc(self: ^MenuItem) -> KeyEquivalentModifierMask {
return msgSend(KeyEquivalentModifierMask, self, "keyEquivalentModifierMask")
}
@(objc_type=MenuItem, objc_name="setSubmenu")
MenuItem_setSubmenu :: proc(self: ^MenuItem, submenu: ^Menu) {
msgSend(nil, self, "setSubmenu:", submenu)
}
@(objc_class="NSMenu")
Menu :: struct {using _: Object}
@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true)
Menu_alloc :: proc() -> ^Menu {
return msgSend(^Menu, Menu, "alloc")
}
@(objc_type=Menu, objc_name="init")
Menu_init :: proc(self: ^Menu) -> ^Menu {
return msgSend(^Menu, self, "init")
}
@(objc_type=Menu, objc_name="initWithTitle")
Menu_initWithTitle :: proc(self: ^Menu, title: ^String) -> ^Menu {
return msgSend(^Menu, self, "initWithTitle:", title)
}
@(objc_type=Menu, objc_name="addItem")
Menu_addItem :: proc(self: ^Menu, item: ^MenuItem) {
msgSend(nil, self, "addItem:", item)
}
@(objc_type=Menu, objc_name="addItemWithTitle")
Menu_addItemWithTitle :: proc(self: ^Menu, title: ^String, selector: SEL, keyEquivalent: ^String) -> ^MenuItem {
return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", title, selector, keyEquivalent)
}
+30
View File
@@ -0,0 +1,30 @@
package objc_Foundation
@(objc_class="NSNotification")
Notification :: struct{using _: Object}
@(objc_type=Notification, objc_name="alloc", objc_is_class_method=true)
Notification_alloc :: proc() -> ^Notification {
return msgSend(^Notification, Notification, "alloc")
}
@(objc_type=Notification, objc_name="init")
Notification_init :: proc(self: ^Notification) -> ^Notification {
return msgSend(^Notification, self, "init")
}
@(objc_type=Notification, objc_name="name")
Notification_name :: proc(self: ^Notification) -> ^String {
return msgSend(^String, self, "name")
}
@(objc_type=Notification, objc_name="object")
Notification_object :: proc(self: ^Notification) -> ^Object {
return msgSend(^Object, self, "object")
}
@(objc_type=Notification, objc_name="userInfo")
Notification_userInfo :: proc(self: ^Notification) -> ^Dictionary {
return msgSend(^Dictionary, self, "userInfo")
}
+154
View File
@@ -0,0 +1,154 @@
package objc_Foundation
when ODIN_OS == .Darwin {
import "core:c"
_ :: c
#assert(size_of(c.long) == size_of(int))
#assert(size_of(c.ulong) == size_of(uint))
}
@(objc_class="NSValue")
Value :: struct{using _: Copying(Value)}
@(objc_type=Value, objc_name="alloc", objc_is_class_method=true)
Value_alloc :: proc() -> ^Value {
return msgSend(^Value, Value, "alloc")
}
@(objc_type=Value, objc_name="init")
Value_init :: proc(self: ^Value) -> ^Value {
return msgSend(^Value, self, "init")
}
@(objc_type=Value, objc_name="valueWithBytes", objc_is_class_method=true)
Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value {
return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type)
}
@(objc_type=Value, objc_name="valueWithPointer", objc_is_class_method=true)
Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value {
return msgSend(^Value, Value, "valueWithPointer:", pointer)
}
@(objc_type=Value, objc_name="initWithBytes")
Value_initWithBytes :: proc(self: ^Value, value: rawptr, type: cstring) -> ^Value {
return msgSend(^Value, self, "initWithBytes:objCType:", value, type)
}
@(objc_type=Value, objc_name="initWithCoder")
Value_initWithCoder :: proc(self: ^Value, coder: ^Coder) -> ^Value {
return msgSend(^Value, self, "initWithCoder:", coder)
}
@(objc_type=Value, objc_name="getValue")
Value_getValue :: proc(self: ^Value, value: rawptr, size: UInteger) {
msgSend(nil, self, "getValue:size:", value, size)
}
@(objc_type=Value, objc_name="objCType")
Value_objCType :: proc "c" (self: ^Value) -> cstring {
return msgSend(cstring, self, "objCType")
}
@(objc_type=Value, objc_name="isEqualToValue")
Value_isEqualToValue :: proc "c" (self, other: ^Value) -> BOOL {
return msgSend(BOOL, self, "isEqualToValue:", other)
}
@(objc_type=Value, objc_name="pointerValue")
Value_pointerValue :: proc "c" (self: ^Value) -> rawptr {
return msgSend(rawptr, self, "pointerValue")
}
@(objc_class="NSNumber")
Number :: struct{using _: Copying(Number), using _: Value}
@(objc_type=Number, objc_name="alloc", objc_is_class_method=true)
Number_alloc :: proc() -> ^Number {
return msgSend(^Number, Number, "alloc")
}
@(objc_type=Number, objc_name="init")
Number_init :: proc(self: ^Number) -> ^Number {
return msgSend(^Number, self, "init")
}
@(objc_type=Number, objc_name="numberWithI8", objc_is_class_method=true) Number_numberWithI8 :: proc(value: i8) -> ^Number { return msgSend(^Number, Number, "numberWithChar:", value) }
@(objc_type=Number, objc_name="numberWithU8", objc_is_class_method=true) Number_numberWithU8 :: proc(value: u8) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:", value) }
@(objc_type=Number, objc_name="numberWithI16", objc_is_class_method=true) Number_numberWithI16 :: proc(value: i16) -> ^Number { return msgSend(^Number, Number, "numberWithShort:", value) }
@(objc_type=Number, objc_name="numberWithU16", objc_is_class_method=true) Number_numberWithU16 :: proc(value: u16) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:", value) }
@(objc_type=Number, objc_name="numberWithI32", objc_is_class_method=true) Number_numberWithI32 :: proc(value: i32) -> ^Number { return msgSend(^Number, Number, "numberWithInt:", value) }
@(objc_type=Number, objc_name="numberWithU32", objc_is_class_method=true) Number_numberWithU32 :: proc(value: u32) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:", value) }
@(objc_type=Number, objc_name="numberWithInt", objc_is_class_method=true) Number_numberWithInt :: proc(value: int) -> ^Number { return msgSend(^Number, Number, "numberWithLong:", value) }
@(objc_type=Number, objc_name="numberWithUint", objc_is_class_method=true) Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:", value) }
@(objc_type=Number, objc_name="numberWithU64", objc_is_class_method=true) Number_numberWithU64 :: proc(value: u64) -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:", value) }
@(objc_type=Number, objc_name="numberWithI64", objc_is_class_method=true) Number_numberWithI64 :: proc(value: i64) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) }
@(objc_type=Number, objc_name="numberWithF32", objc_is_class_method=true) Number_numberWithF32 :: proc(value: f32) -> ^Number { return msgSend(^Number, Number, "numberWithFloat:", value) }
@(objc_type=Number, objc_name="numberWithF64", objc_is_class_method=true) Number_numberWithF64 :: proc(value: f64) -> ^Number { return msgSend(^Number, Number, "numberWithDouble:", value) }
@(objc_type=Number, objc_name="numberWithBool", objc_is_class_method=true) Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:", value) }
Number_number :: proc{
Number_numberWithI8,
Number_numberWithU8,
Number_numberWithI16,
Number_numberWithU16,
Number_numberWithI32,
Number_numberWithU32,
Number_numberWithInt,
Number_numberWithUint,
Number_numberWithU64,
Number_numberWithI64,
Number_numberWithF32,
Number_numberWithF64,
Number_numberWithBool,
}
@(objc_type=Number, objc_name="initWithI8") Number_initWithI8 :: proc(self: ^Number, value: i8) -> ^Number { return msgSend(^Number, self, "initWithChar:", value) }
@(objc_type=Number, objc_name="initWithU8") Number_initWithU8 :: proc(self: ^Number, value: u8) -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:", value) }
@(objc_type=Number, objc_name="initWithI16") Number_initWithI16 :: proc(self: ^Number, value: i16) -> ^Number { return msgSend(^Number, self, "initWithShort:", value) }
@(objc_type=Number, objc_name="initWithU16") Number_initWithU16 :: proc(self: ^Number, value: u16) -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:", value) }
@(objc_type=Number, objc_name="initWithI32") Number_initWithI32 :: proc(self: ^Number, value: i32) -> ^Number { return msgSend(^Number, self, "initWithInt:", value) }
@(objc_type=Number, objc_name="initWithU32") Number_initWithU32 :: proc(self: ^Number, value: u32) -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:", value) }
@(objc_type=Number, objc_name="initWithInt") Number_initWithInt :: proc(self: ^Number, value: int) -> ^Number { return msgSend(^Number, self, "initWithLong:", value) }
@(objc_type=Number, objc_name="initWithUint") Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:", value) }
@(objc_type=Number, objc_name="initWithU64") Number_initWithU64 :: proc(self: ^Number, value: u64) -> ^Number { return msgSend(^Number, self, "initWithLongLong:", value) }
@(objc_type=Number, objc_name="initWithI64") Number_initWithI64 :: proc(self: ^Number, value: i64) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) }
@(objc_type=Number, objc_name="initWithF32") Number_initWithF32 :: proc(self: ^Number, value: f32) -> ^Number { return msgSend(^Number, self, "initWithFloat:", value) }
@(objc_type=Number, objc_name="initWithF64") Number_initWithF64 :: proc(self: ^Number, value: f64) -> ^Number { return msgSend(^Number, self, "initWithDouble:", value) }
@(objc_type=Number, objc_name="initWithBool") Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:", value) }
@(objc_type=Number, objc_name="i8Value") Number_i8Value :: proc(self: ^Number) -> i8 { return msgSend(i8, self, "charValue") }
@(objc_type=Number, objc_name="u8Value") Number_u8Value :: proc(self: ^Number) -> u8 { return msgSend(u8, self, "unsignedCharValue") }
@(objc_type=Number, objc_name="i16Value") Number_i16Value :: proc(self: ^Number) -> i16 { return msgSend(i16, self, "shortValue") }
@(objc_type=Number, objc_name="u16Value") Number_u16Value :: proc(self: ^Number) -> u16 { return msgSend(u16, self, "unsignedShortValue") }
@(objc_type=Number, objc_name="i32Value") Number_i32Value :: proc(self: ^Number) -> i32 { return msgSend(i32, self, "intValue") }
@(objc_type=Number, objc_name="u32Value") Number_u32Value :: proc(self: ^Number) -> u32 { return msgSend(u32, self, "unsignedIntValue") }
@(objc_type=Number, objc_name="intValue") Number_intValue :: proc(self: ^Number) -> int { return msgSend(int, self, "longValue") }
@(objc_type=Number, objc_name="uintValue") Number_uintValue :: proc(self: ^Number) -> uint { return msgSend(uint, self, "unsignedLongValue") }
@(objc_type=Number, objc_name="u64Value") Number_u64Value :: proc(self: ^Number) -> u64 { return msgSend(u64, self, "longLongValue") }
@(objc_type=Number, objc_name="i64Value") Number_i64Value :: proc(self: ^Number) -> i64 { return msgSend(i64, self, "unsignedLongLongValue") }
@(objc_type=Number, objc_name="f32Value") Number_f32Value :: proc(self: ^Number) -> f32 { return msgSend(f32, self, "floatValue") }
@(objc_type=Number, objc_name="f64Value") Number_f64Value :: proc(self: ^Number) -> f64 { return msgSend(f64, self, "doubleValue") }
@(objc_type=Number, objc_name="boolValue") Number_boolValue :: proc(self: ^Number) -> BOOL { return msgSend(BOOL, self, "boolValue") }
@(objc_type=Number, objc_name="integerValue") Number_integerValue :: proc(self: ^Number) -> Integer { return msgSend(Integer, self, "integerValue") }
@(objc_type=Number, objc_name="uintegerValue") Number_uintegerValue :: proc(self: ^Number) -> UInteger { return msgSend(UInteger, self, "unsignedIntegerValue") }
@(objc_type=Number, objc_name="stringValue") Number_stringValue :: proc(self: ^Number) -> ^String { return msgSend(^String, self, "stringValue") }
@(objc_type=Number, objc_name="compare")
Number_compare :: proc(self, other: ^Number) -> ComparisonResult {
return msgSend(ComparisonResult, self, "compare:", other)
}
@(objc_type=Number, objc_name="isEqualToNumber")
Number_isEqualToNumber :: proc(self, other: ^Number) -> BOOL {
return msgSend(BOOL, self, "isEqualToNumber:", other)
}
@(objc_type=Number, objc_name="descriptionWithLocale")
Number_descriptionWithLocale :: proc(self: ^Number, locale: ^Object) -> ^String {
return msgSend(^String, self, "descriptionWithLocale:", locale)
}
+91
View File
@@ -0,0 +1,91 @@
package objc_Foundation
import "core:intrinsics"
methodSignatureForSelector :: proc "c" (obj: ^Object, selector: SEL) -> rawptr {
return msgSend(rawptr, obj, "methodSignatureForSelector:", selector)
}
respondsToSelector :: proc "c" (obj: ^Object, selector: SEL) -> BOOL {
return msgSend(BOOL, obj, "respondsToSelector:", selector)
}
msgSendSafeCheck :: proc "c" (obj: ^Object, selector: SEL) -> BOOL {
return respondsToSelector(obj, selector) || methodSignatureForSelector(obj, selector) != nil
}
@(objc_class="NSObject")
Object :: struct {using _: intrinsics.objc_object}
@(objc_class="NSObject")
Copying :: struct($T: typeid) {using _: Object}
alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
return msgSend(^T, T, "alloc")
}
@(objc_type=Object, objc_name="init")
init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
return msgSend(^T, self, "init")
}
@(objc_type=Object, objc_name="copy")
copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
return msgSend(^T, self, "copy")
}
new :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
return init(alloc(T))
}
@(objc_type=Object, objc_name="retain")
retain :: proc(self: ^Object) {
_ = msgSend(^Object, self, "retain")
}
@(objc_type=Object, objc_name="release")
release :: proc(self: ^Object) {
msgSend(nil, self, "release")
}
@(objc_type=Object, objc_name="autorelease")
autorelease :: proc(self: ^Object) {
msgSend(nil, self, "autorelease")
}
@(objc_type=Object, objc_name="retainCount")
retainCount :: proc(self: ^Object) -> UInteger {
return msgSend(UInteger, self, "retainCount")
}
@(objc_type=Object, objc_name="class")
class :: proc(self: ^Object) -> Class {
return msgSend(Class, self, "class")
}
@(objc_type=Object, objc_name="hash")
hash :: proc(self: ^Object) -> UInteger {
return msgSend(UInteger, self, "hash")
}
@(objc_type=Object, objc_name="isEqual")
isEqual :: proc(self, pObject: ^Object) -> BOOL {
return msgSend(BOOL, self, "isEqual:", pObject)
}
@(objc_type=Object, objc_name="description")
description :: proc(self: ^Object) -> ^String {
return msgSend(^String, self, "description")
}
@(objc_type=Object, objc_name="debugDescription")
debugDescription :: proc(self: ^Object) -> ^String {
if msgSendSafeCheck(self, intrinsics.objc_find_selector("debugDescription")) {
return msgSend(^String, self, "debugDescription")
}
return nil
}
bridgingCast :: proc($T: typeid, obj: ^Object) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
return (T)(obj)
}
@(objc_class="NSCoder")
Coder :: struct {using _: Object}
// TODO(bill): Implement all the methods for this massive type
+22
View File
@@ -0,0 +1,22 @@
package objc_Foundation
Range :: struct {
location: UInteger,
length: UInteger,
}
Range_Make :: proc(loc, len: UInteger) -> Range {
return Range{loc, len}
}
Range_Equal :: proc(a, b: Range) -> BOOL {
return a == b
}
Range_LocationInRange :: proc(self: Range, loc: UInteger) -> BOOL {
return !((loc < self.location) && ((loc - self.location) < self.length))
}
Range_Max :: proc(self: Range) -> UInteger {
return self.location + self.length
}
+140
View File
@@ -0,0 +1,140 @@
package objc_Foundation
foreign import "system:Foundation.framework"
@(objc_class="NSString")
String :: struct {using _: Copying(String)}
StringEncoding :: enum UInteger {
ASCII = 1,
NEXTSTEP = 2,
JapaneseEUC = 3,
UTF8 = 4,
ISOLatin1 = 5,
Symbol = 6,
NonLossyASCII = 7,
ShiftJIS = 8,
ISOLatin2 = 9,
Unicode = 10,
WindowsCP1251 = 11,
WindowsCP1252 = 12,
WindowsCP1253 = 13,
WindowsCP1254 = 14,
WindowsCP1250 = 15,
ISO2022JP = 21,
MacOSRoman = 30,
UTF16 = Unicode,
UTF16BigEndian = 0x90000100,
UTF16LittleEndian = 0x94000100,
UTF32 = 0x8c000100,
UTF32BigEndian = 0x98000100,
UTF32LittleEndian = 0x9c000100,
}
StringCompareOptions :: distinct bit_set[StringCompareOption; UInteger]
StringCompareOption :: enum UInteger {
CaseInsensitive = 0,
LiteralSearch = 1,
BackwardsSearch = 2,
AnchoredSearch = 3,
NumericSearch = 6,
DiacriticInsensitive = 7,
WidthInsensitive = 8,
ForcedOrdering = 9,
RegularExpression = 10,
}
unichar :: distinct u16
@(link_prefix="NS", default_calling_convention="c")
foreign Foundation {
StringFromClass :: proc(cls: Class) -> ^String ---
}
AT :: MakeConstantString
MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
foreign Foundation {
__CFStringMakeConstantString :: proc "c" (c: cstring) -> ^String ---
}
return __CFStringMakeConstantString(c)
}
@(objc_type=String, objc_name="alloc", objc_is_class_method=true)
String_alloc :: proc() -> ^String {
return msgSend(^String, String, "alloc")
}
@(objc_type=String, objc_name="init")
String_init :: proc(self: ^String) -> ^String {
return msgSend(^String, self, "init")
}
@(objc_type=String, objc_name="initWithString")
String_initWithString :: proc(self: ^String, other: ^String) -> ^String {
return msgSend(^String, self, "initWithString:", other)
}
@(objc_type=String, objc_name="initWithCString")
String_initWithCString :: proc(self: ^String, pString: cstring, encoding: StringEncoding) -> ^String {
return msgSend(^String, self, "initWithCstring:encoding:", pString, encoding)
}
@(objc_type=String, objc_name="initWithBytesNoCopy")
String_initWithBytesNoCopy :: proc(self: ^String, pBytes: rawptr, length: UInteger, encoding: StringEncoding, freeWhenDone: bool) -> ^String {
return msgSend(^String, self, "initWithBytesNoCopy:length:encoding:freeWhenDone:", pBytes, length, encoding, freeWhenDone)
}
@(objc_type=String, objc_name="initWithOdinString")
String_initWithOdinString :: proc(self: ^String, str: string) -> ^String {
return String_initWithBytesNoCopy(self, raw_data(str), UInteger(len(str)), .UTF8, false)
}
@(objc_type=String, objc_name="characterAtIndex")
String_characterAtIndex :: proc(self: ^String, index: UInteger) -> unichar {
return msgSend(unichar, self, "characterAtIndex:", index)
}
@(objc_type=String, objc_name="length")
String_length :: proc(self: ^String) -> UInteger {
return msgSend(UInteger, self, "length")
}
@(objc_type=String, objc_name="cstringUsingEncoding")
String_cstringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring {
return msgSend(cstring, self, "cStringUsingEncoding:", encoding)
}
@(objc_type=String, objc_name="UTF8String")
String_UTF8String :: proc(self: ^String) -> cstring {
return msgSend(cstring, self, "UTF8String")
}
@(objc_type=String, objc_name="odinString")
String_odinString :: proc(self: ^String) -> string {
return string(String_UTF8String(self))
}
@(objc_type=String, objc_name="maximumLengthOfBytesUsingEncoding")
String_maximumLengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger {
return msgSend(UInteger, self, "maximumLengthOfBytesUsingEncoding:", encoding)
}
@(objc_type=String, objc_name="lengthOfBytesUsingEncoding")
String_lengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger {
return msgSend(UInteger, self, "lengthOfBytesUsingEncoding:", encoding)
}
@(objc_type=String, objc_name="isEqualToString")
String_isEqualToString :: proc(self, other: ^String) -> BOOL {
return msgSend(BOOL, self, "isEqualToString:", other)
}
@(objc_type=String, objc_name="rangeOfString")
String_rangeOfString :: proc(self, other: ^String, options: StringCompareOptions) -> Range {
return msgSend(Range, self, "rangeOfString:options:", other, options)
}
+47
View File
@@ -0,0 +1,47 @@
package objc_Foundation
import "core:intrinsics"
@(private) msgSend :: intrinsics.objc_send
id :: ^intrinsics.objc_object
SEL :: ^intrinsics.objc_selector
Class :: ^intrinsics.objc_class
TimeInterval :: distinct f64
Integer :: distinct int
UInteger :: distinct uint
IntegerMax :: max(Integer)
Integermin :: min(Integer)
UIntegerMax :: max(UInteger)
BOOL :: bool // TODO(bill): should this be `distinct`?
YES :: true
NO :: false
OperatingSystemVersion :: struct #packed {
majorVersion: Integer,
minorVersion: Integer,
patchVersion: Integer,
}
ComparisonResult :: enum Integer {
OrderedAscending = -1,
OrderedSame = 0,
OrderedDescending = 1,
}
NotFound :: IntegerMax
Float :: distinct (f32 when size_of(uint) == 4 else f64)
Point :: struct {
x: Float,
y: Float,
}
Size :: struct {
width: Float,
height: Float,
}
+30
View File
@@ -0,0 +1,30 @@
package objc_Foundation
@(objc_class="NSURL")
URL :: struct{using _: Copying(URL)}
@(objc_type=URL, objc_name="alloc", objc_is_class_method=true)
URL_alloc :: proc() -> ^URL {
return msgSend(^URL, URL, "alloc")
}
@(objc_type=URL, objc_name="init")
URL_init :: proc(self: ^URL) -> ^URL {
return msgSend(^URL, self, "init")
}
@(objc_type=URL, objc_name="initWithString")
URL_initWithString :: proc(self: ^URL, value: ^String) -> ^URL {
return msgSend(^URL, self, "initWithString:", value)
}
@(objc_type=URL, objc_name="initFileURLWithPath")
URL_initFileURLWithPath :: proc(self: ^URL, path: ^String) -> ^URL {
return msgSend(^URL, self, "initFileURLWithPath:", path)
}
@(objc_type=URL, objc_name="fileSystemRepresentation")
URL_fileSystemRepresentation :: proc(self: ^URL) -> ^String {
return msgSend(^String, self, "fileSystemRepresentation")
}
+162
View File
@@ -0,0 +1,162 @@
package objc_Foundation
import NS "vendor:darwin/Foundation"
Rect :: struct {
using origin: Point,
using size: Size,
}
WindowStyleFlag :: enum NS.UInteger {
Titled = 0,
Closable = 1,
Miniaturizable = 2,
Resizable = 3,
TexturedBackground = 8,
UnifiedTitleAndToolbar = 12,
FullScreen = 14,
FullSizeContentView = 15,
UtilityWindow = 4,
DocModalWindow = 6,
NonactivatingPanel = 7,
HUDWindow = 13,
}
WindowStyleMask :: distinct bit_set[WindowStyleFlag; NS.UInteger]
WindowStyleMaskBorderless :: WindowStyleMask{}
WindowStyleMaskTitled :: WindowStyleMask{.Titled}
WindowStyleMaskClosable :: WindowStyleMask{.Closable}
WindowStyleMaskMiniaturizable :: WindowStyleMask{.Miniaturizable}
WindowStyleMaskResizable :: WindowStyleMask{.Resizable}
WindowStyleMaskTexturedBackground :: WindowStyleMask{.TexturedBackground}
WindowStyleMaskUnifiedTitleAndToolbar :: WindowStyleMask{.UnifiedTitleAndToolbar}
WindowStyleMaskFullScreen :: WindowStyleMask{.FullScreen}
WindowStyleMaskFullSizeContentView :: WindowStyleMask{.FullSizeContentView}
WindowStyleMaskUtilityWindow :: WindowStyleMask{.UtilityWindow}
WindowStyleMaskDocModalWindow :: WindowStyleMask{.DocModalWindow}
WindowStyleMaskNonactivatingPanel :: WindowStyleMask{.NonactivatingPanel}
WindowStyleMaskHUDWindow :: WindowStyleMask{.HUDWindow}
BackingStoreType :: enum NS.UInteger {
Retained = 0,
Nonretained = 1,
Buffered = 2,
}
@(objc_class="NSColor")
Color :: struct {using _: Object}
@(objc_class="CALayer")
Layer :: struct { using _: NS.Object }
@(objc_type=Layer, objc_name="contentsScale")
Layer_contentsScale :: proc(self: ^Layer) -> Float {
return msgSend(Float, self, "contentsScale")
}
@(objc_type=Layer, objc_name="setContentsScale")
Layer_setContentsScale :: proc(self: ^Layer, scale: Float) {
msgSend(nil, self, "setContentsScale:", scale)
}
@(objc_type=Layer, objc_name="frame")
Layer_frame :: proc(self: ^Layer) -> Rect {
return msgSend(Rect, self, "frame")
}
@(objc_type=Layer, objc_name="addSublayer")
Layer_addSublayer :: proc(self: ^Layer, layer: ^Layer) {
msgSend(nil, self, "addSublayer:", layer)
}
@(objc_class="NSResponder")
Responder :: struct {using _: Object}
@(objc_class="NSView")
View :: struct {using _: Responder}
@(objc_type=View, objc_name="initWithFrame")
View_initWithFrame :: proc(self: ^View, frame: Rect) -> ^View {
return msgSend(^View, self, "initWithFrame:", frame)
}
@(objc_type=View, objc_name="layer")
View_layer :: proc(self: ^View) -> ^Layer {
return msgSend(^Layer, self, "layer")
}
@(objc_type=View, objc_name="setLayer")
View_setLayer :: proc(self: ^View, layer: ^Layer) {
msgSend(nil, self, "setLayer:", layer)
}
@(objc_type=View, objc_name="wantsLayer")
View_wantsLayer :: proc(self: ^View) -> BOOL {
return msgSend(BOOL, self, "wantsLayer")
}
@(objc_type=View, objc_name="setWantsLayer")
View_setWantsLayer :: proc(self: ^View, wantsLayer: BOOL) {
msgSend(nil, self, "setWantsLayer:", wantsLayer)
}
@(objc_class="NSWindow")
Window :: struct {using _: Responder}
@(objc_type=Window, objc_name="alloc", objc_is_class_method=true)
Window_alloc :: proc() -> ^Window {
return msgSend(^Window, Window, "alloc")
}
@(objc_type=Window, objc_name="initWithContentRect")
Window_initWithContentRect :: proc (self: ^Window, contentRect: Rect, styleMask: WindowStyleMask, backing: BackingStoreType, doDefer: bool) -> ^Window {
self := self
// HACK: due to a compiler bug, the generated calling code does not
// currently work for this message. Has to do with passing a struct along
// with other parameters, so we don't send the rect here.
// Omiting the rect argument here actually works, because of how the C
// calling conventions are defined.
self = msgSend(^Window, self, "initWithContentRect:styleMask:backing:defer:", styleMask, backing, doDefer)
// apply the contentRect now, since we did not pass it to the init call
msgSend(nil, self, "setContentSize:", contentRect.size)
msgSend(nil, self, "setFrameOrigin:", contentRect.origin)
return self
}
@(objc_type=Window, objc_name="contentView")
Window_contentView :: proc(self: ^Window) -> ^View {
return msgSend(^View, self, "contentView")
}
@(objc_type=Window, objc_name="setContentView")
Window_setContentView :: proc(self: ^Window, content_view: ^View) {
msgSend(nil, self, "setContentView:", content_view)
}
@(objc_type=Window, objc_name="frame")
Window_frame :: proc(self: ^Window) -> Rect {
return msgSend(Rect, self, "frame")
}
@(objc_type=Window, objc_name="setFrame")
Window_setFrame :: proc(self: ^Window, frame: Rect) {
msgSend(nil, self, "setFrame:", frame)
}
@(objc_type=Window, objc_name="opaque")
Window_opaque :: proc(self: ^Window) -> NS.BOOL {
return msgSend(NS.BOOL, self, "opaque")
}
@(objc_type=Window, objc_name="setOpaque")
Window_setOpaque :: proc(self: ^Window, ok: NS.BOOL) {
msgSend(nil, self, "setOpaque:", ok)
}
@(objc_type=Window, objc_name="backgroundColor")
Window_backgroundColor :: proc(self: ^Window) -> ^NS.Color {
return msgSend(^NS.Color, self, "backgroundColor")
}
@(objc_type=Window, objc_name="setBackgroundColor")
Window_setBackgroundColor :: proc(self: ^Window, color: ^NS.Color) {
msgSend(nil, self, "setBackgroundColor:", color)
}
@(objc_type=Window, objc_name="makeKeyAndOrderFront")
Window_makeKeyAndOrderFront :: proc(self: ^Window, key: ^NS.Object) {
msgSend(nil, self, "makeKeyAndOrderFront:", key)
}
@(objc_type=Window, objc_name="setTitle")
Window_setTitle :: proc(self: ^Window, title: ^NS.String) {
msgSend(nil, self, "setTitle:", title)
}
@(objc_type=Window, objc_name="close")
Window_close :: proc(self: ^Window) {
msgSend(nil, self, "close")
}
+73
View File
@@ -0,0 +1,73 @@
package objc_Foundation
foreign import "system:Foundation.framework"
import "core:intrinsics"
import "core:c"
IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id
foreign Foundation {
objc_lookUpClass :: proc "c" (name: cstring) -> Class ---
sel_registerName :: proc "c" (name: cstring) -> SEL ---
objc_allocateClassPair :: proc "c" (superclass: Class, name: cstring, extraBytes: uint) ---
class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
}
@(objc_class="NSZone")
Zone :: struct {using _: Object}
@(link_prefix="NS")
foreign Foundation {
AllocateObject :: proc "c" (aClass: Class, extraBytes: UInteger, zone: ^Zone) -> id ---
DeallocateObject :: proc "c" (object: id) ---
}
Method :: ^objc_method
objc_method :: struct {
method_name: SEL,
method_types: cstring,
method_imp: IMP,
}
objc_method_list :: struct {}
objc_ivar :: struct {}
objc_ivar_list :: struct {}
objc_cache :: struct {
mask: u32,
occupied: u32,
buckets: [1]Method,
}
objc_protocol_list :: struct {
next: ^objc_protocol_list,
count: c.int,
list: [1]^Protocol,
}
@(objc_class="Protocol")
Protocol :: struct{using _: intrinsics.objc_object}
objc_object_internals :: struct {
isa: ^objc_class_internals,
}
objc_class_internals :: struct {
isa: Class,
super_class: Class,
name: cstring,
version: c.long,
info: c.long,
instance_size: c.long,
ivars: ^objc_ivar_list,
methodLists: ^^objc_method_list,
cache: rawptr,
protocols: rawptr,
}
File diff suppressed because it is too large Load Diff
+972
View File
@@ -0,0 +1,972 @@
package objc_Metal
import NS "vendor:darwin/Foundation"
AccelerationStructureUsage :: distinct bit_set[AccelerationStructureUsageFlag; NS.UInteger]
AccelerationStructureUsageFlag :: enum NS.UInteger {
Refit = 0,
PreferFastBuild = 1,
ExtendedLimits = 2,
}
AccelerationStructureInstanceOptions :: distinct bit_set[AccelerationStructureInstanceOption; u32]
AccelerationStructureInstanceOption :: enum u32 {
DisableTriangleCulling = 0,
TriangleFrontFacingWindingCounterClockwise = 1,
Opaque = 2,
NonOpaque = 3,
}
MotionBorderMode :: enum u32 {
Clamp = 0,
Vanish = 1,
}
AccelerationStructureInstanceDescriptorType :: enum NS.UInteger {
Default = 0,
UserID = 1,
Motion = 2,
}
DataType :: enum NS.UInteger {
None = 0,
Struct = 1,
Array = 2,
Float = 3,
Float2 = 4,
Float3 = 5,
Float4 = 6,
Float2x2 = 7,
Float2x3 = 8,
Float2x4 = 9,
Float3x2 = 10,
Float3x3 = 11,
Float3x4 = 12,
Float4x2 = 13,
Float4x3 = 14,
Float4x4 = 15,
Half = 16,
Half2 = 17,
Half3 = 18,
Half4 = 19,
Half2x2 = 20,
Half2x3 = 21,
Half2x4 = 22,
Half3x2 = 23,
Half3x3 = 24,
Half3x4 = 25,
Half4x2 = 26,
Half4x3 = 27,
Half4x4 = 28,
Int = 29,
Int2 = 30,
Int3 = 31,
Int4 = 32,
UInt = 33,
UInt2 = 34,
UInt3 = 35,
UInt4 = 36,
Short = 37,
Short2 = 38,
Short3 = 39,
Short4 = 40,
UShort = 41,
UShort2 = 42,
UShort3 = 43,
UShort4 = 44,
Char = 45,
Char2 = 46,
Char3 = 47,
Char4 = 48,
UChar = 49,
UChar2 = 50,
UChar3 = 51,
UChar4 = 52,
Bool = 53,
Bool2 = 54,
Bool3 = 55,
Bool4 = 56,
Texture = 58,
Sampler = 59,
Pointer = 60,
R8Unorm = 62,
R8Snorm = 63,
R16Unorm = 64,
R16Snorm = 65,
RG8Unorm = 66,
RG8Snorm = 67,
RG16Unorm = 68,
RG16Snorm = 69,
RGBA8Unorm = 70,
RGBA8Unorm_sRGB = 71,
RGBA8Snorm = 72,
RGBA16Unorm = 73,
RGBA16Snorm = 74,
RGB10A2Unorm = 75,
RG11B10Float = 76,
RGB9E5Float = 77,
RenderPipeline = 78,
ComputePipeline = 79,
IndirectCommandBuffer = 80,
Long = 81,
Long2 = 82,
Long3 = 83,
Long4 = 84,
ULong = 85,
ULong2 = 86,
ULong3 = 87,
ULong4 = 88,
VisibleFunctionTable = 115,
IntersectionFunctionTable = 116,
PrimitiveAccelerationStructure = 117,
InstanceAccelerationStructure = 118,
}
ArgumentType :: enum NS.UInteger {
Buffer = 0,
ThreadgroupMemory = 1,
Texture = 2,
Sampler = 3,
ImageblockData = 16,
Imageblock = 17,
VisibleFunctionTable = 24,
PrimitiveAccelerationStructure = 25,
InstanceAccelerationStructure = 26,
IntersectionFunctionTable = 27,
}
ArgumentAccess :: enum NS.UInteger {
ReadOnly = 0,
ReadWrite = 1,
WriteOnly = 2,
}
BinaryArchiveError :: enum NS.UInteger {
None = 0,
InvalidFile = 1,
UnexpectedElement = 2,
CompilationFailure = 3,
}
BlitOptionFlag :: enum NS.UInteger {
DepthFromDepthStencil = 0,
StencilFromDepthStencil = 1,
RowLinearPVRTC = 2,
}
BlitOption :: distinct bit_set[BlitOptionFlag; NS.UInteger]
CaptureError :: enum NS.Integer {
NotSupported = 1,
AlreadyCapturing = 2,
InvalidDescriptor = 3,
}
CaptureDestination :: enum NS.Integer {
DeveloperTools = 1,
GPUTraceDocument = 2,
}
CommandBufferStatus :: enum NS.UInteger {
NotEnqueued = 0,
Enqueued = 1,
Committed = 2,
Scheduled = 3,
Completed = 4,
Error = 5,
}
CommandBufferError :: enum NS.UInteger {
None = 0,
Timeout = 2,
PageFault = 3,
AccessRevoked = 4,
Blacklisted = 4,
NotPermitted = 7,
OutOfMemory = 8,
InvalidResource = 9,
Memoryless = 10,
DeviceRemoved = 11,
StackOverflow = 12,
}
CommandBufferErrorOptionFlag :: enum NS.UInteger {
EncoderExecutionStatus = 0,
}
CommandBufferErrorOption :: distinct bit_set[CommandBufferErrorOptionFlag; NS.UInteger]
CommandEncoderErrorState :: enum NS.Integer {
Unknown = 0,
Completed = 1,
Affected = 2,
Pending = 3,
Faulted = 4,
}
CommandBufferHandler :: distinct rawptr
DispatchType :: enum NS.UInteger {
Serial = 0,
Concurrent = 1,
}
ResourceUsageFlag :: enum NS.UInteger {
Read = 0,
Write = 1,
Sample = 2,
}
ResourceUsage :: distinct bit_set[ResourceUsageFlag; NS.UInteger]
BarrierScopeFlag :: enum NS.UInteger {
Buffers = 0,
Textures = 1,
RenderTargets = 2,
}
BarrierScope :: distinct bit_set[BarrierScopeFlag; NS.UInteger]
CounterSampleBufferError :: enum NS.Integer {
OutOfMemory = 0,
Invalid = 1,
}
CompareFunction :: enum NS.UInteger {
Never = 0,
Less = 1,
Equal = 2,
LessEqual = 3,
Greater = 4,
NotEqual = 5,
GreaterEqual = 6,
Always = 7,
}
StencilOperation :: enum NS.UInteger {
Keep = 0,
Zero = 1,
Replace = 2,
IncrementClamp = 3,
DecrementClamp = 4,
Invert = 5,
IncrementWrap = 6,
DecrementWrap = 7,
}
FeatureSet :: enum NS.UInteger {
iOS_GPUFamily1_v1 = 0,
iOS_GPUFamily2_v1 = 1,
iOS_GPUFamily1_v2 = 2,
iOS_GPUFamily2_v2 = 3,
iOS_GPUFamily3_v1 = 4,
iOS_GPUFamily1_v3 = 5,
iOS_GPUFamily2_v3 = 6,
iOS_GPUFamily3_v2 = 7,
iOS_GPUFamily1_v4 = 8,
iOS_GPUFamily2_v4 = 9,
iOS_GPUFamily3_v3 = 10,
iOS_GPUFamily4_v1 = 11,
iOS_GPUFamily1_v5 = 12,
iOS_GPUFamily2_v5 = 13,
iOS_GPUFamily3_v4 = 14,
iOS_GPUFamily4_v2 = 15,
iOS_GPUFamily5_v1 = 16,
macOS_GPUFamily1_v1 = 10000,
OSX_GPUFamily1_v1 = 10000,
macOS_GPUFamily1_v2 = 10001,
OSX_GPUFamily1_v2 = 10001,
OSX_ReadWriteTextureTier2 = 10002,
macOS_ReadWriteTextureTier2 = 10002,
macOS_GPUFamily1_v3 = 10003,
macOS_GPUFamily1_v4 = 10004,
macOS_GPUFamily2_v1 = 10005,
watchOS_GPUFamily1_v1 = 20000,
WatchOS_GPUFamily1_v1 = 20000,
watchOS_GPUFamily2_v1 = 20001,
WatchOS_GPUFamily2_v1 = 20001,
tvOS_GPUFamily1_v1 = 30000,
TVOS_GPUFamily1_v1 = 30000,
tvOS_GPUFamily1_v2 = 30001,
tvOS_GPUFamily1_v3 = 30002,
tvOS_GPUFamily2_v1 = 30003,
tvOS_GPUFamily1_v4 = 30004,
tvOS_GPUFamily2_v2 = 30005,
}
GPUFamily :: enum NS.Integer {
Apple1 = 1001,
Apple2 = 1002,
Apple3 = 1003,
Apple4 = 1004,
Apple5 = 1005,
Apple6 = 1006,
Apple7 = 1007,
Apple8 = 1008,
Mac1 = 2001,
Mac2 = 2002,
Common1 = 3001,
Common2 = 3002,
Common3 = 3003,
MacCatalyst1 = 4001,
MacCatalyst2 = 4002,
}
DeviceLocation :: enum NS.UInteger {
BuiltIn = 0,
Slot = 1,
External = 2,
Unspecified = NS.UIntegerMax,
}
PipelineOptionFlag :: enum NS.UInteger {
ArgumentInfo = 0,
BufferTypeInfo = 1,
FailOnBinaryArchiveMiss = 2,
}
PipelineOption :: distinct bit_set[PipelineOptionFlag; NS.UInteger]
ReadWriteTextureTier :: enum NS.UInteger {
TierNone = 0,
Tier1 = 1,
Tier2 = 2,
}
ArgumentBuffersTier :: enum NS.UInteger {
Tier1 = 0,
Tier2 = 1,
}
SparseTextureRegionAlignmentMode :: enum NS.UInteger {
Outward = 0,
Inward = 1,
}
CounterSamplingPoint :: enum NS.UInteger {
AtStageBoundary = 0,
AtDrawBoundary = 1,
AtDispatchBoundary = 2,
AtTileDispatchBoundary = 3,
AtBlitBoundary = 4,
}
DynamicLibraryError :: enum NS.UInteger {
None = 0,
InvalidFile = 1,
CompilationFailure = 2,
UnresolvedInstallName = 3,
DependencyLoadFailure = 4,
Unsupported = 5,
}
FunctionOption :: enum NS.UInteger {
CompileToBinary = 0,
}
FunctionOptions :: distinct bit_set[FunctionOption; NS.UInteger]
FunctionLogType :: enum NS.UInteger {
Validation = 0,
}
HeapType :: enum NS.Integer {
Automatic = 0,
Placement = 1,
Sparse = 2,
}
IndirectCommandTypeFlag :: enum NS.UInteger {
Draw = 0,
DrawIndexed = 1,
DrawPatches = 2,
DrawIndexedPatches = 3,
ConcurrentDispatch = 5,
ConcurrentDispatchThreads = 6,
}
IndirectCommandType :: distinct bit_set[IndirectCommandTypeFlag; NS.UInteger]
IntersectionFunctionSignatureFlag :: enum NS.UInteger {
Instancing = 0,
TriangleData = 1,
WorldSpaceData = 2,
InstanceMotion = 3,
PrimitiveMotion = 4,
ExtendedLimits = 5,
}
IntersectionFunctionSignature :: distinct bit_set[IntersectionFunctionSignatureFlag; NS.UInteger]
PatchType :: enum NS.UInteger {
None = 0,
Triangle = 1,
Quad = 2,
}
FunctionType :: enum NS.UInteger {
Vertex = 1,
Fragment = 2,
Kernel = 3,
Visible = 5,
Intersection = 6,
}
LanguageVersion :: enum NS.UInteger {
Version1_0 = 65536,
Version1_1 = 65537,
Version1_2 = 65538,
Version2_0 = 131072,
Version2_1 = 131073,
Version2_2 = 131074,
Version2_3 = 131075,
Version2_4 = 131076,
}
LibraryType :: enum NS.Integer {
Executable = 0,
Dynamic = 1,
}
LibraryError :: enum NS.UInteger {
Unsupported = 1,
CompileFailure = 3,
CompileWarning = 4,
FunctionNotFound = 5,
FileNotFound = 6,
}
Mutability :: enum NS.UInteger {
Default = 0,
Mutable = 1,
Immutable = 2,
}
PixelFormat :: enum NS.UInteger {
Invalid = 0,
A8Unorm = 1,
R8Unorm = 10,
R8Unorm_sRGB = 11,
R8Snorm = 12,
R8Uint = 13,
R8Sint = 14,
R16Unorm = 20,
R16Snorm = 22,
R16Uint = 23,
R16Sint = 24,
R16Float = 25,
RG8Unorm = 30,
RG8Unorm_sRGB = 31,
RG8Snorm = 32,
RG8Uint = 33,
RG8Sint = 34,
B5G6R5Unorm = 40,
A1BGR5Unorm = 41,
ABGR4Unorm = 42,
BGR5A1Unorm = 43,
R32Uint = 53,
R32Sint = 54,
R32Float = 55,
RG16Unorm = 60,
RG16Snorm = 62,
RG16Uint = 63,
RG16Sint = 64,
RG16Float = 65,
RGBA8Unorm = 70,
RGBA8Unorm_sRGB = 71,
RGBA8Snorm = 72,
RGBA8Uint = 73,
RGBA8Sint = 74,
BGRA8Unorm = 80,
BGRA8Unorm_sRGB = 81,
RGB10A2Unorm = 90,
RGB10A2Uint = 91,
RG11B10Float = 92,
RGB9E5Float = 93,
BGR10A2Unorm = 94,
RG32Uint = 103,
RG32Sint = 104,
RG32Float = 105,
RGBA16Unorm = 110,
RGBA16Snorm = 112,
RGBA16Uint = 113,
RGBA16Sint = 114,
RGBA16Float = 115,
RGBA32Uint = 123,
RGBA32Sint = 124,
RGBA32Float = 125,
BC1_RGBA = 130,
BC1_RGBA_sRGB = 131,
BC2_RGBA = 132,
BC2_RGBA_sRGB = 133,
BC3_RGBA = 134,
BC3_RGBA_sRGB = 135,
BC4_RUnorm = 140,
BC4_RSnorm = 141,
BC5_RGUnorm = 142,
BC5_RGSnorm = 143,
BC6H_RGBFloat = 150,
BC6H_RGBUfloat = 151,
BC7_RGBAUnorm = 152,
BC7_RGBAUnorm_sRGB = 153,
PVRTC_RGB_2BPP = 160,
PVRTC_RGB_2BPP_sRGB = 161,
PVRTC_RGB_4BPP = 162,
PVRTC_RGB_4BPP_sRGB = 163,
PVRTC_RGBA_2BPP = 164,
PVRTC_RGBA_2BPP_sRGB = 165,
PVRTC_RGBA_4BPP = 166,
PVRTC_RGBA_4BPP_sRGB = 167,
EAC_R11Unorm = 170,
EAC_R11Snorm = 172,
EAC_RG11Unorm = 174,
EAC_RG11Snorm = 176,
EAC_RGBA8 = 178,
EAC_RGBA8_sRGB = 179,
ETC2_RGB8 = 180,
ETC2_RGB8_sRGB = 181,
ETC2_RGB8A1 = 182,
ETC2_RGB8A1_sRGB = 183,
ASTC_4x4_sRGB = 186,
ASTC_5x4_sRGB = 187,
ASTC_5x5_sRGB = 188,
ASTC_6x5_sRGB = 189,
ASTC_6x6_sRGB = 190,
ASTC_8x5_sRGB = 192,
ASTC_8x6_sRGB = 193,
ASTC_8x8_sRGB = 194,
ASTC_10x5_sRGB = 195,
ASTC_10x6_sRGB = 196,
ASTC_10x8_sRGB = 197,
ASTC_10x10_sRGB = 198,
ASTC_12x10_sRGB = 199,
ASTC_12x12_sRGB = 200,
ASTC_4x4_LDR = 204,
ASTC_5x4_LDR = 205,
ASTC_5x5_LDR = 206,
ASTC_6x5_LDR = 207,
ASTC_6x6_LDR = 208,
ASTC_8x5_LDR = 210,
ASTC_8x6_LDR = 211,
ASTC_8x8_LDR = 212,
ASTC_10x5_LDR = 213,
ASTC_10x6_LDR = 214,
ASTC_10x8_LDR = 215,
ASTC_10x10_LDR = 216,
ASTC_12x10_LDR = 217,
ASTC_12x12_LDR = 218,
ASTC_4x4_HDR = 222,
ASTC_5x4_HDR = 223,
ASTC_5x5_HDR = 224,
ASTC_6x5_HDR = 225,
ASTC_6x6_HDR = 226,
ASTC_8x5_HDR = 228,
ASTC_8x6_HDR = 229,
ASTC_8x8_HDR = 230,
ASTC_10x5_HDR = 231,
ASTC_10x6_HDR = 232,
ASTC_10x8_HDR = 233,
ASTC_10x10_HDR = 234,
ASTC_12x10_HDR = 235,
ASTC_12x12_HDR = 236,
GBGR422 = 240,
BGRG422 = 241,
Depth16Unorm = 250,
Depth32Float = 252,
Stencil8 = 253,
Depth24Unorm_Stencil8 = 255,
Depth32Float_Stencil8 = 260,
X32_Stencil8 = 261,
X24_Stencil8 = 262,
BGRA10_XR = 552,
BGRA10_XR_sRGB = 553,
BGR10_XR = 554,
BGR10_XR_sRGB = 555,
}
PrimitiveType :: enum NS.UInteger {
Point = 0,
Line = 1,
LineStrip = 2,
Triangle = 3,
TriangleStrip = 4,
}
VisibilityResultMode :: enum NS.UInteger {
Disabled = 0,
Boolean = 1,
Counting = 2,
}
CullMode :: enum NS.UInteger {
None = 0,
Front = 1,
Back = 2,
}
Winding :: enum NS.UInteger {
Clockwise = 0,
CounterClockwise = 1,
}
DepthClipMode :: enum NS.UInteger {
Clip = 0,
Clamp = 1,
}
TriangleFillMode :: enum NS.UInteger {
Fill = 0,
Lines = 1,
}
RenderStage :: enum NS.UInteger {
Vertex = 0,
Fragment = 1,
Tile = 2,
}
RenderStages :: distinct bit_set[RenderStage; NS.UInteger]
LoadAction :: enum NS.UInteger {
DontCare = 0,
Load = 1,
Clear = 2,
}
StoreAction :: enum NS.UInteger {
DontCare = 0,
Store = 1,
MultisampleResolve = 2,
StoreAndMultisampleResolve = 3,
Unknown = 4,
CustomSampleDepthStore = 5,
}
StoreActionOption :: enum NS.UInteger {
CustomSamplePositions = 1,
}
StoreActionOptions :: distinct bit_set[StoreActionOption; NS.UInteger]
MultisampleDepthResolveFilter :: enum NS.UInteger {
Sample0 = 0,
Min = 1,
Max = 2,
}
MultisampleStencilResolveFilter :: enum NS.UInteger {
Sample0 = 0,
DepthResolvedSample = 1,
}
BlendFactor :: enum NS.UInteger {
Zero = 0,
One = 1,
SourceColor = 2,
OneMinusSourceColor = 3,
SourceAlpha = 4,
OneMinusSourceAlpha = 5,
DestinationColor = 6,
OneMinusDestinationColor = 7,
DestinationAlpha = 8,
OneMinusDestinationAlpha = 9,
SourceAlphaSaturated = 10,
BlendColor = 11,
OneMinusBlendColor = 12,
BlendAlpha = 13,
OneMinusBlendAlpha = 14,
Source1Color = 15,
OneMinusSource1Color = 16,
Source1Alpha = 17,
OneMinusSource1Alpha = 18,
}
BlendOperation :: enum NS.UInteger {
Add = 0,
Subtract = 1,
ReverseSubtract = 2,
Min = 3,
Max = 4,
}
ColorWriteMaskFlag :: enum NS.UInteger {
Alpha = 0,
Blue = 1,
Green = 2,
Red = 3,
}
ColorWriteMask :: distinct bit_set[ColorWriteMaskFlag; NS.UInteger]
ColorWriteMaskAll :: ColorWriteMask{.Alpha, .Blue, .Green, .Red}
PrimitiveTopologyClass :: enum NS.UInteger {
Unspecified = 0,
Point = 1,
Line = 2,
Triangle = 3,
}
TessellationPartitionMode :: enum NS.UInteger {
Pow2 = 0,
Integer = 1,
FractionalOdd = 2,
FractionalEven = 3,
}
TessellationFactorStepFunction :: enum NS.UInteger {
Constant = 0,
PerPatch = 1,
PerInstance = 2,
PerPatchAndPerInstance = 3,
}
TessellationFactorFormat :: enum NS.UInteger {
Half = 0,
}
TessellationControlPointIndexType :: enum NS.UInteger {
None = 0,
UInt16 = 1,
UInt32 = 2,
}
PurgeableState :: enum NS.UInteger {
KeepCurrent = 1,
NonVolatile = 2,
Volatile = 3,
Empty = 4,
}
CPUCacheMode :: enum NS.UInteger {
DefaultCache = 0,
WriteCombined = 1,
}
StorageMode :: enum NS.UInteger {
Shared = 0,
Managed = 1,
Private = 2,
Memoryless = 3,
}
HazardTrackingMode :: enum NS.UInteger {
Default = 0,
Untracked = 1,
Tracked = 2,
}
ResourceOption :: enum NS.UInteger {
CPUCacheModeWriteCombined = 0,
StorageModeManaged = 4,
StorageModePrivate = 5,
HazardTrackingModeUntracked = 8,
HazardTrackingModeTracked = 9,
}
ResourceOptions :: distinct bit_set[ResourceOption; NS.UInteger]
ResourceStorageModeShared :: ResourceOptions{}
ResourceHazardTrackingModeDefault :: ResourceOptions{}
ResourceCPUCacheModeDefaultCache :: ResourceOptions{}
ResourceOptionCPUCacheModeDefault :: ResourceOptions{}
ResourceStorageModeMemoryless :: ResourceOptions{.StorageModeManaged, .StorageModePrivate}
SparseTextureMappingMode :: enum NS.UInteger {
Map = 0,
Unmap = 1,
}
SamplerMinMagFilter :: enum NS.UInteger {
Nearest = 0,
Linear = 1,
}
SamplerMipFilter :: enum NS.UInteger {
NotMipmapped = 0,
Nearest = 1,
Linear = 2,
}
SamplerAddressMode :: enum NS.UInteger {
ClampToEdge = 0,
MirrorClampToEdge = 1,
Repeat = 2,
MirrorRepeat = 3,
ClampToZero = 4,
ClampToBorderColor = 5,
}
SamplerBorderColor :: enum NS.UInteger {
TransparentBlack = 0,
OpaqueBlack = 1,
OpaqueWhite = 2,
}
AttributeFormat :: enum NS.UInteger {
Invalid = 0,
UChar2 = 1,
UChar3 = 2,
UChar4 = 3,
Char2 = 4,
Char3 = 5,
Char4 = 6,
UChar2Normalized = 7,
UChar3Normalized = 8,
UChar4Normalized = 9,
Char2Normalized = 10,
Char3Normalized = 11,
Char4Normalized = 12,
UShort2 = 13,
UShort3 = 14,
UShort4 = 15,
Short2 = 16,
Short3 = 17,
Short4 = 18,
UShort2Normalized = 19,
UShort3Normalized = 20,
UShort4Normalized = 21,
Short2Normalized = 22,
Short3Normalized = 23,
Short4Normalized = 24,
Half2 = 25,
Half3 = 26,
Half4 = 27,
Float = 28,
Float2 = 29,
Float3 = 30,
Float4 = 31,
Int = 32,
Int2 = 33,
Int3 = 34,
Int4 = 35,
UInt = 36,
UInt2 = 37,
UInt3 = 38,
UInt4 = 39,
Int1010102Normalized = 40,
UInt1010102Normalized = 41,
UChar4Normalized_BGRA = 42,
UChar = 45,
Char = 46,
UCharNormalized = 47,
CharNormalized = 48,
UShort = 49,
Short = 50,
UShortNormalized = 51,
ShortNormalized = 52,
Half = 53,
}
IndexType :: enum NS.UInteger {
UInt16 = 0,
UInt32 = 1,
}
StepFunction :: enum NS.UInteger {
Constant = 0,
PerVertex = 1,
PerInstance = 2,
PerPatch = 3,
PerPatchControlPoint = 4,
ThreadPositionInGridX = 5,
ThreadPositionInGridY = 6,
ThreadPositionInGridXIndexed = 7,
ThreadPositionInGridYIndexed = 8,
}
TextureType :: enum NS.UInteger {
Type1D = 0,
Type1DArray = 1,
Type2D = 2,
Type2DArray = 3,
Type2DMultisample = 4,
TypeCube = 5,
TypeCubeArray = 6,
Type3D = 7,
Type2DMultisampleArray = 8,
TypeTextureBuffer = 9,
}
TextureSwizzle :: enum u8 {
Zero = 0,
One = 1,
Red = 2,
Green = 3,
Blue = 4,
Alpha = 5,
}
TextureUsageFlag :: enum NS.UInteger {
ShaderRead = 0,
ShaderWrite = 1,
RenderTarget = 2,
PixelFormatView = 4,
}
TextureUsage :: distinct bit_set[TextureUsageFlag; NS.UInteger]
TextureCompressionType :: enum NS.Integer {
Lossless = 0,
Lossy = 1,
}
VertexFormat :: enum NS.UInteger {
Invalid = 0,
UChar2 = 1,
UChar3 = 2,
UChar4 = 3,
Char2 = 4,
Char3 = 5,
Char4 = 6,
UChar2Normalized = 7,
UChar3Normalized = 8,
UChar4Normalized = 9,
Char2Normalized = 10,
Char3Normalized = 11,
Char4Normalized = 12,
UShort2 = 13,
UShort3 = 14,
UShort4 = 15,
Short2 = 16,
Short3 = 17,
Short4 = 18,
UShort2Normalized = 19,
UShort3Normalized = 20,
UShort4Normalized = 21,
Short2Normalized = 22,
Short3Normalized = 23,
Short4Normalized = 24,
Half2 = 25,
Half3 = 26,
Half4 = 27,
Float = 28,
Float2 = 29,
Float3 = 30,
Float4 = 31,
Int = 32,
Int2 = 33,
Int3 = 34,
Int4 = 35,
UInt = 36,
UInt2 = 37,
UInt3 = 38,
UInt4 = 39,
Int1010102Normalized = 40,
UInt1010102Normalized = 41,
UChar4Normalized_BGRA = 42,
UChar = 45,
Char = 46,
UCharNormalized = 47,
CharNormalized = 48,
UShort = 49,
Short = 50,
UShortNormalized = 51,
ShortNormalized = 52,
Half = 53,
}
VertexStepFunction :: enum NS.UInteger {
Constant = 0,
PerVertex = 1,
PerInstance = 2,
PerPatch = 3,
PerPatchControlPoint = 4,
}
+39
View File
@@ -0,0 +1,39 @@
package objc_Metal
import NS "vendor:darwin/Foundation"
foreign import "system:Metal.framework"
CommonCounter :: ^NS.String
CommonCounterSet :: ^NS.String
DeviceNotificationName :: ^NS.String
foreign Metal {
@(linkage="weak") CommonCounterTimestamp: CommonCounter
@(linkage="weak") CommonCounterTessellationInputPatches: CommonCounter
@(linkage="weak") CommonCounterVertexInvocations: CommonCounter
@(linkage="weak") CommonCounterPostTessellationVertexInvocations: CommonCounter
@(linkage="weak") CommonCounterClipperInvocations: CommonCounter
@(linkage="weak") CommonCounterClipperPrimitivesOut: CommonCounter
@(linkage="weak") CommonCounterFragmentInvocations: CommonCounter
@(linkage="weak") CommonCounterFragmentsPassed: CommonCounter
@(linkage="weak") CommonCounterComputeKernelInvocations: CommonCounter
@(linkage="weak") CommonCounterTotalCycles: CommonCounter
@(linkage="weak") CommonCounterVertexCycles: CommonCounter
@(linkage="weak") CommonCounterTessellationCycles: CommonCounter
@(linkage="weak") CommonCounterPostTessellationVertexCycles: CommonCounter
@(linkage="weak") CommonCounterFragmentCycles: CommonCounter
@(linkage="weak") CommonCounterRenderTargetWriteCycles: CommonCounter
}
foreign Metal {
@(linkage="weak") CommonCounterSetTimestamp: CommonCounterSet
@(linkage="weak") CommonCounterSetStageUtilization: CommonCounterSet
@(linkage="weak") CommonCounterSetStatistic: CommonCounterSet
}
foreign Metal {
@(linkage="weak") DeviceWasAddedNotification: DeviceNotificationName
@(linkage="weak") DeviceRemovalRequestedNotification: DeviceNotificationName
@(linkage="weak") DeviceWasRemovedNotification: DeviceNotificationName
}
+19
View File
@@ -0,0 +1,19 @@
package objc_Metal
import NS "vendor:darwin/Foundation"
@(require)
foreign import "system:Metal.framework"
@(default_calling_convention="c", link_prefix="MTL")
foreign Metal {
CopyAllDevices :: proc() -> ^NS.Array ---
CopyAllDevicesWithObserver :: proc(observer: ^id, handler: DeviceNotificationHandler) -> ^NS.Array ---
CreateSystemDefaultDevice :: proc() -> ^Device ---
RemoveDeviceObserver :: proc(observer: id) ---
}
new :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, NS.Object) {
return T.alloc()->init()
}
+199
View File
@@ -0,0 +1,199 @@
package objc_Metal
import NS "vendor:darwin/Foundation"
import "core:intrinsics"
BOOL :: NS.BOOL
id :: ^NS.Object
CFTimeInterval :: NS.TimeInterval
IOSurfaceRef :: distinct rawptr
dispatch_queue_t :: id
dispatch_data_t :: id
@(private)
msgSend :: intrinsics.objc_send
AccelerationStructureInstanceDescriptor :: struct {
transformationMatrix: PackedFloat4x3,
options: AccelerationStructureInstanceOptions,
mask: u32,
intersectionFunctionTableOffset: u32,
accelerationStructureIndex: u32,
}
AccelerationStructureSizes :: struct {
accelerationStructureSize: NS.Integer,
buildScratchBufferSize: NS.Integer,
refitScratchBufferSize: NS.Integer,
}
AxisAlignedBoundingBox :: struct {
min: PackedFloat3,
max: PackedFloat3,
}
ClearColor :: struct {
red: f64,
green: f64,
blue: f64,
alpha: f64,
}
Coordinate2D :: struct {
x: f32,
y: f32,
}
CounterResultStageUtilization :: struct {
totalCycles: u64,
vertexCycles: u64,
tessellationCycles: u64,
postTessellationVertexCycles: u64,
fragmentCycles: u64,
renderTargetCycles: u64,
}
CounterResultStatistic :: struct {
tessellationInputPatches: u64,
vertexInvocations: u64,
postTessellationVertexInvocations: u64,
clipperInvocations: u64,
clipperPrimitivesOut: u64,
fragmentInvocations: u64,
fragmentsPassed: u64,
computeKernelInvocations: u64,
}
CounterResultTimestamp :: struct {
timestamp: u64,
}
DispatchThreadgroupsIndirectArguments :: struct {
threadgroupsPerGrid: [3]u32,
}
DrawIndexedPrimitivesIndirectArguments :: struct {
indexCount: u32,
instanceCount: u32,
indexStart: u32,
baseVertex: i32,
baseInstance: u32,
}
DrawPatchIndirectArguments :: struct {
patchCount: u32,
instanceCount: u32,
patchStart: u32,
baseInstance: u32,
}
DrawPrimitivesIndirectArguments :: struct {
vertexCount: u32,
instanceCount: u32,
vertexStart: u32,
baseInstance: u32,
}
IndirectCommandBufferExecutionRange :: struct {
location: u32,
length: u32,
}
MapIndirectArguments :: struct {
regionOriginX: u32,
regionOriginY: u32,
regionOriginZ: u32,
regionSizeWidth: u32,
regionSizeHeight: u32,
regionSizeDepth: u32,
mipMapLevel: u32,
sliceId: u32,
}
Origin :: distinct [3]NS.Integer
PackedFloat3 :: distinct [3]f32
PackedFloat4x3 :: struct {
columns: [4]PackedFloat3,
}
QuadTessellationFactorsHalf :: struct {
edgeTessellationFactor: [4]u16,
insideTessellationFactor: [2]u16,
}
Region :: struct {
origin: Origin,
size: Size,
}
SamplePosition :: distinct [2]f32
ScissorRect :: struct {
x: NS.Integer,
y: NS.Integer,
width: NS.Integer,
height: NS.Integer,
}
Size :: struct {
width: NS.Integer,
height: NS.Integer,
depth: NS.Integer,
}
SizeAndAlign :: struct {
size: NS.UInteger,
align: NS.UInteger,
}
StageInRegionIndirectArguments :: struct {
stageInOrigin: [3]u32,
stageInSize: [3]u32,
}
TextureSwizzleChannels :: struct {
red: TextureSwizzle,
green: TextureSwizzle,
blue: TextureSwizzle,
alpha: TextureSwizzle,
}
TriangleTessellationFactorsHalf :: struct {
edgeTessellationFactor: [3]u16,
insideTessellationFactor: u16,
}
VertexAmplificationViewMapping :: struct {
viewportArrayIndexOffset: u32,
renderTargetArrayIndexOffset: u32,
}
Viewport :: struct {
originX: f64,
originY: f64,
width: f64,
height: f64,
znear: f64,
zfar: f64,
}
Timestamp :: distinct u64
DeviceNotificationHandler :: ^NS.Block
AutoreleasedComputePipelineReflection :: ^ComputePipelineReflection
AutoreleasedRenderPipelineReflection :: ^RenderPipelineReflection
NewLibraryCompletionHandler :: ^NS.Block
NewRenderPipelineStateCompletionHandler :: ^NS.Block
NewRenderPipelineStateWithReflectionCompletionHandler :: ^NS.Block
NewComputePipelineStateCompletionHandler :: ^NS.Block
NewComputePipelineStateWithReflectionCompletionHandler :: ^NS.Block
SharedEventNotificationBlock :: ^NS.Block
DrawablePresentedHandler :: ^NS.Block
AutoreleasedArgument :: ^Argument
+155
View File
@@ -0,0 +1,155 @@
## About
**metal-odin** is a low overhead Odin interface for Metal that helps developers add Metal functionality to graphics applications that are written in Odin. **metal-odin** removes the need to create a shim and allows developers to call Metal functions directly from anywhere in their existing Odin code.
## Highlights
- Drop in Odin alternative interface to the Metal Objective-C headers.
- Direct mapping of all Metal Objective-C classes, constants, enums and bit_sets to Odin
- No measurable overhead compared to calling Metal Objective-C headers, due to inlining of Odin procedure calls.
- No usage of wrapper containers that require additional allocations.
- Identical header files and procedure/constant/enum availability for iOS, macOS and tvOS.
- Backwards compatibility: All `MTL.Device.supports...()` procedure check if their required selectors exist and automatically return `false` if not.
- String (`ErrorDomain`) constants are `@(linkage="weak")` and automatically set to `nil` if not available.
## Memory Allocation Policy
**metal-odin** follows the object allocation policies of Cocoa and Cocoa Touch. Understanding those rules is especially important when using `metal-odin`, as Odin values are not eligible for automatic reference counting (ARC).
**metal-odin** objects are reference counted. To help convey and manage object lifecycles, the following conventions are observed:
### AutoreleasePools and Objects
Several methods that create temporary objects in **metal-odin** add them to an `AutoreleasePool` to help manage their lifetimes. In these situations, after **metal-odin** creates the object, it adds it to an `AutoreleasePool`, which will release its objects when you release (or drain) it.
By adding temporary objects to an AutoreleasePool, you do not need to explicitly call `release()` to deallocate them. Instead, you can rely on the `AutoreleasePool` to implicitly manage those lifetimes.
If you create an object with a method that does not begin with `alloc`, or `copy`, the creating method adds the object to an autorelease pool.
The typical scope of an `AutoreleasePool` is one frame of rendering for the main thread of the program. When the thread returns control to the RunLoop (an object responsible for receiving input and events from the windowing system), the pool is *drained*, releasing its objects.
You can create and manage additional `AutoreleasePool`s at smaller scopes to reduce your program's working set, and you are required to do so for any additional threads your program creates.
If an object's lifecycle needs to be extended beyond the `AutoreleasePool`'s scope, you can claim ownership of it (avoiding its release beyond the pool's scope) by calling its `retain()` method before its pool is drained. In these cases, you will be responsible for making the appropriate `release()` call on the object after you no longer need it.
You can find a more-detailed introduction to the memory management rules here: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html.
For more details about the application's RunLoop, please find its documentation here: https://developer.apple.com/documentation/foundation/nsrunloop
### Use and debug AutoreleasePools
When you create an autoreleased object and there is no enclosing `AutoreleasePool`, the object is leaked.
To prevent this, you normally create an `AutoreleasePool` in your program's `main` procedure, and in the entry procedure for every thread you create. You may also create additional `AutoreleasePool`s to avoid growing your program's high memory watermark when you create several autoreleased objects, such as when rendering.
Use the Environment Variable `OBJC_DEBUG_MISSING_POOLS=YES` to print a runtime warning when an autoreleased object is leaked because no enclosing `AutoreleasePool` is available for its thread.
You can also run `leaks --autoreleasePools` on a memgraph file or a process ID (macOS only) to view a listing of your program's `AutoreleasePool`s and all objects they contain.
### nil
Similar to Objective-C, it is legal to call any method, including `retain()` and `release()`, on `nil` "objects". While calling methods on `nil` still does incur in procedure call overhead, the effective result is equivalent of a NOP.
Conversely, do not assume that because calling a method on a pointer did not result in a crash, that the pointed-to object is valid.
## Adding `metal-odin` to a Project
Simply `import MTL "core:sys/darwin/Metal"`. To ensure that the selector and class symbols are linked.
```odin
import MTL "core:sys/darwin/Metal"
```
## Examples
#### Creating the device
###### Objective-C (with automatic reference counting)
```objc
id< MTLDevice > device = MTLCreateSystemDefaultDevice();
// ...
```
###### Objective-C
```objc
id< MTLDevice > device = MTLCreateSystemDefaultDevice();
// ...
[device release];
```
###### Odin
```odin
device := MTL.CreateSystemDefaultDevice()
// ...
device->release()
```
#### Metal function calls map directly to Odin
###### Objective-C (with automatic reference counting)
```objc
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
[samplerDescriptor setSAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setTAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setRAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setMagFilter: MTLSamplerMinMagFilterLinear];
[samplerDescriptor setMinFilter: MTLSamplerMinMagFilterLinear];
[samplerDescriptor setMipFilter: MTLSamplerMipFilterLinear];
[samplerDescriptor setSupportArgumentBuffers: YES];
id< MTLSamplerState > samplerState = [device newSamplerStateWithDescriptor:samplerDescriptor];
```
###### Objective-C
```objc
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
[samplerDescriptor setSAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setTAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setRAddressMode: MTLSamplerAddressModeRepeat];
[samplerDescriptor setMagFilter: MTLSamplerMinMagFilterLinear];
[samplerDescriptor setMinFilter: MTLSamplerMinMagFilterLinear];
[samplerDescriptor setMipFilter: MTLSamplerMipFilterLinear];
[samplerDescriptor setSupportArgumentBuffers: YES];
id< MTLSamplerState > samplerState = [device newSamplerStateWithDescriptor:samplerDescriptor];
[samplerDescriptor release];
// ...
[samplerState release];
```
###### Odin
```odin
samplerDescriptor := MTL.SamplerDescriptor.alloc()->init()
samplerDescriptor->setSAddressMode(.Repeat)
samplerDescriptor->setTAddressMode(.Repeat)
samplerDescriptor->setRAddressMode(.Repeat)
samplerDescriptor->setMagFilter(.Linear)
samplerDescriptor->setMinFilter(.Linear)
samplerDescriptor->setMipFilter(.Linear)
samplerDescriptor->setSupportArgumentBuffers(true)
samplerState := device->newSamplerState(samplerDescriptor)
samplerDescriptor->release()
// ...
samplerState->release()
```
+259
View File
@@ -0,0 +1,259 @@
package objc_MetalKit
import NS "vendor:darwin/Foundation"
import MTL "vendor:darwin/Metal"
import CA "vendor:darwin/QuartzCore"
import "core:intrinsics"
@(require)
foreign import "system:MetalKit.framework"
@(private)
msgSend :: intrinsics.objc_send
ColorSpaceRef :: struct {}
ViewDelegate :: struct {
drawInMTKView: proc "c" (self: ^ViewDelegate, view: ^View),
drawableSizeWillChange: proc "c" (self: ^ViewDelegate, view: ^View, size: NS.Size),
user_data: rawptr,
}
@(objc_class="MTKView")
View :: struct {using _: NS.View}
@(objc_type=View, objc_name="alloc", objc_is_class_method=true)
View_alloc :: proc() -> ^View {
return msgSend(^View, View, "alloc")
}
@(objc_type=View, objc_name="initWithFrame")
View_initWithFrame :: proc(self: ^View, frame: NS.Rect, device: ^MTL.Device) -> ^View {
return msgSend(^View, self, "initWithFrame:device:", frame, device)
}
@(objc_type=View, objc_name="initWithCoder")
View_initWithCoder :: proc(self: ^View, coder: ^NS.Coder) -> ^View {
return msgSend(^View, self, "initWithCoder:", coder)
}
@(objc_type=View, objc_name="setDevice")
View_setDevice :: proc(self: ^View, device: ^MTL.Device) {
msgSend(nil, self, "setDevice:", device)
}
@(objc_type=View, objc_name="device")
View_device :: proc(self: ^View) -> ^MTL.Device {
return msgSend(^MTL.Device, self, "device")
}
@(objc_type=View, objc_name="draw")
View_draw :: proc(self: ^View) {
msgSend(nil, self, "draw")
}
@(objc_type=View, objc_name="setDelegate")
View_setDelegate :: proc(self: ^View, delegate: ^ViewDelegate) {
drawDispatch :: proc "c" (self: ^NS.Value, cmd: NS.SEL, view: ^View) {
del := (^ViewDelegate)(self->pointerValue())
del->drawInMTKView(view)
}
drawableSizeWillChange :: proc "c" (self: ^NS.Value, cmd: NS.SEL, view: ^View, size: NS.Size) {
del := (^ViewDelegate)(self->pointerValue())
del->drawableSizeWillChange(view, size)
}
wrapper := NS.Value.valueWithPointer(delegate)
NS.class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("drawInMTKView:"), auto_cast drawDispatch, "v@:@")
cbparams :: "v@:@{CGSize=ff}" when size_of(NS.Float) == size_of(f32) else "v@:@{CGSize=dd}"
NS.class_addMethod(intrinsics.objc_find_class("NSValue"), intrinsics.objc_find_selector("mtkView:drawableSizeWillChange:"), auto_cast drawableSizeWillChange, cbparams)
msgSend(nil, self, "setDelegate:", wrapper)
}
@(objc_type=View, objc_name="delegate")
View_delegate :: proc(self: ^View) -> ^ViewDelegate {
wrapper := msgSend(^NS.Value, self, "delegate")
if wrapper != nil {
return (^ViewDelegate)(wrapper->pointerValue())
}
return nil
}
@(objc_type=View, objc_name="currentDrawable")
View_currentDrawable :: proc(self: ^View) -> ^CA.MetalDrawable {
return msgSend(^CA.MetalDrawable, self, "currentDrawable")
}
@(objc_type=View, objc_name="setFramebufferOnly")
View_setFramebufferOnly :: proc(self: ^View, framebufferOnly: bool) {
msgSend(nil, self, "setFramebufferOnly:", framebufferOnly)
}
@(objc_type=View, objc_name="framebufferOnly")
View_framebufferOnly :: proc(self: ^View) -> bool {
return msgSend(bool, self, "framebufferOnly")
}
@(objc_type=View, objc_name="setDepthStencilAttachmentTextureUsage")
View_setDepthStencilAttachmentTextureUsage :: proc(self: ^View, textureUsage: MTL.TextureUsage) {
msgSend(nil, self, "setDepthStencilAttachmentTextureUsage:", textureUsage)
}
@(objc_type=View, objc_name="depthStencilAttachmentTextureUsage")
View_depthStencilAttachmentTextureUsage :: proc(self: ^View) -> MTL.TextureUsage {
return msgSend(MTL.TextureUsage, self, "depthStencilAttachmentTextureUsage")
}
@(objc_type=View, objc_name="setMultisampleColorAttachmentTextureUsage")
View_setMultisampleColorAttachmentTextureUsage :: proc(self: ^View, textureUsage: MTL.TextureUsage) {
msgSend(nil, self, "setMultisampleColorAttachmentTextureUsage:", textureUsage)
}
@(objc_type=View, objc_name="multisampleColorAttachmentTextureUsage")
View_multisampleColorAttachmentTextureUsage :: proc(self: ^View) -> MTL.TextureUsage {
return msgSend(MTL.TextureUsage, self, "multisampleColorAttachmentTextureUsage")
}
@(objc_type=View, objc_name="setPresentsWithTransaction")
View_setPresentsWithTransaction :: proc(self: ^View, presentsWithTransaction: bool) {
msgSend(nil, self, "setPresentsWithTransaction:", presentsWithTransaction)
}
@(objc_type=View, objc_name="presentsWithTransaction")
View_presentsWithTransaction :: proc(self: ^View) -> bool {
return msgSend(bool, self, "presentsWithTransaction")
}
@(objc_type=View, objc_name="setColorPixelFormat")
View_setColorPixelFormat :: proc(self: ^View, colorPixelFormat: MTL.PixelFormat) {
msgSend(nil, self, "setColorPixelFormat:", colorPixelFormat)
}
@(objc_type=View, objc_name="colorPixelFormat")
View_colorPixelFormat :: proc(self: ^View) -> MTL.PixelFormat {
return msgSend(MTL.PixelFormat, self, "colorPixelFormat")
}
@(objc_type=View, objc_name="setDepthStencilPixelFormat")
View_setDepthStencilPixelFormat :: proc(self: ^View, colorPixelFormat: MTL.PixelFormat) {
msgSend(nil, self, "setDepthStencilPixelFormat:", colorPixelFormat)
}
@(objc_type=View, objc_name="depthStencilPixelFormat")
View_depthStencilPixelFormat :: proc(self: ^View) -> MTL.PixelFormat {
return msgSend(MTL.PixelFormat, self, "depthStencilPixelFormat")
}
@(objc_type=View, objc_name="setSampleCount")
View_setSampleCount :: proc(self: ^View, sampleCount: NS.UInteger) {
msgSend(nil, self, "setSampleCount:", sampleCount)
}
@(objc_type=View, objc_name="sampleCount")
View_sampleCount :: proc(self: ^View) -> NS.UInteger {
return msgSend(NS.UInteger, self, "sampleCount")
}
@(objc_type=View, objc_name="setClearColor")
View_setClearColor :: proc(self: ^View, clearColor: MTL.ClearColor) {
msgSend(nil, self, "setClearColor:", clearColor)
}
@(objc_type=View, objc_name="clearColor")
View_clearColor :: proc(self: ^View) -> MTL.ClearColor {
return msgSend(MTL.ClearColor, self, "clearColor")
}
@(objc_type=View, objc_name="setClearDepth")
View_setClearDepth :: proc(self: ^View, clearDepth: f64) {
msgSend(nil, self, "setClearDepth:", clearDepth)
}
@(objc_type=View, objc_name="clearDepth")
View_clearDepth :: proc(self: ^View) -> f64 {
return msgSend(f64, self, "clearDepth")
}
@(objc_type=View, objc_name="setClearStencil")
View_setClearStencil :: proc(self: ^View, clearStencil: u32) {
msgSend(nil, self, "setClearStencil:", clearStencil)
}
@(objc_type=View, objc_name="clearStencil")
View_clearStencil :: proc(self: ^View) -> u32 {
return msgSend(u32, self, "clearStencil")
}
@(objc_type=View, objc_name="depthStencilTexture")
View_depthStencilTexture :: proc(self: ^View) -> ^MTL.Texture {
return msgSend(^MTL.Texture, self, "depthStencilTexture")
}
@(objc_type=View, objc_name="multisampleColorTexture")
View_multisampleColorTexture :: proc(self: ^View) -> ^MTL.Texture {
return msgSend(^MTL.Texture, self, "multisampleColorTexture")
}
@(objc_type=View, objc_name="releaseDrawables")
View_releaseDrawables :: proc(self: ^View) {
msgSend(nil, self, "releaseDrawables")
}
@(objc_type=View, objc_name="currentRenderPassDescriptor")
View_currentRenderPassDescriptor :: proc(self: ^View) -> ^MTL.RenderPassDescriptor {
return msgSend(^MTL.RenderPassDescriptor, self, "currentRenderPassDescriptor")
}
@(objc_type=View, objc_name="setPreferredFramesPerSecond")
View_setPreferredFramesPerSecond :: proc(self: ^View, preferredFramesPerSecond: NS.Integer) {
msgSend(nil, self, "setPreferredFramesPerSecond:", preferredFramesPerSecond)
}
@(objc_type=View, objc_name="preferredFramesPerSecond")
View_preferredFramesPerSecond :: proc(self: ^View) -> NS.Integer {
return msgSend(NS.Integer, self, "preferredFramesPerSecond")
}
@(objc_type=View, objc_name="setEnableSetNeedsDisplay")
View_setEnableSetNeedsDisplay :: proc(self: ^View, enableSetNeedsDisplay: bool) {
msgSend(nil, self, "setEnableSetNeedsDisplay:", enableSetNeedsDisplay)
}
@(objc_type=View, objc_name="enableSetNeedsDisplay")
View_enableSetNeedsDisplay :: proc(self: ^View) -> bool {
return msgSend(bool, self, "enableSetNeedsDisplay")
}
@(objc_type=View, objc_name="setAutoresizeDrawable")
View_setAutoresizeDrawable :: proc(self: ^View, autoresizeDrawable: bool) {
msgSend(nil, self, "setAutoresizeDrawable:", autoresizeDrawable)
}
@(objc_type=View, objc_name="autoresizeDrawable")
View_autoresizeDrawable :: proc(self: ^View) -> bool {
return msgSend(bool, self, "autoresizeDrawable")
}
@(objc_type=View, objc_name="setDrawableSize")
View_setDrawableSize :: proc(self: ^View, drawableSize: NS.Size) {
msgSend(nil, self, "setDrawableSize:", drawableSize)
}
@(objc_type=View, objc_name="drawableSize")
View_drawableSize :: proc(self: ^View) -> NS.Size {
return msgSend(NS.Size, self, "drawableSize")
}
@(objc_type=View, objc_name="preferredDrawableSize")
View_preferredDrawableSize :: proc(self: ^View) -> NS.Size {
return msgSend(NS.Size, self, "preferredDrawableSize")
}
@(objc_type=View, objc_name="preferredDevice")
View_preferredDevice :: proc(self: ^View) -> ^MTL.Device {
return msgSend(^MTL.Device, self, "preferredDevice")
}
@(objc_type=View, objc_name="setPaused")
View_setPaused :: proc(self: ^View, isPaused: bool) {
msgSend(nil, self, "setPaused:", isPaused)
}
@(objc_type=View, objc_name="isPaused")
View_isPaused :: proc(self: ^View) -> bool {
return msgSend(bool, self, "isPaused")
}
@(objc_type=View, objc_name="setColorSpace")
View_setColorSpace :: proc(self: ^View, colorSpace: ColorSpaceRef) {
msgSend(nil, self, "setColorSpace:", colorSpace)
}
@(objc_type=View, objc_name="colorSpace")
View_colorSpace :: proc(self: ^View) -> ColorSpaceRef {
return msgSend(ColorSpaceRef, self, "colorSpace")
}
+87
View File
@@ -0,0 +1,87 @@
package objc_QuartzCore
import NS "vendor:darwin/Foundation"
import MTL "vendor:darwin/Metal"
import "core:intrinsics"
@(private)
msgSend :: intrinsics.objc_send
@(objc_class="CAMetalLayer")
MetalLayer :: struct{ using _: NS.Layer}
@(objc_type=MetalLayer, objc_name="layer", objc_is_class_method=true)
MetalLayer_layer :: proc() -> ^MetalLayer {
return msgSend(^MetalLayer, MetalLayer, "layer")
}
@(objc_type=MetalLayer, objc_name="device")
MetalLayer_device :: proc(self: ^MetalLayer) -> ^MTL.Device {
return msgSend(^MTL.Device, self, "device")
}
@(objc_type=MetalLayer, objc_name="setDevice")
MetalLayer_setDevice :: proc(self: ^MetalLayer, device: ^MTL.Device) {
msgSend(nil, self, "setDevice:", device)
}
@(objc_type=MetalLayer, objc_name="opaque")
MetalLayer_opaque :: proc(self: ^MetalLayer) -> NS.BOOL {
return msgSend(NS.BOOL, self, "opaque")
}
@(objc_type=MetalLayer, objc_name="setOpaque")
MetalLayer_setOpaque :: proc(self: ^MetalLayer, opaque: NS.BOOL) {
msgSend(nil, self, "setOpaque:", opaque)
}
@(objc_type=MetalLayer, objc_name="preferredDevice")
MetalLayer_preferredDevice :: proc(self: ^MetalLayer) -> ^MTL.Device {
return msgSend(^MTL.Device, self, "preferredDevice")
}
@(objc_type=MetalLayer, objc_name="pixelFormat")
MetalLayer_pixelFormat :: proc(self: ^MetalLayer) -> MTL.PixelFormat {
return msgSend(MTL.PixelFormat, self, "pixelFormat")
}
@(objc_type=MetalLayer, objc_name="setPixelFormat")
MetalLayer_setPixelFormat :: proc(self: ^MetalLayer, pixelFormat: MTL.PixelFormat) {
msgSend(nil, self, "setPixelFormat:", pixelFormat)
}
@(objc_type=MetalLayer, objc_name="framebufferOnly")
MetalLayer_framebufferOnly :: proc(self: ^MetalLayer) -> NS.BOOL {
return msgSend(NS.BOOL, self, "framebufferOnly")
}
@(objc_type=MetalLayer, objc_name="setFramebufferOnly")
MetalLayer_setFramebufferOnly :: proc(self: ^MetalLayer, ok: NS.BOOL) {
msgSend(nil, self, "setFramebufferOnly:", ok)
}
@(objc_type=MetalLayer, objc_name="frame")
MetalLayer_frame :: proc(self: ^MetalLayer) -> NS.Rect {
return msgSend(NS.Rect, self, "frame")
}
@(objc_type=MetalLayer, objc_name="setFrame")
MetalLayer_setFrame :: proc(self: ^MetalLayer, frame: NS.Rect) {
msgSend(nil, self, "setFrame:", frame)
}
@(objc_type=MetalLayer, objc_name="nextDrawable")
MetalLayer_nextDrawable :: proc(self: ^MetalLayer) -> ^MetalDrawable {
return msgSend(^MetalDrawable, self, "nextDrawable")
}
@(objc_class="CAMetalDrawable")
MetalDrawable :: struct { using _: MTL.Drawable }
@(objc_type=MetalDrawable, objc_name="layer")
MetalDrawable_layer :: proc(self: ^MetalDrawable) -> ^MetalLayer {
return msgSend(^MetalLayer, self, "layer")
}
@(objc_type=MetalDrawable, objc_name="texture")
MetalDrawable_texture :: proc(self: ^MetalDrawable) -> ^MTL.Texture {
return msgSend(^MTL.Texture, self, "texture")
}
+3627
View File
File diff suppressed because it is too large Load Diff
+5169
View File
File diff suppressed because it is too large Load Diff
+532
View File
@@ -0,0 +1,532 @@
package directx_d3d12
FL9_1_REQ_TEXTURE1D_U_DIMENSION :: 2048
FL9_3_REQ_TEXTURE1D_U_DIMENSION :: 4096
FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 2048
FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION :: 4096
FL9_1_REQ_TEXTURECUBE_DIMENSION :: 512
FL9_3_REQ_TEXTURECUBE_DIMENSION :: 4096
FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 256
FL9_1_DEFAULT_MAX_ANISOTROPY :: 2
FL9_1_IA_PRIMITIVE_MAX_COUNT :: 65535
FL9_2_IA_PRIMITIVE_MAX_COUNT :: 1048575
FL9_1_SIMULTANEOUS_RENDER_TARGET_COUNT :: 1
FL9_3_SIMULTANEOUS_RENDER_TARGET_COUNT :: 4
FL9_1_MAX_TEXTURE_REPEAT :: 128
FL9_2_MAX_TEXTURE_REPEAT :: 2048
FL9_3_MAX_TEXTURE_REPEAT :: 8192
COMPONENT_MASK_X :: 1
COMPONENT_MASK_Y :: 2
COMPONENT_MASK_Z :: 4
COMPONENT_MASK_W :: 8
_16BIT_INDEX_STRIP_CUT_VALUE :: 0xffff
_32BIT_INDEX_STRIP_CUT_VALUE :: 0xffffffff
_8BIT_INDEX_STRIP_CUT_VALUE :: 0xff
APPEND_ALIGNED_ELEMENT :: 0xffffffff
ARRAY_AXIS_ADDRESS_RANGE_BIT_COUNT :: 9
CLIP_OR_CULL_DISTANCE_COUNT :: 8
CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT :: 2
COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT :: 14
COMMONSHADER_CONSTANT_BUFFER_COMPONENTS :: 4
COMMONSHADER_CONSTANT_BUFFER_COMPONENT_BIT_COUNT :: 32
COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT :: 15
COMMONSHADER_CONSTANT_BUFFER_PARTIAL_UPDATE_EXTENTS_BYTE_ALIGNMENT :: 16
COMMONSHADER_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4
COMMONSHADER_CONSTANT_BUFFER_REGISTER_COUNT :: 15
COMMONSHADER_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1
COMMONSHADER_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1
COMMONSHADER_FLOWCONTROL_NESTING_LIMIT :: 64
COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COMPONENTS :: 4
COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_COUNT :: 1
COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READS_PER_INST :: 1
COMMONSHADER_IMMEDIATE_CONSTANT_BUFFER_REGISTER_READ_PORTS :: 1
COMMONSHADER_IMMEDIATE_VALUE_COMPONENT_BIT_COUNT :: 32
COMMONSHADER_INPUT_RESOURCE_REGISTER_COMPONENTS :: 1
COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT :: 128
COMMONSHADER_INPUT_RESOURCE_REGISTER_READS_PER_INST :: 1
COMMONSHADER_INPUT_RESOURCE_REGISTER_READ_PORTS :: 1
COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT :: 128
COMMONSHADER_SAMPLER_REGISTER_COMPONENTS :: 1
COMMONSHADER_SAMPLER_REGISTER_COUNT :: 16
COMMONSHADER_SAMPLER_REGISTER_READS_PER_INST :: 1
COMMONSHADER_SAMPLER_REGISTER_READ_PORTS :: 1
COMMONSHADER_SAMPLER_SLOT_COUNT :: 16
COMMONSHADER_SUBROUTINE_NESTING_LIMIT :: 32
COMMONSHADER_TEMP_REGISTER_COMPONENTS :: 4
COMMONSHADER_TEMP_REGISTER_COMPONENT_BIT_COUNT :: 32
COMMONSHADER_TEMP_REGISTER_COUNT :: 4096
COMMONSHADER_TEMP_REGISTER_READS_PER_INST :: 3
COMMONSHADER_TEMP_REGISTER_READ_PORTS :: 3
COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MAX :: 10
COMMONSHADER_TEXCOORD_RANGE_REDUCTION_MIN :: -10
COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE :: -8
COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE :: 7
CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT :: 256
CS_4_X_BUCKET00_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 256
CS_4_X_BUCKET00_MAX_NUM_THREADS_PER_GROUP :: 64
CS_4_X_BUCKET01_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 240
CS_4_X_BUCKET01_MAX_NUM_THREADS_PER_GROUP :: 68
CS_4_X_BUCKET02_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 224
CS_4_X_BUCKET02_MAX_NUM_THREADS_PER_GROUP :: 72
CS_4_X_BUCKET03_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 208
CS_4_X_BUCKET03_MAX_NUM_THREADS_PER_GROUP :: 76
CS_4_X_BUCKET04_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 192
CS_4_X_BUCKET04_MAX_NUM_THREADS_PER_GROUP :: 84
CS_4_X_BUCKET05_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 176
CS_4_X_BUCKET05_MAX_NUM_THREADS_PER_GROUP :: 92
CS_4_X_BUCKET06_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 160
CS_4_X_BUCKET06_MAX_NUM_THREADS_PER_GROUP :: 100
CS_4_X_BUCKET07_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 144
CS_4_X_BUCKET07_MAX_NUM_THREADS_PER_GROUP :: 112
CS_4_X_BUCKET08_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 128
CS_4_X_BUCKET08_MAX_NUM_THREADS_PER_GROUP :: 128
CS_4_X_BUCKET09_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 112
CS_4_X_BUCKET09_MAX_NUM_THREADS_PER_GROUP :: 144
CS_4_X_BUCKET10_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 96
CS_4_X_BUCKET10_MAX_NUM_THREADS_PER_GROUP :: 168
CS_4_X_BUCKET11_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 80
CS_4_X_BUCKET11_MAX_NUM_THREADS_PER_GROUP :: 204
CS_4_X_BUCKET12_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 64
CS_4_X_BUCKET12_MAX_NUM_THREADS_PER_GROUP :: 256
CS_4_X_BUCKET13_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 48
CS_4_X_BUCKET13_MAX_NUM_THREADS_PER_GROUP :: 340
CS_4_X_BUCKET14_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 32
CS_4_X_BUCKET14_MAX_NUM_THREADS_PER_GROUP :: 512
CS_4_X_BUCKET15_MAX_BYTES_TGSM_WRITABLE_PER_THREAD :: 16
CS_4_X_BUCKET15_MAX_NUM_THREADS_PER_GROUP :: 768
CS_4_X_DISPATCH_MAX_THREAD_GROUPS_IN_Z_DIMENSION :: 1
CS_4_X_RAW_UAV_BYTE_ALIGNMENT :: 256
CS_4_X_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 768
CS_4_X_THREAD_GROUP_MAX_X :: 768
CS_4_X_THREAD_GROUP_MAX_Y :: 768
CS_4_X_UAV_REGISTER_COUNT :: 1
CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION :: 65535
CS_TGSM_REGISTER_COUNT :: 8192
CS_TGSM_REGISTER_READS_PER_INST :: 1
CS_TGSM_RESOURCE_REGISTER_COMPONENTS :: 1
CS_TGSM_RESOURCE_REGISTER_READ_PORTS :: 1
CS_THREADGROUPID_REGISTER_COMPONENTS :: 3
CS_THREADGROUPID_REGISTER_COUNT :: 1
CS_THREADIDINGROUPFLATTENED_REGISTER_COMPONENTS :: 1
CS_THREADIDINGROUPFLATTENED_REGISTER_COUNT :: 1
CS_THREADIDINGROUP_REGISTER_COMPONENTS :: 3
CS_THREADIDINGROUP_REGISTER_COUNT :: 1
CS_THREADID_REGISTER_COMPONENTS :: 3
CS_THREADID_REGISTER_COUNT :: 1
CS_THREAD_GROUP_MAX_THREADS_PER_GROUP :: 1024
CS_THREAD_GROUP_MAX_X :: 1024
CS_THREAD_GROUP_MAX_Y :: 1024
CS_THREAD_GROUP_MAX_Z :: 64
CS_THREAD_GROUP_MIN_X :: 1
CS_THREAD_GROUP_MIN_Y :: 1
CS_THREAD_GROUP_MIN_Z :: 1
CS_THREAD_LOCAL_TEMP_REGISTER_POOL :: 16384
DEFAULT_BLEND_FACTOR_ALPHA :: 1.0
DEFAULT_BLEND_FACTOR_BLUE :: 1.0
DEFAULT_BLEND_FACTOR_GREEN :: 1.0
DEFAULT_BLEND_FACTOR_RED :: 1.0
DEFAULT_BORDER_COLOR_COMPONENT :: 0.0
DEFAULT_DEPTH_BIAS :: 0
DEFAULT_DEPTH_BIAS_CLAMP :: 0.0
DEFAULT_MAX_ANISOTROPY :: 16
DEFAULT_MIP_LOD_BIAS :: 0.0
DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 4194304
DEFAULT_RENDER_TARGET_ARRAY_INDEX :: 0
DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT :: 65536
DEFAULT_SAMPLE_MASK :: 0xffffffff
DEFAULT_SCISSOR_ENDX :: 0
DEFAULT_SCISSOR_ENDY :: 0
DEFAULT_SCISSOR_STARTX :: 0
DEFAULT_SCISSOR_STARTY :: 0
DEFAULT_SLOPE_SCALED_DEPTH_BIAS :: 0.0
DEFAULT_STENCIL_READ_MASK :: 0xff
DEFAULT_STENCIL_REFERENCE :: 0
DEFAULT_STENCIL_WRITE_MASK :: 0xff
DEFAULT_VIEWPORT_AND_SCISSORRECT_INDEX :: 0
DEFAULT_VIEWPORT_HEIGHT :: 0
DEFAULT_VIEWPORT_MAX_DEPTH :: 0.0
DEFAULT_VIEWPORT_MIN_DEPTH :: 0.0
DEFAULT_VIEWPORT_TOPLEFTX :: 0
DEFAULT_VIEWPORT_TOPLEFTY :: 0
DEFAULT_VIEWPORT_WIDTH :: 0
DESCRIPTOR_RANGE_OFFSET_APPEND :: 0xffffffff
DRIVER_RESERVED_REGISTER_SPACE_VALUES_END :: 0xfffffff7
DRIVER_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0
DS_INPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968
DS_INPUT_CONTROL_POINT_REGISTER_COMPONENTS :: 4
DS_INPUT_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32
DS_INPUT_CONTROL_POINT_REGISTER_COUNT :: 32
DS_INPUT_CONTROL_POINT_REGISTER_READS_PER_INST :: 2
DS_INPUT_CONTROL_POINT_REGISTER_READ_PORTS :: 1
DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENTS :: 3
DS_INPUT_DOMAIN_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32
DS_INPUT_DOMAIN_POINT_REGISTER_COUNT :: 1
DS_INPUT_DOMAIN_POINT_REGISTER_READS_PER_INST :: 2
DS_INPUT_DOMAIN_POINT_REGISTER_READ_PORTS :: 1
DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4
DS_INPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32
DS_INPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32
DS_INPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2
DS_INPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1
DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1
DS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
DS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1
DS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2
DS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1
DS_OUTPUT_REGISTER_COMPONENTS :: 4
DS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
DS_OUTPUT_REGISTER_COUNT :: 32
FLOAT16_FUSED_TOLERANCE_IN_ULP :: 0.6
FLOAT32_MAX :: 3.402823466e+38
FLOAT32_TO_INTEGER_TOLERANCE_IN_ULP :: 0.6
FLOAT_TO_SRGB_EXPONENT_DENOMINATOR :: 2.4
FLOAT_TO_SRGB_EXPONENT_NUMERATOR :: 1.0
FLOAT_TO_SRGB_OFFSET :: 0.055
FLOAT_TO_SRGB_SCALE_1 :: 12.92
FLOAT_TO_SRGB_SCALE_2 :: 1.055
FLOAT_TO_SRGB_THRESHOLD :: 0.0031308
FTOI_INSTRUCTION_MAX_INPUT :: 2147483647.999
FTOI_INSTRUCTION_MIN_INPUT :: -2147483648.999
FTOU_INSTRUCTION_MAX_INPUT :: 4294967295.999
FTOU_INSTRUCTION_MIN_INPUT :: 0.0
GS_INPUT_INSTANCE_ID_READS_PER_INST :: 2
GS_INPUT_INSTANCE_ID_READ_PORTS :: 1
GS_INPUT_INSTANCE_ID_REGISTER_COMPONENTS :: 1
GS_INPUT_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
GS_INPUT_INSTANCE_ID_REGISTER_COUNT :: 1
GS_INPUT_PRIM_CONST_REGISTER_COMPONENTS :: 1
GS_INPUT_PRIM_CONST_REGISTER_COMPONENT_BIT_COUNT :: 32
GS_INPUT_PRIM_CONST_REGISTER_COUNT :: 1
GS_INPUT_PRIM_CONST_REGISTER_READS_PER_INST :: 2
GS_INPUT_PRIM_CONST_REGISTER_READ_PORTS :: 1
GS_INPUT_REGISTER_COMPONENTS :: 4
GS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
GS_INPUT_REGISTER_COUNT :: 32
GS_INPUT_REGISTER_READS_PER_INST :: 2
GS_INPUT_REGISTER_READ_PORTS :: 1
GS_INPUT_REGISTER_VERTICES :: 32
GS_MAX_INSTANCE_COUNT :: 32
GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES :: 1024
GS_OUTPUT_ELEMENTS :: 32
GS_OUTPUT_REGISTER_COMPONENTS :: 4
GS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
GS_OUTPUT_REGISTER_COUNT :: 32
HS_CONTROL_POINT_PHASE_INPUT_REGISTER_COUNT :: 32
HS_CONTROL_POINT_PHASE_OUTPUT_REGISTER_COUNT :: 32
HS_CONTROL_POINT_REGISTER_COMPONENTS :: 4
HS_CONTROL_POINT_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_CONTROL_POINT_REGISTER_READS_PER_INST :: 2
HS_CONTROL_POINT_REGISTER_READ_PORTS :: 1
HS_FORK_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff
HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENTS :: 1
HS_INPUT_FORK_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_INPUT_FORK_INSTANCE_ID_REGISTER_COUNT :: 1
HS_INPUT_FORK_INSTANCE_ID_REGISTER_READS_PER_INST :: 2
HS_INPUT_FORK_INSTANCE_ID_REGISTER_READ_PORTS :: 1
HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENTS :: 1
HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_INPUT_JOIN_INSTANCE_ID_REGISTER_COUNT :: 1
HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READS_PER_INST :: 2
HS_INPUT_JOIN_INSTANCE_ID_REGISTER_READ_PORTS :: 1
HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENTS :: 1
HS_INPUT_PRIMITIVE_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_INPUT_PRIMITIVE_ID_REGISTER_COUNT :: 1
HS_INPUT_PRIMITIVE_ID_REGISTER_READS_PER_INST :: 2
HS_INPUT_PRIMITIVE_ID_REGISTER_READ_PORTS :: 1
HS_JOIN_PHASE_INSTANCE_COUNT_UPPER_BOUND :: 0xffffffff
HS_MAXTESSFACTOR_LOWER_BOUND :: 1.0
HS_MAXTESSFACTOR_UPPER_BOUND :: 64.0
HS_OUTPUT_CONTROL_POINTS_MAX_TOTAL_SCALARS :: 3968
HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENTS :: 1
HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_OUTPUT_CONTROL_POINT_ID_REGISTER_COUNT :: 1
HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READS_PER_INST :: 2
HS_OUTPUT_CONTROL_POINT_ID_REGISTER_READ_PORTS :: 1
HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENTS :: 4
HS_OUTPUT_PATCH_CONSTANT_REGISTER_COMPONENT_BIT_COUNT :: 32
HS_OUTPUT_PATCH_CONSTANT_REGISTER_COUNT :: 32
HS_OUTPUT_PATCH_CONSTANT_REGISTER_READS_PER_INST :: 2
HS_OUTPUT_PATCH_CONSTANT_REGISTER_READ_PORTS :: 1
HS_OUTPUT_PATCH_CONSTANT_REGISTER_SCALAR_COMPONENTS :: 128
IA_DEFAULT_INDEX_BUFFER_OFFSET_IN_BYTES :: 0
IA_DEFAULT_PRIMITIVE_TOPOLOGY :: 0
IA_DEFAULT_VERTEX_BUFFER_OFFSET_IN_BYTES :: 0
IA_INDEX_INPUT_RESOURCE_SLOT_COUNT :: 1
IA_INSTANCE_ID_BIT_COUNT :: 32
IA_INTEGER_ARITHMETIC_BIT_COUNT :: 32
IA_PATCH_MAX_CONTROL_POINT_COUNT :: 32
IA_PRIMITIVE_ID_BIT_COUNT :: 32
IA_VERTEX_ID_BIT_COUNT :: 32
IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT :: 32
IA_VERTEX_INPUT_STRUCTURE_ELEMENTS_COMPONENTS :: 128
IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT :: 32
INTEGER_DIVIDE_BY_ZERO_QUOTIENT :: 0xffffffff
INTEGER_DIVIDE_BY_ZERO_REMAINDER :: 0xffffffff
KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL :: 0xffffffff
KEEP_UNORDERED_ACCESS_VIEWS :: 0xffffffff
LINEAR_GAMMA :: 1.0
MAJOR_VERSION :: 12
MAX_BORDER_COLOR_COMPONENT :: 1.0
MAX_DEPTH :: 1.0
MAX_LIVE_STATIC_SAMPLERS :: 2032
MAX_MAXANISOTROPY :: 16
MAX_MULTISAMPLE_SAMPLE_COUNT :: 32
MAX_POSITION_VALUE :: 3.402823466e+34
MAX_ROOT_COST :: 64
MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000
MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000
MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048
MAX_TEXTURE_DIMENSION_2_TO_EXP :: 17
MAX_VIEW_INSTANCE_COUNT :: 4
MINOR_VERSION :: 0
MIN_BORDER_COLOR_COMPONENT :: 0.0
MIN_DEPTH :: 0.0
MIN_MAXANISOTROPY :: 0
MIP_LOD_BIAS_MAX :: 15.99
MIP_LOD_BIAS_MIN :: -16.0
MIP_LOD_FRACTIONAL_BIT_COUNT :: 8
MIP_LOD_RANGE_BIT_COUNT :: 8
MULTISAMPLE_ANTIALIAS_LINE_WIDTH :: 1.4
NONSAMPLE_FETCH_OUT_OF_RANGE_ACCESS_RESULT :: 0
OS_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff
OS_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff8
PACKED_TILE :: 0xffffffff
PIXEL_ADDRESS_RANGE_BIT_COUNT :: 15
PRE_SCISSOR_PIXEL_ADDRESS_RANGE_BIT_COUNT :: 16
PS_CS_UAV_REGISTER_COMPONENTS :: 1
PS_CS_UAV_REGISTER_COUNT :: 8
PS_CS_UAV_REGISTER_READS_PER_INST :: 1
PS_CS_UAV_REGISTER_READ_PORTS :: 1
PS_FRONTFACING_DEFAULT_VALUE :: 0xffffffff
PS_FRONTFACING_FALSE_VALUE :: 0
PS_FRONTFACING_TRUE_VALUE :: 0xffffffff
PS_INPUT_REGISTER_COMPONENTS :: 4
PS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
PS_INPUT_REGISTER_COUNT :: 32
PS_INPUT_REGISTER_READS_PER_INST :: 2
PS_INPUT_REGISTER_READ_PORTS :: 1
PS_LEGACY_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.0
PS_OUTPUT_DEPTH_REGISTER_COMPONENTS :: 1
PS_OUTPUT_DEPTH_REGISTER_COMPONENT_BIT_COUNT :: 32
PS_OUTPUT_DEPTH_REGISTER_COUNT :: 1
PS_OUTPUT_MASK_REGISTER_COMPONENTS :: 1
PS_OUTPUT_MASK_REGISTER_COMPONENT_BIT_COUNT :: 32
PS_OUTPUT_MASK_REGISTER_COUNT :: 1
PS_OUTPUT_REGISTER_COMPONENTS :: 4
PS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
PS_OUTPUT_REGISTER_COUNT :: 8
PS_PIXEL_CENTER_FRACTIONAL_COMPONENT :: 0.5
RAW_UAV_SRV_BYTE_ALIGNMENT :: 16
RAYTRACING_AABB_BYTE_ALIGNMENT :: 8
RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT :: 256
RAYTRACING_INSTANCE_DESCS_BYTE_ALIGNMENT :: 16
RAYTRACING_MAX_ATTRIBUTE_SIZE_IN_BYTES :: 32
RAYTRACING_MAX_DECLARABLE_TRACE_RECURSION_DEPTH :: 31
RAYTRACING_MAX_GEOMETRIES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 16777216
RAYTRACING_MAX_INSTANCES_PER_TOP_LEVEL_ACCELERATION_STRUCTURE :: 16777216
RAYTRACING_MAX_PRIMITIVES_PER_BOTTOM_LEVEL_ACCELERATION_STRUCTURE :: 536870912
RAYTRACING_MAX_RAY_GENERATION_SHADER_THREADS :: 1073741824
RAYTRACING_MAX_SHADER_RECORD_STRIDE :: 4096
RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT :: 32
RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT :: 64
RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT :: 16
REQ_BLEND_OBJECT_COUNT_PER_DEVICE :: 4096
REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP :: 27
REQ_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096
REQ_DEPTH_STENCIL_OBJECT_COUNT_PER_DEVICE :: 4096
REQ_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 32
REQ_DRAW_VERTEX_COUNT_2_TO_EXP :: 32
REQ_FILTERING_HW_ADDRESSABLE_RESOURCE_DIMENSION :: 16384
REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT :: 1024
REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT :: 4096
REQ_MAXANISOTROPY :: 16
REQ_MIP_LEVELS :: 15
REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES :: 2048
REQ_RASTERIZER_OBJECT_COUNT_PER_DEVICE :: 4096
REQ_RENDER_TO_BUFFER_WINDOW_WIDTH :: 16384
REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_A_TERM :: 128
REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_B_TERM :: 0.25
REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM :: 2048
REQ_RESOURCE_VIEW_COUNT_PER_DEVICE_2_TO_EXP :: 20
REQ_SAMPLER_OBJECT_COUNT_PER_DEVICE :: 4096
REQ_SUBRESOURCES :: 30720
REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION :: 2048
REQ_TEXTURE1D_U_DIMENSION :: 16384
REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION :: 2048
REQ_TEXTURE2D_U_OR_V_DIMENSION :: 16384
REQ_TEXTURE3D_U_V_OR_W_DIMENSION :: 2048
REQ_TEXTURECUBE_DIMENSION :: 16384
RESINFO_INSTRUCTION_MISSING_COMPONENT_RETVAL :: 0
RESOURCE_BARRIER_ALL_SUBRESOURCES :: 0xffffffff
RS_SET_SHADING_RATE_COMBINER_COUNT :: 2
SHADER_IDENTIFIER_SIZE_IN_BYTES :: 32
SHADER_MAJOR_VERSION :: 5
SHADER_MAX_INSTANCES :: 65535
SHADER_MAX_INTERFACES :: 253
SHADER_MAX_INTERFACE_CALL_SITES :: 4096
SHADER_MAX_TYPES :: 65535
SHADER_MINOR_VERSION :: 1
SHIFT_INSTRUCTION_PAD_VALUE :: 0
SHIFT_INSTRUCTION_SHIFT_VALUE_BIT_COUNT :: 5
SIMULTANEOUS_RENDER_TARGET_COUNT :: 8
SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :: 65536
SMALL_RESOURCE_PLACEMENT_ALIGNMENT :: 4096
SO_BUFFER_MAX_STRIDE_IN_BYTES :: 2048
SO_BUFFER_MAX_WRITE_WINDOW_IN_BYTES :: 512
SO_BUFFER_SLOT_COUNT :: 4
SO_DDI_REGISTER_INDEX_DENOTING_GAP :: 0xffffffff
SO_NO_RASTERIZED_STREAM :: 0xffffffff
SO_OUTPUT_COMPONENT_COUNT :: 128
SO_STREAM_COUNT :: 4
SPEC_DATE_DAY :: 14
SPEC_DATE_MONTH :: 11
SPEC_DATE_YEAR :: 2014
SPEC_VERSION :: 1.16
SRGB_GAMMA :: 2.2
SRGB_TO_FLOAT_DENOMINATOR_1 :: 12.92
SRGB_TO_FLOAT_DENOMINATOR_2 :: 1.055
SRGB_TO_FLOAT_EXPONENT :: 2.4
SRGB_TO_FLOAT_OFFSET :: 0.055
SRGB_TO_FLOAT_THRESHOLD :: 0.04045
SRGB_TO_FLOAT_TOLERANCE_IN_ULP :: 0.5
STANDARD_COMPONENT_BIT_COUNT :: 32
STANDARD_COMPONENT_BIT_COUNT_DOUBLED :: 64
STANDARD_MAXIMUM_ELEMENT_ALIGNMENT_BYTE_MULTIPLE :: 4
STANDARD_PIXEL_COMPONENT_COUNT :: 128
STANDARD_PIXEL_ELEMENT_COUNT :: 32
STANDARD_VECTOR_SIZE :: 4
STANDARD_VERTEX_ELEMENT_COUNT :: 32
STANDARD_VERTEX_TOTAL_COMPONENT_COUNT :: 64
SUBPIXEL_FRACTIONAL_BIT_COUNT :: 8
SUBTEXEL_FRACTIONAL_BIT_COUNT :: 8
SYSTEM_RESERVED_REGISTER_SPACE_VALUES_END :: 0xffffffff
SYSTEM_RESERVED_REGISTER_SPACE_VALUES_START :: 0xfffffff0
TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR :: 64
TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 64
TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR :: 63
TESSELLATOR_MAX_TESSELLATION_FACTOR :: 64
TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR :: 2
TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR :: 1
TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR :: 1
TEXEL_ADDRESS_RANGE_BIT_COUNT :: 16
TEXTURE_DATA_PITCH_ALIGNMENT :: 256
TEXTURE_DATA_PLACEMENT_ALIGNMENT :: 512
TILED_RESOURCE_TILE_SIZE_IN_BYTES :: 65536
TRACKED_WORKLOAD_MAX_INSTANCES :: 32
UAV_COUNTER_PLACEMENT_ALIGNMENT :: 4096
UAV_SLOT_COUNT :: 64
UNBOUND_MEMORY_ACCESS_RESULT :: 0
VIDEO_DECODE_MAX_ARGUMENTS :: 10
VIDEO_DECODE_MAX_HISTOGRAM_COMPONENTS :: 4
VIDEO_DECODE_MIN_BITSTREAM_OFFSET_ALIGNMENT :: 256
VIDEO_DECODE_MIN_HISTOGRAM_OFFSET_ALIGNMENT :: 256
VIDEO_DECODE_STATUS_MACROBLOCKS_AFFECTED_UNKNOWN :: 0xffffffff
VIDEO_PROCESS_MAX_FILTERS :: 32
VIDEO_PROCESS_STEREO_VIEWS :: 2
VIEWPORT_AND_SCISSORRECT_MAX_INDEX :: 15
VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE :: 16
VIEWPORT_BOUNDS_MAX :: 32767
VIEWPORT_BOUNDS_MIN :: -32768
VS_INPUT_REGISTER_COMPONENTS :: 4
VS_INPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
VS_INPUT_REGISTER_COUNT :: 32
VS_INPUT_REGISTER_READS_PER_INST :: 2
VS_INPUT_REGISTER_READ_PORTS :: 1
VS_OUTPUT_REGISTER_COMPONENTS :: 4
VS_OUTPUT_REGISTER_COMPONENT_BIT_COUNT :: 32
VS_OUTPUT_REGISTER_COUNT :: 32
WHQL_CONTEXT_COUNT_FOR_RESOURCE_LIMIT :: 10
WHQL_DRAWINDEXED_INDEX_COUNT_2_TO_EXP :: 25
WHQL_DRAW_VERTEX_COUNT_2_TO_EXP :: 25
SHADER_COMPONENT_MAPPING_MASK :: 0x7
SHADER_COMPONENT_MAPPING_SHIFT :: 3
FILTER_REDUCTION_TYPE_MASK :: 0x3
FILTER_REDUCTION_TYPE_SHIFT :: 7
FILTER_TYPE_MASK :: 0x3
MIN_FILTER_SHIFT :: 4
MAG_FILTER_SHIFT :: 2
MIP_FILTER_SHIFT :: 0
ANISOTROPIC_FILTERING_BIT :: 0x40
INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT :: 1024
SHADING_RATE_X_AXIS_SHIFT :: 2
SHADING_RATE_VALID_MASK :: 3
RETURN_PARAMETER_INDEX :: -1
SHADER_REQUIRES_DOUBLES :: 0x00000001
SHADER_REQUIRES_EARLY_DEPTH_STENCIL :: 0x00000002
SHADER_REQUIRES_UAVS_AT_EVERY_STAGE :: 0x00000004
SHADER_REQUIRES_64_UAVS :: 0x00000008
SHADER_REQUIRES_MINIMUM_PRECISION :: 0x00000010
SHADER_REQUIRES_11_1_DOUBLE_EXTENSIONS :: 0x00000020
SHADER_REQUIRES_11_1_SHADER_EXTENSIONS :: 0x00000040
SHADER_REQUIRES_LEVEL_9_COMPARISON_FILTERING :: 0x00000080
SHADER_REQUIRES_TILED_RESOURCES :: 0x00000100
SHADER_REQUIRES_STENCIL_REF :: 0x00000200
SHADER_REQUIRES_INNER_COVERAGE :: 0x00000400
SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS :: 0x00000800
SHADER_REQUIRES_ROVS :: 0x00001000
SHADER_REQUIRES_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER :: 0x00002000
+228
View File
@@ -0,0 +1,228 @@
package directx_d3d_compiler
foreign import d3dcompiler "d3dcompiler_47.lib"
D3DCOMPILER_DLL_A :: "d3dcompiler_47.dll"
COMPILER_VERSION :: 47
import "../dxgi"
BOOL :: dxgi.BOOL
IID :: dxgi.IID
SIZE_T :: dxgi.SIZE_T
HRESULT :: dxgi.HRESULT
IUnknown :: dxgi.IUnknown
IUnknown_VTable :: dxgi.IUnknown_VTable
@(default_calling_convention="stdcall", link_prefix="D3D")
foreign d3dcompiler {
ReadFileToBlob :: proc(pFileName: [^]u16, ppContents: ^^ID3DBlob) -> HRESULT ---
WriteBlobToFile :: proc(pBlob: ^ID3DBlob, pFileName: [^]u16, bOverwrite: BOOL) -> HRESULT ---
Compile :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT ---
Compile2 :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, SecondaryDataFlags: u32, pSecondaryData: rawptr, SecondaryDataSize: SIZE_T, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT ---
CompileFromFile :: proc(pFileName: [^]u16, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, pEntrypoint: cstring, pTarget: cstring, Flags1: u32, Flags2: u32, ppCode: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT ---
Preprocess :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pSourceName: cstring, pDefines: ^SHADER_MACRO, pInclude: ^ID3DInclude, ppCodeText: ^^ID3DBlob, ppErrorMsgs: ^^ID3DBlob) -> HRESULT ---
GetDebugInfo :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppDebugInfo: ^^ID3DBlob) -> HRESULT ---
Reflect :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, pInterface: ^IID, ppReflector: ^rawptr) -> HRESULT ---
ReflectLibrary :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, riid: ^IID, ppReflector: ^rawptr) -> HRESULT ---
Disassemble :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, ppDisassembly: ^^ID3DBlob) -> HRESULT ---
DisassembleRegion :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, szComments: cstring, StartByteOffset: SIZE_T, NumInsts: SIZE_T, pFinishByteOffset: ^SIZE_T, ppDisassembly: ^^ID3DBlob) -> HRESULT ---
CreateLinker :: proc(ppLinker: ^^ID3D11Linker) -> HRESULT ---
LoadModule :: proc(pSrcData: rawptr, cbSrcDataSize: SIZE_T, ppModule: ^^ID3D11Module) -> HRESULT ---
GetTraceInstructionOffsets :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Flags: u32, StartInstIndex: SIZE_T, NumInsts: SIZE_T, pOffsets: ^SIZE_T, pTotalInsts: ^SIZE_T) -> HRESULT ---
GetInputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT ---
GetOutputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT ---
GetInputAndOutputSignatureBlob :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, ppSignatureBlob: ^^ID3DBlob) -> HRESULT ---
StripShader :: proc(pShaderBytecode: rawptr, BytecodeLength: SIZE_T, uStripFlags: u32, ppStrippedBlob: ^^ID3DBlob) -> HRESULT ---
GetBlobPart :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Part: BLOB_PART, Flags: u32, ppPart: ^^ID3DBlob) -> HRESULT ---
SetBlobPart :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, Part: BLOB_PART, Flags: u32, pPart: rawptr, PartSize: SIZE_T, ppNewShader: ^^ID3DBlob) -> HRESULT ---
CreateBlob :: proc(Size: SIZE_T, ppBlob: ^^ID3DBlob) -> HRESULT ---
CompressShaders :: proc(uNumShaders: u32, pShaderData: ^SHADER_DATA, uFlags: u32, ppCompressedData: ^^ID3DBlob) -> HRESULT ---
DecompressShaders :: proc(pSrcData: rawptr, SrcDataSize: SIZE_T, uNumShaders: u32, uStartIndex: u32, pIndices: ^u32, uFlags: u32, ppShaders: ^^ID3DBlob, pTotalShaders: ^u32) -> HRESULT ---
Disassemble10Effect :: proc(pEffect: ^ID3D10Effect, Flags: u32, ppDisassembly: ^^ID3DBlob) -> HRESULT ---
}
D3DCOMPILE :: enum u32 { // TODO: make bit_field
DEBUG = 1 << 0,
SKIP_VALIDATION = 1 << 1,
SKIP_OPTIMIZATION = 1 << 2,
PACK_MATRIX_ROW_MAJOR = 1 << 3,
PACK_MATRIX_COLUMN_MAJOR = 1 << 4,
PARTIAL_PRECISION = 1 << 5,
FORCE_VS_SOFTWARE_NO_OPT = 1 << 6,
FORCE_PS_SOFTWARE_NO_OPT = 1 << 7,
NO_PRESHADER = 1 << 8,
AVOID_FLOW_CONTROL = 1 << 9,
PREFER_FLOW_CONTROL = 1 << 10,
ENABLE_STRICTNESS = 1 << 11,
ENABLE_BACKWARDS_COMPATIBILITY = 1 << 12,
IEEE_STRICTNESS = 1 << 13,
OPTIMIZATION_LEVEL0 = 1 << 14,
OPTIMIZATION_LEVEL1 = 0,
OPTIMIZATION_LEVEL2 = (1 << 14)|(1 << 15), // Added manually
OPTIMIZATION_LEVEL3 = 1 << 15,
RESERVED16 = 1 << 16,
RESERVED17 = 1 << 17,
WARNINGS_ARE_ERRORS = 1 << 18,
RESOURCES_MAY_ALIAS = 1 << 19,
ENABLE_UNBOUNDED_DESCRIPTOR_TABLES = 1 << 20,
ALL_RESOURCES_BOUND = 1 << 21,
DEBUG_NAME_FOR_SOURCE = 1 << 22,
DEBUG_NAME_FOR_BINARY = 1 << 23,
}
EFFECT :: enum u32 { // TODO: make bit_field
CHILD_EFFECT = 1 << 0,
ALLOW_SLOW_OPS = 1 << 1,
}
FLAGS2 :: enum u32 { // TODO: make bit_field
FORCE_ROOT_SIGNATURE_LATEST = 0,
FORCE_ROOT_SIGNATURE_1_0 = 1 << 4,
FORCE_ROOT_SIGNATURE_1_1 = 1 << 5,
}
SECDATA :: enum u32 { // TODO: make bit_field
MERGE_UAV_SLOTS = 0x00000001,
PRESERVE_TEMPLATE_SLOTS = 0x00000002,
REQUIRE_TEMPLATE_MATCH = 0x00000004,
}
DISASM_ENABLE_COLOR_CODE :: 0x00000001
DISASM_ENABLE_DEFAULT_VALUE_PRINTS :: 0x00000002
DISASM_ENABLE_INSTRUCTION_NUMBERING :: 0x00000004
DISASM_ENABLE_INSTRUCTION_CYCLE :: 0x00000008
DISASM_DISABLE_DEBUG_INFO :: 0x00000010
DISASM_ENABLE_INSTRUCTION_OFFSET :: 0x00000020
DISASM_INSTRUCTION_ONLY :: 0x00000040
DISASM_PRINT_HEX_LITERALS :: 0x00000080
GET_INST_OFFSETS_INCLUDE_NON_EXECUTABLE :: 0x00000001
COMPRESS_SHADER_KEEP_ALL_PARTS :: 0x00000001
SHADER_MACRO :: struct {
Name: cstring,
Definition: cstring,
}
ID3D10Blob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102"
ID3D10Blob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}}
ID3D10Blob :: struct #raw_union {
#subtype iunknown: IUnknown,
using id3d10blob_vtable: ^ID3D10Blob_VTable,
}
ID3D10Blob_VTable :: struct {
using iunknown_vtable: IUnknown_VTable,
GetBufferPointer: proc "stdcall" (this: ^ID3D10Blob) -> rawptr,
GetBufferSize: proc "stdcall" (this: ^ID3D10Blob) -> SIZE_T,
}
ID3DBlob :: ID3D10Blob
ID3DBlob_VTable :: ID3D10Blob_VTable
INCLUDE_TYPE :: enum i32 {
INCLUDE_LOCAL = 0,
INCLUDE_SYSTEM = 1,
_10_INCLUDE_LOCAL = 0,
_10_INCLUDE_SYSTEM = 1,
INCLUDE_FORCE_DWORD = 2147483647,
}
ID3DInclude :: struct {
vtable: ^ID3DInclude_VTable,
}
ID3DInclude_VTable :: struct {
Open: proc "stdcall" (this: ^ID3DInclude, IncludeType: INCLUDE_TYPE, pFileName: cstring, pParentData: rawptr, ppData: ^rawptr, pBytes: ^u32) -> HRESULT,
Close: proc "stdcall" (this: ^ID3DInclude, pData: rawptr) -> HRESULT,
}
ID3D11Module :: struct #raw_union {
#subtype iunknown: IUnknown,
using id3d11module_vtable: ^ID3D11Module_VTable,
}
ID3D11Module_VTable :: struct {
using iunknown_vtable: IUnknown_VTable,
CreateInstance: proc "stdcall" (this: ^ID3D11Module, pNamespace: cstring, ppModuleInstance: ^^ID3D11ModuleInstance) -> HRESULT,
}
ID3D11ModuleInstance :: struct #raw_union {
#subtype iunknown: IUnknown,
using id3d11moduleinstance_vtable: ^ID3D11ModuleInstance_VTable,
}
ID3D11ModuleInstance_VTable :: struct {
using iunknown_vtable: IUnknown_VTable,
BindConstantBuffer: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, cbDstOffset: u32) -> HRESULT,
BindConstantBufferByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, cbDstOffset: u32) -> HRESULT,
BindResource: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT,
BindResourceByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT,
BindSampler: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT,
BindSamplerByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT,
BindUnorderedAccessView: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSlot: u32, uDstSlot: u32, uCount: u32) -> HRESULT,
BindUnorderedAccessViewByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pName: cstring, uDstSlot: u32, uCount: u32) -> HRESULT,
BindResourceAsUnorderedAccessView: proc "stdcall" (this: ^ID3D11ModuleInstance, uSrcSrvSlot: u32, uDstUavSlot: u32, uCount: u32) -> HRESULT,
BindResourceAsUnorderedAccessViewByName: proc "stdcall" (this: ^ID3D11ModuleInstance, pSrvName: cstring, uDstUavSlot: u32, uCount: u32) -> HRESULT,
}
ID3D11Linker :: struct #raw_union {
#subtype iunknown: IUnknown,
using id3d11linker_vtable: ^ID3D11Linker_VTable,
}
ID3D11Linker_VTable :: struct {
using iunknown_vtable: IUnknown_VTable,
Link: proc "stdcall" (this: ^ID3D11Linker, pEntry: ^ID3D11ModuleInstance, pEntryName: cstring, pTargetName: cstring, uFlags: u32, ppShaderBlob: ^^ID3DBlob, ppErrorBuffer: ^^ID3DBlob) -> HRESULT,
UseLibrary: proc "stdcall" (this: ^ID3D11Linker, pLibraryMI: ^ID3D11ModuleInstance) -> HRESULT,
AddClipPlaneFromCBuffer: proc "stdcall" (this: ^ID3D11Linker, uCBufferSlot: u32, uCBufferEntry: u32) -> HRESULT,
}
pD3DCompile :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: cstring, a6: cstring, a7: u32, a8: u32, a9: ^^ID3DBlob, a10: ^^ID3DBlob) -> HRESULT
pD3DPreprocess :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: cstring, a3: ^SHADER_MACRO, a4: ^ID3DInclude, a5: ^^ID3DBlob, a6: ^^ID3DBlob) -> HRESULT
pD3DDisassemble :: #type proc "c" (a0: rawptr, a1: SIZE_T, a2: u32, a3: cstring, a4: ^^ID3DBlob) -> HRESULT
D3DCOMPILER_STRIP_FLAGS :: enum u32 { // TODO: make bit_field
REFLECTION_DATA = 0x1,
DEBUG_INFO = 0x2,
TEST_BLOBS = 0x4,
PRIVATE_DATA = 0x8,
ROOT_SIGNATURE = 0x10,
FORCE_DWORD = 0x7fffffff,
}
BLOB_PART :: enum i32 {
INPUT_SIGNATURE_BLOB = 0,
OUTPUT_SIGNATURE_BLOB = 1,
INPUT_AND_OUTPUT_SIGNATURE_BLOB = 2,
PATCH_CONSTANT_SIGNATURE_BLOB = 3,
ALL_SIGNATURE_BLOB = 4,
DEBUG_INFO = 5,
LEGACY_SHADER = 6,
XNA_PREPASS_SHADER = 7,
XNA_SHADER = 8,
PDB = 9,
PRIVATE_DATA = 10,
ROOT_SIGNATURE = 11,
DEBUG_NAME = 12,
TEST_ALTERNATE_SHADER = 32768,
TEST_COMPILE_DETAILS = 32769,
TEST_COMPILE_PERF = 32770,
TEST_COMPILE_REPORT = 32771,
}
SHADER_DATA :: struct {
pBytecode: rawptr,
BytecodeLength: SIZE_T,
}
ID3D10Effect :: struct {
// ????
}
Binary file not shown.
Binary file not shown.
+1170
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2009-2019 GroundStorm Studios, LLC. (http://ggpo.net)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+526
View File
@@ -0,0 +1,526 @@
package ggpo
foreign import lib "GGPO.lib"
import c "core:c/libc"
Session :: distinct rawptr
MAX_PLAYERS :: 4
MAX_PREDICTION_FRAMES :: 8
MAX_SPECTATORS :: 32
SPECTATOR_INPUT_INTERVAL :: 4
PlayerHandle :: distinct c.int
PlayerType :: enum c.int {
LOCAL,
REMOTE,
SPECTATOR,
}
/*
* The Player structure used to describe players in add_player
*
* size: Should be set to the size_of(Player)
*
* type: One of the PlayerType values describing how inputs should be handled
* Local players must have their inputs updated every frame via
* add_local_inputs. Remote players values will come over the
* network.
*
* player_num: The player number. Should be between 1 and the number of players
* In the game (e.g. in a 2 player game, either 1 or 2).
*
* If type == PLAYERTYPE_REMOTE:
*
* remote.ip_address: The ip address of the ggpo session which will host this
* player.
*
* remote.port: The port where udp packets should be sent to reach this player.
* All the local inputs for this session will be sent to this player at
* ip_address:port.
*
*/
Player :: struct {
size: c.int,
type: PlayerType,
player_num: c.int,
using u: struct #raw_union {
local: struct {},
remove: struct {
ip_address: [32]byte,
port: u16,
},
},
}
LocalEndpoint :: struct {
player_num: c.int,
}
ErrorCode :: enum c.int {
OK = 0,
SUCCESS = 0,
GENERAL_FAILURE = -1,
INVALID_SESSION = 1,
INVALID_PLAYER_HANDLE = 2,
PLAYER_OUT_OF_RANGE = 3,
PREDICTION_THRESHOLD = 4,
UNSUPPORTED = 5,
NOT_SYNCHRONIZED = 6,
IN_ROLLBACK = 7,
INPUT_DROPPED = 8,
PLAYER_DISCONNECTED = 9,
TOO_MANY_SPECTATORS = 10,
INVALID_REQUEST = 11,
}
INVALID_HANDLE :: PlayerHandle(-1)
/*
* The EventCode enumeration describes what type of event just happened.
*
* CONNECTED_TO_PEER - Handshake with the game running on the
* other side of the network has been completed.
*
* SYNCHRONIZING_WITH_PEER - Beginning the synchronization
* process with the client on the other end of the networking. The count
* and total fields in the u.synchronizing struct of the Event
* object indicate progress.
*
* SYNCHRONIZED_WITH_PEER - The synchronziation with this
* peer has finished.
*
* RUNNING - All the clients have synchronized. You may begin
* sending inputs with synchronize_inputs.
*
* DISCONNECTED_FROM_PEER - The network connection on
* the other end of the network has closed.
*
* TIMESYNC - The time synchronziation code has determined
* that this client is too far ahead of the other one and should slow
* down to ensure fairness. The u.timesync.frames_ahead parameter in
* the Event object indicates how many frames the client is.
*
*/
EventCode :: enum c.int {
CONNECTED_TO_PEER = 1000,
SYNCHRONIZING_WITH_PEER = 1001,
SYNCHRONIZED_WITH_PEER = 1002,
RUNNING = 1003,
DISCONNECTED_FROM_PEER = 1004,
TIMESYNC = 1005,
CONNECTION_INTERRUPTED = 1006,
CONNECTION_RESUMED = 1007,
}
/*
* The Event structure contains an asynchronous event notification sent
* by the on_event callback. See EventCode, above, for a detailed
* explanation of each event.
*/
Event :: struct {
code: EventCode,
using u: struct #raw_union {
connected: struct {
player: PlayerHandle,
},
synchronizing: struct {
player: PlayerHandle,
count: c.int,
total: c.int,
},
synchronized: struct {
player: PlayerHandle,
},
disconnected: struct {
player: PlayerHandle,
},
timesync: struct {
frames_ahead: c.int,
},
connection_interrupted: struct {
player: PlayerHandle,
disconnect_timeout: c.int,
},
connection_resumed: struct {
player: PlayerHandle,
},
},
}
/*
* The SessionCallbacks structure contains the callback functions that
* your application must implement. GGPO.net will periodically call these
* functions during the game. All callback functions must be implemented.
*/
SessionCallbacks :: struct {
/*
* begin_game callback - This callback has been deprecated. You must
* implement it, but should ignore the 'game' parameter.
*/
begin_game: proc "c" (game: cstring) -> bool,
/*
* save_game_state - The client should allocate a buffer, copy the
* entire contents of the current game state into it, and copy the
* length into the len parameter. Optionally, the client can compute
* a checksum of the data and store it in the checksum argument.
*/
save_game_state: proc "c" (buffer: ^[^]byte, len: ^c.int, checksum: ^c.int, frame: c.int) -> bool,
/*
* load_game_state - GGPO.net will call this function at the beginning
* of a rollback. The buffer and len parameters contain a previously
* saved state returned from the save_game_state function. The client
* should make the current game state match the state contained in the
* buffer.
*/
load_game_state: proc "c" (buffer: [^]byte, len: c.int) -> bool,
/*
* log_game_state - Used in diagnostic testing. The client should use
* the log function to write the contents of the specified save
* state in a human readible form.
*/
log_game_state: proc "c" (filename: cstring, buffer: [^]byte, len: c.int) -> bool,
/*
* free_buffer - Frees a game state allocated in save_game_state. You
* should deallocate the memory contained in the buffer.
*/
free_buffer: proc "c" (buffer: rawptr),
/*
* advance_frame - Called during a rollback. You should advance your game
* state by exactly one frame. Before each frame, call synchronize_input
* to retrieve the inputs you should use for that frame. After each frame,
* you should call advance_frame to notify GGPO.net that you're
* finished.
*
* The flags parameter is reserved. It can safely be ignored at this time.
*/
advance_frame: proc "c" (flags: c.int) -> bool,
/*
* on_event - Notification that something has happened. See the EventCode
* structure above for more information.
*/
on_event: proc "c" (info: ^Event) -> bool,
}
/*
* The NetworkStats function contains some statistics about the current
* session.
*
* network.send_queue_len - The length of the queue containing UDP packets
* which have not yet been acknowledged by the end client. The length of
* the send queue is a rough indication of the quality of the connection.
* The longer the send queue, the higher the round-trip time between the
* clients. The send queue will also be longer than usual during high
* packet loss situations.
*
* network.recv_queue_len - The number of inputs currently buffered by the
* GGPO.net network layer which have yet to be validated. The length of
* the prediction queue is roughly equal to the current frame number
* minus the frame number of the last packet in the remote queue.
*
* network.ping - The roundtrip packet transmission time as calcuated
* by GGPO.net. This will be roughly equal to the actual round trip
* packet transmission time + 2 the interval at which you call idle
* or advance_frame.
*
* network.kbps_sent - The estimated bandwidth used between the two
* clients, in kilobits per second.
*
* timesync.local_frames_behind - The number of frames GGPO.net calculates
* that the local client is behind the remote client at this instant in
* time. For example, if at this instant the current game client is running
* frame 1002 and the remote game client is running frame 1009, this value
* will mostly likely roughly equal 7.
*
* timesync.remote_frames_behind - The same as local_frames_behind, but
* calculated from the perspective of the remote player.
*
*/
NetworkStats :: struct {
network: struct {
send_queue_len: c.int,
recv_queue_len: c.int,
ping: c.int,
kbps_sent: c.int,
},
timesync: struct {
local_frames_behind: c.int,
remote_frames_behind: c.int,
},
}
@(default_calling_convention="c")
@(link_prefix="ggpo_")
foreign lib {
/*
* start_session --
*
* Used to being a new GGPO.net session. The ggpo object returned by start_session
* uniquely identifies the state for this session and should be passed to all other
* functions.
*
* session - An out parameter to the new ggpo session object.
*
* cb - A SessionCallbacks structure which contains the callbacks you implement
* to help GGPO.net synchronize the two games. You must implement all functions in
* cb, even if they do nothing but 'return true';
*
* game - The name of the game. This is used internally for GGPO for logging purposes only.
*
* num_players - The number of players which will be in this game. The number of players
* per session is fixed. If you need to change the number of players or any player
* disconnects, you must start a new session.
*
* input_size - The size of the game inputs which will be passsed to add_local_input.
*
* local_port - The port GGPO should bind to for UDP traffic.
*/
start_session :: proc(session: ^^Session,
cb: ^SessionCallbacks,
game: cstring,
num_players: c.int,
input_size: c.int,
localport: u16) -> ErrorCode ---
/*
* add_player --
*
* Must be called for each player in the session (e.g. in a 3 player session, must
* be called 3 times).
*
* player - A Player struct used to describe the player.
*
* handle - An out parameter to a handle used to identify this player in the future.
* (e.g. in the on_event callbacks).
*/
add_player :: proc(session: ^Session,
player: ^Player,
handle: ^PlayerHandle) -> ErrorCode ---
/*
* start_synctest --
*
* Used to being a new GGPO.net sync test session. During a sync test, every
* frame of execution is run twice: once in prediction mode and once again to
* verify the result of the prediction. If the checksums of your save states
* do not match, the test is aborted.
*
* cb - A SessionCallbacks structure which contains the callbacks you implement
* to help GGPO.net synchronize the two games. You must implement all functions in
* cb, even if they do nothing but 'return true';
*
* game - The name of the game. This is used internally for GGPO for logging purposes only.
*
* num_players - The number of players which will be in this game. The number of players
* per session is fixed. If you need to change the number of players or any player
* disconnects, you must start a new session.
*
* input_size - The size of the game inputs which will be passsed to add_local_input.
*
* frames - The number of frames to run before verifying the prediction. The
* recommended value is 1.
*
*/
start_synctest :: proc(session: ^^Session,
cb: ^SessionCallbacks,
game: cstring,
num_players: c.int,
input_size: c.int,
frames: c.int) -> ErrorCode ---
/*
* start_spectating --
*
* Start a spectator session.
*
* cb - A SessionCallbacks structure which contains the callbacks you implement
* to help GGPO.net synchronize the two games. You must implement all functions in
* cb, even if they do nothing but 'return true';
*
* game - The name of the game. This is used internally for GGPO for logging purposes only.
*
* num_players - The number of players which will be in this game. The number of players
* per session is fixed. If you need to change the number of players or any player
* disconnects, you must start a new session.
*
* input_size - The size of the game inputs which will be passsed to add_local_input.
*
* local_port - The port GGPO should bind to for UDP traffic.
*
* host_ip - The IP address of the host who will serve you the inputs for the game. Any
* player partcipating in the session can serve as a host.
*
* host_port - The port of the session on the host
*/
start_spectating :: proc(session: ^^Session,
cb: ^SessionCallbacks,
game: cstring,
num_players: c.int,
input_size: c.int,
local_port: u16,
host_ip: cstring,
host_port: u16) -> ErrorCode ---
/*
* close_session --
* Used to close a session. You must call close_session to
* free the resources allocated in start_session.
*/
close_session :: proc(session: ^Session) -> ErrorCode ---
/*
* set_frame_delay --
*
* Change the amount of frames ggpo will delay local input. Must be called
* before the first call to synchronize_input.
*/
set_frame_delay :: proc(session: ^Session,
player: PlayerHandle,
frame_delay: c.int) -> ErrorCode ---
/*
* idle --
* Should be called periodically by your application to give GGPO.net
* a chance to do some work. Most packet transmissions and rollbacks occur
* in idle.
*
* timeout - The amount of time GGPO.net is allowed to spend in this function,
* in milliseconds.
*/
idle :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* add_local_input --
*
* Used to notify GGPO.net of inputs that should be trasmitted to remote
* players. add_local_input must be called once every frame for
* all player of type PLAYERTYPE_LOCAL.
*
* player - The player handle returned for this player when you called
* add_local_player.
*
* values - The controller inputs for this player.
*
* size - The size of the controller inputs. This must be exactly equal to the
* size passed into start_session.
*/
add_local_input :: proc(session: ^Session,
player: PlayerHandle,
values: rawptr,
size: c.int) -> ErrorCode ---
/*
* synchronize_input --
*
* You should call synchronize_input before every frame of execution,
* including those frames which happen during rollback.
*
* values - When the function returns, the values parameter will contain
* inputs for this frame for all players. The values array must be at
* least (size * players) large.
*
* size - The size of the values array.
*
* disconnect_flags - Indicated whether the input in slot (1 << flag) is
* valid. If a player has disconnected, the input in the values array for
* that player will be zeroed and the i-th flag will be set. For example,
* if only player 3 has disconnected, disconnect flags will be 8 (i.e. 1 << 3).
*/
synchronize_input :: proc(session: ^Session,
values: rawptr,
size: c.int,
disconnect_flags: ^c.int) -> ErrorCode ---
/*
* disconnect_player --
*
* Disconnects a remote player from a game. Will return ERRORCODE_PLAYER_DISCONNECTED
* if you try to disconnect a player who has already been disconnected.
*/
disconnect_player :: proc(session: ^Session,
player: PlayerHandle) -> ErrorCode ---
/*
* advance_frame --
*
* You should call advance_frame to notify GGPO.net that you have
* advanced your gamestate by a single frame. You should call this everytime
* you advance the gamestate by a frame, even during rollbacks. GGPO.net
* may call your save_state callback before this function returns.
*/
advance_frame :: proc(session: ^Session) -> ErrorCode ---
/*
* get_network_stats --
*
* Used to fetch some statistics about the quality of the network connection.
*
* player - The player handle returned from the add_player function you used
* to add the remote player.
*
* stats - Out parameter to the network statistics.
*/
get_network_stats :: proc(session: ^Session,
player: PlayerHandle,
stats: ^NetworkStats) -> ErrorCode ---
/*
* set_disconnect_timeout --
*
* Sets the disconnect timeout. The session will automatically disconnect
* from a remote peer if it has not received a packet in the timeout window.
* You will be notified of the disconnect via a EVENTCODE_DISCONNECTED_FROM_PEER
* event.
*
* Setting a timeout value of 0 will disable automatic disconnects.
*
* timeout - The time in milliseconds to wait before disconnecting a peer.
*/
set_disconnect_timeout :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* set_disconnect_notify_start --
*
* The time to wait before the first EVENTCODE_NETWORK_INTERRUPTED timeout
* will be sent.
*
* timeout - The amount of time which needs to elapse without receiving a packet
* before the EVENTCODE_NETWORK_INTERRUPTED event is sent.
*/
set_disconnect_notify_start :: proc(session: ^Session,
timeout: c.int) -> ErrorCode ---
/*
* log --
*
* Used to write to the ggpo.net log. In the current versions of the
* SDK, a log file is only generated if the "quark.log" environment
* variable is set to 1. This will change in future versions of the
* SDK.
*/
log :: proc(session: ^Session, fmt: cstring, #c_vararg args: ..any) ---
/*
* logv --
*
* A varargs compatible version of log. See log for
* more details.
*/
logv :: proc(session: ^Session, fmt: cstring, args: c.va_list) ---
}
+3 -3
View File
@@ -1,6 +1,6 @@
package glfw
when ODIN_OS == "windows" {
when ODIN_OS == .Windows {
import win32 "core:sys/windows"
foreign import glfw { "lib/glfw3.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" }
@@ -12,7 +12,7 @@ when ODIN_OS == "windows" {
GetWin32Window :: proc(window: WindowHandle) -> win32.HWND ---
GetWGLContext :: proc(window: WindowHandle) -> rawptr ---
}
} else when ODIN_OS == "linux" {
} else when ODIN_OS == .Linux {
// TODO: Native Linux
// Display* glfwGetX11Display(void);
// RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
@@ -24,7 +24,7 @@ when ODIN_OS == "windows" {
// struct wl_display* glfwGetWaylandDisplay(void);
// struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
// struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
} else when ODIN_OS == "darwin" {
} else when ODIN_OS == .Darwin {
// TODO: Native Darwin
// CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
// id glfwGetCocoaWindow(GLFWwindow* window);
+2 -2
View File
@@ -309,7 +309,7 @@ init :: proc(ctx: ^Context) {
ctx.draw_frame = default_draw_frame
ctx._style = default_style
ctx.style = &ctx._style
ctx.text_input = strings.builder_from_slice(ctx._text_store[:])
ctx.text_input = strings.builder_from_bytes(ctx._text_store[:])
}
begin :: proc(ctx: ^Context) {
@@ -353,7 +353,7 @@ end :: proc(ctx: ^Context) {
/* reset input state */
ctx.key_pressed_bits = {} // clear
strings.reset_builder(&ctx.text_input)
strings.builder_reset(&ctx.text_input)
ctx.mouse_pressed_bits = {} // clear
ctx.mouse_released_bits = {} // clear
ctx.scroll_delta = Vec2{0, 0}
+34 -84
View File
@@ -2,19 +2,26 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
handle :: distinct rawptr
/* SIMD alignment in bytes. Currently set to 64 bytes in preparation for future AVX-512 optimizations. */
SIMD_ALIGNMENT :: 64
/* SIMD alignment in bytes. Currently set to 32 bytes in preparation for future AVX optimizations. */
SIMD_ALIGNMENT :: 32
LOG_LEVEL_DEBUG :: 4
LOG_LEVEL_INFO :: 3
LOG_LEVEL_WARNING :: 2
LOG_LEVEL_ERROR :: 1
log_level :: enum c.int {
LOG_LEVEL_DEBUG = 4,
LOG_LEVEL_INFO = 3,
LOG_LEVEL_WARNING = 2,
LOG_LEVEL_ERROR = 1,
}
channel :: enum u8 {
@@ -153,13 +160,13 @@ result :: enum c.int {
FAILED_TO_STOP_BACKEND_DEVICE = -303,
}
MIN_CHANNELS :: 1
MAX_CHANNELS :: 32
MAX_CHANNELS :: 254
MAX_FILTER_ORDER :: 8
stream_format :: enum c.int {
pcm = 0,
}
@@ -170,9 +177,9 @@ stream_layout :: enum c.int {
}
dither_mode :: enum c.int {
none = 0,
rectangle,
triangle,
none = 0,
rectangle,
triangle,
}
format :: enum c.int {
@@ -219,7 +226,6 @@ channel_mix_mode :: enum c.int {
rectangular = 0, /* Simple averaging based on the plane(s) the channel is sitting on. */
simple, /* Drop excess channels; zeroed out extra channels. */
custom_weights, /* Use custom weights specified in ma_channel_router_config. */
planar_blend = rectangular,
default = rectangular,
}
@@ -252,6 +258,10 @@ lcg :: struct {
state: i32,
}
/* Spinlocks are 32-bit for compatibility reasons. */
spinlock :: distinct u32
NO_THREADING :: false
when !NO_THREADING {
@@ -267,10 +277,8 @@ thread_priority :: enum c.int {
default = 0,
}
/* Spinlocks are 32-bit for compatibility reasons. */
spinlock :: distinct u32
when ODIN_OS == "windows" {
when ODIN_OS == .Windows {
thread :: distinct rawptr
mutex :: distinct rawptr
event :: distinct rawptr
@@ -292,69 +300,6 @@ when ODIN_OS == "windows" {
}
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/*
Locks a spinlock.
*/
spinlock_lock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
/*
Locks a spinlock, but does not yield() when looping.
*/
spinlock_lock_noyield :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
/*
Unlocks a spinlock.
*/
spinlock_unlock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
/*
Creates a mutex.
A mutex must be created from a valid context. A mutex is initially unlocked.
*/
mutex_init :: proc(pMutex: ^mutex) -> result ---
/*
Deletes a mutex.
*/
mutex_uninit :: proc(pMutex: ^mutex) ---
/*
Locks a mutex with an infinite timeout.
*/
mutex_lock :: proc(pMutex: ^mutex) ---
/*
Unlocks a mutex.
*/
mutex_unlock :: proc(pMutex: ^mutex) ---
/*
Initializes an auto-reset event.
*/
event_init :: proc(pEvent: ^event) -> result ---
/*
Uninitializes an auto-reset event.
*/
event_uninit :: proc(pEvent: ^event) ---
/*
Waits for the specified auto-reset event to become signalled.
*/
event_wait :: proc(pEvent: ^event) -> result ---
/*
Signals the specified auto-reset event.
*/
event_signal :: proc(pEvent: ^event) -> result ---
}
} /* NO_THREADING */
@@ -380,17 +325,22 @@ foreign lib {
result_description :: proc(result: result) -> cstring ---
/*
malloc(). Calls MA_MALLOC().
malloc()
*/
malloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
/*
realloc(). Calls MA_REALLOC().
calloc()
*/
calloc :: proc(sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
/*
realloc()
*/
realloc :: proc(p: rawptr, sz: c.size_t, pAllocationCallbacks: ^allocation_callbacks) -> rawptr ---
/*
free(). Calls MA_FREE().
free()
*/
free :: proc(p: rawptr, pAllocationCallbacks: ^allocation_callbacks) ---
@@ -412,7 +362,7 @@ foreign lib {
/*
Blends two frames in floating point format.
*/
blend_f32 :: proc(pOut, pInA, pInB: ^f32, factor: f32, channels: u32) ---
blend_f32 :: proc(pOut, pInA, pInB: [^]f32, factor: f32, channels: u32) ---
/*
Retrieves the size of a sample in bytes for the given format.
+186 -115
View File
@@ -2,9 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
*************************************************************************************************************************************************************
@@ -32,77 +36,106 @@ linear_resampler_config :: struct {
}
linear_resampler :: struct {
config: linear_resampler_config,
config: linear_resampler_config,
inAdvanceInt: u32,
inAdvanceFrac: u32,
inTimeInt: u32,
inTimeFrac: u32,
x0: struct #raw_union {
f32: [MAX_CHANNELS]f32,
s16: [MAX_CHANNELS]i16,
f32: [^]f32,
s16: [^]i16,
}, /* The previous input frame. */
x1: struct #raw_union {
f32: [MAX_CHANNELS]f32,
s16: [MAX_CHANNELS]i16,
f32: [^]f32,
s16: [^]i16,
}, /* The next input frame. */
lpf: lpf,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
resampling_backend :: struct {}
resampling_backend_vtable :: struct {
onGetHeapSize: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result,
onInit: proc "c" (pUserData: rawptr, pConfig: ^resampler_config, pHeap: rawptr, ppBackend: ^^resampling_backend) -> result,
onUninit: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pAllocationCallbacks: ^allocation_callbacks),
onProcess: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result,
onSetRate: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, sampleRateIn: u32, sampleRateOut: u32) -> result, /* Optional. Rate changes will be disabled. */
onGetInputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */
onGetOutputLatency: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> u64, /* Optional. Latency will be reported as 0. */
onGetRequiredInputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, outputFrameCount: u64, pInputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */
onGetExpectedOutputFrameCount: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result, /* Optional. Latency mitigation will be disabled. */
onReset: proc "c" (pUserData: rawptr, pBackend: ^resampling_backend) -> result,
}
resample_algorithm :: enum {
linear = 0, /* Fastest, lowest quality. Optional low-pass filtering. Default. */
speex,
custom,
}
resampler_config :: struct {
format: format, /* Must be either ma_format_f32 or ma_format_s16. */
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
algorithm: resample_algorithm,
format: format, /* Must be either ma_format_f32 or ma_format_s16. */
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
algorithm: resample_algorithm, /* When set to ma_resample_algorithm_custom, pBackendVTable will be used. */
pBackendVTable: ^resampling_backend_vtable,
pBackendUserData: rawptr,
linear: struct {
lpfOrder: u32,
lpfNyquistFactor: f64,
},
speex: struct {
quality: c.int, /* 0 to 10. Defaults to 3. */
},
}
resampler :: struct {
config: resampler_config,
pBackend: ^resampling_backend,
pBackendVTable: ^resampling_backend_vtable,
pBackendUserData: rawptr,
format: format,
channels: u32,
sampleRateIn: u32,
sampleRateOut: u32,
state: struct #raw_union {
linear: linear_resampler,
speex: struct {
pSpeexResamplerState: rawptr, /* SpeexResamplerState* */
},
},
}, /* State for stock resamplers so we can avoid a malloc. For stock resamplers, pBackend will point here. */
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
linear_resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32) -> linear_resampler_config ---
linear_resampler_init :: proc(pConfig: ^linear_resampler_config, pResampler: ^linear_resampler) -> result ---
linear_resampler_uninit :: proc(pResampler: ^linear_resampler) ---
linear_resampler_get_heap_size :: proc(pConfig: ^linear_resampler_config, pHeapSizeInBytes: ^c.size_t) -> result ---
linear_resampler_init_preallocated :: proc(pConfig: ^linear_resampler_config, pHeap: rawptr, pResampler: ^linear_resampler) -> result ---
linear_resampler_init :: proc(pConfig: ^linear_resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^linear_resampler) -> result ---
linear_resampler_uninit :: proc(pResampler: ^linear_resampler, pAllocationCallbacks: ^allocation_callbacks) ---
linear_resampler_process_pcm_frames :: proc(pResampler: ^linear_resampler, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result ---
linear_resampler_set_rate :: proc(pResampler: ^linear_resampler, sampleRateIn, sampleRateOut: u32) -> result ---
linear_resampler_set_rate_ratio :: proc(pResampler: ^linear_resampler, ratioInOut: f32) -> result ---
linear_resampler_get_required_input_frame_count :: proc(pResampler: ^linear_resampler, outputFrameCount: u64) -> u64 ---
linear_resampler_get_expected_output_frame_count :: proc(pResampler: ^linear_resampler, inputFrameCount: u64) -> u64 ---
linear_resampler_get_input_latency :: proc(pResampler: ^linear_resampler) -> u64 ---
linear_resampler_get_output_latency :: proc(pResampler: ^linear_resampler) -> u64 ---
linear_resampler_get_required_input_frame_count :: proc(pResampler: ^linear_resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
linear_resampler_get_expected_output_frame_count :: proc(pResampler: ^linear_resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
linear_resampler_reset :: proc(pResampler: ^linear_resampler) -> result ---
resampler_config_init :: proc(format: format, channels: u32, sampleRateIn, sampleRateOut: u32, algorithm: resample_algorithm) -> resampler_config ---
resampler_get_heap_size :: proc(pConfig: ^resampler_config, pHeapSizeInBytes: ^c.size_t) -> result ---
resampler_init_preallocated :: proc(pConfig: ^resampler_config, pHeap: rawptr, pResampler: ^resampler) -> result ---
/*
Initializes a new resampler object from a config.
*/
resampler_init :: proc(pConfig: ^resampler_config, pResampler: ^resampler) -> result ---
resampler_init :: proc(pConfig: ^resampler_config, pAllocationCallbacks: ^allocation_callbacks, pResampler: ^resampler) -> result ---
/*
Uninitializes a resampler.
*/
resampler_uninit :: proc(pResampler: ^resampler) ---
resampler_uninit :: proc(pResampler: ^resampler, pAllocationCallbacks: ^allocation_callbacks) ---
/*
Converts the given input data.
@@ -141,23 +174,6 @@ foreign lib {
*/
resampler_set_rate_ratio :: proc(pResampler: ^resampler, ratio: f32) -> result ---
/*
Calculates the number of whole input frames that would need to be read from the client in order to output the specified
number of output frames.
The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
read from the input buffer in order to output the specified number of output frames.
*/
resampler_get_required_input_frame_count :: proc(pResampler: ^resampler, outputFrameCount: u64) -> u64 ---
/*
Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
input frames.
*/
resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64) -> u64 ---
/*
Retrieves the latency introduced by the resampler in input frames.
*/
@@ -167,6 +183,26 @@ foreign lib {
Retrieves the latency introduced by the resampler in output frames.
*/
resampler_get_output_latency :: proc(pResampler: ^resampler) -> u64 ---
/*
Calculates the number of whole input frames that would need to be read from the client in order to output the specified
number of output frames.
The returned value does not include cached input frames. It only returns the number of extra frames that would need to be
read from the input buffer in order to output the specified number of output frames.
*/
resampler_get_required_input_frame_count :: proc(pResampler: ^resampler, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
/*
Calculates the number of whole output frames that would be output after fully reading and consuming the specified number of
input frames.
*/
resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
/*
Resets the resampler's timer and clears it's internal cache.
*/
resampler_reset :: proc(pResampler: ^resampler) -> result ---
}
@@ -175,42 +211,63 @@ foreign lib {
Channel Conversion
**************************************************************************************************************************************************************/
channel_conversion_path :: enum c.int {
unknown,
passthrough,
mono_out, /* Converting to mono. */
mono_in, /* Converting from mono. */
shuffle, /* Simple shuffle. Will use this when all channels are present in both input and output channel maps, but just in a different order. */
weights, /* Blended based on weights. */
}
mono_expansion_mode :: enum c.int {
duplicate = 0, /* The default. */
average, /* Average the mono channel across all channels. */
stereo_only, /* Duplicate to the left and right channels only and ignore the others. */
default = duplicate,
}
channel_converter_config :: struct {
format: format,
channelsIn: u32,
channelsOut: u32,
channelMapIn: [MAX_CHANNELS]channel,
channelMapOut: [MAX_CHANNELS]channel,
mixingMode: channel_mix_mode,
weights: [MAX_CHANNELS][MAX_CHANNELS]f32, /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
format: format,
channelsIn: u32,
channelsOut: u32,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
mixingMode: channel_mix_mode,
ppWeights: ^[^]f32, /* [in][out]. Only used when mixingMode is set to ma_channel_mix_mode_custom_weights. */
}
channel_converter :: struct {
format: format,
channelsIn: u32,
channelsOut: u32,
channelMapIn: [MAX_CHANNELS]channel,
channelMapOut: [MAX_CHANNELS]channel,
mixingMode: channel_mix_mode,
weights: struct #raw_union {
f32: [MAX_CHANNELS][MAX_CHANNELS]f32,
s16: [MAX_CHANNELS][MAX_CHANNELS]i32,
format: format,
channelsIn: u32,
channelsOut: u32,
mixingMode: channel_mix_mode,
conversionPath: channel_conversion_path,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
pShuffleTable: [^]u8,
weights: struct #raw_union { /* [in][out] */
f32: ^[^]f32,
s16: ^[^]i32,
},
isPassthrough: b8,
isSimpleShuffle: b8,
isSimpleMonoExpansion: b8,
isStereoToMono: b8,
shuffleTable: [MAX_CHANNELS]u8,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
channel_converter_config_init :: proc(format: format, channelsIn: u32, pChannelMapIn: ^channel, channelsOut: u32, pChannelMapOut: ^channel, mixingMode: channel_mix_mode) -> channel_converter_config ---
channel_converter_config_init :: proc(format: format, channelsIn: u32, pChannelMapIn: [^]channel, channelsOut: u32, pChannelMapOut: [^]channel, mixingMode: channel_mix_mode) -> channel_converter_config ---
channel_converter_init :: proc(pConfig: ^channel_converter_config, pConverter: ^channel_converter) -> result ---
channel_converter_uninit :: proc(pConverter: ^channel_converter) ---
channel_converter_process_pcm_frames :: proc(pConverter: ^channel_converter, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
channel_converter_get_heap_size :: proc(pConfig: ^channel_converter_config, pHeapSizeInBytes: ^c.size_t) -> result ---
channel_converter_init_preallocated :: proc(pConfig: ^channel_converter_config, pHeap: rawptr, pConverter: ^channel_converter) -> result ---
channel_converter_init :: proc(pConfig: ^channel_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^channel_converter) -> result ---
channel_converter_uninit :: proc(pConverter: ^channel_converter, pAllocationCallbacks: ^allocation_callbacks) ---
channel_converter_process_pcm_frames :: proc(pConverter: ^channel_converter, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
channel_converter_get_input_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
channel_converter_get_output_channel_map :: proc(pConverter: ^channel_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
}
@@ -220,32 +277,39 @@ Data Conversion
**************************************************************************************************************************************************************/
data_converter_config :: struct {
formatIn: format,
formatOut: format,
channelsIn: u32,
channelsOut: u32,
sampleRateIn: u32,
sampleRateOut: u32,
channelMapIn: [MAX_CHANNELS]channel,
channelMapOut: [MAX_CHANNELS]channel,
ditherMode: dither_mode,
channelMixMode: channel_mix_mode,
channelWeights: [MAX_CHANNELS][MAX_CHANNELS]f32, /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */
resampling: struct {
algorithm: resample_algorithm,
allowDynamicSampleRate: b32,
linear: struct {
lpfOrderL: u32,
lpfNyquistFactor: f64,
},
speex: struct {
quality: c.int,
},
},
formatIn: format,
formatOut: format,
channelsIn: u32,
channelsOut: u32,
sampleRateIn: u32,
sampleRateOut: u32,
pChannelMapIn: [^]channel,
pChannelMapOut: [^]channel,
ditherMode: dither_mode,
channelMixMode: channel_mix_mode,
ppChannelWeights: ^[^]f32, /* [in][out]. Only used when channelMixMode is set to ma_channel_mix_mode_custom_weights. */
allowDynamicSampleRate: b32,
resampling: resampler_config,
}
data_converter_execution_path :: enum c.int {
passthrough, /* No conversion. */
format_only, /* Only format conversion. */
channels_only, /* Only channel conversion. */
resample_only, /* Only resampling. */
resample_first, /* All conversions, but resample as the first step. */
channels_first, /* All conversions, but channels as the first step. */
}
data_converter :: struct {
config: data_converter_config,
formatIn: format,
formatOut: format,
channelsIn: u32,
channelsOut: u32,
sampleRateIn: u32,
sampleRateOut: u32,
ditherMode: dither_mode,
executionPath: data_converter_execution_path, /* The execution path the data converter will follow when processing. */
channelConverter: channel_converter,
resampler: resampler,
hasPreFormatConversion: b8,
@@ -253,6 +317,10 @@ data_converter :: struct {
hasChannelConverter: b8,
hasResampler: b8,
isPassthrough: b8,
/* Memory management. */
_ownsHeap: b8,
_pHeap: rawptr,
}
@@ -261,15 +329,20 @@ foreign lib {
data_converter_config_init_default :: proc() -> data_converter_config ---
data_converter_config_init :: proc(formatIn, formatOut: format, channelsIn, channelsOut: u32, sampleRateIn, sampleRateOut: u32) -> data_converter_config ---
data_converter_init :: proc(pConfig: ^data_converter_config, pConverter: ^data_converter) -> result ---
data_converter_uninit :: proc(pConverter: ^data_converter) ---
data_converter_get_heap_size :: proc(pConfig: ^data_converter_config, pHeapSizeInBytes: ^c.size_t) -> result ---
data_converter_init_preallocated :: proc(pConfig: ^data_converter_config, pHeap: rawptr, pConverter: ^data_converter) -> result ---
data_converter_init :: proc(pConfig: ^data_converter_config, pAllocationCallbacks: ^allocation_callbacks, pConverter: ^data_converter) -> result ---
data_converter_uninit :: proc(pConverter: ^data_converter, pAllocationCallbacks: ^allocation_callbacks) ---
data_converter_process_pcm_frames :: proc(pConverter: ^data_converter, pFramesIn: rawptr, pFrameCountIn: ^u64, pFramesOut: rawptr, pFrameCountOut: ^u64) -> result ---
data_converter_set_rate :: proc(pConverter: ^data_converter, sampleRateIn, sampleRateOut: u32) -> result ---
data_converter_set_rate_ratio :: proc(pConverter: ^data_converter, ratioInOut: f32) -> result ---
data_converter_get_required_input_frame_count :: proc(pConverter: ^data_converter, outputFrameCount: u64) -> u64 ---
data_converter_get_expected_output_frame_count :: proc(pConverter: ^data_converter, inputFrameCount: u64) -> u64 ---
data_converter_get_input_latency :: proc(pConverter: ^data_converter) -> u64 ---
data_converter_get_output_latency :: proc(pConverter: ^data_converter) -> u64 ---
data_converter_get_required_input_frame_count :: proc(pConverter: ^data_converter, outputFrameCount: u64, pInputFrameCount: ^u64) -> result ---
data_converter_get_expected_output_frame_count :: proc(pConverter: ^data_converter, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result ---
data_converter_get_input_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
data_converter_get_output_channel_map :: proc(pConverter: ^data_converter, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
data_converter_reset :: proc(pConverter: ^data_converter) -> result ---
}
/************************************************************************************************************************************************************
@@ -328,43 +401,40 @@ CHANNEL_INDEX_NULL :: 255
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/* Retrieves the channel position of the specified channel based on miniaudio's default channel map. */
channel_map_get_default_channel :: proc(channelCount: u32, channelIndex: u32) -> channel ---
/*
Retrieves the channel position of the specified channel in the given channel map.
The pChannelMap parameter can be null, in which case miniaudio's default channel map will be assumed.
*/
channel_map_get_channel :: proc(pChannelMap: ^channel, channelCount: u32, channelIndex: u32) -> channel ---
channel_map_get_channel :: proc(pChannelMap: [^]channel, channelCount: u32, channelIndex: u32) -> channel ---
/*
Initializes a blank channel map.
When a blank channel map is specified anywhere it indicates that the native channel map should be used.
*/
channel_map_init_blank :: proc(channels: u32, pChannelMap: ^channel) ---
channel_map_init_blank :: proc(pChannelMap: [^]channel, channels: u32) ---
/*
Helper for retrieving a standard channel map.
The output channel map buffer must have a capacity of at least `channels`.
The output channel map buffer must have a capacity of at least `channelMapCap`.
*/
get_standard_channel_map :: proc(standardChannelMap: standard_channel_map, channels: u32, pChannelMap: ^channel) ---
channel_map_init_standard :: proc(standardChannelMap: standard_channel_map, pChannelMap: [^]channel, channelMapCap: c.size_t, channels: u32) ---
/*
Copies a channel map.
Both input and output channel map buffers must have a capacity of at at least `channels`.
*/
channel_map_copy :: proc(pOut: ^channel, pIn: ^channel, channels: u32) ---
channel_map_copy :: proc(pOut: [^]channel, pIn: [^]channel, channels: u32) ---
/*
Copies a channel map if one is specified, otherwise copies the default channel map.
The output buffer must have a capacity of at least `channels`. If not NULL, the input channel map must also have a capacity of at least `channels`.
*/
channel_map_copy_or_default :: proc(pOut: ^channel, pIn: ^channel, channels: u32) ---
channel_map_copy_or_default :: proc(pOut: [^]channel, channelMapCapOut: c.size_t, pIn: [^]channel, channels: u32) ---
/*
@@ -374,12 +444,12 @@ foreign lib {
is usually treated as a passthrough.
Invalid channel maps:
- A channel map with no channels
- A channel map with more than one channel and a mono channel
- A channel map with no channels
- A channel map with more than one channel and a mono channel
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_valid :: proc(channels: u32, pChannelMap: ^channel) -> b32 ---
channel_map_is_valid :: proc(pChannelMap: [^]channel, channels: u32) -> b32 ---
/*
Helper for comparing two channel maps for equality.
@@ -388,23 +458,24 @@ foreign lib {
Both channels map buffers must have a capacity of at least `channels`.
*/
channel_map_equal :: proc(channels: u32, pChannelMapA, pChannelMapB: ^channel) -> b32 ---
channel_map_is_equal :: proc(pChannelMapA, pChannelMapB: [^]channel, channels: u32) -> b32 ---
/*
Helper for determining if a channel map is blank (all channels set to MA_CHANNEL_NONE).
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_blank :: proc(channels: u32, pChannelMap: ^channel) -> b32 ---
channel_map_is_blank :: proc(pChannelMap: [^]channel, channels: u32) -> b32 ---
/*
Helper for determining whether or not a channel is present in the given channel map.
The channel map buffer must have a capacity of at least `channels`.
*/
channel_map_contains_channel_position :: proc(channels: u32, pChannelMap: ^channel, channelPosition: channel) -> b32 ---
channel_map_contains_channel_position :: proc(channels: u32, pChannelMap: [^]channel, channelPosition: channel) -> b32 ---
}
/************************************************************************************************************************************************************
Conversion Helpers
@@ -457,9 +528,9 @@ foreign lib {
rb_uninit :: proc(pRB: ^rb) ---
rb_reset :: proc(pRB: ^rb) ---
rb_acquire_read :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result ---
rb_commit_read :: proc(pRB: ^rb, sizeInBytes: c.size_t, pBufferOut: rawptr) -> result ---
rb_commit_read :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result ---
rb_acquire_write :: proc(pRB: ^rb, pSizeInBytes: ^c.size_t, ppBufferOut: ^rawptr) -> result ---
rb_commit_write :: proc(pRB: ^rb, sizeInBytes: c.size_t, pBufferOut: rawptr) -> result ---
rb_commit_write :: proc(pRB: ^rb, sizeInBytes: c.size_t) -> result ---
rb_seek_read :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result ---
rb_seek_write :: proc(pRB: ^rb, offsetInBytes: c.size_t) -> result ---
rb_pointer_distance :: proc(pRB: ^rb) -> i32 --- /* Returns the distance between the write pointer and the read pointer. Should never be negative for a correct program. Will return the number of bytes that can be read before the read pointer hits the write pointer. */
+59 -56
View File
@@ -2,10 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
@@ -19,68 +22,63 @@ you do your own synchronization.
decoding_backend_config :: struct {
preferredFormat: format,
seekPointCount: u32, /* Set to > 0 to generate a seektable if the decoding backend supports it. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
decoding_backend_config_init :: proc(preferredFormat: format) -> decoding_backend_config ---
decoding_backend_config_init :: proc(preferredFormat: format, seekPointCount: u32) -> decoding_backend_config ---
}
decoding_backend_vtable :: struct {
onInit: proc "c" (pUserData: rawptr, onRead: decoder_read_proc, onSeek: decoder_seek_proc, onTell: decoder_tell_proc, pReadSeekTellUserData: rawptr, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result,
onInitFile: proc "c" (pUserData: rawptr, pFilePath: cstring, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */
onInitFile: proc "c" (pUserData: rawptr, pFilePath: cstring, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */
onInitFileW: proc "c" (pUserData: rawptr, pFilePath: [^]c.wchar_t, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */
onInitMemory: proc "c" (pUserData: rawptr, pData: rawptr, dataSize: c.size_t, pConfig: ^decoding_backend_config, pAllocationCallbacks: ^allocation_callbacks, ppBackend: ^^data_source) -> result, /* Optional. */
onUninit: proc "c" (pUserData: rawptr, pBackend: ^data_source, pAllocationCallbacks: ^allocation_callbacks),
onGetChannelMap: proc "c" (pUserData: rawptr, pBackend: ^data_source, pChannelMap: ^channel, channelMapCap: c.size_t) -> result,
}
/* TODO: Convert read and seek to be consistent with the VFS API (ma_result return value, bytes read moved to an output parameter). */
decoder_read_proc :: proc "c" (pDecoder: ^decoder, pBufferOut: rawptr, bytesToRead: c.size_t) -> c.size_t /* Returns the number of bytes read. */
decoder_seek_proc :: proc "c" (pDecoder: ^decoder, byteOffset: i64, origin: seek_origin) -> b32
decoder_read_proc :: proc "c" (pDecoder: ^decoder, pBufferOut: rawptr, bytesToRead: c.size_t, pBytesRead: ^c.size_t) -> result /* Returns the number of bytes read. */
decoder_seek_proc :: proc "c" (pDecoder: ^decoder, byteOffset: i64, origin: seek_origin) -> result
decoder_tell_proc :: proc "c" (pDecoder: ^decoder, pCursor: ^i64) -> result
decoder_config :: struct {
format: format, /* Set to 0 or ma_format_unknown to use the stream's internal format. */
channels: u32, /* Set to 0 to use the stream's internal channels. */
sampleRate: u32, /* Set to 0 to use the stream's internal sample rate. */
channelMap: [MAX_CHANNELS]channel,
channelMixMode: channel_mix_mode,
ditherMode: dither_mode,
resampling: struct {
algorithm: resample_algorithm,
linear: struct {
lpfOrder: u32,
},
speex: struct {
quality: c.int,
},
},
format: format, /* Set to 0 or ma_format_unknown to use the stream's internal format. */
channels: u32, /* Set to 0 to use the stream's internal channels. */
sampleRate: u32, /* Set to 0 to use the stream's internal sample rate. */
channelMap: [^]channel,
channelMixMode: channel_mix_mode,
ditherMode: dither_mode,
resampling: resampler_config,
allocationCallbacks: allocation_callbacks,
encodingFormat: encoding_format,
ppCustomBackendVTables: ^^decoding_backend_vtable,
seekPointCount: u32, /* When set to > 0, specifies the number of seek points to use for the generation of a seek table. Not all decoding backends support this. */
ppCustomBackendVTables: ^[^]decoding_backend_vtable,
customBackendCount: u32,
pCustomBackendUserData: rawptr,
}
decoder :: struct {
ds: data_source_base,
pBackend: ^data_source, /* The decoding backend we'll be pulling data from. */
pBackendVTable: ^^decoding_backend_vtable, /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */
pBackendUserData: rawptr,
onRead: decoder_read_proc,
onSeek: decoder_seek_proc,
onTell: decoder_tell_proc,
pUserData: rawptr,
ds: data_source_base,
pBackend: ^data_source, /* The decoding backend we'll be pulling data from. */
pBackendVTable: ^decoding_backend_vtable, /* The vtable for the decoding backend. This needs to be stored so we can access the onUninit() callback. */
pBackendUserData: rawptr,
onRead: decoder_read_proc,
onSeek: decoder_seek_proc,
onTell: decoder_tell_proc,
pUserData: rawptr,
readPointerInPCMFrames: u64, /* In output sample rate. Used for keeping track of how many frames are available for decoding. */
outputFormat: format,
outputChannels: u32,
outputSampleRate: u32,
outputChannelMap: [MAX_CHANNELS]channel,
converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */
allocationCallbacks: allocation_callbacks,
outputFormat: format,
outputChannels: u32,
outputSampleRate: u32,
converter: data_converter, /* <-- Data conversion is achieved by running frames through this. */
pInputCache: rawptr, /* In input format. Can be null if it's not needed. */
inputCacheCap: u64, /* The capacity of the input cache. */
inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */
inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */
allocationCallbacks: allocation_callbacks,
data: struct #raw_union {
vfs: struct {
pVFS: ^vfs,
@@ -111,6 +109,25 @@ foreign lib {
*/
decoder_uninit :: proc(pDecoder: ^decoder) -> result ---
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
decoder_read_pcm_frames :: proc(pDecoder: ^decoder, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
decoder_seek_to_pcm_frame :: proc(pDecoder: ^decoder, frameIndex: u64) -> result ---
/*
Retrieves the decoder's output data format.
*/
decoder_get_data_format :: proc(pDecoder: ^decoder, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result ---
/*
Retrieves the current position of the read cursor in PCM frames.
*/
@@ -130,21 +147,7 @@ foreign lib {
This function is not thread safe without your own synchronization.
*/
decoder_get_length_in_pcm_frames :: proc(pDecoder: ^decoder) -> u64 ---
/*
Reads PCM frames from the given decoder.
This is not thread safe without your own synchronization.
*/
decoder_read_pcm_frames :: proc(pDecoder: ^decoder, pFramesOut: rawptr, frameCount: u64) -> u64 ---
/*
Seeks to a PCM frame based on it's absolute index.
This is not thread safe without your own synchronization.
*/
decoder_seek_to_pcm_frame :: proc(pDecoder: ^decoder, frameIndex: u64) -> result ---
decoder_get_length_in_pcm_frames :: proc(pDecoder: ^decoder, pLength: ^u64) -> result ---
/*
Retrieves the number of frames that can be read before reaching the end.
@@ -164,4 +167,4 @@ foreign lib {
decode_from_vfs :: proc(pVFS: ^vfs, pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
decode_file :: proc(pFilePath: cstring, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
decode_memory :: proc(pData: rawptr, dataSize: c.size_t, pConfig: ^decoder_config, pFrameCountOut: ^u64, ppPCMFramesOut: ^rawptr) -> result ---
}
}
+496 -299
View File
File diff suppressed because it is too large Load Diff
+238 -165
View File
@@ -2,28 +2,29 @@ package miniaudio
import "core:c"
SUPPORT_WASAPI :: ODIN_OS == "windows"
SUPPORT_DSOUND :: ODIN_OS == "windows"
SUPPORT_WINMM :: ODIN_OS == "windows"
SUPPORT_COREAUDIO :: ODIN_OS == "darwin"
SUPPORT_SNDIO :: ODIN_OS == "openbsd"
SUPPORT_AUDIO4 :: ODIN_OS == "openbsd" || ODIN_OS == "netbsd"
SUPPORT_OSS :: ODIN_OS == "freebsd"
SUPPORT_PULSEAUDIO :: ODIN_OS == "linux"
SUPPORT_ALSA :: ODIN_OS == "linux"
SUPPORT_JACK :: ODIN_OS == "windows"
SUPPORT_AAUDIO :: ODIN_OS == "android"
SUPPORT_OPENSL :: ODIN_OS == "android"
SUPPORT_WEBAUDIO :: ODIN_OS == "emscripten"
SUPPORT_WASAPI :: ODIN_OS == .Windows
SUPPORT_DSOUND :: ODIN_OS == .Windows
SUPPORT_WINMM :: ODIN_OS == .Windows
SUPPORT_COREAUDIO :: ODIN_OS == .Darwin
SUPPORT_SNDIO :: ODIN_OS == .OpenBSD
SUPPORT_AUDIO4 :: false // ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD
SUPPORT_OSS :: ODIN_OS == .FreeBSD
SUPPORT_PULSEAUDIO :: ODIN_OS == .Linux
SUPPORT_ALSA :: ODIN_OS == .Linux
SUPPORT_JACK :: ODIN_OS == .Windows
SUPPORT_AAUDIO :: false // ODIN_OS == .Android
SUPPORT_OPENSL :: false // ODIN_OS == .Android
SUPPORT_WEBAUDIO :: false // ODIN_OS == .Emscripten
SUPPORT_CUSTOM :: true
SUPPORT_NULL :: ODIN_OS != "emscripten"
STATE_UNINITIALIZED :: 0
STATE_STOPPED :: 1 /* The device's default state after initialization. */
STATE_STARTED :: 2 /* The device is started and is requesting and/or delivering audio data. */
STATE_STARTING :: 3 /* Transitioning from a stopped state to started. */
STATE_STOPPING :: 4 /* Transitioning from a started state to stopped. */
SUPPORT_NULL :: true // ODIN_OS != .Emscripten
device_state :: enum c.int {
uninitialized = 0,
stopped = 1, /* The device's default state after initialization. */
started = 2, /* The device is started and is requesting and/or delivering audio data. */
starting = 3, /* Transitioning from a stopped state to started. */
stopping = 4, /* Transitioning from a started state to stopped. */
}
when SUPPORT_WASAPI {
@@ -56,6 +57,96 @@ backend :: enum c.int {
BACKEND_COUNT :: len(backend)
/*
Device job thread. This is used by backends that require asynchronous processing of certain
operations. It is not used by all backends.
The device job thread is made up of a thread and a job queue. You can post a job to the thread with
ma_device_job_thread_post(). The thread will do the processing of the job.
*/
device_job_thread_config :: struct {
noThread: b32, /* Set this to true if you want to process jobs yourself. */
jobQueueCapacity: u32,
jobQueueFlags: u32,
}
device_job_thread :: struct {
thread: thread,
jobQueue: job_queue,
_hasThread: b32,
}
/* Device notification types. */
device_notification_type :: enum c.int {
started,
stopped,
rerouted,
interruption_began,
interruption_ended,
}
device_notification :: struct {
pDevice: ^device,
type: device_notification_type,
data: struct #raw_union {
started: struct {
_unused: c.int,
},
stopped: struct {
_unused: c.int,
},
rerouted: struct {
_unused: c.int,
},
interruption: struct {
_unused: c.int,
},
},
}
/*
The notification callback for when the application should be notified of a change to the device.
This callback is used for notifying the application of changes such as when the device has started,
stopped, rerouted or an interruption has occurred. Note that not all backends will post all
notification types. For example, some backends will perform automatic stream routing without any
kind of notification to the host program which means miniaudio will never know about it and will
never be able to fire the rerouted notification. You should keep this in mind when designing your
program.
The stopped notification will *not* get fired when a device is rerouted.
Parameters
----------
pNotification (in)
A pointer to a structure containing information about the event. Use the `pDevice` member of
this object to retrieve the relevant device. The `type` member can be used to discriminate
against each of the notification types.
Remarks
-------
Do not restart or uninitialize the device from the callback.
Not all notifications will be triggered by all backends, however the started and stopped events
should be reliable for all backends. Some backends do not have a good way to detect device
stoppages due to unplugging the device which may result in the stopped callback not getting
fired. This has been observed with at least one BSD variant.
The rerouted notification is fired *after* the reroute has occurred. The stopped notification will
*not* get fired when a device is rerouted. The following backends are known to do automatic stream
rerouting, but do not have a way to be notified of the change:
* DirectSound
The interruption notifications are used on mobile platforms for detecting when audio is interrupted
due to things like an incoming phone call. Currently this is only implemented on iOS. None of the
Android backends will report this notification.
*/
device_notification_proc :: proc "c" (pNotification: ^device_notification)
/*
The callback for processing audio data from the device.
@@ -96,9 +187,11 @@ callback. The following APIs cannot be called from inside the callback:
The proper way to stop the device is to call `ma_device_stop()` from a different thread, normally the main application thread.
*/
device_callback_proc :: proc "c" (pDevice: ^device, pOutput: rawptr, pInput: rawptr, frameCount: u32)
device_data_proc :: proc "c" (pDevice: ^device, pOutput, pInput: rawptr, frameCount: u32)
/*
DEPRECATED. Use ma_device_notification_proc instead.
The callback for when the device has been stopped.
This will be called when the device is stopped explicitly with `ma_device_stop()` and also called implicitly when the device is stopped through external forces
@@ -108,48 +201,15 @@ such as being unplugged or an internal error occuring.
Parameters
----------
pDevice (in)
A pointer to the device that has just stopped.
A pointer to the device that has just stopped.
Remarks
-------
Do not restart or uninitialize the device from the callback.
*/
stop_proc :: proc "c" (pDevice: ^device)
stop_proc :: proc "c" (pDevice: ^device) /* DEPRECATED. Use ma_device_notification_proc instead. */
/*
The callback for handling log messages.
Parameters
----------
pContext (in)
A pointer to the context the log message originated from.
pDevice (in)
A pointer to the device the log message originate from, if any. This can be null, in which case the message came from the context.
logLevel (in)
The log level. This can be one of the following:
+----------------------+
| Log Level |
+----------------------+
| MA_LOG_LEVEL_DEBUG |
| MA_LOG_LEVEL_INFO |
| MA_LOG_LEVEL_WARNING |
| MA_LOG_LEVEL_ERROR |
+----------------------+
message (in)
The log message.
Remarks
-------
Do not modify the state of the device from inside the callback.
*/
log_proc :: proc "c" (pContext: context_type, pDevice: ^device, logLevel: u32, message: cstring)
device_type :: enum c.int {
playback = 1,
@@ -279,29 +339,14 @@ device_id :: struct #raw_union {
DATA_FORMAT_FLAG_EXCLUSIVE_MODE :: 1 << 1 /* If set, this is supported in exclusive mode. Otherwise not natively supported by exclusive mode. */
MAX_DEVICE_NAME_LENGTH :: 255
device_info :: struct {
/* Basic info. This is the only information guaranteed to be filled in during device enumeration. */
id: device_id,
name: [256]byte,
name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* +1 for null terminator. */
isDefault: b32,
/*
Detailed info. As much of this is filled as possible with ma_context_get_device_info(). Note that you are allowed to initialize
a device with settings outside of this range, but it just means the data will be converted using miniaudio's data conversion
pipeline before sending the data to/from the device. Most programs will need to not worry about these values, but it's provided
here mainly for informational purposes or in the rare case that someone might find it useful.
These will be set to 0 when returned by ma_context_enumerate_devices() or ma_context_get_devices().
*/
formatCount: u32,
formats: [format]format,
minChannels: u32,
maxChannels: u32,
minSampleRate: u32,
maxSampleRate: u32,
/* Experimental. Don't use these right now. */
nativeDataFormatCount: u32,
nativeDataFormats: [/*len(format_count) * standard_sample_rate.rate_count * MAX_CHANNELS*/ 64]struct { /* Not sure how big to make this. There can be *many* permutations for virtual devices which can support anything. */
format: format, /* Sample format. If set to ma_format_unknown, all sample formats are supported. */
@@ -312,31 +357,26 @@ device_info :: struct {
}
device_config :: struct {
deviceType: device_type,
sampleRate: u32,
periodSizeInFrames: u32,
periodSizeInMilliseconds: u32,
periods: u32,
performanceProfile: performance_profile,
noPreZeroedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
dataCallback: device_callback_proc,
stopCallback: stop_proc,
pUserData: rawptr,
resampling: struct {
algorithm: resample_algorithm,
linear: struct {
lpfOrder: u32,
},
speex: struct {
quality: c.int,
},
},
deviceType: device_type,
sampleRate: u32,
periodSizeInFrames: u32,
periodSizeInMilliseconds: u32,
periods: u32,
performanceProfile: performance_profile,
noPreSilencedOutputBuffer: b8, /* When set to true, the contents of the output buffer passed into the data callback will be left undefined rather than initialized to zero. */
noClip: b8, /* When set to true, the contents of the output buffer passed into the data callback will be clipped after returning. Only applies when the playback sample format is f32. */
noDisableDenormals: b8, /* Do not disable denormals when firing the data callback. */
noFixedSizedCallback: b8, /* Disables strict fixed-sized data callbacks. Setting this to true will result in the period size being treated only as a hint to the backend. This is an optimization for those who don't need fixed sized callbacks. */
dataCallback: device_data_proc,
notificationCallback: device_notification_proc,
stopCallback: stop_proc,
pUserData: rawptr,
resampling: resampler_config,
playback: struct {
pDeviceID: ^device_id,
format: format,
channels: u32,
channelMap: [MAX_CHANNELS]channel,
channelMap: [^]channel,
channelMixMode: channel_mix_mode,
shareMode: share_mode,
},
@@ -344,7 +384,7 @@ device_config :: struct {
pDeviceID: ^device_id,
format: format,
channels: u32,
channelMap: [MAX_CHANNELS]channel,
channelMap: [^]channel,
channelMixMode: channel_mix_mode,
shareMode: share_mode,
},
@@ -373,9 +413,10 @@ device_config :: struct {
recordingPreset: opensl_recording_preset,
},
aaudio: struct {
usage: aaudio_usage,
contentType: aaudio_content_type,
inputPreset: aaudio_input_preset,
usage: aaudio_usage,
contentType: aaudio_content_type,
inputPreset: aaudio_input_preset,
noAutoStartAfterReroute: b32,
},
}
@@ -425,14 +466,14 @@ to many devices. A device is created from a context.
The general flow goes like this:
1) A context is created with `onContextInit()`
1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required.
1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required.
1a) Available devices can be enumerated with `onContextEnumerateDevices()` if required.
1b) Detailed information about a device can be queried with `onContextGetDeviceInfo()` if required.
2) A device is created from the context that was created in the first step using `onDeviceInit()`, and optionally a device ID that was
selected from device enumeration via `onContextEnumerateDevices()`.
selected from device enumeration via `onContextEnumerateDevices()`.
3) A device is started or stopped with `onDeviceStart()` / `onDeviceStop()`
4) Data is delivered to and from the device by the backend. This is always done based on the native format returned by the prior call
to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by
miniaudio internally.
to `onDeviceInit()`. Conversion between the device's native format and the format requested by the application will be handled by
miniaudio internally.
Initialization of the context is quite simple. You need to do any necessary initialization of internal objects and then output the
callbacks defined in this structure.
@@ -440,7 +481,7 @@ callbacks defined in this structure.
Once the context has been initialized you can initialize a device. Before doing so, however, the application may want to know which
physical devices are available. This is where `onContextEnumerateDevices()` comes in. This is fairly simple. For each device, fire the
given callback with, at a minimum, the basic information filled out in `ma_device_info`. When the callback returns `MA_FALSE`, enumeration
needs to stop and the `onContextEnumerateDevices()` function return with a success code.
needs to stop and the `onContextEnumerateDevices()` function returns with a success code.
Detailed device information can be retrieved from a device ID using `onContextGetDeviceInfo()`. This takes as input the device type and ID,
and on output returns detailed information about the device in `ma_device_info`. The `onContextGetDeviceInfo()` callback must handle the
@@ -455,7 +496,7 @@ internally by miniaudio.
On input, if the sample format is set to `ma_format_unknown`, the backend is free to use whatever sample format it desires, so long as it's
supported by miniaudio. When the channel count is set to 0, the backend should use the device's native channel count. The same applies for
sample rate. For the channel map, the default should be used when `ma_channel_map_blank()` returns true (all channels set to
sample rate. For the channel map, the default should be used when `ma_channel_map_is_blank()` returns true (all channels set to
`MA_CHANNEL_NONE`). On input, the `periodSizeInFrames` or `periodSizeInMilliseconds` option should always be set. The backend should
inspect both of these variables. If `periodSizeInFrames` is set, it should take priority, otherwise it needs to be derived from the period
size in milliseconds (`periodSizeInMilliseconds`) and the sample rate, keeping in mind that the sample rate may be 0, in which case the
@@ -474,14 +515,17 @@ This allows miniaudio to then process any necessary data conversion and then pas
If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback
which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional.
The audio thread should run data delivery logic in a loop while `ma_device_get_state() == MA_STATE_STARTED` and no errors have been
The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been
encounted. Do not start or stop the device here. That will be handled from outside the `onDeviceDataLoop()` callback.
The invocation of the `onDeviceDataLoop()` callback will be handled by miniaudio. When you start the device, miniaudio will fire this
callback. When the device is stopped, the `ma_device_get_state() == MA_STATE_STARTED` condition will fail and the loop will be terminated
callback. When the device is stopped, the `ma_device_get_state() == ma_device_state_started` condition will fail and the loop will be terminated
which will then fall through to the part that stops the device. For an example on how to implement the `onDeviceDataLoop()` callback,
look at `ma_device_audio_thread__default_read_write()`. Implement the `onDeviceDataLoopWakeup()` callback if you need a mechanism to
wake up the audio thread.
If the backend supports an optimized retrieval of device information from an initialized `ma_device` object, it should implement the
`onDeviceGetInfo()` callback. This is optional, in which case it will fall back to `onContextGetDeviceInfo()` which is less efficient.
*/
backend_callbacks :: struct {
onContextInit: proc "c" (pContext: ^context_type, pConfig: ^context_config, pCallbacks: ^backend_callbacks) -> result,
@@ -496,10 +540,10 @@ backend_callbacks :: struct {
onDeviceWrite: proc "c" (pDevice: ^device, pFrames: rawptr, frameCount: u32, pFramesWritten: ^u32) -> result,
onDeviceDataLoop: proc "c" (pDevice: ^device) -> result,
onDeviceDataLoopWakeup: proc "c" (pDevice: ^device) -> result,
onDeviceGetInfo: proc "c" (pDevice: ^device, type: device_type, pDeviceInfo: ^device_info) -> result,
}
context_config :: struct {
logCallback: log_proc, /* Legacy logging callback. Will be removed in version 0.11. */
pLog: ^log,
threadPriority: thread_priority,
threadStackSize: c.size_t,
@@ -538,7 +582,7 @@ context_command__wasapi :: struct {
deviceType: device_type,
pAudioClient: rawptr,
ppAudioClientService: ^rawptr,
pResult: ^rawptr, /* The result from creating the audio client service. */
pResult: ^result, /* The result from creating the audio client service. */
},
releaseAudioClient: struct {
pDevice: ^device,
@@ -548,21 +592,20 @@ context_command__wasapi :: struct {
}
context_type :: struct {
callbacks: backend_callbacks,
backend: backend, /* DirectSound, ALSA, etc. */
pLog: ^log,
log: log, /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
logCallback: log_proc, /* Legacy callback. Will be removed in version 0.11. */
threadPriority: thread_priority,
threadStackSize: c.size_t,
pUserData: rawptr,
allocationCallbacks: allocation_callbacks,
deviceEnumLock: mutex, /* Used to make ma_context_get_devices() thread safe. */
deviceInfoLock: mutex, /* Used to make ma_context_get_device_info() thread safe. */
deviceInfoCapacity: u32, /* Total capacity of pDeviceInfos. */
callbacks: backend_callbacks,
backend: backend, /* DirectSound, ALSA, etc. */
pLog: ^log,
log: log, /* Only used if the log is owned by the context. The pLog member will be set to &log in this case. */
threadPriority: thread_priority,
threadStackSize: c.size_t,
pUserData: rawptr,
allocationCallbacks: allocation_callbacks,
deviceEnumLock: mutex, /* Used to make ma_context_get_devices() thread safe. */
deviceInfoLock: mutex, /* Used to make ma_context_get_device_info() thread safe. */
deviceInfoCapacity: u32, /* Total capacity of pDeviceInfos. */
playbackDeviceInfoCount: u32,
captureDeviceInfoCount: u32,
pDeviceInfos: [^]device_info, /* Playback devices first, then capture. */
captureDeviceInfoCount: u32,
pDeviceInfos: [^]device_info, /* Playback devices first, then capture. */
using _: struct #raw_union {
wasapi: (struct {
@@ -575,7 +618,7 @@ context_type :: struct {
} when SUPPORT_WASAPI else struct {}),
dsound: (struct {
DSoundDLL: handle,
hDSoundDLL: handle,
DirectSoundCreate: proc "system" (),
DirectSoundEnumerateA: proc "system" (),
DirectSoundCaptureCreate: proc "system" (),
@@ -739,8 +782,10 @@ context_type :: struct {
pa_stream_writable_size: proc "system" (),
pa_stream_readable_size: proc "system" (),
/*pa_mainloop**/ pMainLoop: ptr,
/*pa_context**/ pPulseContext: ptr,
/*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr,
pApplicationName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
pServerName: cstring, /* Set when the context is initialized. Used by devices for their local pa_context objects. */
} when SUPPORT_PULSEAUDIO else struct {}),
jack: (struct {
@@ -762,7 +807,7 @@ context_type :: struct {
jack_port_get_buffer: proc "system" (),
jack_free: proc "system" (),
pClientName: [^]c.char,
pClientName: cstring,
tryStartServer: b32,
} when SUPPORT_JACK else struct {}),
@@ -791,7 +836,7 @@ context_type :: struct {
AudioUnitInitialize: proc "system" (),
AudioUnitRender: proc "system" (),
/*AudioComponent*/ component: ptr,
/*AudioComponent*/ component: rawptr,
noAudioSessionDeactivate: b32, /* For tracking whether or not the iOS audio session should be explicitly deactivated. Set from the config in ma_context_init__coreaudio(). */
} when SUPPORT_COREAUDIO else struct {}),
@@ -817,7 +862,7 @@ context_type :: struct {
} when SUPPORT_SNDIO else struct {}),
audio4: (struct {
_unused: cint,
_unused: c.int,
} when SUPPORT_AUDIO4 else struct {}),
oss: (struct {
@@ -855,6 +900,7 @@ context_type :: struct {
AAudioStream_getFramesPerBurst: proc "system" (),
AAudioStream_requestStart: proc "system" (),
AAudioStream_requestStop: proc "system" (),
jobThread: device_job_thread, /* For processing operations outside of the error callback, specifically device disconnections and rerouting. */
} when SUPPORT_AAUDIO else struct {}),
opensl: (struct {
@@ -895,7 +941,7 @@ context_type :: struct {
RegOpenKeyExA: proc "system" (),
RegCloseKey: proc "system" (),
RegQueryValueExA: proc "system" (),
} when ODIN_OS == "windows" else struct {}),
} when ODIN_OS == .Windows else struct {}),
posix: (struct {
pthreadSO: handle,
@@ -914,44 +960,47 @@ context_type :: struct {
pthread_attr_setschedpolicy: proc "system" (),
pthread_attr_getschedparam: proc "system" (),
pthread_attr_setschedparam: proc "system" (),
} when ODIN_OS != "windows" else struct {}),
} when ODIN_OS != .Windows else struct {}),
_unused: c.int,
},
}
device :: struct {
pContext: ^context_type,
type: device_type,
sampleRate: u32,
state: u32, /*atomic*/ /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
onData: device_callback_proc, /* Set once at initialization time and should not be changed after. */
onStop: stop_proc, /* Set once at initialization time and should not be changed after. */
pUserData: rawptr, /* Application defined data. */
startStopLock: mutex,
wakeupEvent: event,
startEvent: event,
stopEvent: event,
device_thread: thread,
workResult: result, /* This is set by the worker thread after it's finished doing a job. */
isOwnerOfContext: b8, /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
noPreZeroedOutputBuffer: b8,
noClip: b8,
masterVolumeFactor: f32, /*atomic*/ /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
duplexRB: duplex_rb, /* Intermediary buffer for duplex device on asynchronous backends. */
pContext: ^context_type,
type: device_type,
sampleRate: u32,
state: u32, /*atomic*/ /* The state of the device is variable and can change at any time on any thread. Must be used atomically. */
onData: device_data_proc, /* Set once at initialization time and should not be changed after. */
onNotification: device_notification_proc, /* Set once at initialization time and should not be changed after. */
onStop: stop_proc, /* DEPRECATED. Use the notification callback instead. Set once at initialization time and should not be changed after. */
pUserData: rawptr, /* Application defined data. */
startStopLock: mutex,
wakeupEvent: event,
startEvent: event,
stopEvent: event,
device_thread: thread,
workResult: result, /* This is set by the worker thread after it's finished doing a job. */
isOwnerOfContext: b8, /* When set to true, uninitializing the device will also uninitialize the context. Set to true when NULL is passed into ma_device_init(). */
noPreSilencedOutputBuffer: b8,
noClip: b8,
noDisableDenormals: b8,
noFixedSizedCallback: b8,
masterVolumeFactor: f32, /*atomic*/ /* Linear 0..1. Can be read and written simultaneously by different threads. Must be used atomically. */
duplexRB: duplex_rb, /* Intermediary buffer for duplex device on asynchronous backends. */
resampling: struct {
algorithm: resample_algorithm,
algorithm: resample_algorithm,
pBackendVTable: ^resampling_backend_vtable,
pBackendUserData: rawptr,
linear: struct {
lpfOrder: u32,
},
speex: struct {
quality: c.int,
},
},
playback: struct {
id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
name: [256]byte, /* Maybe temporary. Likely to be replaced with a query API. */
shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */
pID: ^device_id, /* Set to NULL if using default ID, otherwise set to the address of "id". */
id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* Maybe temporary. Likely to be replaced with a query API. */
shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */
playback_format: format,
channels: u32,
channelMap: [MAX_CHANNELS]channel,
@@ -963,11 +1012,19 @@ device :: struct {
internalPeriods: u32,
channelMixMode: channel_mix_mode,
converter: data_converter,
pIntermediaryBuffer: rawptr, /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */
intermediaryBufferCap: u32,
intermediaryBufferLen: u32, /* How many valid frames are sitting in the intermediary buffer. */
pInputCache: rawptr, /* In external format. Can be null. */
inputCacheCap: u64,
inputCacheConsumed: u64,
inputCacheRemaining: u64,
},
capture: struct {
id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
name: [256]byte, /* Maybe temporary. Likely to be replaced with a query API. */
shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */
pID: ^device_id, /* Set to NULL if using default ID, otherwise set to the address of "id". */
id: device_id, /* If using an explicit device, will be set to a copy of the ID used for initialization. Otherwise cleared to 0. */
name: [MAX_DEVICE_NAME_LENGTH + 1]c.char, /* Maybe temporary. Likely to be replaced with a query API. */
shareMode: share_mode, /* Set to whatever was passed in when the device was initialized. */
capture_format: format,
channels: u32,
channelMap: [MAX_CHANNELS]channel,
@@ -979,6 +1036,9 @@ device :: struct {
internalPeriods: u32,
channelMixMode: channel_mix_mode,
converter: data_converter,
pIntermediaryBuffer: rawptr, /* For implementing fixed sized buffer callbacks. Will be null if using variable sized callbacks. */
intermediaryBufferCap: u32,
intermediaryBufferLen: u32, /* How many valid frames are sitting in the intermediary buffer. */
},
using _: struct #raw_union {
@@ -991,7 +1051,7 @@ device :: struct {
notificationClient: IMMNotificationClient,
/*HANDLE*/ hEventPlayback: handle, /* Auto reset. Initialized to signaled. */
/*HANDLE*/ hEventCapture: handle, /* Auto reset. Initialized to unsignaled. */
actualPeriodSizeInFramesPlayback: u32, /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */
actualPeriodSizeInFramesPlayback: u32, /* Value from GetBufferSize(). internalPeriodSizeInFrames is not set to the _actual_ buffer size when low-latency shared mode is being used due to the way the IAudioClient3 API works. */
actualPeriodSizeInFramesCapture: u32,
originalPeriodSizeInFrames: u32,
originalPeriodSizeInMilliseconds: u32,
@@ -999,8 +1059,14 @@ device :: struct {
originalPerformanceProfile: performance_profile,
periodSizeInFramesPlayback: u32,
periodSizeInFramesCapture: u32,
isStartedCapture: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
isStartedPlayback: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
pMappedBufferCapture: rawptr,
mappedBufferCaptureCap: u32,
mappedBufferCaptureLen: u32,
pMappedBufferPlayback: rawptr,
mappedBufferPlaybackCap: u32,
mappedBufferPlaybackLen: u32,
isStartedCapture: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
isStartedPlayback: b32, /*atomic*/ /* Can be read and written simultaneously across different threads. Must be used atomically, and must be 32-bit. */
noAutoConvertSRC: b8, /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM. */
noDefaultQualitySRC: b8, /* When set to true, disables the use of AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY. */
noHardwareOffloading: b8,
@@ -1049,14 +1115,16 @@ device :: struct {
} when SUPPORT_ALSA else struct {}),
pulse: (struct {
/*pa_mainloop**/ pMainLoop: rawptr,
/*pa_context**/ pPulseContext: rawptr,
/*pa_stream**/ pStreamPlayback: rawptr,
/*pa_stream**/ pStreamCapture: rawptr,
} when SUPPORT_PULSEAUDIO else struct {}),
jack: (struct {
/*jack_client_t**/ pClient: rawptr,
/*jack_port_t**/ pPortsPlayback: [MAX_CHANNELS]rawptr,
/*jack_port_t**/ pPortsCapture: [MAX_CHANNELS]rawptr,
/*jack_port_t**/ pPortsPlayback: [^]rawptr,
/*jack_port_t**/ pPortsCapture: [^]rawptr,
pIntermediaryBufferPlayback: [^]f32, /* Typed as a float because JACK is always floating point. */
pIntermediaryBufferCapture: [^]f32,
} when SUPPORT_JACK else struct {}),
@@ -1079,6 +1147,7 @@ device :: struct {
isSwitchingCaptureDevice: b32, /* <-- Set to true when the default device has changed and miniaudio is in the process of switching. */
pRouteChangeHandler: rawptr, /* Only used on mobile platforms. Obj-C object for handling route changes. */
} when SUPPORT_COREAUDIO else struct {}),
sndio: (struct {
handlePlayback: rawptr,
handleCapture: rawptr,
@@ -1099,6 +1168,10 @@ device :: struct {
aaudio: (struct {
/*AAudioStream**/ pStreamPlayback: rawptr,
/*AAudioStream**/ pStreamCapture: rawptr,
usage: aaudio_usage,
contentType: aaudio_content_type,
inputPreset: aaudio_input_preset,
noAutoStartAfterReroute: b32,
} when SUPPORT_AAUDIO else struct {}),
opensl: (struct {
+2548 -407
View File
File diff suppressed because it is too large Load Diff
+300
View File
@@ -0,0 +1,300 @@
package miniaudio
import c "core:c/libc"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/*
Delay
*/
delay_config :: struct {
channels: u32,
sampleRate: u32,
delayInFrames: u32,
delayStart: b32, /* Set to true to delay the start of the output; false otherwise. */
wet: f32, /* 0..1. Default = 1. */
dry: f32, /* 0..1. Default = 1. */
decay: f32, /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */
}
delay :: struct {
config: delay_config,
cursor: u32, /* Feedback is written to this cursor. Always equal or in front of the read cursor. */
bufferSizeInFrames: u32, /* The maximum of config.startDelayInFrames and config.feedbackDelayInFrames. */
pBuffer: [^]f32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
delay_config_init :: proc(channels, sampleRate, delayInFrames: u32, decay: f32) -> delay_config ---
delay_init :: proc(pConfig: ^delay_config, pAllocationCallbacks: ^allocation_callbacks, pDelay: ^delay) -> result ---
delay_uninit :: proc(pDelay: ^delay, pAllocationCallbacks: ^allocation_callbacks) ---
delay_process_pcm_frames :: proc(pDelay: ^delay, pFramesOut, pFramesIn: rawptr, frameCount: u32) -> result ---
delay_set_wet :: proc(pDelay: ^delay, value: f32) ---
delay_get_wet :: proc(pDelay: ^delay) -> f32 ---
delay_set_dry :: proc(pDelay: ^delay, value: f32) ---
delay_get_dry :: proc(pDelay: ^delay) -> f32 ---
delay_set_decay :: proc(pDelay: ^delay, value: f32) ---
delay_get_decay :: proc(pDelay: ^delay) -> f32 ---
}
/* Gainer for smooth volume changes. */
gainer_config :: struct {
channels: u32,
smoothTimeInFrames: u32,
}
gainer :: struct {
config: gainer_config,
t: u32,
pOldGains: [^]f32,
pNewGains: [^]f32,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
gainer_config_init :: proc(channels, smoothTimeInFrames: u32) -> gainer_config ---
gainer_get_heap_size :: proc(pConfig: ^gainer_config, pHeapSizeInBytes: ^c.size_t) -> result ---
gainer_init_preallocated :: proc(pConfig: ^gainer_config, pHeap: rawptr, pGainer: ^gainer) -> result ---
gainer_init :: proc(pConfig: ^gainer_config, pAllocationCallbacks: ^allocation_callbacks, pGainer: ^gainer) -> result ---
gainer_uninit :: proc(pGainer: ^gainer, pAllocationCallbacks: ^allocation_callbacks) ---
gainer_process_pcm_frames :: proc(pGainer: ^gainer, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
gainer_set_gain :: proc(pGainer: ^gainer, newGain: f32) -> result ---
gainer_set_gains :: proc(pGainer: ^gainer, pNewGains: [^]f32) -> result ---
}
/* Stereo panner. */
pan_mode :: enum c.int {
balance = 0, /* Does not blend one side with the other. Technically just a balance. Compatible with other popular audio engines and therefore the default. */
pan, /* A true pan. The sound from one side will "move" to the other side and blend with it. */
}
panner_config :: struct {
format: format,
channels: u32,
mode: pan_mode,
pan: f32,
}
panner :: struct {
format: format,
channels: u32,
mode: pan_mode,
pan: f32, /* -1..1 where 0 is no pan, -1 is left side, +1 is right side. Defaults to 0. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
panner_config_init :: proc(format: format, channels: u32) -> panner_config ---
panner_init :: proc(pConfig: ^panner_config, pPanner: ^panner) -> result ---
panner_process_pcm_frames :: proc(pPanner: ^panner, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
panner_set_mode :: proc(pPanner: ^panner, mode: pan_mode) ---
panner_get_mode :: proc(pPanner: ^panner) -> pan_mode ---
panner_set_pan :: proc(pPanner: ^panner, pan: f32) ---
panner_get_pan :: proc(pPanner: ^panner) -> f32 ---
}
/* Fader. */
fader_config :: struct {
format: format,
channels: u32,
sampleRate: u32,
}
fader :: struct {
config: fader_config,
volumeBeg: f32, /* If volumeBeg and volumeEnd is equal to 1, no fading happens (ma_fader_process_pcm_frames() will run as a passthrough). */
volumeEnd: f32,
lengthInFrames: u64, /* The total length of the fade. */
cursorInFrames: u64, /* The current time in frames. Incremented by ma_fader_process_pcm_frames(). */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
fader_config_init :: proc(format: format, channels, sampleRate: u32) -> fader_config ---
fader_init :: proc(pConfig: ^fader_config, pFader: ^fader) -> result ---
fader_process_pcm_frames :: proc(pFader: ^fader, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
fader_get_data_format :: proc(pFader: ^fader, pFormat: ^format, pChannels, pSampleRate: ^u32) ---
fader_set_fade :: proc(pFader: ^fader, volumeBeg, volumeEnd: f32, lengthInFrames: u64) ---
fader_get_current_volume :: proc(pFader: ^fader) -> f32 ---
}
/* Spatializer. */
vec3f :: struct {
x: f32,
y: f32,
z: f32,
}
attenuation_model :: enum c.int {
none, /* No distance attenuation and no spatialization. */
inverse, /* Equivalent to OpenAL's AL_INVERSE_DISTANCE_CLAMPED. */
linear, /* Linear attenuation. Equivalent to OpenAL's AL_LINEAR_DISTANCE_CLAMPED. */
exponential, /* Exponential attenuation. Equivalent to OpenAL's AL_EXPONENT_DISTANCE_CLAMPED. */
}
positioning :: enum c.int {
absolute,
relative,
}
handedness :: enum c.int {
right,
left,
}
spatializer_listener_config :: struct {
channelsOut: u32,
pChannelMapOut: [^]channel,
handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
coneInnerAngleInRadians: f32,
coneOuterAngleInRadians: f32,
coneOuterGain: f32,
speedOfSound: f32,
worldUp: vec3f,
}
spatializer_listener :: struct {
config: spatializer_listener_config,
position: vec3f, /* The absolute position of the listener. */
direction: vec3f, /* The direction the listener is facing. The world up vector is config.worldUp. */
velocity: vec3f,
isEnabled: b32,
/* Memory management. */
_ownsHeap: b32,
_pHeap: rawptr,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
spatializer_listener_config_init :: proc(channelsOut: u32) -> spatializer_listener_config ---
spatializer_listener_get_heap_size :: proc(pConfig: ^spatializer_listener_config, pHeapSizeInBytes: ^c.size_t) -> result ---
spatializer_listener_init_preallocated :: proc(pConfig: ^spatializer_listener_config, pHeap: rawptr, pListener: ^spatializer_listener) -> result ---
spatializer_listener_init :: proc(pConfig: ^spatializer_listener_config, pAllocationCallbacks: ^allocation_callbacks, pListener: ^spatializer_listener) -> result ---
spatializer_listener_uninit :: proc(pListener: ^spatializer_listener, pAllocationCallbacks: ^allocation_callbacks) ---
spatializer_listener_get_channel_map :: proc(pListener: ^spatializer_listener) -> ^channel ---
spatializer_listener_set_cone :: proc(pListener: ^spatializer_listener, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
spatializer_listener_get_cone :: proc(pListener: ^spatializer_listener, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
spatializer_listener_set_position :: proc(pListener: ^spatializer_listener, x, y, z: f32) ---
spatializer_listener_get_position :: proc(pListener: ^spatializer_listener) -> vec3f ---
spatializer_listener_set_direction :: proc(pListener: ^spatializer_listener, x, y, z: f32) ---
spatializer_listener_get_direction :: proc(pListener: ^spatializer_listener) -> vec3f ---
spatializer_listener_set_velocity :: proc(pListener: ^spatializer_listener, x, y, z: f32) ---
spatializer_listener_get_velocity :: proc(pListener: ^spatializer_listener) -> vec3f ---
spatializer_listener_set_speed_of_sound :: proc(pListener: ^spatializer_listener, speedOfSound: f32) ---
spatializer_listener_get_speed_of_sound :: proc(pListener: ^spatializer_listener) -> f32 ---
spatializer_listener_set_world_up :: proc(pListener: ^spatializer_listener, x, y, z: f32) ---
spatializer_listener_get_world_up :: proc(pListener: ^spatializer_listener) -> vec3f ---
spatializer_listener_set_enabled :: proc(pListener: ^spatializer_listener, isEnabled: b32) ---
spatializer_listener_is_enabled :: proc(pListener: ^spatializer_listener) -> b32 ---
}
spatializer_config :: struct {
channelsIn: u32,
channelsOut: u32,
pChannelMapIn: [^]channel,
attenuationModel: attenuation_model,
positioning: positioning,
handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
minGain: f32,
maxGain: f32,
minDistance: f32,
maxDistance: f32,
rolloff: f32,
coneInnerAngleInRadians: f32,
coneOuterAngleInRadians: f32,
coneOuterGain: f32,
dopplerFactor: f32, /* Set to 0 to disable doppler effect. */
directionalAttenuationFactor: f32, /* Set to 0 to disable directional attenuation. */
gainSmoothTimeInFrames: u32, /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
}
spatializer :: struct {
channelsIn: u32,
channelsOut: u32,
pChannelMapIn: [^]channel,
attenuationModel: attenuation_model,
positioning: positioning,
handedness: handedness, /* Defaults to right. Forward is -1 on the Z axis. In a left handed system, forward is +1 on the Z axis. */
minGain: f32,
maxGain: f32,
minDistance: f32,
maxDistance: f32,
rolloff: f32,
coneInnerAngleInRadians: f32,
coneOuterAngleInRadians: f32,
coneOuterGain: f32,
dopplerFactor: f32, /* Set to 0 to disable doppler effect. */
directionalAttenuationFactor: f32, /* Set to 0 to disable directional attenuation. */
gainSmoothTimeInFrames: u32, /* When the gain of a channel changes during spatialization, the transition will be linearly interpolated over this number of frames. */
position: vec3f,
direction: vec3f,
velocity: vec3f, /* For doppler effect. */
dopplerPitch: f32, /* Will be updated by ma_spatializer_process_pcm_frames() and can be used by higher level functions to apply a pitch shift for doppler effect. */
gainer: gainer, /* For smooth gain transitions. */
pNewChannelGainsOut: [^]f32, /* An offset of _pHeap. Used by ma_spatializer_process_pcm_frames() to store new channel gains. The number of elements in this array is equal to config.channelsOut. */
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
spatializer_config_init :: proc(channelsIn, channelsOut: u32) -> spatializer_config ---
spatializer_get_heap_size :: proc(pConfig: ^spatializer_config, pHeapSizeInBytes: ^c.size_t) -> result ---
spatializer_init_preallocated :: proc(pConfig: ^spatializer_config, pHeap: rawptr, pSpatializer: ^spatializer) -> result ---
spatializer_init :: proc(pConfig: ^spatializer_config, pAllocationCallbacks: ^allocation_callbacks, pSpatializer: ^spatializer) -> result ---
spatializer_uninit :: proc(pSpatializer: ^spatializer, pAllocationCallbacks: ^allocation_callbacks) ---
spatializer_process_pcm_frames :: proc(pSpatializer: ^spatializer, pListener: ^spatializer_listener, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
spatializer_get_input_channels :: proc(pSpatializer: ^spatializer) -> u32 ---
spatializer_get_output_channels :: proc(pSpatializer: ^spatializer) -> u32 ---
spatializer_set_attenuation_model :: proc(pSpatializer: ^spatializer, attenuationModel: attenuation_model) ---
spatializer_get_attenuation_model :: proc(pSpatializer: ^spatializer) -> attenuation_model ---
spatializer_set_positioning :: proc(pSpatializer: ^spatializer, positioning: positioning) ---
spatializer_get_positioning :: proc(pSpatializer: ^spatializer) -> positioning ---
spatializer_set_rolloff :: proc(pSpatializer: ^spatializer, rolloff: f32) ---
spatializer_get_rolloff :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_min_gain :: proc(pSpatializer: ^spatializer, minGain: f32) ---
spatializer_get_min_gain :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_max_gain :: proc(pSpatializer: ^spatializer, maxGain: f32) ---
spatializer_get_max_gain :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_min_distance :: proc(pSpatializer: ^spatializer, minDistance: f32) ---
spatializer_get_min_distance :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_max_distance :: proc(pSpatializer: ^spatializer, maxDistance: f32) ---
spatializer_get_max_distance :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_cone :: proc(pSpatializer: ^spatializer, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
spatializer_get_cone :: proc(pSpatializer: ^spatializer, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
spatializer_set_doppler_factor :: proc(pSpatializer: ^spatializer, dopplerFactor: f32) ---
spatializer_get_doppler_factor :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_directional_attenuation_factor :: proc(pSpatializer: ^spatializer, directionalAttenuationFactor: f32) ---
spatializer_get_directional_attenuation_factor :: proc(pSpatializer: ^spatializer) -> f32 ---
spatializer_set_position :: proc(pSpatializer: ^spatializer, x, y, z: f32) ---
spatializer_get_position :: proc(pSpatializer: ^spatializer) -> vec3f ---
spatializer_set_direction :: proc(pSpatializer: ^spatializer, x, y, z: f32) ---
spatializer_get_direction :: proc(pSpatializer: ^spatializer) -> vec3f ---
spatializer_set_velocity :: proc(pSpatializer: ^spatializer, x, y, z: f32) ---
spatializer_get_velocity :: proc(pSpatializer: ^spatializer) -> vec3f ---
spatializer_get_relative_position_and_direction :: proc(pSpatializer: ^spatializer, pListener: ^spatializer_listener, pRelativePos, pRelativeDir: ^vec3f) ---
}
+23 -11
View File
@@ -2,8 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
@@ -14,14 +19,14 @@ Encoders do not perform any format conversion for you. If your target format doe
************************************************************************************************************************************************************/
encoder_write_proc :: proc "c" (pEncoder: ^encoder, pBufferIn: rawptr, bytesToWrite: c.size_t) -> c.size_t /* Returns the number of bytes written. */
encoder_seek_proc :: proc "c" (pEncoder: ^encoder, byteOffset: c.int, origin: seek_origin) -> b32
encoder_write_proc :: proc "c" (pEncoder: ^encoder, pBufferIn: rawptr, bytesToWrite: c.size_t, pBytesWritten: ^c.size_t) -> result
encoder_seek_proc :: proc "c" (pEncoder: ^encoder, offset: i64, origin: seek_origin) -> result
encoder_init_proc :: proc "c" (pEncoder: ^encoder) -> result
encoder_uninit_proc :: proc "c" (pEncoder: ^encoder)
encoder_write_pcm_frames_proc :: proc "c" (pEncoder: ^encoder, pFramesIn: rawptr, frameCount: u64) -> u64
encoder_uninit_proc :: proc "c" (pEncoder: ^encoder)
encoder_write_pcm_frames_proc :: proc "c" (pEncoder: ^encoder, pFramesIn: rawptr, frameCount: u64, pFramesWritten: ^u64) -> result
encoder_config :: struct {
resourceFormat: resource_format,
encodingFormat: encoding_format,
format: format,
channels: u32,
sampleRate: u32,
@@ -37,16 +42,23 @@ encoder :: struct {
onWritePCMFrames: encoder_write_pcm_frames_proc,
pUserData: rawptr,
pInternalEncoder: rawptr, /* <-- The drwav/drflac/stb_vorbis/etc. objects. */
pFile: rawptr, /* FILE*. Only used when initialized with ma_encoder_init_file(). */
data: struct #raw_union {
vfs: struct {
pVFS: ^vfs,
file: vfs_file,
},
},
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
encoder_config_init :: proc(resourceFormat: resource_format, format: format, channels: u32, sampleRate: u32) -> encoder_config ---
encoder_config_init :: proc(encodingFormat: encoding_format, format: format, channels: u32, sampleRate: u32) -> encoder_config ---
encoder_init :: proc(onWrite: encoder_write_proc, onSeek: encoder_seek_proc, pUserData: rawptr, pConfig: ^encoder_config, pEncoder: ^encoder) -> result ---
encoder_init_vfs :: proc(pVFS: ^vfs, pFilePath: cstring, pConfig: ^encoder_config, pEncoder: ^encoder) -> result ---
encoder_init_vfs_w :: proc(pVFS: ^vfs, pFilePath: [^]c.wchar_t, pConfig: ^encoder_config, pEncoder: ^encoder) -> result ---
encoder_init_file :: proc(pFilePath: cstring, pConfig: ^encoder_config, pEncoder: ^encoder) -> result ---
encoder_init_file_w :: proc(pFilePath: [^]c.wchar_t, pConfig: ^encoder_config, pEncoder: ^encoder) -> result ---
encoder_uninit :: proc(pEncoder: ^encoder) ---
encoder_write_pcm_frames :: proc(pEncoder: ^encoder, FramesIn: rawptr, frameCount: u64) -> u64 ---
}
encoder_write_pcm_frames :: proc(pEncoder: ^encoder, FramesIn: rawptr, frameCount: u64, pFramesWritten: ^u64) -> result ---
}
+341
View File
@@ -0,0 +1,341 @@
package miniaudio
import "core:c"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
Engine
************************************************************************************************************************************************************/
/* Sound flags. */
sound_flags :: enum c.int {
STREAM = 0x00000001, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM */
DECODE = 0x00000002, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE */
ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */
WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */
NO_DEFAULT_ATTACHMENT = 0x00000010, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */
NO_PITCH = 0x00000020, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */
NO_SPATIALIZATION = 0x00000040, /* Disable spatialization. */
}
ENGINE_MAX_LISTENERS :: 4
LISTENER_INDEX_CLOSEST :: 255
engine_node_type :: enum c.int {
sound,
group,
}
engine_node_config :: struct {
pEngine: ^engine,
type: engine_node_type,
channelsIn: u32,
channelsOut: u32,
sampleRate: u32, /* Only used when the type is set to ma_engine_node_type_sound. */
isPitchDisabled: b8, /* Pitching can be explicitly disable with MA_SOUND_FLAG_NO_PITCH to optimize processing. */
isSpatializationDisabled: b8, /* Spatialization can be explicitly disabled with MA_SOUND_FLAG_NO_SPATIALIZATION. */
pinnedListenerIndex: u8, /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
}
/* Base node object for both ma_sound and ma_sound_group. */
engine_node :: struct {
baseNode: node_base, /* Must be the first member for compatiblity with the ma_node API. */
pEngine: ^engine, /* A pointer to the engine. Set based on the value from the config. */
sampleRate: u32, /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */
fader: fader,
resampler: linear_resampler, /* For pitch shift. */
spatializer: spatializer,
panner: panner,
pitch: f32, /*atomic*/
oldPitch: f32, /* For determining whether or not the resampler needs to be updated to reflect the new pitch. The resampler will be updated on the mixing thread. */
oldDopplerPitch: f32, /* For determining whether or not the resampler needs to be updated to take a new doppler pitch into account. */
isPitchDisabled: b32, /*atomic*/ /* When set to true, pitching will be disabled which will allow the resampler to be bypassed to save some computation. */
isSpatializationDisabled: b32, /*atomic*/ /* Set to false by default. When set to false, will not have spatialisation applied. */
pinnedListenerIndex: u32, /*atomic*/ /* The index of the listener this node should always use for spatialization. If set to MA_LISTENER_INDEX_CLOSEST the engine will use the closest listener. */
/* Memory management. */
_ownsHeap: b8,
_pHeap: rawptr,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
engine_node_config_init :: proc(pEngine: ^engine, type: engine_node_type, flags: u32) -> engine_node_config ---
engine_node_get_heap_size :: proc(pConfig: ^engine_node_config, pHeapSizeInBytes: ^c.size_t) -> result ---
engine_node_init_preallocated :: proc(pConfig: ^engine_node_config, pHeap: rawptr, pEngineNode: ^engine_node) -> result ---
engine_node_init :: proc(pConfig: ^engine_node_config, pAllocationCallbacks: ^allocation_callbacks, pEngineNode: ^engine_node) -> result ---
engine_node_uninit :: proc(pEngineNode: ^engine_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
SOUND_SOURCE_CHANNEL_COUNT :: 0xFFFFFFFF
sound_config :: struct {
pFilePath: cstring, /* Set this to load from the resource manager. */
pFilePathW: [^]c.wchar_t, /* Set this to load from the resource manager. */
pDataSource: ^data_source, /* Set this to load from an existing data source. */
pInitialAttachment: ^node, /* If set, the sound will be attached to an input of this node. This can be set to a ma_sound. If set to NULL, the sound will be attached directly to the endpoint unless MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT is set in `flags`. */
initialAttachmentInputBusIndex: u32, /* The index of the input bus of pInitialAttachment to attach the sound to. */
channelsIn: u32, /* Ignored if using a data source as input (the data source's channel count will be used always). Otherwise, setting to 0 will cause the engine's channel count to be used. */
channelsOut: u32, /* Set this to 0 (default) to use the engine's channel count. Set to MA_SOUND_SOURCE_CHANNEL_COUNT to use the data source's channel count (only used if using a data source as input). */
flags: u32, /* A combination of MA_SOUND_FLAG_* flags. */
initialSeekPointInPCMFrames: u64, /* Initializes the sound such that it's seeked to this location by default. */
rangeBegInPCMFrames: u64,
rangeEndInPCMFrames: u64,
loopPointBegInPCMFrames: u64,
loopPointEndInPCMFrames: u64,
isLooping: b32,
pDoneFence: ^fence, /* Released when the resource manager has finished decoding the entire sound. Not used with streams. */
}
sound :: struct {
engineNode: engine_node, /* Must be the first member for compatibility with the ma_node API. */
pDataSource: ^data_source,
seekTarget: u64, /*atomic*/ /* The PCM frame index to seek to in the mixing thread. Set to (~(ma_uint64)0) to not perform any seeking. */
atEnd: b32, /*atomic*/
ownsDataSource: b8,
/*
We're declaring a resource manager data source object here to save us a malloc when loading a
sound via the resource manager, which I *think* will be the most common scenario.
*/
pResourceManagerDataSource: ^resource_manager_data_source,
}
/* Structure specifically for sounds played with ma_engine_play_sound(). Making this a separate structure to reduce overhead. */
sound_inlined :: struct {
sound: sound,
pNext: ^sound_inlined,
pPrev: ^sound_inlined,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
sound_config_init :: proc() -> sound_config ---
sound_init_from_file :: proc(pEngine: ^engine, pFilePath: cstring, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
sound_init_from_file_w :: proc(pEngine: ^engine, pFilePath: [^]c.wchar_t, flags: u32, pGroup: ^sound_group, pDoneFence: ^fence, pSound: ^sound) -> result ---
sound_init_copy :: proc(pEngine: ^engine, pExistingSound: ^sound, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result ---
sound_init_from_data_source :: proc(pEngine: ^engine, pDataSource: ^data_source, flags: u32, pGroup: ^sound_group, pSound: ^sound) -> result ---
sound_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_config, pSound: ^sound) -> result ---
sound_uninit :: proc(pSound: ^sound) ---
sound_get_engine :: proc(pSound: ^sound) -> ^engine ---
sound_get_data_source :: proc(pSound: ^sound) -> ^data_source ---
sound_start :: proc(pSound: ^sound) -> result ---
sound_stop :: proc(pSound: ^sound) -> result ---
sound_set_volume :: proc(pSound: ^sound, volume: f32) ---
sound_get_volume :: proc(pSound: ^sound) -> f32 ---
sound_set_pan :: proc(pSound: ^sound, pan: f32) ---
sound_get_pan :: proc(pSound: ^sound) -> f32 ---
sound_set_pan_mode :: proc(pSound: ^sound, panMode: pan_mode) ---
sound_get_pan_mode :: proc(pSound: ^sound) -> pan_mode ---
sound_set_pitch :: proc(pSound: ^sound, pitch: f32) ---
sound_get_pitch :: proc(pSound: ^sound) -> f32 ---
sound_set_spatialization_enabled :: proc(pSound: ^sound, enabled: b32) ---
sound_is_spatialization_enabled :: proc(pSound: ^sound) -> b32 ---
sound_set_pinned_listener_index :: proc(pSound: ^sound, listenerIndex: u32) ---
sound_get_pinned_listener_index :: proc(pSound: ^sound) -> u32 ---
sound_get_listener_index :: proc(pSound: ^sound) -> u32 ---
sound_get_direction_to_listener :: proc(pSound: ^sound) -> vec3f ---
sound_set_position :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_position :: proc(pSound: ^sound) -> vec3f ---
sound_set_direction :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_direction :: proc(pSound: ^sound) -> vec3f ---
sound_set_velocity :: proc(pSound: ^sound, x, y, z: f32) ---
sound_get_velocity :: proc(pSound: ^sound) -> vec3f ---
sound_set_attenuation_model :: proc(pSound: ^sound, attenuationModel: attenuation_model) ---
sound_get_attenuation_model :: proc(pSound: ^sound) -> attenuation_model ---
sound_set_positioning :: proc(pSound: ^sound, positioning: positioning) ---
sound_get_positioning :: proc(pSound: ^sound) -> positioning ---
sound_set_rolloff :: proc(pSound: ^sound, rolloff: f32) ---
sound_get_rolloff :: proc(pSound: ^sound) -> f32 ---
sound_set_min_gain :: proc(pSound: ^sound, minGain: f32) ---
sound_get_min_gain :: proc(pSound: ^sound) -> f32 ---
sound_set_max_gain :: proc(pSound: ^sound, maxGain: f32) ---
sound_get_max_gain :: proc(pSound: ^sound) -> f32 ---
sound_set_min_distance :: proc(pSound: ^sound, minDistance: f32) ---
sound_get_min_distance :: proc(pSound: ^sound) -> f32 ---
sound_set_max_distance :: proc(pSound: ^sound, maxDistance: f32) ---
sound_get_max_distance :: proc(pSound: ^sound) -> f32 ---
sound_set_cone :: proc(pSound: ^sound, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
sound_get_cone :: proc(pSound: ^sound, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
sound_set_doppler_factor :: proc(pSound: ^sound, dopplerFactor: f32) ---
sound_get_doppler_factor :: proc(pSound: ^sound) -> f32 ---
sound_set_directional_attenuation_factor :: proc(pSound: ^sound, directionalAttenuationFactor: f32) ---
sound_get_directional_attenuation_factor :: proc(pSound: ^sound) -> f32 ---
sound_set_fade_in_pcm_frames :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) ---
sound_set_fade_in_milliseconds :: proc(pSound: ^sound, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) ---
sound_get_current_fade_volume :: proc(pSound: ^sound) -> f32 ---
sound_set_start_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) ---
sound_set_start_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) ---
sound_set_stop_time_in_pcm_frames :: proc(pSound: ^sound, absoluteGlobalTimeInFrames: u64) ---
sound_set_stop_time_in_milliseconds :: proc(pSound: ^sound, absoluteGlobalTimeInMilliseconds: u64) ---
sound_is_playing :: proc(pSound: ^sound) -> b32 ---
sound_get_time_in_pcm_frames :: proc(pSound: ^sound) -> u64 ---
sound_set_looping :: proc(pSound: ^sound, isLooping: b32) ---
sound_is_looping :: proc(pSound: ^sound) -> b32 ---
sound_at_end :: proc(pSound: ^sound) -> b32 ---
sound_seek_to_pcm_frame :: proc(pSound: ^sound, frameIndex: u64) -> result --- /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */
sound_get_data_format :: proc(pSound: ^sound, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result ---
sound_get_cursor_in_pcm_frames :: proc(pSound: ^sound, pCursor: ^u64) -> result ---
sound_get_length_in_pcm_frames :: proc(pSound: ^sound, pLength: ^u64) -> result ---
sound_get_cursor_in_seconds :: proc(pSound: ^sound, pCursor: ^f32) -> result ---
sound_get_length_in_seconds :: proc(pSound: ^sound, pLength: ^f32) -> result ---
}
/* A sound group is just a sound. */
sound_group_config :: distinct sound_config
sound_group :: distinct sound
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
sound_group_config_init :: proc() -> sound_group_config ---
sound_group_init :: proc(pEngine: ^engine, flags: u32, pParentGroup, pGroup: ^sound_group) -> result ---
sound_group_init_ex :: proc(pEngine: ^engine, pConfig: ^sound_group_config, pGroup: ^sound_group) -> result ---
sound_group_uninit :: proc(pGroup: ^sound_group) ---
sound_group_get_engine :: proc(pGroup: ^sound_group) -> ^engine ---
sound_group_start :: proc(pGroup: ^sound_group) -> result ---
sound_group_stop :: proc(pGroup: ^sound_group) -> result ---
sound_group_set_volume :: proc(pGroup: ^sound_group, volume: f32) ---
sound_group_get_volume :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_pan :: proc(pGroup: ^sound_group, pan: f32) ---
sound_group_get_pan :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_pan_mode :: proc(pGroup: ^sound_group, panMode: pan_mode) ---
sound_group_get_pan_mode :: proc(pGroup: ^sound_group) -> pan_mode ---
sound_group_set_pitch :: proc(pGroup: ^sound_group, pitch: f32) ---
sound_group_get_pitch :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_spatialization_enabled :: proc(pGroup: ^sound_group, enabled: b32) ---
sound_group_is_spatialization_enabled :: proc(pGroup: ^sound_group) -> b32 ---
sound_group_set_pinned_listener_index :: proc(pGroup: ^sound_group, listenerIndex: u32) ---
sound_group_get_pinned_listener_index :: proc(pGroup: ^sound_group) -> u32 ---
sound_group_get_listener_index :: proc(pGroup: ^sound_group) -> u32 ---
sound_group_get_direction_to_listener :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_position :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_position :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_direction :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_direction :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_velocity :: proc(pGroup: ^sound_group, x, y, z: f32) ---
sound_group_get_velocity :: proc(pGroup: ^sound_group) -> vec3f ---
sound_group_set_attenuation_model :: proc(pGroup: ^sound_group, attenuationModel: attenuation_model) ---
sound_group_get_attenuation_model :: proc(pGroup: ^sound_group) -> attenuation_model ---
sound_group_set_positioning :: proc(pGroup: ^sound_group, positioning: positioning) ---
sound_group_get_positioning :: proc(pGroup: ^sound_group) -> positioning ---
sound_group_set_rolloff :: proc(pGroup: ^sound_group, rolloff: f32) ---
sound_group_get_rolloff :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_min_gain :: proc(pGroup: ^sound_group, minGain: f32) ---
sound_group_get_min_gain :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_max_gain :: proc(pGroup: ^sound_group, maxGain: f32) ---
sound_group_get_max_gain :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_min_distance :: proc(pGroup: ^sound_group, minDistance: f32) ---
sound_group_get_min_distance :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_max_distance :: proc(pGroup: ^sound_group, maxDistance: f32) ---
sound_group_get_max_distance :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_cone :: proc(pGroup: ^sound_group, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
sound_group_get_cone :: proc(pGroup: ^sound_group, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
sound_group_set_doppler_factor :: proc(pGroup: ^sound_group, dopplerFactor: f32) ---
sound_group_get_doppler_factor :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_directional_attenuation_factor :: proc(pGroup: ^sound_group, directionalAttenuationFactor: f32) ---
sound_group_get_directional_attenuation_factor :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_fade_in_pcm_frames :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInFrames: u64) ---
sound_group_set_fade_in_milliseconds :: proc(pGroup: ^sound_group, volumeBeg, volumeEnd: f32, fadeLengthInMilliseconds: u64) ---
sound_group_get_current_fade_volume :: proc(pGroup: ^sound_group) -> f32 ---
sound_group_set_start_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) ---
sound_group_set_start_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) ---
sound_group_set_stop_time_in_pcm_frames :: proc(pGroup: ^sound_group, absoluteGlobalTimeInFrames: u64) ---
sound_group_set_stop_time_in_milliseconds :: proc(pGroup: ^sound_group, absoluteGlobalTimeInMilliseconds: u64) ---
sound_group_is_playing :: proc(pGroup: ^sound_group) -> b32 ---
sound_group_get_time_in_pcm_frames :: proc(pGroup: ^sound_group) -> u64 ---
}
engine_config :: struct {
pResourceManager: ^resource_manager, /* Can be null in which case a resource manager will be created for you. */
pContext: ^context_type,
pDevice: ^device, /* If set, the caller is responsible for calling ma_engine_data_callback() in the device's data callback. */
pPlaybackDeviceID: ^device_id, /* The ID of the playback device to use with the default listener. */
pLog: ^log, /* When set to NULL, will use the context's log. */
listenerCount: u32, /* Must be between 1 and MA_ENGINE_MAX_LISTENERS. */
channels: u32, /* The number of channels to use when mixing and spatializing. When set to 0, will use the native channel count of the device. */
sampleRate: u32, /* The sample rate. When set to 0 will use the native channel count of the device. */
periodSizeInFrames: u32, /* If set to something other than 0, updates will always be exactly this size. The underlying device may be a different size, but from the perspective of the mixer that won't matter.*/
periodSizeInMilliseconds: u32, /* Used if periodSizeInFrames is unset. */
gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */
gainSmoothTimeInMilliseconds: u32, /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */
allocationCallbacks: allocation_callbacks,
noAutoStart: b32, /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */
noDevice: b32, /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */
monoExpansionMode: mono_expansion_mode, /* Controls how the mono channel should be expanded to other channels when spatialization is disabled on a sound. */
pResourceManagerVFS: ^vfs, /* A pointer to a pre-allocated VFS object to use with the resource manager. This is ignored if pResourceManager is not NULL. */
}
engine :: struct {
nodeGraph: node_graph, /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */
pResourceManager: ^resource_manager,
pDevice: ^device, /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */
pLog: ^log,
sampleRate: u32,
listenerCount: u32,
listeners: [ENGINE_MAX_LISTENERS]spatializer_listener,
allocationCallbacks: allocation_callbacks,
ownsResourceManager: b8,
ownsDevice: b8,
inlinedSoundLock: spinlock, /* For synchronizing access so the inlined sound list. */
pInlinedSoundHead: ^sound_inlined, /* The first inlined sound. Inlined sounds are tracked in a linked list. */
inlinedSoundCount: u32, /*atomic*/ /* The total number of allocated inlined sound objects. Used for debugging. */
gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. */
monoExpansionMode: mono_expansion_mode,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
engine_config_init :: proc() -> engine_config ---
engine_init :: proc(pConfig: ^engine_config, pEngine: ^engine) -> result ---
engine_uninit :: proc(pEngine: ^engine) ---
engine_read_pcm_frames :: proc(pEngine: ^engine, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
engine_get_node_graph :: proc(pEngine: ^engine) -> ^node_graph ---
engine_get_resource_manager :: proc(pEngine: ^engine) -> ^resource_manager ---
engine_get_device :: proc(pEngine: ^engine) -> ^device ---
engine_get_log :: proc(pEngine: ^engine) -> ^log ---
engine_get_endpoint :: proc(pEngine: ^engine) -> ^node ---
engine_get_time :: proc(pEngine: ^engine) -> u64 ---
engine_set_time :: proc(pEngine: ^engine, globalTime: u64) -> result ---
engine_get_channels :: proc(pEngine: ^engine) -> u32 ---
engine_get_sample_rate :: proc(pEngine: ^engine) -> u32 ---
engine_start :: proc(pEngine: ^engine) -> result ---
engine_stop :: proc(pEngine: ^engine) -> result ---
engine_set_volume :: proc(pEngine: ^engine, volume: f32) -> result ---
engine_set_gain_db :: proc(pEngine: ^engine, gainDB: f32) -> result ---
engine_get_listener_count :: proc(pEngine: ^engine) -> u32 ---
engine_find_closest_listener :: proc(pEngine: ^engine, absolutePosX, absolutePosY, absolutePosZ: f32) -> u32 ---
engine_listener_set_position :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_position :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_direction :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_direction :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_velocity :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_velocity :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_cone :: proc(pEngine: ^engine, listenerIndex: u32, innerAngleInRadians, outerAngleInRadians, outerGain: f32) ---
engine_listener_get_cone :: proc(pEngine: ^engine, listenerIndex: u32, pInnerAngleInRadians, pOuterAngleInRadians, pOuterGain: ^f32) ---
engine_listener_set_world_up :: proc(pEngine: ^engine, listenerIndex: u32, x, y, z: f32) ---
engine_listener_get_world_up :: proc(pEngine: ^engine, listenerIndex: u32) -> vec3f ---
engine_listener_set_enabled :: proc(pEngine: ^engine, listenerIndex: u32, isEnabled: b32) ---
engine_listener_is_enabled :: proc(pEngine: ^engine, listenerIndex: u32) -> b32 ---
engine_play_sound_ex :: proc(pEngine: ^engine, pFilePath: cstring, pNode: ^node, nodeInputBusIndex: u32) -> result ---
engine_play_sound :: proc(pEngine: ^engine, pFilePath: cstring, pGroup: ^sound_group) -> result --- /* Fire and forget. */
}
+106 -32
View File
@@ -1,7 +1,14 @@
package miniaudio
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
import c "core:c/libc"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/**************************************************************************************************************************************************************
@@ -14,14 +21,14 @@ biquad_coefficient :: struct #raw_union {
}
biquad_config :: struct {
format: format,
format: format,
channels: u32,
b0: f64,
b1: f64,
b2: f64,
a0: f64,
a1: f64,
a2: f64,
b0: f64,
b1: f64,
b2: f64,
a0: f64,
a1: f64,
a2: f64,
}
biquad :: struct {
@@ -32,17 +39,25 @@ biquad :: struct {
b2: biquad_coefficient,
a1: biquad_coefficient,
a2: biquad_coefficient,
r1: [MAX_CHANNELS]biquad_coefficient,
r2: [MAX_CHANNELS]biquad_coefficient,
pR1: ^biquad_coefficient,
pR2: ^biquad_coefficient,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
biquad_config_init :: proc(format: format, channels: u32, b0, b1, b2, a0, a1, a2: f64) -> biquad_config ---
biquad_init :: proc(pConfig: ^biquad_config, pBQ: ^biquad) -> result ---
biquad_get_heap_size :: proc(pConfig: ^biquad_config, pHeapSizeInBytes: ^c.size_t) -> result ---
biquad_init_preallocated :: proc(pConfig: ^biquad_config, pHeap: rawptr, pBQ: ^biquad) -> result ---
biquad_init :: proc(pConfig: ^biquad_config, pAllocationCallbacks: ^allocation_callbacks, pBQ: ^biquad) -> result ---
biquad_uninit :: proc(pBQ: ^biquad, pAllocationCallbacks: ^allocation_callbacks) ---
biquad_reinit :: proc(pConfig: ^biquad_config, pBQ: ^biquad) -> result ---
biquad_process_pcm_frames :: proc(pBQ: ^biquad, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
biquad_clear_cache :: proc(pBQ: ^biquad) -> result ---
biquad_process_pcm_frames :: proc(pBQ: ^biquad, pFramesOut, pFramesIn: rawptr, frameCount: u64) -> result ---
biquad_get_latency :: proc(pBQ: ^biquad) -> u32 ---
}
@@ -65,7 +80,11 @@ lpf1 :: struct {
format: format,
channels: u32,
a: biquad_coefficient,
r1: [MAX_CHANNELS]biquad_coefficient,
pR1: ^biquad_coefficient,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
lpf2 :: struct {
@@ -86,8 +105,12 @@ lpf :: struct {
sampleRate: u32,
lpf1Count: u32,
lpf2Count: u32,
lpf1: [1]lpf1,
lpf2: [MAX_FILTER_ORDER/2]lpf2,
pLPF1: ^lpf1,
pLPF2: ^lpf2,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@@ -96,20 +119,32 @@ foreign lib {
lpf1_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64) -> lpf1_config ---
lpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency, q: f64) -> lpf2_config ---
lpf1_init :: proc(pConfig: ^lpf1_config, pLPF: ^lpf1) -> result ---
lpf1_get_heap_size :: proc(pConfig: ^lpf1_config, pHeapSizeInBytes: ^c.size_t) -> result ---
lpf1_init_preallocated :: proc(pConfig: ^lpf1_config, pHeap: rawptr, pLPF: ^lpf1) -> result ---
lpf1_init :: proc(pConfig: ^lpf1_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf1) -> result ---
lpf1_uninit :: proc(pLPF: ^lpf1, pAllocationCallbacks: ^allocation_callbacks) ---
lpf1_reinit :: proc(pConfig: ^lpf1_config, pLPF: ^lpf1) -> result ---
lpf1_clear_cache :: proc(pLPF: ^lpf1) -> result ---
lpf1_process_pcm_frames :: proc(pLPF: ^lpf1, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
lpf1_get_latency :: proc(pLPF: ^lpf1) -> u32 ---
lpf2_init :: proc(pConfig: ^lpf2_config, pLPF: ^lpf2) -> result ---
lpf2_get_heap_size :: proc(pConfig: ^lpf2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
lpf2_init_preallocated :: proc(pConfig: ^lpf2_config, pHeap: rawptr, pHPF: ^lpf2) -> result ---
lpf2_init :: proc(pConfig: ^lpf2_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf2) -> result ---
lpf2_uninit :: proc(pLPF: ^lpf2, pAllocationCallbacks: ^allocation_callbacks) ---
lpf2_reinit :: proc(pConfig: ^lpf2_config, pLPF: ^lpf2) -> result ---
lpf2_clear_cache :: proc(pLPF: ^lpf2) -> result ---
lpf2_process_pcm_frames :: proc(pLPF: ^lpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
lpf2_get_latency :: proc(pLPF: ^lpf2) -> u32 ---
lpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> lpf_config ---
lpf_init :: proc(pConfig: ^lpf_config, pLPF: ^lpf) -> result ---
lpf_get_heap_size :: proc(pConfig: ^lpf_config, pHeapSizeInBytes: ^c.size_t) -> result ---
lpf_init_preallocated :: proc(pConfig: ^lpf_config, pHeap: rawptr, pLPF: ^lpf) -> result ---
lpf_init :: proc(pConfig: ^lpf_config, pAllocationCallbacks: ^allocation_callbacks, pLPF: ^lpf) -> result ---
lpf_uninit :: proc(pLPF: ^lpf, pAllocationCallbacks: ^allocation_callbacks) ---
lpf_reinit :: proc(pConfig: ^lpf_config, pLPF: ^lpf) -> result ---
lpf_clear_cache :: proc(pLPF: ^lpf) -> result ---
lpf_process_pcm_frames :: proc(pLPF: ^lpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
lpf_get_latency :: proc(pLPF: ^lpf) -> u32 ---
}
@@ -133,7 +168,11 @@ hpf1 :: struct {
format: format,
channels: u32,
a: biquad_coefficient,
r1: [MAX_CHANNELS]biquad_coefficient,
pR1: ^biquad_coefficient,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
hpf2 :: struct {
@@ -154,8 +193,12 @@ hpf :: struct {
sampleRate: u32,
hpf1Count: u32,
hpf2Count: u32,
hpf1: [1]hpf1,
hpf2: [MAX_FILTER_ORDER/2]hpf2,
pHPF1: ^hpf1,
pHPF2: ^hpf2,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@@ -164,19 +207,28 @@ foreign lib {
hpf1_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64) -> hpf1_config ---
hpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency, q: f64) -> hpf2_config ---
hpf1_init :: proc(pConfig: ^hpf1_config, pHPF: ^hpf1) -> result ---
hpf1_get_heap_size :: proc(pConfig: ^hpf1_config, pHeapSizeInBytes: ^c.size_t) -> result ---
hpf1_init_preallocated :: proc(pConfig: ^hpf1_config, pHeap: rawptr, pLPF: ^hpf1) -> result ---
hpf1_init :: proc(pConfig: ^hpf1_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf1) -> result ---
hpf1_uninit :: proc(pHPF: ^hpf1, pAllocationCallbacks: ^allocation_callbacks) ---
hpf1_reinit :: proc(pConfig: ^hpf1_config, pHPF: ^hpf1) -> result ---
hpf1_process_pcm_frames :: proc(pHPF: ^hpf1, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
hpf1_get_latency :: proc(pHPF: ^hpf1) -> u32 ---
hpf2_init :: proc(pConfig: ^hpf2_config, pHPF: ^hpf2) -> result ---
hpf2_get_heap_size :: proc(pConfig: ^hpf2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
hpf2_init_preallocated :: proc(pConfig: ^hpf2_config, pHeap: rawptr, pHPF: ^hpf2) -> result ---
hpf2_init :: proc(pConfig: ^hpf2_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf2) -> result ---
hpf2_uninit :: proc(pHPF: ^hpf2, pAllocationCallbacks: ^allocation_callbacks) ---
hpf2_reinit :: proc(pConfig: ^hpf2_config, pHPF: ^hpf2) -> result ---
hpf2_process_pcm_frames :: proc(pHPF: ^hpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
hpf2_get_latency :: proc(pHPF: ^hpf2) -> u32 ---
hpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> hpf_config ---
hpf_init :: proc(pConfig: ^hpf_config, pHPF: ^hpf) -> result ---
hpf_get_heap_size :: proc(pConfig: ^hpf_config, pHeapSizeInBytes: ^c.size_t) -> result ---
hpf_init_preallocated :: proc(pConfig: ^hpf_config, pHeap: rawptr, pLPF: ^hpf) -> result ---
hpf_init :: proc(pConfig: ^hpf_config, pAllocationCallbacks: ^allocation_callbacks, pHPF: ^hpf) -> result ---
hpf_uninit :: proc(pHPF: ^hpf, pAllocationCallbacks: ^allocation_callbacks) ---
hpf_reinit :: proc(pConfig: ^hpf_config, pHPF: ^hpf) -> result ---
hpf_process_pcm_frames :: proc(pHPF: ^hpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
hpf_get_latency :: proc(pHPF: ^hpf) -> u32 ---
@@ -212,21 +264,31 @@ bpf :: struct {
format: format,
channels: u32,
bpf2Count: u32,
bpf2: [MAX_FILTER_ORDER/2]bpf2,
pBPF2: ^bpf2,
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
bpf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, q: f64) -> bpf2_config ---
bpf2_init :: proc(pConfig: ^bpf2_config, pBPF: ^bpf2) -> result ---
bpf2_get_heap_size :: proc(pConfig: ^bpf2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
bpf2_init_preallocated :: proc(pConfig: ^bpf2_config, pHeap: rawptr, pBPF: ^bpf2) -> result ---
bpf2_init :: proc(pConfig: ^bpf2_config, pAllocationCallbacks: ^allocation_callbacks, pBPF: ^bpf2) -> result ---
bpf2_uninit :: proc(pBPF: ^bpf2, pAllocationCallbacks: ^allocation_callbacks) ---
bpf2_reinit :: proc(pConfig: ^bpf2_config, pBPF: ^bpf2) -> result ---
bpf2_process_pcm_frames :: proc(pBPF: ^bpf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
bpf2_get_latency :: proc(pBPF: ^bpf2) -> u32 ---
bpf_config_init :: proc(format: format, channels: u32, sampleRate: u32, cutoffFrequency: f64, order: u32) -> bpf_config ---
bpf_init :: proc(pConfig: ^bpf_config, pBPF: ^bpf) -> result ---
bpf_get_heap_size :: proc(pConfig: ^bpf_config, pHeapSizeInBytes: ^c.size_t) -> result ---
bpf_init_preallocated :: proc(pConfig: ^bpf_config, pHeap: rawptr, pBPF: ^bpf) -> result ---
bpf_init :: proc(pConfig: ^bpf_config, pAllocationCallbacks: ^allocation_callbacks, pBPF: ^bpf) -> result ---
bpf_uninit :: proc(pBPF: ^bpf, pAllocationCallbacks: ^allocation_callbacks) ---
bpf_reinit :: proc(pConfig: ^bpf_config, pBPF: ^bpf) -> result ---
bpf_process_pcm_frames :: proc(pBPF: ^bpf, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
bpf_get_latency :: proc(pBPF: ^bpf) -> u32 ---
@@ -255,7 +317,10 @@ notch2 :: struct {
foreign lib {
notch2_config_init :: proc(format: format, channels: u32, sampleRate: u32, q: f64, frequency: f64) -> notch2_config ---
notch2_init :: proc(pConfig: ^notch2_config, pFilter: ^notch2) -> result ---
notch2_get_heap_size :: proc(pConfig: ^notch2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
notch2_init_preallocated :: proc(pConfig: ^notch2_config, pHeap: rawptr, pFilter: ^notch2) -> result ---
notch2_init :: proc(pConfig: ^notch2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^notch2) -> result ---
notch2_uninit :: proc(pFilter: ^notch2, pAllocationCallbacks: ^allocation_callbacks) ---
notch2_reinit :: proc(pConfig: ^notch2_config, pFilter: ^notch2) -> result ---
notch2_process_pcm_frames :: proc(pFilter: ^notch2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
notch2_get_latency :: proc(pFilter: ^notch2) -> u32 ---
@@ -285,7 +350,10 @@ peak2 :: struct {
foreign lib {
peak2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, q, frequency: f64) -> peak2_config ---
peak2_init :: proc(pConfig: ^peak2_config, pFilter: ^peak2) -> result ---
peak2_get_heap_size :: proc(pConfig: ^peak2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
peak2_init_preallocated :: proc(pConfig: ^peak2_config, pHeap: rawptr, pFilter: ^peak2) -> result ---
peak2_init :: proc(pConfig: ^peak2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^peak2) -> result ---
peak2_uninit :: proc(pFilter: ^peak2, pAllocationCallbacks: ^allocation_callbacks) ---
peak2_reinit :: proc(pConfig: ^peak2_config, pFilter: ^peak2) -> result ---
peak2_process_pcm_frames :: proc(pFilter: ^peak2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
peak2_get_latency :: proc(pFilter: ^peak2) -> u32 ---
@@ -315,7 +383,10 @@ loshelf2 :: struct {
foreign lib {
loshelf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, shelfSlope, frequency: f64) -> loshelf2_config ---
loshelf2_init :: proc(pConfig: ^loshelf2_config, pFilter: ^loshelf2) -> result ---
loshelf2_get_heap_size :: proc(pConfig: ^loshelf2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
loshelf2_init_preallocated :: proc(pConfig: ^loshelf2_config, pHeap: rawptr, pFilter: ^loshelf2) -> result ---
loshelf2_init :: proc(pConfig: ^loshelf2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^loshelf2) -> result ---
loshelf2_uninit :: proc(pFilter: ^loshelf2, pAllocationCallbacks: ^allocation_callbacks) ---
loshelf2_reinit :: proc(pConfig: ^loshelf2_config, pFilter: ^loshelf2) -> result ---
loshelf2_process_pcm_frames :: proc(pFilter: ^loshelf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
loshelf2_get_latency :: proc(pFilter: ^loshelf2) -> u32 ---
@@ -345,7 +416,10 @@ hishelf2 :: struct {
foreign lib {
hishelf2_config_init :: proc(format: format, channels: u32, sampleRate: u32, gainDB, shelfSlope, frequency: f64) -> hishelf2_config ---
hishelf2_init :: proc(pConfig: ^hishelf2_config, pFilter: ^hishelf2) -> result ---
hishelf2_get_heap_size :: proc(pConfig: ^hishelf2_config, pHeapSizeInBytes: ^c.size_t) -> result ---
hishelf2_init_preallocated :: proc(pConfig: ^hishelf2_config, pHeap: rawptr, pFilter: ^hishelf2) -> result ---
hishelf2_init :: proc(pConfig: ^hishelf2_config, pAllocationCallbacks: ^allocation_callbacks, pFilter: ^hishelf2) -> result ---
hishelf2_uninit :: proc(pFilter: ^hishelf2, pAllocationCallbacks: ^allocation_callbacks) ---
hishelf2_reinit :: proc(pConfig: ^hishelf2_config, pFilter: ^hishelf2) -> result ---
hishelf2_process_pcm_frames :: proc(pFilter: ^hishelf2, pFramesOut: rawptr, pFramesIn: rawptr, frameCount: u64) -> result ---
hishelf2_get_latency :: proc(pFilter: ^hishelf2) -> u32 ---
+25 -14
View File
@@ -2,8 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
waveform_type :: enum c.int {
sine,
@@ -51,14 +56,18 @@ noise :: struct {
lcg: lcg,
state: struct #raw_union {
pink: struct {
bin: [MAX_CHANNELS][16]f64,
accumulation: [MAX_CHANNELS]f64,
counter: [MAX_CHANNELS]u32,
bin: ^[^]f64,
accumulation: [^]f64,
counter: [^]u32,
},
brownian: struct {
accumulation: [MAX_CHANNELS]f64,
accumulation: [^]f64,
},
},
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
@@ -67,7 +76,7 @@ foreign lib {
waveform_init :: proc(pConfig: ^waveform_config, pWaveform: ^waveform) -> result ---
waveform_uninit :: proc(pWaveform: ^waveform) ---
waveform_read_pcm_frames :: proc(pWaveform: ^waveform, pFramesOut: rawptr, frameCount: u64) -> u64 ---
waveform_read_pcm_frames :: proc(pWaveform: ^waveform, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
waveform_seek_to_pcm_frame :: proc(pWaveform: ^waveform, frameIndex: u64) -> result ---
waveform_set_amplitude :: proc(pWaveform: ^waveform, amplitude: f64) -> result ---
waveform_set_frequency :: proc(pWaveform: ^waveform, frequency: f64) -> result ---
@@ -76,10 +85,12 @@ foreign lib {
noise_config_init :: proc(format: format, channels: u32, type: noise_type, seed: i32, amplitude: f64) -> noise_config ---
noise_init :: proc(pConfig: ^noise_config, pNoise: ^noise) -> result ---
noise_uninit :: proc(pNoise: ^noise) ---
noise_read_pcm_frames :: proc(pNoise: ^noise, pFramesOut: rawptr, frameCount: u64) -> u64 ---
noise_set_amplitude :: proc(pNoise: ^noise, amplitude: f64) -> result ---
noise_set_seed :: proc(pNoise: ^noise, seed: i32) -> result ---
noise_set_type :: proc(pNoise: ^noise, type: noise_type) -> result ---
}
noise_get_heap_size :: proc(pConfig: ^noise_config, pHeapSizeInBytes: ^c.size_t) -> result ---
noise_init_preallocated :: proc(pConfig: ^noise_config, pHeap: rawptr, pNoise: ^noise) -> result ---
noise_init :: proc(pConfig: ^noise_config, pAllocationCallbacks: ^allocation_callbacks, pNoise: ^noise) -> result ---
noise_uninit :: proc(pNoise: ^noise, pAllocationCallbacks: ^allocation_callbacks) ---
noise_read_pcm_frames :: proc(pNoise: ^noise, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
noise_set_amplitude :: proc(pNoise: ^noise, amplitude: f64) -> result ---
noise_set_seed :: proc(pNoise: ^noise, seed: i32) -> result ---
noise_set_type :: proc(pNoise: ^noise, type: noise_type) -> result ---
}
+239
View File
@@ -0,0 +1,239 @@
package miniaudio
import c "core:c/libc"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/*
Slot Allocator
--------------
The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used
as the insertion point for an object.
Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs.
The slot index is stored in the low 32 bits. The reference counter is stored in the high 32 bits:
+-----------------+-----------------+
| 32 Bits | 32 Bits |
+-----------------+-----------------+
| Reference Count | Slot Index |
+-----------------+-----------------+
*/
slot_allocator_config :: struct {
capacity: u32, /* The number of slots to make available. */
}
slot_allocator_group :: struct {
bitfield: u32, /*atomic*/ /* Must be used atomically because the allocation and freeing routines need to make copies of this which must never be optimized away by the compiler. */
}
slot_allocator :: struct {
pGroups: [^]slot_allocator_group, /* Slots are grouped in chunks of 32. */
pSlots: [^]u32, /* 32 bits for reference counting for ABA mitigation. */
count: u32, /* Allocation count. */
capacity: u32,
/* Memory management. */
_ownsHeap: b32,
_pHeap: rawptr,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
slot_allocator_config_init :: proc(capacity: u32) -> slot_allocator_config ---
slot_allocator_get_heap_size :: proc(pConfig: ^slot_allocator_config, pHeapSizeInBytes: ^c.size_t) -> result ---
slot_allocator_init_preallocated :: proc(pConfig: ^slot_allocator_config, pHeap: rawptr, pAllocator: ^slot_allocator) -> result ---
slot_allocator_init :: proc(pConfig: ^slot_allocator_config, pAllocationCallbacks: ^allocation_callbacks, pAllocator: ^slot_allocator) -> result ---
slot_allocator_uninit :: proc(pAllocator: ^slot_allocator, pAllocationCallbacks: ^allocation_callbacks) ---
slot_allocator_alloc :: proc(pAllocator: ^slot_allocator, pSlot: ^u64) -> result ---
slot_allocator_free :: proc(pAllocator: ^slot_allocator, slot: u64) -> result ---
}
/*
Callback for processing a job. Each job type will have their own processing callback which will be
called by ma_job_process().
*/
job_proc :: proc "c" (pJob: ^job)
/* When a job type is added here an callback needs to be added go "g_jobVTable" in the implementation section. */
job_type :: enum c.int {
/* Miscellaneous. */
QUIT = 0,
CUSTOM,
/* Resource Manager. */
RESOURCE_MANAGER_LOAD_DATA_BUFFER_NODE,
RESOURCE_MANAGER_FREE_DATA_BUFFER_NODE,
RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE,
RESOURCE_MANAGER_LOAD_DATA_BUFFER,
RESOURCE_MANAGER_FREE_DATA_BUFFER,
RESOURCE_MANAGER_LOAD_DATA_STREAM,
RESOURCE_MANAGER_FREE_DATA_STREAM,
RESOURCE_MANAGER_PAGE_DATA_STREAM,
RESOURCE_MANAGER_SEEK_DATA_STREAM,
/* Device. */
DEVICE_AAUDIO_REROUTE,
/* Count. Must always be last. */
COUNT,
}
job :: struct {
toc: struct #raw_union { /* 8 bytes. We encode the job code into the slot allocation data to save space. */
breakup: struct {
code: u16, /* Job type. */
slot: u16, /* Index into a ma_slot_allocator. */
refcount: u32,
},
allocation: u64,
},
next: u64, /*atomic*/ /* refcount + slot for the next item. Does not include the job code. */
order: u32, /* Execution order. Used to create a data dependency and ensure a job is executed in order. Usage is contextual depending on the job type. */
data: struct #raw_union {
/* Miscellaneous. */
custom: struct {
proc_: job_proc,
data0: uintptr,
data1: uintptr,
},
/* Resource Manager */
resourceManager: struct #raw_union {
loadDataBufferNode: struct {
pResourceManager: rawptr /*ma_resource_manager**/,
pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/,
pFilePath: cstring,
pFilePathW: [^]c.wchar_t,
flags: u32, /* Resource manager data source flags that were used when initializing the data buffer. */
pInitNotification: ^async_notification, /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */
pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. Will be passed through to MA_JOB_TYPE_RESOURCE_MANAGER_PAGE_DATA_BUFFER_NODE when decoding. */
pInitFence: ^fence, /* Released when initialization of the decoder is complete. */
pDoneFence: ^fence, /* Released if initialization of the decoder fails. Passed through to PAGE_DATA_BUFFER_NODE untouched if init is successful. */
},
freeDataBufferNode: struct {
pResourceManager: rawptr /*ma_resource_manager**/,
pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/,
pDoneNotification: ^async_notification,
pDoneFence: ^fence,
},
pageDataBufferNode: struct {
pResourceManager: rawptr /*ma_resource_manager**/,
pDataBufferNode: rawptr /*ma_resource_manager_data_buffer_node**/,
pDecoder: rawptr /*ma_decoder**/,
pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. */
pDoneFence: ^fence, /* Passed through from LOAD_DATA_BUFFER_NODE and released when the data buffer completes decoding or an error occurs. */
},
loadDataBuffer: struct {
pDataBuffer: rawptr /*ma_resource_manager_data_buffer**/,
pInitNotification: ^async_notification, /* Signalled when the data buffer has been initialized and the format/channels/rate can be retrieved. */
pDoneNotification: ^async_notification, /* Signalled when the data buffer has been fully decoded. */
pInitFence: ^fence, /* Released when the data buffer has been initialized and the format/channels/rate can be retrieved. */
pDoneFence: ^fence, /* Released when the data buffer has been fully decoded. */
rangeBegInPCMFrames: u64,
rangeEndInPCMFrames: u64,
loopPointBegInPCMFrames: u64,
loopPointEndInPCMFrames: u64,
isLooping: u32,
},
freeDataBuffer: struct {
pDataBuffer: rawptr /*ma_resource_manager_data_buffer**/,
pDoneNotification: ^async_notification,
pDoneFence: ^fence,
},
loadDataStream: struct {
pDataStream: rawptr /*ma_resource_manager_data_stream**/,
pFilePath: cstring, /* Allocated when the job is posted, freed by the job thread after loading. */
pFilePathW: [^]c.wchar_t, /* ^ As above ^. Only used if pFilePath is NULL. */
initialSeekPoint: u64,
pInitNotification: ^async_notification, /* Signalled after the first two pages have been decoded and frames can be read from the stream. */
pInitFence: ^fence,
},
freeDataStream: struct {
pDataStream: rawptr /*ma_resource_manager_data_stream**/,
pDoneNotification: ^async_notification,
pDoneFence: ^fence,
},
pageDataStream: struct {
pDataStream: rawptr /*ma_resource_manager_data_stream**/,
pageIndex: u32, /* The index of the page to decode into. */
},
seekDataStream: struct {
pDataStream: rawptr /*ma_resource_manager_data_stream**/,
frameIndex: u64,
},
},
/* Device. */
device: struct #raw_union {
aaudio: struct #raw_union {
reroute: struct {
pDevice: rawptr /*ma_device**/,
deviceType: u32 /*ma_device_type*/,
},
},
},
},
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
job_init :: proc(code: u16) -> job ---
job_process :: proc(pJob: ^job) -> result ---
}
/*
When set, ma_job_queue_next() will not wait and no semaphore will be signaled in
ma_job_queue_post(). ma_job_queue_next() will return MA_NO_DATA_AVAILABLE if nothing is available.
This flag should always be used for platforms that do not support multithreading.
*/
job_queue_flags :: enum c.int {
NON_BLOCKING = 0x00000001,
}
job_queue_config :: struct {
flags: u32,
capacity: u32, /* The maximum number of jobs that can fit in the queue at a time. */
}
USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE :: false
job_queue :: struct {
flags: u32, /* Flags passed in at initialization time. */
capacity: u32, /* The maximum number of jobs that can fit in the queue at a time. Set by the config. */
head: u64, /*atomic*/ /* The first item in the list. Required for removing from the top of the list. */
tail: u64, /*atomic*/ /* The last item in the list. Required for appending to the end of the list. */
sem: (struct {} when NO_THREADING else semaphore), /* Only used when MA_JOB_QUEUE_FLAG_NON_BLOCKING is unset. */
allocator: slot_allocator,
pJobs: [^]job,
lock: (struct {} when USE_EXPERIMENTAL_LOCK_FREE_JOB_QUEUE else spinlock),
/* Memory management. */
_pHeap: rawptr,
_ownsHeap: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
job_queue_config_init :: proc(flags, capacity: u32) -> job_queue_config ---
job_queue_get_heap_size :: proc(pConfig: ^job_queue_config, pHeapSizeInBytes: ^c.size_t) -> result ---
job_queue_init_preallocated :: proc(pConfig: ^job_queue_config, pHeap: rawptr, pQueue: ^job_queue) -> result ---
job_queue_init :: proc(pConfig: ^job_queue_config, pAllocationCallbacks: ^allocation_callbacks, pQueue: ^job_queue) -> result ---
job_queue_uninit :: proc(pQueue: ^job_queue, pAllocationCallbacks: ^allocation_callbacks) ---
job_queue_post :: proc(pQueue: ^job_queue, pJob: ^job) -> result ---
job_queue_next :: proc(pQueue: ^job_queue, pJob: ^job) -> result --- /* Returns MA_CANCELLED if the next job is a quit job. */
}
Binary file not shown.
+38 -3
View File
@@ -2,11 +2,46 @@ package miniaudio
import c "core:c/libc"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
MAX_LOG_CALLBACKS :: 4
/*
The callback for handling log messages.
Parameters
----------
pUserData (in)
The user data pointer that was passed into ma_log_register_callback().
logLevel (in)
The log level. This can be one of the following:
+----------------------+
| Log Level |
+----------------------+
| MA_LOG_LEVEL_DEBUG |
| MA_LOG_LEVEL_INFO |
| MA_LOG_LEVEL_WARNING |
| MA_LOG_LEVEL_ERROR |
+----------------------+
pMessage (in)
The log message.
Remarks
-------
Do not modify the state of the device from inside the callback.
*/
log_callback_proc :: proc "c" (pUserData: rawptr, level: u32, pMessage: cstring)
log_callback :: struct {
@@ -32,4 +67,4 @@ foreign lib {
log_post :: proc(pLog: ^log, level: u32, pMessage: cstring) -> result ---
log_postv :: proc(pLog: ^log, level: u32, pFormat: cstring, args: c.va_list) -> result ---
log_postf :: proc(pLog: ^log, level: u32, pFormat: cstring, #c_vararg args: ..any) -> result ---
}
}
+469
View File
@@ -0,0 +1,469 @@
package miniaudio
import "core:c"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
Node Graph
************************************************************************************************************************************************************/
/* Must never exceed 254. */
MAX_NODE_BUS_COUNT :: 254
/* Used internally by miniaudio for memory management. Must never exceed MA_MAX_NODE_BUS_COUNT. */
MAX_NODE_LOCAL_BUS_COUNT :: 2
/* Use this when the bus count is determined by the node instance rather than the vtable. */
NODE_BUS_COUNT_UNKNOWN :: 255
node :: struct {}
/* Node flags. */
node_flags :: enum c.int {
PASSTHROUGH = 0x00000001,
CONTINUOUS_PROCESSING = 0x00000002,
ALLOW_NULL_INPUT = 0x00000004,
DIFFERENT_PROCESSING_RATES = 0x00000008,
SILENT_OUTPUT = 0x00000010,
}
/* The playback state of a node. Either started or stopped. */
node_state :: enum c.int {
started = 0,
stopped = 1,
}
node_vtable :: struct {
/*
Extended processing callback. This callback is used for effects that process input and output
at different rates (i.e. they perform resampling). This is similar to the simple version, only
they take two seperate frame counts: one for input, and one for output.
On input, `pFrameCountOut` is equal to the capacity of the output buffer for each bus, whereas
`pFrameCountIn` will be equal to the number of PCM frames in each of the buffers in `ppFramesIn`.
On output, set `pFrameCountOut` to the number of PCM frames that were actually output and set
`pFrameCountIn` to the number of input frames that were consumed.
*/
onProcess: proc "c" (pNode: ^node, ppFramesIn: ^[^]f32, pFrameCountIn: ^u32, ppFramesOut: ^[^]f32, pFrameCountOut: ^u32),
/*
A callback for retrieving the number of a input frames that are required to output the
specified number of output frames. You would only want to implement this when the node performs
resampling. This is optional, even for nodes that perform resampling, but it does offer a
small reduction in latency as it allows miniaudio to calculate the exact number of input frames
to read at a time instead of having to estimate.
*/
onGetRequiredInputFrameCount: proc "c" (pNode: ^node, outputFrameCount: u32, pInputFrameCount: ^u32) -> result,
/*
The number of input buses. This is how many sub-buffers will be contained in the `ppFramesIn`
parameters of the callbacks above.
*/
inputBusCount: u8,
/*
The number of output buses. This is how many sub-buffers will be contained in the `ppFramesOut`
parameters of the callbacks above.
*/
outputBusCount: u8,
/*
Flags describing characteristics of the node. This is currently just a placeholder for some
ideas for later on.
*/
flags: u32,
}
node_config :: struct {
vtable: ^node_vtable, /* Should never be null. Initialization of the node will fail if so. */
initialState: node_state, /* Defaults to ma_node_state_started. */
inputBusCount: u32, /* Only used if the vtable specifies an input bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise must be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */
outputBusCount: u32, /* Only used if the vtable specifies an output bus count of `MA_NODE_BUS_COUNT_UNKNOWN`, otherwise be set to `MA_NODE_BUS_COUNT_UNKNOWN` (default). */
pInputChannels: ^u32, /* The number of elements are determined by the input bus count as determined by the vtable, or `inputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */
pOutputChannels: ^u32, /* The number of elements are determined by the output bus count as determined by the vtable, or `outputBusCount` if the vtable specifies `MA_NODE_BUS_COUNT_UNKNOWN`. */
}
/*
A node has multiple output buses. An output bus is attached to an input bus as an item in a linked
list. Think of the input bus as a linked list, with the output bus being an item in that list.
*/
node_output_bus :: struct {
/* Immutable. */
pNode: ^node, /* The node that owns this output bus. The input node. Will be null for dummy head and tail nodes. */
outputBusIndex: u8, /* The index of the output bus on pNode that this output bus represents. */
channels: u8, /* The number of channels in the audio stream for this bus. */
/* Mutable via multiple threads. Must be used atomically. The weird ordering here is for packing reasons. */
inputNodeInputBusIndex: u8, /*atomic*/ /* The index of the input bus on the input. Required for detaching. */
flags: u32, /*atomic*/ /* Some state flags for tracking the read state of the output buffer. A combination of MA_NODE_OUTPUT_BUS_FLAG_*. */
refCount: u32, /*atomic*/ /* Reference count for some thread-safety when detaching. */
isAttached: b32, /*atomic*/ /* This is used to prevent iteration of nodes that are in the middle of being detached. Used for thread safety. */
lock: spinlock, /*atomic*/ /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
volume: f32, /*atomic*/ /* Linear. */
pNext: ^node_output_bus, /*atomic*/ /* If null, it's the tail node or detached. */
pPrev: ^node_output_bus, /*atomic*/ /* If null, it's the head node or detached. */
pInputNode: ^node, /*atomic*/ /* The node that this output bus is attached to. Required for detaching. */
}
/*
A node has multiple input buses. The output buses of a node are connecting to the input busses of
another. An input bus is essentially just a linked list of output buses.
*/
node_input_bus :: struct {
/* Mutable via multiple threads. */
head: node_output_bus, /* Dummy head node for simplifying some lock-free thread-safety stuff. */
nextCounter: u32, /*atomic*/ /* This is used to determine whether or not the input bus is finding the next node in the list. Used for thread safety when detaching output buses. */
lock: spinlock, /*atomic*/ /* Unfortunate lock, but significantly simplifies the implementation. Required for thread-safe attaching and detaching. */
/* Set once at startup. */
channels: u8, /* The number of channels in the audio stream for this bus. */
}
node_base :: struct {
/* These variables are set once at startup. */
pNodeGraph: ^node_graph, /* The graph this node belongs to. */
vtable: ^node_vtable,
pCachedData: [^]f32, /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */
cachedDataCapInFramesPerBus: u16, /* The capacity of the input data cache in frames, per bus. */
/* These variables are read and written only from the audio thread. */
cachedFrameCountOut: u16,
cachedFrameCountIn: u16,
consumedFrameCountIn: u16,
/* These variables are read and written between different threads. */
state: node_state, /*atomic*/ /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */
stateTimes: [2]u64, /*atomic*/ /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */
localTime: u64, /*atomic*/ /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */
inputBusCount: u32,
outputBusCount: u32,
pInputBuses: [^]node_input_bus,
pOutputBuses: [^]node_output_bus,
/* Memory management. */
_inputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_input_bus,
_outputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_output_bus,
_pHeap: rawptr, /* A heap allocation for internal use only. pInputBuses and/or pOutputBuses will point to this if the bus count exceeds MA_MAX_NODE_LOCAL_BUS_COUNT. */
_ownsHeap: b32, /* If set to true, the node owns the heap allocation and _pHeap will be freed in ma_node_uninit(). */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
node_config_init :: proc() -> node_config ---
node_get_heap_size :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pHeapSizeInBytes: ^c.size_t) -> result ---
node_init_preallocated :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pHeap: rawptr, pNode: ^node) -> result ---
node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^node) -> result ---
node_uninit :: proc(pNode: ^node, pAllocationCallbacks: ^allocation_callbacks) ---
node_get_node_graph :: proc(pNode: ^node) -> ^node_graph ---
node_get_input_bus_count :: proc(pNode: ^node) -> u32 ---
node_get_output_bus_count :: proc(pNode: ^node) -> u32 ---
node_get_input_channels :: proc(pNode: ^node, inputBusIndex: u32) -> u32 ---
node_get_output_channels :: proc(pNode: ^node, outputBusIndex: u32) -> u32 ---
node_attach_output_bus :: proc(pNode: ^node, outputBusIndex: u32, pOtherNode: ^node, otherNodeInputBusIndex: u32) -> result ---
node_detach_output_bus :: proc(pNode: ^node, outputBusIndex: u32) -> result ---
node_detach_all_output_buses :: proc(pNode: ^node) -> result ---
node_set_output_bus_volume :: proc(pNode: ^node, outputBusIndex: u32, volume: f32) -> result ---
node_get_output_bus_volume :: proc(pNode: ^node, outputBusIndex: u32) -> f32 ---
node_set_state :: proc(pNode: ^node, state: node_state) -> result ---
node_get_state :: proc(pNode: ^node) -> node_state ---
node_set_state_time :: proc(pNode: ^node, state: node_state, globalTime: u64) -> result ---
node_get_state_time :: proc(pNode: ^node, state: node_state) -> u64 ---
node_get_state_by_time :: proc(pNode: ^node, globalTime: u64) -> node_state ---
node_get_state_by_time_range :: proc(pNode: ^node, globalTimeBeg: u64, globalTimeEnd: u64) -> node_state ---
node_get_time :: proc(pNode: ^node) -> u64 ---
node_set_time :: proc(pNode: ^node, localTime: u64) -> result ---
}
node_graph_config :: struct {
channels: u32,
nodeCacheCapInFrames: u16,
}
node_graph :: struct {
/* Immutable. */
base: node_base, /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */
endpoint: node_base, /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */
nodeCacheCapInFrames: u16,
/* Read and written by multiple threads. */
isReading: b32, /*atomic*/
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
node_graph_config_init :: proc(channels: u32) -> node_graph_config ---
node_graph_init :: proc(pConfig: ^node_graph_config, pAllocationCallbacks: ^allocation_callbacks, pNodeGraph: ^node_graph) -> result ---
node_graph_uninit :: proc(pNodeGraph: ^node_graph, pAllocationCallbacks: ^allocation_callbacks) ---
node_graph_get_endpoint :: proc(pNodeGraph: ^node_graph) -> ^node ---
node_graph_read_pcm_frames :: proc(pNodeGraph: ^node_graph, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
node_graph_get_channels :: proc(pNodeGraph: ^node_graph) -> u32 ---
node_graph_get_time :: proc(pNodeGraph: ^node_graph) -> u64 ---
node_graph_set_time :: proc(pNodeGraph: ^node_graph, globalTime: u64) -> result ---
}
/* Data source node. 0 input buses, 1 output bus. Used for reading from a data source. */
data_source_node_config :: struct {
nodeConfig: node_config,
pDataSource: ^data_source,
}
data_source_node :: struct {
base: node_base,
pDataSource: ^data_source,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
data_source_node_config_init :: proc(pDataSource: ^data_source) -> data_source_node_config ---
data_source_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^data_source_node_config, pAllocationCallbacks: ^allocation_callbacks, pDataSourceNode: ^data_source_node) -> result ---
data_source_node_uninit :: proc(pDataSourceNode: ^data_source_node, pAllocationCallbacks: ^allocation_callbacks) ---
data_source_node_set_looping :: proc(pDataSourceNode: ^data_source_node, isLooping: b32) -> result ---
data_source_node_is_looping :: proc(pDataSourceNode: ^data_source_node) -> b32 ---
}
/* Splitter Node. 1 input, 2 outputs. Used for splitting/copying a stream so it can be as input into two separate output nodes. */
splitter_node_config :: struct {
nodeConfig: node_config,
channels: u32,
}
splitter_node :: struct {
base: node_base,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
splitter_node_config_init :: proc(channels: u32) -> splitter_node_config ---
splitter_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^splitter_node_config, pAllocationCallbacks: ^allocation_callbacks, pSplitterNode: ^splitter_node) -> result ---
splitter_node_uninit :: proc(pSplitterNode: ^splitter_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Biquad Node
*/
biquad_node_config :: struct {
nodeConfig: node_config,
biquad: biquad_config,
}
biquad_node :: struct {
baseNode: node_base,
biquad: biquad,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
biquad_node_config_init :: proc(channels: u32, b0, b1, b2, a0, a1, a2: f32) -> biquad_node_config ---
biquad_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^biquad_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^biquad_node) -> result ---
biquad_node_reinit :: proc(pConfig: ^biquad_config, pNode: ^biquad_node) -> result ---
biquad_node_uninit :: proc(pNode: ^biquad_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Low Pass Filter Node
*/
lpf_node_config :: struct {
nodeConfig: node_config,
lpf: lpf_config,
}
lpf_node :: struct {
baseNode: node_base,
lpf: lpf,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
lpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> lpf_node_config ---
lpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^lpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^lpf_node) -> result ---
lpf_node_reinit :: proc(pConfig: ^lpf_config, pNode: ^lpf_node) -> result ---
lpf_node_uninit :: proc(pNode: ^lpf_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
High Pass Filter Node
*/
hpf_node_config :: struct {
nodeConfig: node_config,
hpf: hpf_config,
}
hpf_node :: struct {
baseNode: node_base,
hpf: hpf,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
hpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> hpf_node_config ---
hpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^hpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^hpf_node) -> result ---
hpf_node_reinit :: proc(pConfig: ^hpf_config, pNode: ^hpf_node) -> result ---
hpf_node_uninit :: proc(pNode: ^hpf_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Band Pass Filter Node
*/
bpf_node_config :: struct {
nodeConfig: node_config,
bpf: bpf_config,
}
bpf_node :: struct {
baseNode: node_base,
bpf: bpf,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
bpf_node_config_init :: proc(channels, sampleRate: u32, cutoffFrequency: f64, order: u32) -> bpf_node_config ---
bpf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^bpf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^bpf_node) -> result ---
bpf_node_reinit :: proc(pConfig: ^bpf_config, pNode: ^bpf_node) -> result ---
bpf_node_uninit :: proc(pNode: ^bpf_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Notching Filter Node
*/
notch_node_config :: struct {
nodeConfig: node_config,
notch: notch_config,
}
notch_node :: struct {
baseNode: node_base,
notch: notch2,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
notch_node_config_init :: proc(channels, sampleRate: u32, q, frequency: f64) -> notch_node_config ---
notch_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^notch_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^notch_node) -> result ---
notch_node_reinit :: proc(pConfig: ^notch_config, pNode: ^notch_node) -> result ---
notch_node_uninit :: proc(pNode: ^notch_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Peaking Filter Node
*/
peak_node_config :: struct {
nodeConfig: node_config,
peak: peak_config,
}
peak_node :: struct {
baseNode: node_base,
peak: peak2,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
peak_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> peak_node_config ---
peak_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^peak_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^peak_node) -> result ---
peak_node_reinit :: proc(pConfig: ^peak_config, pNode: ^peak_node) -> result ---
peak_node_uninit :: proc(pNode: ^peak_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Low Shelf Filter Node
*/
loshelf_node_config :: struct {
nodeConfig: node_config,
loshelf: loshelf_config,
}
loshelf_node :: struct {
baseNode: node_base,
loshelf: loshelf2,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
loshelf_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> loshelf_node_config ---
loshelf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^loshelf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^loshelf_node) -> result ---
loshelf_node_reinit :: proc(pConfig: ^loshelf_config, pNode: ^loshelf_node) -> result ---
loshelf_node_uninit :: proc(pNode: ^loshelf_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
High Shelf Filter Node
*/
hishelf_node_config :: struct {
nodeConfig: node_config,
hishelf: hishelf_config,
}
hishelf_node :: struct {
baseNode: node_base,
hishelf: hishelf2,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
hishelf_node_config_init :: proc(channels, sampleRate: u32, gainDB, q, frequency: f64) -> hishelf_node_config ---
hishelf_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^hishelf_node_config, pAllocationCallbacks: ^allocation_callbacks, pNode: ^hishelf_node) -> result ---
hishelf_node_reinit :: proc(pConfig: ^hishelf_config, pNode: ^hishelf_node) -> result ---
hishelf_node_uninit :: proc(pNode: ^hishelf_node, pAllocationCallbacks: ^allocation_callbacks) ---
}
/*
Delay Filter Node
*/
delay_node_config :: struct {
nodeConfig: node_config,
delay: delay_config,
}
delay_node :: struct {
baseNode: node_base,
delay: delay,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
delay_node_config_init :: proc(channels, sampleRate, delayInFrames: u32, decay: f32) -> delay_node_config ---
delay_node_init :: proc(pNodeGraph: ^node_graph, pConfig: ^delay_node_config, pAllocationCallbacks: ^allocation_callbacks, pDelayNode: ^delay_node) -> result ---
delay_node_uninit :: proc(pDelayNode: ^delay_node, pAllocationCallbacks: ^allocation_callbacks) ---
delay_node_set_wet :: proc(pDelayNode: ^delay_node, value: f32) ---
delay_node_get_wet :: proc(pDelayNode: ^delay_node) -> f32 ---
delay_node_set_dry :: proc(pDelayNode: ^delay_node, value: f32) ---
delay_node_get_dry :: proc(pDelayNode: ^delay_node) -> f32 ---
delay_node_set_decay :: proc(pDelayNode: ^delay_node, value: f32) ---
delay_node_get_decay :: proc(pDelayNode: ^delay_node) -> f32 ---
}
+288
View File
@@ -0,0 +1,288 @@
package miniaudio
import "core:c"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
Resource Manager
************************************************************************************************************************************************************/
resource_manager_data_source_flags :: enum c.int {
STREAM = 0x00000001, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */
WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
UNKNOWN_LENGTH = 0x00000010, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */
}
/*
Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional.
*/
resource_manager_pipeline_stage_notification :: struct {
pNotification: ^async_notification,
pFence: ^fence,
}
resource_manager_pipeline_notifications :: struct {
init: resource_manager_pipeline_stage_notification, /* Initialization of the decoder. */
done: resource_manager_pipeline_stage_notification, /* Decoding fully completed. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
resource_manager_pipeline_notifications_init :: proc() -> resource_manager_pipeline_notifications ---
}
/* BEGIN BACKWARDS COMPATIBILITY */
/* TODO: Remove this block in version 0.12. */
resource_manager_job :: job
resource_manager_job_init :: job_init
JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING :: job_queue_flags.NON_BLOCKING
resource_manager_job_queue_config :: job_queue_config
resource_manager_job_queue_config_init :: job_queue_config_init
resource_manager_job_queue :: job_queue
resource_manager_job_queue_get_heap_size :: job_queue_get_heap_size
resource_manager_job_queue_init_preallocated :: job_queue_init_preallocated
resource_manager_job_queue_init :: job_queue_init
resource_manager_job_queue_uninit :: job_queue_uninit
resource_manager_job_queue_post :: job_queue_post
resource_manager_job_queue_next :: job_queue_next
/* END BACKWARDS COMPATIBILITY */
/* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */
RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT :: 64
resource_manager_flags :: enum c.int {
/* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
NON_BLOCKING = 0x00000001,
/* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
NO_THREADING = 0x00000002,
}
resource_manager_data_source_config :: struct {
pFilePath: cstring,
pFilePathW: [^]c.wchar_t,
pNotifications: ^resource_manager_pipeline_notifications,
initialSeekPointInPCMFrames: u64,
rangeBegInPCMFrames: u64,
rangeEndInPCMFrames: u64,
loopPointBegInPCMFrames: u64,
loopPointEndInPCMFrames: u64,
isLooping: b32,
flags: u32,
}
resource_manager_data_supply_type :: enum c.int {
unknown = 0, /* Used for determining whether or the data supply has been initialized. */
encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */
decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */
decoded_paged, /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */
}
resource_manager_data_supply :: struct {
type: resource_manager_data_supply_type, /*atomic*/ /* Read and written from different threads so needs to be accessed atomically. */
backend: struct #raw_union {
encoded: struct {
pData: rawptr,
sizeInBytes: c.size_t,
},
decoded: struct {
pData: rawptr,
totalFrameCount: u64,
decodedFrameCount: u64,
format: format,
channels: u32,
sampleRate: u32,
},
decodedPaged: struct {
data: paged_audio_buffer_data,
decodedFrameCount: u64,
sampleRate: u32,
},
},
}
resource_manager_data_buffer_node :: struct {
hashedName32: u32, /* The hashed name. This is the key. */
refCount: u32,
result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */
executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
isDataOwnedByResourceManager: b32, /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */
data: resource_manager_data_supply,
pParent: ^resource_manager_data_buffer_node,
pChildLo: ^resource_manager_data_buffer_node,
pChildHi: ^resource_manager_data_buffer_node,
}
resource_manager_data_buffer :: struct {
ds: data_source_base, /* Base data source. A data buffer is a data source. */
pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this buffer. */
pNode: ^resource_manager_data_buffer_node, /* The data node. This is reference counted and is what supplies the data. */
flags: u32, /* The flags that were passed used to initialize the buffer. */
executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
seekTargetInPCMFrames: u64, /* Only updated by the public API. Never written nor read from the job thread. */
seekToCursorOnNextRead: b32, /* On the next read we need to seek to the frame cursor. */
result: result, /*atomic*/ /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */
isLooping: b32, /*atomic*/ /* Can be read and written by different threads at the same time. Must be used atomically. */
isConnectorInitialized: b32, /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */
connector: struct #raw_union {
decoder: decoder, /* Supply type is ma_resource_manager_data_supply_type_encoded */
buffer: audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded */
pagedBuffer: paged_audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */
}, /* Connects this object to the node's data supply. */
}
resource_manager_data_stream :: struct {
ds: data_source_base, /* Base data source. A data stream is a data source. */
pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this data stream. */
flags: u32, /* The flags that were passed used to initialize the stream. */
decoder: decoder, /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */
isDecoderInitialized: b32, /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */
totalLengthInPCMFrames: u64, /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */
relativeCursor: u32, /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */
absoluteCursor: u64, /*atomic*/ /* The playback cursor, in absolute position starting from the start of the file. */
currentPageIndex: u32, /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */
executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
/* Written by the public API, read by the job thread. */
isLooping: b32, /*atomic*/ /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */
/* Written by the job thread, read by the public API. */
pPageData: rawptr, /* Buffer containing the decoded data of each page. Allocated once at initialization time. */
pageFrameCount: [2]u32, /*atomic*/ /* The number of valid PCM frames in each page. Used to determine the last valid frame. */
/* Written and read by both the public API and the job thread. These must be atomic. */
result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */
isDecoderAtEnd: b32, /*atomic*/ /* Whether or not the decoder has reached the end. */
isPageValid: [2]b32, /*atomic*/ /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */
seekCounter: b32, /*atomic*/ /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */
}
resource_manager_data_source :: struct {
backend: struct #raw_union {
buffer: resource_manager_data_buffer,
stream: resource_manager_data_stream,
}, /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */
flags: u32, /* The flags that were passed in to ma_resource_manager_data_source_init(). */
executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
}
resource_manager_config :: struct {
allocationCallbacks: allocation_callbacks,
pLog: ^log,
decodedFormat: format, /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */
decodedChannels: u32, /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */
decodedSampleRate: u32, /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */
jobThreadCount: u32, /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */
jobQueueCapacity: u32, /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */
flags: u32,
pVFS: ^vfs, /* Can be NULL in which case defaults will be used. */
ppCustomDecodingBackendVTables: ^[^]decoding_backend_vtable,
customDecodingBackendCount: u32,
pCustomDecodingBackendUserData: rawptr,
}
resource_manager :: struct {
config: resource_manager_config,
pRootDataBufferNode: ^resource_manager_data_buffer_node, /* The root buffer in the binary tree. */
dataBufferBSTLock: (struct {} when NO_THREADING else mutex), /* For synchronizing access to the data buffer binary tree. */
jobThreads: (struct {} when NO_THREADING else [RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]thread), /* The threads for executing jobs. */
jobQueue: job_queue, /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */
defaultVFS: default_vfs, /* Only used if a custom VFS is not specified. */
log: log, /* Only used if no log was specified in the config. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
resource_manager_data_source_config_init :: proc() -> resource_manager_data_source_config ---
resource_manager_config_init :: proc() -> resource_manager_config ---
/* Init. */
resource_manager_init :: proc(pConfig: ^resource_manager_config, pResourceManager: ^resource_manager) -> result ---
resource_manager_uninit :: proc(pResourceManager: ^resource_manager) ---
resource_manager_get_log :: proc(pResourceManager: ^resource_manager) -> ^log ---
/* Registration. */
resource_manager_register_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32) -> result ---
resource_manager_register_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32) -> result ---
resource_manager_register_decoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
resource_manager_register_decoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result ---
resource_manager_register_encoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, sizeInBytes: c.size_t) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
resource_manager_register_encoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, sizeInBytes: c.size_t) -> result ---
resource_manager_unregister_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring) -> result ---
resource_manager_unregister_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t) -> result ---
resource_manager_unregister_data :: proc(pResourceManager: ^resource_manager, pName: cstring) -> result ---
resource_manager_unregister_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t) -> result ---
/* Data Buffers. */
resource_manager_data_buffer_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataBuffer, pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_uninit :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_read_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
resource_manager_data_buffer_seek_to_pcm_frame :: proc(pDataBuffer: ^resource_manager_data_buffer, frameIndex: u64) -> result ---
resource_manager_data_buffer_get_data_format :: proc(pDataBuffer: ^resource_manager_data_buffer, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
resource_manager_data_buffer_get_cursor_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pCursor: ^u64) -> result ---
resource_manager_data_buffer_get_length_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pLength: ^u64) -> result ---
resource_manager_data_buffer_result :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result ---
resource_manager_data_buffer_set_looping :: proc(pDataBuffer: ^resource_manager_data_buffer, isLooping: b32) -> result ---
resource_manager_data_buffer_is_looping :: proc(pDataBuffer: ^resource_manager_data_buffer) -> b32 ---
resource_manager_data_buffer_get_available_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pAvailableFrames: ^u64) -> result ---
/* Data Streams. */
resource_manager_data_stream_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataStream: ^resource_manager_data_stream) -> result ---
resource_manager_data_stream_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result ---
resource_manager_data_stream_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result ---
resource_manager_data_stream_uninit :: proc(pDataStream: ^resource_manager_data_stream) -> result ---
resource_manager_data_stream_read_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
resource_manager_data_stream_seek_to_pcm_frame :: proc(pDataStream: ^resource_manager_data_stream, frameIndex: u64) -> result ---
resource_manager_data_stream_get_data_format :: proc(pDataStream: ^resource_manager_data_stream, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
resource_manager_data_stream_get_cursor_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pCursor: ^u64) -> result ---
resource_manager_data_stream_get_length_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pLength: ^u64) -> result ---
resource_manager_data_stream_result :: proc(pDataStream: ^resource_manager_data_stream) -> result ---
resource_manager_data_stream_set_looping :: proc(pDataStream: ^resource_manager_data_stream, isLooping: b32) -> result ---
resource_manager_data_stream_is_looping :: proc(pDataStream: ^resource_manager_data_stream) -> b32 ---
resource_manager_data_stream_get_available_frames :: proc(pDataStream: ^resource_manager_data_stream, pAvailableFrames: ^u64) -> result ---
/* Data Sources. */
resource_manager_data_source_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_init :: proc(pResourceManager: ^resource_manager, pName: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_init_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataSource, pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_uninit :: proc(pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_read_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
resource_manager_data_source_seek_to_pcm_frame :: proc(pDataSource: ^resource_manager_data_source, frameIndex: u64) -> result ---
resource_manager_data_source_get_data_format :: proc(pDataSource: ^resource_manager_data_source, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
resource_manager_data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pCursor: ^u64) -> result ---
resource_manager_data_source_get_length_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pLength: ^u64) -> result ---
resource_manager_data_source_result :: proc(pDataSource: ^resource_manager_data_source) -> result ---
resource_manager_data_source_set_looping :: proc(pDataSource: ^resource_manager_data_source, isLooping: b32) -> result ---
resource_manager_data_source_is_looping :: proc(pDataSource: ^resource_manager_data_source) -> b32 ---
resource_manager_data_source_get_available_frames :: proc(pDataSource: ^resource_manager_data_source, pAvailableFrames: ^u64) -> result ---
/* Job management. */
resource_manager_post_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result ---
resource_manager_post_job_quit :: proc(pResourceManager: ^resource_manager) -> result --- /* Helper for posting a quit job. */
resource_manager_next_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result ---
resource_manager_process_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result --- /* DEPRECATED. Use ma_job_process(). Will be removed in version 0.12. */
resource_manager_process_next_job :: proc(pResourceManager: ^resource_manager) -> result --- /* Returns MA_CANCELLED if a MA_JOB_TYPE_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */
}
+3 -3
View File
@@ -1,6 +1,6 @@
all:
mkdir -p ../lib
gcc -c -O2 -Os -fPIC miniaudio.c
ar rcs ../lib/miniaudio.a miniaudio.o
#gcc -fPIC -shared -Wl,-soname=miniaudio.so -o ../lib/miniaudio.so miniaudio.o
$(CC) -c -O2 -Os -fPIC miniaudio.c
$(AR) rcs ../lib/miniaudio.a miniaudio.o
#$(CC) -fPIC -shared -Wl,-soname=miniaudio.so -o ../lib/miniaudio.so miniaudio.o
rm *.o
+27411 -7221
View File
File diff suppressed because it is too large Load Diff
+152
View File
@@ -0,0 +1,152 @@
package miniaudio
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/*
Locks a spinlock.
*/
spinlock_lock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
/*
Locks a spinlock, but does not yield() when looping.
*/
spinlock_lock_noyield :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
/*
Unlocks a spinlock.
*/
spinlock_unlock :: proc(/*volatile*/ pSpinlock: ^spinlock) -> result ---
when NO_THREADING {
/*
Creates a mutex.
A mutex must be created from a valid context. A mutex is initially unlocked.
*/
mutex_init :: proc(pMutex: ^mutex) -> result ---
/*
Deletes a mutex.
*/
mutex_uninit :: proc(pMutex: ^mutex) ---
/*
Locks a mutex with an infinite timeout.
*/
mutex_lock :: proc(pMutex: ^mutex) ---
/*
Unlocks a mutex.
*/
mutex_unlock :: proc(pMutex: ^mutex) ---
/*
Initializes an auto-reset event.
*/
event_init :: proc(pEvent: ^event) -> result ---
/*
Uninitializes an auto-reset event.
*/
event_uninit :: proc(pEvent: ^event) ---
/*
Waits for the specified auto-reset event to become signalled.
*/
event_wait :: proc(pEvent: ^event) -> result ---
/*
Signals the specified auto-reset event.
*/
event_signal :: proc(pEvent: ^event) -> result ---
} /* NO_THREADING */
}
/*
Fence
=====
This locks while the counter is larger than 0. Counter can be incremented and decremented by any
thread, but care needs to be taken when waiting. It is possible for one thread to acquire the
fence just as another thread returns from ma_fence_wait().
The idea behind a fence is to allow you to wait for a group of operations to complete. When an
operation starts, the counter is incremented which locks the fence. When the operation completes,
the fence will be released which decrements the counter. ma_fence_wait() will block until the
counter hits zero.
If threading is disabled, ma_fence_wait() will spin on the counter.
*/
fence :: struct {
e: (struct {} when NO_THREADING else event),
counter: (u32 when NO_THREADING else struct {}),
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
fence_init :: proc(pFence: ^fence) -> result ---
fence_uninit :: proc(pFence: ^fence) ---
fence_acquire :: proc(pFence: ^fence) -> result --- /* Increment counter. */
fence_release :: proc(pFence: ^fence) -> result --- /* Decrement counter. */
fence_wait :: proc(pFence: ^fence) -> result --- /* Wait for counter to reach 0. */
}
/*
Notification callback for asynchronous operations.
*/
async_notification :: struct {}
async_notification_callbacks :: struct {
onSignal: proc "c" (pNotification: ^async_notification),
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
async_notification_signal :: proc(pNotification: ^async_notification) -> result ---
}
/*
Simple polling notification.
This just sets a variable when the notification has been signalled which is then polled with ma_async_notification_poll_is_signalled()
*/
async_notification_poll :: struct {
cb: async_notification_callbacks,
signalled: b32,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
async_notification_poll_init :: proc(pNotificationPoll: ^async_notification_poll) -> result ---
async_notification_poll_is_signalled :: proc(pNotificationPoll: ^async_notification_poll) -> b32 ---
}
/*
Event Notification
This uses an ma_event. If threading is disabled (MA_NO_THREADING), initialization will fail.
*/
async_notification_event :: struct {
cb: async_notification_callbacks,
e: (struct {} when NO_THREADING else event),
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
async_notification_event_init :: proc(pNotificationEvent: ^async_notification_event) -> result ---
async_notification_event_uninit :: proc(pNotificationEvent: ^async_notification_event) -> result ---
async_notification_event_wait :: proc(pNotificationEvent: ^async_notification_event) -> result ---
async_notification_event_signal :: proc(pNotificationEvent: ^async_notification_event) -> result ---
}
+128 -58
View File
@@ -1,17 +1,17 @@
package miniaudio
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
import c "core:c/libc"
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
/*
Adjust buffer size based on a scaling factor.
This just multiplies the base size by the scaling factor, making sure it's a size of at least 1.
*/
scale_buffer_size :: proc(baseBufferSize: u32, scale: f32) -> u32 ---
/*
Calculates a buffer size in milliseconds from the specified number of frames and sample rate.
*/
@@ -46,9 +46,14 @@ foreign lib {
/*
Clips f32 samples.
Clips samples.
*/
clip_samples_f32 :: proc(p: [^]f32, sampleCount: u64) ---
clip_samples_u8 :: proc(pDst: [^]u8, pSrc: [^]i16, count: u64) ---
clip_samples_s16 :: proc(pDst: [^]i16, pSrc: [^]i32, count: u64) ---
clip_samples_s24 :: proc(pDst: [^]u8, pSrc: [^]i64, count: u64) ---
clip_samples_s32 :: proc(pDst: [^]i32, pSrc: [^]i64, count: u64) ---
clip_samples_f32 :: proc(pDst, pSrc: [^]f32, count: u64) ---
clip_pcm_frames :: proc(pDst, pSrc: rawptr, frameCount: u64, format: format, channels: u32) ---
/*
Helper for applying a volume factor to samples.
@@ -81,20 +86,26 @@ foreign lib {
apply_volume_factor_pcm_frames_f32 :: proc(pFrames: [^]f32, frameCount: u64, channels: u32, factor: f32) ---
apply_volume_factor_pcm_frames :: proc(pFrames: rawptr, frameCount: u64, format: format, channels: u32, factor: f32) ---
copy_and_apply_volume_factor_per_channel_f32 :: proc(pFramesOut, pFramesIn: [^]f32, frameCount: u64, channels: u32, pChannelGains: [^]f32) ---
ma_copy_and_apply_volume_and_clip_samples_u8 :: proc(pDst: [^]u8, pSrc: [^]i16, count: u64, volume: f32) ---
ma_copy_and_apply_volume_and_clip_samples_s16 :: proc(pDst: [^]i16, pSrc: [^]i32, count: u64, volume: f32) ---
ma_copy_and_apply_volume_and_clip_samples_s24 :: proc(pDst: [^]u8, pSrc: [^]i64, count: u64, volume: f32) ---
ma_copy_and_apply_volume_and_clip_samples_s32 :: proc(pDst: [^]i32, pSrc: [^]i64, count: u64, volume: f32) ---
ma_copy_and_apply_volume_and_clip_samples_f32 :: proc(pDst, pSrc: [^]f32, count: u64, volume: f32) ---
ma_copy_and_apply_volume_and_clip_pcm_frames :: proc(pDst, pSrc: rawptr, frameCount: u64, format: format, channels: u32, volume: f32) ---
/*
Helper for converting a linear factor to gain in decibels.
*/
factor_to_gain_db :: proc(factor: f32) -> f32 ---
volume_linear_to_db :: proc(factor: f32) -> f32 ---
/*
Helper for converting gain in decibels to a linear factor.
*/
gain_db_to_factor :: proc(gain: f32) -> f32 ---
}
zero_pcm_frames :: #force_inline proc "c" (p: rawptr, frameCount: u64, format: format, channels: u32) {
silence_pcm_frames(p, frameCount, format, channels)
volume_db_to_linear :: proc(gain: f32) -> f32 ---
}
offset_pcm_frames_ptr_f32 :: #force_inline proc "c" (p: [^]f32, offsetInFrames: u64, channels: u32) -> [^]f32 {
@@ -104,23 +115,20 @@ offset_pcm_frames_const_ptr_f32 :: #force_inline proc "c" (p: [^]f32, offsetInFr
return cast([^]f32)offset_pcm_frames_ptr(p, offsetInFrames, .f32, channels)
}
clip_pcm_frames_f32 :: #force_inline proc "c" (p: [^]f32, frameCount: u64, channels: u32) {
clip_samples_f32(p, frameCount*u64(channels))
}
data_source :: struct {}
DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT :: 0x00000001
data_source_vtable :: struct {
onRead: proc "c" (pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result,
onSeek: proc "c" (pDataSource: ^data_source, frameIndex: u64) -> result,
onMap: proc "c" (pDataSource: ^data_source, ppFramesOut: ^rawptr, pFrameCount: ^u64) -> result, /* Returns MA_AT_END if the end has been reached. This should be considered successful. */
onUnmap: proc "c" (pDataSource: ^data_source, frameCount: u64) -> result,
onGetDataFormat: proc "c" (pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32) -> result,
onGetDataFormat: proc "c" (pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result,
onGetCursor: proc "c" (pDataSource: ^data_source, pCursor: ^u64) -> result,
onGetLength: proc "c" (pDataSource: ^data_source, pLength: ^u64) -> result,
onSetLooping: proc "c" (pDataSource: ^data_source, isLooping: b32) -> result,
flags: u32,
}
data_source_callbacks :: data_source_vtable /* TODO: Remove ma_data_source_callbacks in version 0.11. */
data_source_get_next_proc :: proc "c" (pDataSource: ^data_source) -> ^data_source
@@ -129,45 +137,43 @@ data_source_config :: struct {
}
data_source_base :: struct {
cb: data_source_callbacks, /* TODO: Remove this. */
/* Variables below are placeholder and not yet used. */
vtable: ^data_source_vtable,
rangeBegInFrames: u64,
rangeEndInFrames: u64, /* Set to -1 for unranged (default). */
loopBegInFrames: u64, /* Relative to rangeBegInFrames. */
loopEndInFrames: u64, /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */
pCurrent: ^data_source, /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */
pNext: ^data_source, /* When set to NULL, onGetNext will be used. */
onGetNext: ^data_source_get_next_proc, /* Will be used when pNext is NULL. If both are NULL, no next will be used. */
rangeEndInFrames: u64, /* Set to -1 for unranged (default). */
loopBegInFrames: u64, /* Relative to rangeBegInFrames. */
loopEndInFrames: u64, /* Relative to rangeBegInFrames. Set to -1 for the end of the range. */
pCurrent: ^data_source, /* When non-NULL, the data source being initialized will act as a proxy and will route all operations to pCurrent. Used in conjunction with pNext/onGetNext for seamless chaining. */
pNext: ^data_source, /* When set to NULL, onGetNext will be used. */
onGetNext: data_source_get_next_proc, /* Will be used when pNext is NULL. If both are NULL, no next will be used. */
isLooping: b32, /*atomic*/
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
ma_data_source_config_init :: proc() -> data_source_config ---
data_source_config_init :: proc() -> data_source_config ---
data_source_init :: proc(pConfig: ^data_source_config, pDataSource: ^data_source) -> result ---
data_source_uninit :: proc(pDataSource: ^data_source) ---
data_source_read_pcm_frames :: proc(pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64, loop: b32) -> result --- /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
data_source_seek_pcm_frames :: proc(pDataSource: ^data_source, frameCount: u64, pFramesSeeked: ^u64, loop: b32) -> result --- /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
data_source_seek_to_pcm_frame :: proc(pDataSource: ^data_source, frameIndex: u64) -> result ---
data_source_map :: proc(pDataSource: ^data_source, ppFramesOut: ^rawptr, pFrameCount: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if mapping is not supported. */
data_source_unmap :: proc(pDataSource: ^data_source, frameCount: u64) -> result --- /* Returns MA_AT_END if the end has been reached. */
data_source_get_data_format :: proc(pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32) -> result ---
data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^data_source, pCursor: ^u64) -> result ---
data_source_get_length_in_pcm_frames :: proc(pDataSource: ^data_source, pLength: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
// #if defined(MA_EXPERIMENTAL__DATA_LOOPING_AND_CHAINING)
// MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 rangeBegInFrames, ma_uint64 rangeEndInFrames);
// MA_API void ma_data_source_get_range_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pRangeBegInFrames, ma_uint64* pRangeEndInFrames);
// MA_API ma_result ma_data_source_set_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64 loopBegInFrames, ma_uint64 loopEndInFrames);
// MA_API void ma_data_source_get_loop_point_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLoopBegInFrames, ma_uint64* pLoopEndInFrames);
// MA_API ma_result ma_data_source_set_current(ma_data_source* pDataSource, ma_data_source* pCurrentDataSource);
// MA_API ma_data_source* ma_data_source_get_current(ma_data_source* pDataSource);
// MA_API ma_result ma_data_source_set_next(ma_data_source* pDataSource, ma_data_source* pNextDataSource);
// MA_API ma_data_source* ma_data_source_get_next(ma_data_source* pDataSource);
// MA_API ma_result ma_data_source_set_next_callback(ma_data_source* pDataSource, ma_data_source_get_next_proc onGetNext);
// MA_API ma_data_source_get_next_proc ma_data_source_get_next_callback(ma_data_source* pDataSource);
// #endif
data_source_init :: proc(pConfig: ^data_source_config, pDataSource: ^data_source) -> result ---
data_source_uninit :: proc(pDataSource: ^data_source) ---
data_source_read_pcm_frames :: proc(pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* Must support pFramesOut = NULL in which case a forward seek should be performed. */
data_source_seek_pcm_frames :: proc(pDataSource: ^data_source, frameCount: u64, pFramesSeeked: ^u64) -> result --- /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */
data_source_seek_to_pcm_frame :: proc(pDataSource: ^data_source, frameIndex: u64) -> result ---
data_source_get_data_format :: proc(pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^data_source, pCursor: ^u64) -> result ---
data_source_get_length_in_pcm_frames :: proc(pDataSource: ^data_source, pLength: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */
data_source_get_cursor_in_seconds :: proc(pDataSource: ^data_source, pCursor: ^f32) -> result ---
data_source_get_length_in_seconds :: proc(pDataSource: ^data_source, pLength: ^f32) -> result ---
data_source_set_looping :: proc(pDataSource: ^data_source, isLooping: b32) -> result ---
data_source_is_looping :: proc(pDataSource: ^data_source) -> b32 ---
data_source_set_range_in_pcm_frames :: proc(pDataSource: ^data_source, rangeBegInFrames: u64, rangeEndInFrames: u64) -> result ---
data_source_get_range_in_pcm_frames :: proc(pDataSource: ^data_source, pRangeBegInFrames: ^u64, pRangeEndInFrames: ^u64) ---
data_source_set_loop_point_in_pcm_frames :: proc(pDataSource: ^data_source, loopBegInFrames: u64, loopEndInFrames: u64) -> result ---
data_source_get_loop_point_in_pcm_frames :: proc(pDataSource: ^data_source, pLoopBegInFrames: ^u64, pLoopEndInFrames: ^u64) ---
data_source_set_current :: proc(pDataSource: ^data_source, pCurrentDataSource: ^data_source) -> result ---
data_source_get_current :: proc(pDataSource: ^data_source) -> ^data_source ---
data_source_set_next :: proc(pDataSource: ^data_source, pNextDataSource: ^data_source) -> result ---
data_source_get_next :: proc(pDataSource: ^data_source) -> ^data_source ---
data_source_set_next_callback :: proc(pDataSource: ^data_source, onGetNext: ^data_source_get_next_proc) -> result ---
data_source_get_next_callback :: proc(pDataSource: ^data_source) -> ^data_source_get_next_proc ---
}
@@ -175,6 +181,7 @@ audio_buffer_ref :: struct {
ds: data_source_base,
format: format,
channels: u32,
sampleRate: u32,
cursor: u64,
sizeInFrames: u64,
pData: rawptr,
@@ -199,6 +206,7 @@ foreign lib {
audio_buffer_config :: struct {
format: format,
channels: u32,
sampleRate: u32,
sizeInFrames: u64,
pData: rawptr, /* If set to NULL, will allocate a block of memory for you. */
allocationCallbacks: allocation_callbacks,
@@ -228,4 +236,66 @@ foreign lib {
audio_buffer_get_cursor_in_pcm_frames :: proc(pAudioBuffer: ^audio_buffer, pCursor: ^u64) -> result ---
audio_buffer_get_length_in_pcm_frames :: proc(pAudioBuffer: ^audio_buffer, pLength: ^u64) -> result ---
audio_buffer_get_available_frames :: proc(pAudioBuffer: ^audio_buffer, pAvailableFrames: ^u64) -> result ---
}
}
/*
Paged Audio Buffer
==================
A paged audio buffer is made up of a linked list of pages. It's expandable, but not shrinkable. It
can be used for cases where audio data is streamed in asynchronously while allowing data to be read
at the same time.
This is lock-free, but not 100% thread safe. You can append a page and read from the buffer across
simultaneously across different threads, however only one thread at a time can append, and only one
thread at a time can read and seek.
*/
paged_audio_buffer_page :: struct {
pNext: ^paged_audio_buffer_page, /*atomic*/
sizeInFrames: u64,
pAudioData: [1]u8,
}
paged_audio_buffer_data :: struct {
format: format,
channels: u32,
head: paged_audio_buffer_page, /* Dummy head for the lock-free algorithm. Always has a size of 0. */
pTail: ^paged_audio_buffer_page, /*atomic*/ /* Never null. Initially set to &head. */
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
paged_audio_buffer_data_init :: proc(format: format, channels: u32, pData: ^paged_audio_buffer_data) -> result ---
paged_audio_buffer_data_uninit :: proc(pData: ^paged_audio_buffer_data, pAllocationCallbacks: ^allocation_callbacks) ---
paged_audio_buffer_data_get_head :: proc(pData: ^paged_audio_buffer_data) -> ^paged_audio_buffer_page ---
paged_audio_buffer_data_get_tail :: proc(pData: ^paged_audio_buffer_data) -> ^paged_audio_buffer_page ---
paged_audio_buffer_data_get_length_in_pcm_frames :: proc(pData: ^paged_audio_buffer_data, pLength: ^u64) -> result ---
paged_audio_buffer_data_allocate_page :: proc(pData: ^paged_audio_buffer_data, pageSizeInFrames: u64, pInitialData: rawptr, pAllocationCallbacks: ^allocation_callbacks, ppPage: ^^paged_audio_buffer_page) -> result ---
paged_audio_buffer_data_free_page :: proc(pData: ^paged_audio_buffer_data, pPage: ^paged_audio_buffer_page, pAllocationCallbacks: ^allocation_callbacks) -> result ---
paged_audio_buffer_data_append_page :: proc(pData: ^paged_audio_buffer_data, pPage: ^paged_audio_buffer_page) -> result ---
paged_audio_buffer_data_allocate_and_append_page :: proc(pData: ^paged_audio_buffer_data, pageSizeInFrames: u32, pInitialData: rawptr, pAllocationCallbacks: ^allocation_callbacks) -> result ---
}
paged_audio_buffer_config :: struct {
pData: ^paged_audio_buffer_data, /* Must not be null. */
}
paged_audio_buffer :: struct {
ds: data_source_base,
pData: ^paged_audio_buffer_data, /* Audio data is read from here. Cannot be null. */
pCurrent: ^paged_audio_buffer_page,
relativeCursor: u64, /* Relative to the current page. */
absoluteCursor: u64,
}
@(default_calling_convention="c", link_prefix="ma_")
foreign lib {
paged_audio_buffer_config_init :: proc(pData: ^paged_audio_buffer_data) -> paged_audio_buffer_config ---
paged_audio_buffer_init :: proc(pConfig: ^paged_audio_buffer_config, pPagedAudioBuffer: ^paged_audio_buffer) -> result ---
paged_audio_buffer_uninit :: proc(pPagedAudioBuffer: ^paged_audio_buffer) ---
paged_audio_buffer_read_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* Returns MA_AT_END if no more pages available. */
paged_audio_buffer_seek_to_pcm_frame :: proc(pPagedAudioBuffer: ^paged_audio_buffer, frameIndex: u64) -> result ---
paged_audio_buffer_get_cursor_in_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pCursor: ^u64) -> result ---
paged_audio_buffer_get_length_in_pcm_frames :: proc(pPagedAudioBuffer: ^paged_audio_buffer, pLength: ^u64) -> result ---
}
+11 -8
View File
@@ -2,8 +2,13 @@ package miniaudio
import "core:c"
when ODIN_OS == "windows" { foreign import lib "lib/miniaudio.lib" }
when ODIN_OS == "linux" { foreign import lib "lib/miniaudio.a" }
when ODIN_OS == .Windows {
foreign import lib "lib/miniaudio.lib"
} else when ODIN_OS == .Linux {
foreign import lib "lib/miniaudio.a"
} else {
foreign import lib "system:miniaudio"
}
/************************************************************************************************************************************************************
@@ -17,8 +22,10 @@ appropriate for a given situation.
vfs :: struct {}
vfs_file :: distinct handle
OPEN_MODE_READ :: 0x00000001
OPEN_MODE_WRITE :: 0x00000002
open_mode_flags :: enum c.int {
READ = 0x00000001,
WRITE = 0x00000002,
}
seek_origin :: enum c.int {
start,
@@ -66,10 +73,6 @@ foreign lib {
default_vfs_init :: proc(pVFS: ^default_vfs, pAllocationCallbacks: ^allocation_callbacks) -> result ---
}
resource_format :: enum c.int {
wav,
}
encoding_format :: enum c.int {
unknown = 0,
wav,
+4 -2
View File
@@ -3,12 +3,14 @@ package portmidi
import "core:c"
import "core:strings"
when ODIN_OS == "windows" {
when ODIN_OS == .Windows {
foreign import lib {
"portmidi_s.lib",
"system:Winmm.lib",
"system:Advapi32.lib",
}
} else {
foreign import lib "system:portmidi"
}
#assert(size_of(b32) == size_of(c.int))
@@ -519,4 +521,4 @@ foreign lib {
WriteSysEx() writes a timestamped system-exclusive midi message.
*/
WriteSysEx :: proc(stream: Stream, whence: Timestamp, msg: cstring) -> Error ---
}
}
+6 -2
View File
@@ -7,7 +7,11 @@ package portmidi
import "core:c"
when ODIN_OS == "windows" { foreign import lib "portmidi_s.lib" }
when ODIN_OS == .Windows {
foreign import lib "portmidi_s.lib"
} else {
foreign import lib "system:portmidi"
}
Queue :: distinct rawptr
@@ -118,4 +122,4 @@ foreign lib {
state, returns .NoError if successfully set overflow state.
*/
SetOverflow :: proc(queue: Queue) -> Error ---
}
}
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More