Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ var sharedCxxSettings: [CXXSetting] = [
]
var sharedSwiftSettings: [SwiftSetting] = [
.swiftLanguageMode(.v5),
.enableUpcomingFeature("InternalImportsByDefault"),
]
if libraryEvolutionCondition {
// NOTE: -enable-library-evolution will cause module verify failure for `swift build`.
Expand Down Expand Up @@ -245,7 +246,7 @@ let openRenderBoxTestsTarget = Target.testTarget(
let openRenderBoxCompatibilityTestTarget = Target.testTarget(
name: "OpenRenderBoxCompatibilityTests",
dependencies: [
.product(name: "RealModule", package: "swift-numerics"),
.product(name: "Numerics", package: "swift-numerics"),
],
exclude: ["README.md"],
cSettings: sharedCSettings + [.define("SWIFT_TESTING")],
Expand Down
148 changes: 148 additions & 0 deletions Sources/OpenRenderBoxCxx/Color/ColorSpace.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//
// ColorSpace.cpp
// OpenRenderBox

#include <OpenRenderBoxCxx/Color/ColorSpace.hpp>

#if ORB_TARGET_OS_DARWIN

#include <CoreFoundation/CFBase.h>

namespace ORB {

std::optional<ColorSpace> color_space_from_cg_name(CFStringRef name) {
if (name == nullptr) {
return std::nullopt;
} else if (CFEqual(name, kCGColorSpaceSRGB) ||
CFEqual(name, kCGColorSpaceExtendedSRGB)) {
return ColorSpace::SRGB;
} else if (CFEqual(name, kCGColorSpaceLinearSRGB) ||
CFEqual(name, kCGColorSpaceExtendedLinearSRGB)) {
return ColorSpace::LinearSRGB;
} else if (CFEqual(name, kCGColorSpaceDisplayP3) ||
CFEqual(name, kCGColorSpaceExtendedDisplayP3)) {
return ColorSpace::DisplayP3;
} else if (CFEqual(name, kCGColorSpaceLinearDisplayP3) ||
CFEqual(name, kCGColorSpaceExtendedLinearDisplayP3)) {
return ColorSpace::LinearDisplayP3;
} else {
return std::nullopt;
}
}

std::optional<ColorSpace> color_space_from_cg(CGColorSpaceRef colorSpace) {
if (colorSpace == nullptr) {
return std::nullopt;
}
CFStringRef name = CGColorSpaceGetName(colorSpace);
return color_space_from_cg_name(name);
}

CGColorSpaceRef cg_color_space(ColorSpace colorSpace, bool extended) {
switch (colorSpace) {
case ColorSpace::LinearSRGB:
return extended ? extended_linear_srgb_colorspace() : linear_srgb_colorspace();
case ColorSpace::SRGB:
return extended ? extended_srgb_colorspace() : srgb_colorspace();
case ColorSpace::LinearDisplayP3:
return extended ? extended_linear_display_p3_colorspace() : linear_display_p3_colorspace();
case ColorSpace::DisplayP3:
return extended ? extended_display_p3_colorspace() : display_p3_colorspace();
case ColorSpace::PQ:
return pq_colorspace();
case ColorSpace::Unknown:
abort();
}
}

CGColorSpaceRef linear_srgb_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceLinearSRGB);
return colorSpace;
}

CGColorSpaceRef extended_linear_srgb_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearSRGB);
return colorSpace;
}

CGColorSpaceRef srgb_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
return colorSpace;
}

CGColorSpaceRef extended_srgb_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB);
return colorSpace;
}

CGColorSpaceRef linear_display_p3_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceLinearDisplayP3);
return colorSpace;
}

CGColorSpaceRef extended_linear_display_p3_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearDisplayP3);
return colorSpace;
}

CGColorSpaceRef display_p3_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceDisplayP3);
return colorSpace;
}

CGColorSpaceRef extended_display_p3_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedDisplayP3);
return colorSpace;
}

CGColorSpaceRef pq_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceITUR_2100_PQ);
return colorSpace;
}

CGColorSpaceRef gray_colorspace() {
static CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2);
return colorSpace;
}

} /* namespace ORB */

