mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-28 17:04:34 +00:00
Merge branch 'odin-lang:master' into patch-2
This commit is contained in:
@@ -64,8 +64,16 @@ Image_Metadata :: union #shared_nil {
|
||||
^QOI_Info,
|
||||
^TGA_Info,
|
||||
^BMP_Info,
|
||||
^JPEG_Info,
|
||||
}
|
||||
|
||||
Exif :: struct {
|
||||
byte_order: enum {
|
||||
little_endian,
|
||||
big_endian,
|
||||
},
|
||||
data: []u8 `fmt:"-"`,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -112,8 +120,7 @@ Image_Option:
|
||||
|
||||
`.alpha_drop_if_present`
|
||||
If the image has an alpha channel, drop it.
|
||||
You may want to use `.alpha_
|
||||
tiply` in this case.
|
||||
You may want to use `.alpha_premultiply` in this case.
|
||||
|
||||
NOTE: For PNG, this also skips handling of the tRNS chunk, if present,
|
||||
unless you select `alpha_premultiply`.
|
||||
@@ -163,6 +170,7 @@ Error :: union #shared_nil {
|
||||
PNG_Error,
|
||||
QOI_Error,
|
||||
BMP_Error,
|
||||
JPEG_Error,
|
||||
|
||||
compress.Error,
|
||||
compress.General_Error,
|
||||
@@ -575,6 +583,138 @@ TGA_Info :: struct {
|
||||
extension: Maybe(TGA_Extension),
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
JPEG-specific
|
||||
*/
|
||||
JFIF_Magic := [?]byte{0x4A, 0x46, 0x49, 0x46} // "JFIF"
|
||||
JFXX_Magic := [?]byte{0x4A, 0x46, 0x58, 0x58} // "JFXX"
|
||||
Exif_Magic := [?]byte{0x45, 0x78, 0x69, 0x66} // "Exif"
|
||||
|
||||
JPEG_Error :: enum {
|
||||
None = 0,
|
||||
Duplicate_SOI_Marker,
|
||||
Invalid_JFXX_Extension_Code,
|
||||
Encountered_SOS_Before_SOF,
|
||||
Invalid_Quantization_Table_Precision,
|
||||
Invalid_Quantization_Table_Index,
|
||||
Invalid_Huffman_Coefficient_Type,
|
||||
Invalid_Huffman_Table_Index,
|
||||
Unsupported_Frame_Type,
|
||||
Invalid_Frame_Bit_Depth_Combo,
|
||||
Invalid_Sampling_Factor,
|
||||
Unsupported_12_Bit_Depth,
|
||||
Multiple_SOS_Markers,
|
||||
Encountered_RST_Marker_Outside_ECS,
|
||||
Extra_Data_After_SOS, // Image seemed to have decoded okay, but there's more data after SOS
|
||||
Invalid_Thumbnail_Size,
|
||||
Huffman_Symbols_Exceeds_Max,
|
||||
}
|
||||
|
||||
JFIF_Unit :: enum byte {
|
||||
None = 0,
|
||||
Dots_Per_Inch = 1,
|
||||
Dots_Per_Centimeter = 2,
|
||||
}
|
||||
|
||||
JFIF_APP0 :: struct {
|
||||
version: u16be,
|
||||
x_density: u16be,
|
||||
y_density: u16be,
|
||||
units: JFIF_Unit,
|
||||
x_thumbnail: u8,
|
||||
y_thumbnail: u8,
|
||||
greyscale_thumbnail: bool,
|
||||
thumbnail: []RGB_Pixel `fmt:"-"`,
|
||||
}
|
||||
|
||||
JFXX_APP0 :: struct {
|
||||
extension_code: JFXX_Extension_Code,
|
||||
x_thumbnail: u8,
|
||||
y_thumbnail: u8,
|
||||
thumbnail: []byte `fmt:"-"`,
|
||||
}
|
||||
|
||||
JFXX_Extension_Code :: enum u8 {
|
||||
Thumbnail_JPEG = 0x10,
|
||||
Thumbnail_1_Byte_Palette = 0x11,
|
||||
Thumbnail_3_Byte_RGB = 0x13,
|
||||
}
|
||||
|
||||
JPEG_Marker :: enum u8 {
|
||||
SOF0 = 0xC0,
|
||||
SOF1 = 0xC1,
|
||||
SOF2 = 0xC2,
|
||||
SOF3 = 0xC3,
|
||||
DHT = 0xC4,
|
||||
SOF5 = 0xC5,
|
||||
SOF6 = 0xC6,
|
||||
SOF7 = 0xC7,
|
||||
JPG = 0xC8,
|
||||
SOF9 = 0xC9,
|
||||
SOF10 = 0xCA,
|
||||
SOF11 = 0xCB,
|
||||
DAC = 0xCC,
|
||||
SOF13 = 0xCD,
|
||||
SOF14 = 0xCE,
|
||||
SOF15 = 0xCF,
|
||||
RST0 = 0xD0,
|
||||
RST1 = 0xD1,
|
||||
RST2 = 0xD2,
|
||||
RST3 = 0xD3,
|
||||
RST4 = 0xD4,
|
||||
RST5 = 0xD5,
|
||||
RST6 = 0xD6,
|
||||
RST7 = 0xD7,
|
||||
SOI = 0xD8,
|
||||
EOI = 0xD9,
|
||||
SOS = 0xDA,
|
||||
DQT = 0xDB,
|
||||
DNL = 0xDC,
|
||||
DRI = 0xDD,
|
||||
DHP = 0xDE,
|
||||
EXP = 0xDF,
|
||||
APP0 = 0xE0,
|
||||
APP1 = 0xE1,
|
||||
APP2 = 0xE2,
|
||||
APP3 = 0xE3,
|
||||
APP4 = 0xE4,
|
||||
APP5 = 0xE5,
|
||||
APP6 = 0xE6,
|
||||
APP7 = 0xE7,
|
||||
APP8 = 0xE8,
|
||||
APP9 = 0xE9,
|
||||
APP10 = 0xEA,
|
||||
APP11 = 0xEB,
|
||||
APP12 = 0xEC,
|
||||
APP13 = 0xED,
|
||||
APP14 = 0xEE,
|
||||
APP15 = 0xEF,
|
||||
JPG0 = 0xF0,
|
||||
JPG1 = 0xF1,
|
||||
JPG2 = 0xF2,
|
||||
JPG3 = 0xF3,
|
||||
JPG4 = 0xF4,
|
||||
JPG5 = 0xF5,
|
||||
JPG6 = 0xF6,
|
||||
JPG7 = 0xF7,
|
||||
JPG8 = 0xF8,
|
||||
JPG9 = 0xF9,
|
||||
JPG10 = 0xFA,
|
||||
JPG11 = 0xFB,
|
||||
JPG12 = 0xFC,
|
||||
JPG13 = 0xFD,
|
||||
COM = 0xFE,
|
||||
TEM = 0x01,
|
||||
}
|
||||
|
||||
JPEG_Info :: struct {
|
||||
jfif_app0: Maybe(JFIF_APP0),
|
||||
jfxx_app0: Maybe(JFXX_APP0),
|
||||
comments: [dynamic]string,
|
||||
exif: [dynamic]Exif,
|
||||
}
|
||||
|
||||
// Function to help with image buffer calculations
|
||||
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
|
||||
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
|
||||
|
||||
@@ -147,7 +147,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
|
||||
return .JPEG
|
||||
case s[:3] == "\xff\xd8\xff":
|
||||
switch s[3] {
|
||||
case 0xdb, 0xee, 0xe1, 0xe0:
|
||||
case 0xdb, 0xee, 0xe1, 0xe0, 0xfe, 0xed:
|
||||
return .JPEG
|
||||
}
|
||||
switch {
|
||||
|
||||
1016
core/image/jpeg/jpeg.odin
Normal file
1016
core/image/jpeg/jpeg.odin
Normal file
File diff suppressed because it is too large
Load Diff
3
core/image/jpeg/jpeg_js.odin
Normal file
3
core/image/jpeg/jpeg_js.odin
Normal file
@@ -0,0 +1,3 @@
|
||||
package jpeg
|
||||
|
||||
load :: proc{load_from_bytes, load_from_context}
|
||||
18
core/image/jpeg/jpeg_os.odin
Normal file
18
core/image/jpeg/jpeg_os.odin
Normal file
@@ -0,0 +1,18 @@
|
||||
package jpeg
|
||||
|
||||
import "core:os"
|
||||
|
||||
load :: proc{load_from_file, load_from_bytes, load_from_context}
|
||||
|
||||
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
data, ok := os.read_entire_file(filename)
|
||||
defer delete(data)
|
||||
|
||||
if ok {
|
||||
return load_from_bytes(data, options)
|
||||
} else {
|
||||
return nil, .Unable_To_Read_File
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ chrm :: proc(c: image.PNG_Chunk) -> (res: cHRM, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
|
||||
exif :: proc(c: image.PNG_Chunk) -> (res: image.Exif, ok: bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
@@ -396,4 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
|
||||
General helper functions
|
||||
*/
|
||||
|
||||
compute_buffer_size :: image.compute_buffer_size
|
||||
compute_buffer_size :: image.compute_buffer_size
|
||||
|
||||
@@ -138,14 +138,6 @@ Text :: struct {
|
||||
text: string,
|
||||
}
|
||||
|
||||
Exif :: struct {
|
||||
byte_order: enum {
|
||||
little_endian,
|
||||
big_endian,
|
||||
},
|
||||
data: []u8,
|
||||
}
|
||||
|
||||
iCCP :: struct {
|
||||
name: string,
|
||||
profile: []u8,
|
||||
@@ -250,10 +242,14 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) {
|
||||
header := (^image.PNG_IHDR)(raw_data(c.data))^
|
||||
// Validate IHDR
|
||||
using header
|
||||
if width == 0 || height == 0 || u128(width) * u128(height) > image.MAX_DIMENSIONS {
|
||||
if width == 0 || height == 0 {
|
||||
return {}, .Invalid_Image_Dimensions
|
||||
}
|
||||
|
||||
if u128(width) * u128(height) > image.MAX_DIMENSIONS {
|
||||
return {}, .Image_Dimensions_Too_Large
|
||||
}
|
||||
|
||||
if compression_method != 0 {
|
||||
return {}, compress.General_Error.Unknown_Compression_Method
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#+build linux, darwin, openbsd, freebsd, netbsd, haiku
|
||||
package posix
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
|
||||
@@ -24,7 +24,7 @@ _sleep :: proc "contextless" (d: Duration) {
|
||||
|
||||
_tick_now :: proc "contextless" () -> Tick {
|
||||
foreign odin_env {
|
||||
tick_now :: proc "contextless" () -> f32 ---
|
||||
tick_now :: proc "contextless" () -> f64 ---
|
||||
}
|
||||
return Tick{i64(tick_now()*1e6)}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ package all
|
||||
@(require) import "core:image/png"
|
||||
@(require) import "core:image/qoi"
|
||||
@(require) import "core:image/tga"
|
||||
@(require) import "core:image/jpeg"
|
||||
|
||||
@(require) import "core:io"
|
||||
@(require) import "core:log"
|
||||
|
||||
@@ -6473,7 +6473,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
}
|
||||
|
||||
if (e && e->kind == Entity_Constant && is_type_proc(e->type)) {
|
||||
if (o->mode != Addressing_Constant) {
|
||||
bool ok = false;
|
||||
if (o->mode == Addressing_Constant) {
|
||||
ok = true;
|
||||
} else if (o->value.kind == ExactValue_Procedure) {
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (show_error) {
|
||||
error(o->expr, "Expected a constant procedure value for the argument '%.*s'", LIT(e->token.string));
|
||||
}
|
||||
@@ -7947,7 +7954,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
s = gb_string_append_fmt(s, "$%.*s", LIT(name));
|
||||
|
||||
if (v->kind == Entity_TypeName) {
|
||||
if (v->type->kind != Type_Generic) {
|
||||
if (v->type != nullptr && v->type->kind != Type_Generic) {
|
||||
s = gb_string_append_fmt(s, "=");
|
||||
s = write_type_to_string(s, v->type, false);
|
||||
}
|
||||
@@ -11423,6 +11430,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
o->type = type;
|
||||
o->value = exact_value_procedure(node);
|
||||
case_end;
|
||||
|
||||
case_ast_node(te, TernaryIfExpr, node);
|
||||
|
||||
@@ -1797,6 +1797,9 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
|
||||
}
|
||||
|
||||
expr = unparen_expr(expr);
|
||||
if (expr == nullptr) {
|
||||
break;
|
||||
};
|
||||
}
|
||||
mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
1
tests/core/.gitignore
vendored
1
tests/core/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
*.bmp
|
||||
*.zip
|
||||
*.png
|
||||
*.jpg
|
||||
math_big_test_library.*
|
||||
@@ -7,7 +7,7 @@ import zipfile
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
TEST_SUITES = ['PNG', 'XML', 'BMP']
|
||||
TEST_SUITES = ['PNG', 'XML', 'BMP', 'JPG']
|
||||
DOWNLOAD_BASE_PATH = sys.argv[1] + "/{}"
|
||||
ASSETS_BASE_URL = "https://raw.githubusercontent.com/odin-lang/test-assets/master/{}/{}"
|
||||
HMAC_KEY = "https://odin-lang.org"
|
||||
@@ -280,7 +280,9 @@ HMAC_DIGESTS = {
|
||||
'rletopdown.bmp': "37500893aad0b40656aa80fd5c7c5f9b35d033018b8070d8b1d7baeb34c90f90462288b13295204b90aa3e5c9be797d22a328e3714ab259334e879a09a3de175",
|
||||
'shortfile.bmp': "be3ffade7999304f00f9b7d152b5b27811ad1166d0fd43004392467a28f44b6a4ec02a23c0296bacd4f02f8041cd824b9ca6c9fc31fed27e36e572113bb47d73",
|
||||
|
||||
'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae",
|
||||
'emblem-1024.jpg': "d7b7e3ffaa5cda04c667e3742752091d78e02aa2d3c7a63406af679ce810a0a86666b10fcab12cc7ead2fadf2f6c2e1237bc94f892a62a4c218e18a20f96dbe4",
|
||||
|
||||
'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae",
|
||||
}
|
||||
|
||||
def try_download_file(url, out_file):
|
||||
|
||||
@@ -19,6 +19,7 @@ import pbm "core:image/netpbm"
|
||||
import "core:image/png"
|
||||
import "core:image/qoi"
|
||||
import "core:image/tga"
|
||||
import "core:image/jpeg"
|
||||
|
||||
import "core:bytes"
|
||||
import "core:hash"
|
||||
@@ -28,6 +29,7 @@ import "core:time"
|
||||
|
||||
TEST_SUITE_PATH_PNG :: ODIN_ROOT + "tests/core/assets/PNG"
|
||||
TEST_SUITE_PATH_BMP :: ODIN_ROOT + "tests/core/assets/BMP"
|
||||
TEST_SUITE_PATH_JPG :: ODIN_ROOT + "tests/core/assets/JPG"
|
||||
|
||||
I_Error :: image.Error
|
||||
|
||||
@@ -2360,6 +2362,52 @@ run_bmp_suite :: proc(t: ^testing.T, suite: []Test) {
|
||||
return
|
||||
}
|
||||
|
||||
// JPG test image
|
||||
Basic_JPG_Tests := []Test{
|
||||
{
|
||||
"emblem-1024", {
|
||||
{Default, nil, {1024, 1024, 3, 8}, 0x_46a29e0f},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@test
|
||||
jpeg_test_basic :: proc(t: ^testing.T) {
|
||||
run_jpg_suite(t, Basic_JPG_Tests)
|
||||
}
|
||||
|
||||
run_jpg_suite :: proc(t: ^testing.T, suite: []Test) {
|
||||
for file in suite {
|
||||
test_file := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".jpg"}, context.allocator)
|
||||
defer delete(test_file)
|
||||
|
||||
for test in file.tests {
|
||||
img, err := jpeg.load(test_file, test.options)
|
||||
|
||||
passed := (test.expected_error == nil && err == nil) || (test.expected_error == err)
|
||||
testing.expectf(t, passed, "%q failed to load with error %v.", file.file, err)
|
||||
|
||||
if err == nil { // No point in running the other tests if it didn't load.
|
||||
pixels := bytes.buffer_to_bytes(&img.pixels)
|
||||
|
||||
dims := Dims{img.width, img.height, img.channels, img.depth}
|
||||
testing.expectf(t, test.dims == dims, "%v has %v, expected: %v.", file.file, dims, test.dims)
|
||||
|
||||
img_hash := hash.crc32(pixels)
|
||||
testing.expectf(t, test.hash == img_hash, "%v test #1's hash is %08x, expected %08x with %v.", file.file, img_hash, test.hash, test.options)
|
||||
|
||||
// Save to BMP file to check load
|
||||
test_bmp := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".bmp"}, context.temp_allocator)
|
||||
|
||||
save_err := bmp.save(test_bmp, img)
|
||||
testing.expectf(t, save_err == nil, "expected saving to BMP in memory not to raise error, got %v", save_err)
|
||||
}
|
||||
bmp.destroy(img)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@test
|
||||
will_it_blend :: proc(t: ^testing.T) {
|
||||
Pixel :: image.RGB_Pixel
|
||||
|
||||
2
vendor/box2d/box2d.odin
vendored
2
vendor/box2d/box2d.odin
vendored
@@ -1370,7 +1370,7 @@ foreign lib {
|
||||
|
||||
// Create a motor joint
|
||||
// @see b2MotorJointDef for details
|
||||
CreateMotorJoint :: proc(worldId: WorldId, def: MotorJointDef) -> JointId ---
|
||||
CreateMotorJoint :: proc(worldId: WorldId, #by_ptr def: MotorJointDef) -> JointId ---
|
||||
|
||||
// Set the motor joint linear offset target
|
||||
MotorJoint_SetLinearOffset :: proc(jointId: JointId, linearOffset: Vec2) ---
|
||||
|
||||
Reference in New Issue
Block a user