std::optional<ORB::ColorSpace> orb_color_space(ORBColorSpace orbColorSpace) {
switch (orbColorSpace) {
case ORBColorSpaceDefault:
return std::nullopt;
case ORBColorSpaceSRGB:
return ORB::ColorSpace::SRGB;
case ORBColorSpaceLinearSRGB:
return ORB::ColorSpace::LinearSRGB;
case ORBColorSpaceDisplayP3:
return ORB::ColorSpace::DisplayP3;
case ORBColorSpaceLinearDisplayP3:
return ORB::ColorSpace::LinearDisplayP3;
default:
return std::nullopt;
}
}

ORBColorSpace orb_color_space(std::optional<ORB::ColorSpace> colorSpace) {
if (!colorSpace.has_value()) {
return ORBColorSpaceDefault;
}
switch (colorSpace.value()) {
case ORB::ColorSpace::LinearSRGB:
return ORBColorSpaceLinearSRGB;
case ORB::ColorSpace::SRGB:
return ORBColorSpaceSRGB;
case ORB::ColorSpace::LinearDisplayP3:
return ORBColorSpaceLinearDisplayP3;
case ORB::ColorSpace::DisplayP3:
return ORBColorSpaceDisplayP3;
case ORB::ColorSpace::Unknown:
case ORB::ColorSpace::PQ:
return ORBColorSpaceDefault;
default:
return ORBColorSpaceLinearSRGB;
}
}

#endif /* ORB_TARGET_OS_DARWIN */
143 changes: 143 additions & 0 deletions Sources/OpenRenderBoxCxx/Color/ORBColor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
//
// ORBColor.cpp
// OpenRenderBox

#include <OpenRenderBox/ORBColor.h>
#include <OpenRenderBoxCxx/Color/ColorSpace.hpp>
#include <math.h>

using namespace ORB;

// Global color constants
const ORBColor ORBColorClear = { 0.0f, 0.0f, 0.0f, 0.0f };
const ORBColor ORBColorBlack = { 0.0f, 0.0f, 0.0f, 1.0f };
const ORBColor ORBColorWhite = { 1.0f, 1.0f, 1.0f, 1.0f };
const ORBColor ORBColorNull = { ORBColorInvalidComponent, ORBColorInvalidComponent, ORBColorInvalidComponent, ORBColorInvalidComponent };
const float ORBColorInvalidComponent = -32768.0f;

// sRGB to linear constants
static const float kSRGBToLinearThreshold = 0.04045f;
static const float kSRGBToLinearScale = 12.92f;
static const float kSRGBToLinearGammaOffset = 0.055f;
static const float kSRGBToLinearGammaScale = 1.055f;
static const float kSRGBToLinearGamma = 2.4f;

// Linear to sRGB constants
static const float kLinearToSRGBThreshold = 0.0031308f;
static const float kLinearToSRGBScale = 12.92f;
static const float kLinearToSRGBGammaScale = 1.055f;
static const float kLinearToSRGBGammaOffset = 0.055f;
static const float kLinearToSRGBGamma = 1.0f / 2.4f;

static inline float sRGBToLinear(float value) {
float absValue = value > 0.0f ? value : -value;
float result;
if (absValue <= kSRGBToLinearThreshold) {
result = absValue / kSRGBToLinearScale;
} else {
result = powf((absValue + kSRGBToLinearGammaOffset) / kSRGBToLinearGammaScale, kSRGBToLinearGamma);
}
return value < 0.0f ? -result : result;
}

static inline float linearToSRGB(float value) {
float absValue = value > 0.0f ? value : -value;
float result;
if (absValue <= kLinearToSRGBThreshold) {
result = absValue * kLinearToSRGBScale;
} else {
result = kLinearToSRGBGammaScale * powf(absValue, kLinearToSRGBGamma) - kLinearToSRGBGammaOffset;
}
return value < 0.0f ? -result : result;
}

ORBColor ORBColorMake(float red, float green, float blue, float alpha) {
return (ORBColor){ red, green, blue, alpha };
}

ORBColor ORBColorMakeLinear(float red, float green, float blue, float alpha) {
return (ORBColor){
sRGBToLinear(red),
sRGBToLinear(green),
sRGBToLinear(blue),
alpha
};
}

ORBColor ORBColorToLinear(ORBColor color) {
return (ORBColor){
sRGBToLinear(color.red),
sRGBToLinear(color.green),
sRGBToLinear(color.blue),
color.alpha
};
}

ORBColor ORBColorFromLinear(ORBColor color) {
return (ORBColor){
linearToSRGB(color.red),
linearToSRGB(color.green),
linearToSRGB(color.blue),
color.alpha
};
}

bool ORBColorEqualToColor(ORBColor lhs, ORBColor rhs) {
return lhs.red == rhs.red &&
lhs.green == rhs.green &&
lhs.blue == rhs.blue &&
lhs.alpha == rhs.alpha;
}

#if ORB_TARGET_OS_DARWIN

#include <CoreGraphics/CGColorSpace.h>

ORBColor ORBColorFromComponents(CGColorSpaceRef colorSpace, const CGFloat *components, bool premultiplied) {
size_t componentCount = premultiplied ? 2 : 1;
return ORBColorFromComponents2(colorSpace, components, componentCount);
}

ORBColor ORBColorFromComponents2(CGColorSpaceRef colorSpace, const CGFloat *components, size_t componentCount) {
// TODO: Implement proper color space conversion
(void)colorSpace;
(void)componentCount;
return (ORBColor){
static_cast<float>(components[0]),
static_cast<float>(components[1]),
static_cast<float>(components[2]),
static_cast<float>(components[3])
};
}

ORBColor ORBColorFromCGColor(CGColorRef color, bool premultiplied) {
CGColorSpaceRef colorSpace = CGColorGetColorSpace(color);
const CGFloat *components = CGColorGetComponents(color);
size_t componentCount = premultiplied ? 2 : 1;
return ORBColorFromComponents2(colorSpace, components, componentCount);
}

ORBColor ORBColorFromCGColor2(CGColorRef color, size_t componentCount) {
CGColorSpaceRef colorSpace = CGColorGetColorSpace(color);
const CGFloat *components = CGColorGetComponents(color);
return ORBColorFromComponents2(colorSpace, components, componentCount);
}

CGColorRef ORBColorCopyCGColor(ORBColor color, ORBColorSpace orbColorSpace) {
CGFloat components[4] = {
static_cast<CGFloat>(color.red),
static_cast<CGFloat>(color.green),
static_cast<CGFloat>(color.blue),
static_cast<CGFloat>(color.alpha)
};
bool isRedOutOfRange = (color.red < 0.0f || color.red > 1.0f);
bool isGreenOutOfRange = (color.green < 0.0f || color.green > 1.0f);
bool isBlueOutOfRange = (color.blue < 0.0f || color.blue > 1.0f);
ORB::ColorSpace colorSpace = orb_color_space(orbColorSpace).value_or(ORB::ColorSpace::LinearSRGB);
bool extended = isRedOutOfRange || isGreenOutOfRange || isBlueOutOfRange;
CGColorSpaceRef cgColorSpace = ORB::cg_color_space(colorSpace, extended);
CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
return cgColor;
}

#endif /* ORB_TARGET_OS_DARWIN */
42 changes: 42 additions & 0 deletions Sources/OpenRenderBoxCxx/Color/ORBColorMode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// ORBColorMode.cpp
// OpenRenderBox

#include <OpenRenderBox/ORBColorMode.h>

ORBColorSpace ORBColorModeWorkingColorSpace(ORBColorMode mode) {
switch (mode) {
case ORBColorMode0:
case ORBColorMode3:
case ORBColorMode4:
case ORBColorMode5:
case ORBColorMode9:
case ORBColorMode11:
case ORBColorMode12:
case ORBColorMode14:
return ORBColorSpaceSRGB;
case ORBColorMode1:
case ORBColorMode2:
case ORBColorMode6:
case ORBColorMode7:
case ORBColorMode8:
case ORBColorMode10:
case ORBColorMode13:
case ORBColorMode15:
return ORBColorSpaceLinearSRGB;
default:
return ORBColorSpaceDefault;
}
}

bool ORBColorModeHasExtendedRange(ORBColorMode mode) {
switch (mode) {
case ORBColorMode2:
case ORBColorMode11:
case ORBColorMode12:
case ORBColorMode13:
return true;
default:
return false;
}
}
Loading