Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8d4b45c
First attempt to update to iOS16
slarson Jun 30, 2025
8f1ddce
Corrected commit without fix.patch
slarson Jun 30, 2025
304d630
Additional updates to modernize code base
slarson Jun 30, 2025
a953faf
Run pod install to update workspace
slarson Jun 30, 2025
6e7c29c
Merge pull request #8 from openworm/codex/migrate-rendering-code-to-m…
slarson Jun 30, 2025
59e9b16
clarify xcodebuild requirement
slarson Jun 30, 2025
6021735
Merge pull request #9 from openworm/codex/fix-build-errors-and-update…
slarson Jun 30, 2025
56efa67
Remove leftover OpenGL types
slarson Jul 1, 2025
3d97e09
Merge pull request #10 from openworm/codex/analyze-and-adjust-code-fo…
slarson Jul 1, 2025
0d0a505
Restore OWGLViewController for compatibility
slarson Jul 1, 2025
694cae3
Merge pull request #11 from openworm/codex/analyze-and-port-code-to-m…
slarson Jul 1, 2025
a788799
Port remaining structs to simd and implement Metal picking
slarson Jul 1, 2025
2747deb
Merge pull request #12 from openworm/codex/address-glkit-vector-depen…
slarson Jul 1, 2025
bdd0de0
Update setup script and instructions
slarson Jul 1, 2025
d94ebe8
Merge pull request #13 from openworm/codex/update-setup-for-pod-install
slarson Jul 1, 2025
abde227
Added a new enumeration, OWViewButtonTag, for cleaner button tag hand…
slarson Jul 1, 2025
775975e
Add camera transforms and depth for Metal
slarson Jul 1, 2025
caf92a7
Merge pull request #14 from openworm/codex/review-code-for-metal-comp…
slarson Jul 1, 2025
69fa69d
remove fix.patch
slarson Jul 1, 2025
1f375b7
Fix vector accessor and cast count
slarson Jul 1, 2025
2405f52
Merge pull request #15 from openworm/codex/fix-illegal-vector-compone…
slarson Jul 1, 2025
7c61285
Fix compilation errors and warnings
slarson Jul 1, 2025
686151d
Merge pull request #16 from openworm/codex/fix-deprecated-usage-and-u…
slarson Jul 1, 2025
2aff1e4
Remove unused global uniforms array
slarson Jul 1, 2025
ef9bfab
Merge pull request #17 from openworm/codex/fix-ios-version-mismatch-a…
slarson Jul 1, 2025
b2cbba9
fixes to build
slarson Jul 1, 2025
61a2f11
Fix deprecations and warnings
slarson Jul 1, 2025
24df368
Merge pull request #18 from openworm/fmqkj2-codex/fix-deprecated-api-…
slarson Jul 1, 2025
8506f26
updating configuration
slarson Jul 1, 2025
7dfe81d
Fix deprecations and link WebKit
slarson Jul 1, 2025
6de4f51
Merge pull request #19 from openworm/codex/fix-deprecated-warnings-an…
slarson Jul 1, 2025
117fdb3
updates for build
slarson Jul 1, 2025
dea8314
updates to get this to build on xcode
slarson Jul 2, 2025
48cbb83
Adjust deployment target
slarson Jul 2, 2025
9277db5
Fix LaunchScreen storyboard type
slarson Jul 2, 2025
2282568
Fix LaunchScreen storyboard compile failure
slarson Jul 2, 2025
8044025
Merge pull request #22 from openworm/bdxdeu-codex/fix-compilestoryboa…
slarson Jul 2, 2025
6b6327d
Merge branch 'ios16.7.11' into 0oodcc-codex/fix-compilestoryboard-err…
slarson Jul 2, 2025
5b30404
Merge pull request #21 from openworm/0oodcc-codex/fix-compilestoryboa…
slarson Jul 2, 2025
4eb75de
Merge pull request #20 from openworm/codex/fix-compilestoryboard-erro…
slarson Jul 2, 2025
f9545b2
Port rendering to Metal and add comprehensive test suite
slarson Dec 27, 2025
63ecb83
Fix infinite recursion crash in setPaused: method
slarson Dec 27, 2025
f5e4162
Fix layer rendering and background color
slarson Dec 27, 2025
323aee1
Fix pinch-to-zoom gesture during camera animation
slarson Dec 27, 2025
e962656
Fix Metal renderer: distinct neuron colors and slider behavior
slarson Dec 27, 2025
8fcd021
Fix horizontal slider mode: draw layers back-to-front for transparency
slarson Dec 27, 2025
acb2341
Add selection rendering to Metal - show selected geometry with faded …
slarson Dec 27, 2025
73ce885
Fix button positions in landscape to avoid notch - tuck into upper ri…
slarson Dec 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# AGENT Instructions
- After modifying `Podfile` or any pod dependency, run `pod install --allow-root` to regenerate the workspace.
- Ensure project build settings in `OpenWorm.xcodeproj/project.pbxproj` are updated accordingly when bumping deployment target or architectures.

This repository contains the Objective-C implementation of the OpenWorm Browser for iOS. The project relies on CocoaPods and **Metal** for rendering worm models. After cloning, run `./setup.sh` to install CocoaPods if needed and execute `pod install`. When modifying the `Podfile` or pod dependencies, re-run `pod install --allow-root` (or `./setup.sh`) to regenerate the workspace. Then open `OpenWorm.xcworkspace` in Xcode to build the app. Keep the project file in sync with resource changes so it continues to build on recent Xcode versions.
2,863 changes: 2,863 additions & 0 deletions Doxyfile

Large diffs are not rendered by default.

396 changes: 300 additions & 96 deletions OpenWorm.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions OpenWormTests/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
244 changes: 244 additions & 0 deletions OpenWormTests/OWInterpolantTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
//
// OWInterpolantTests.m
// OpenWormTests
//
// Created by Claude Code on 2025-12-26.
// Tests for OWInterpolant smooth animation tweening
//

#import <XCTest/XCTest.h>
#import "OWInterpolant.h"

@interface OWInterpolantTests : XCTestCase
@end

@implementation OWInterpolantTests

#pragma mark - Initialization Tests

- (void)testInitWithValue {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:5.0f];

XCTAssertNotNil(interpolant, @"Interpolant should be created");
XCTAssertEqual(interpolant.present, 5.0f, @"Present value should be 5.0");
XCTAssertEqual(interpolant.future, 5.0f, @"Future value should match present initially");
}

- (void)testInitWithZero {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];

XCTAssertEqual(interpolant.present, 0.0f, @"Present value should be 0.0");
XCTAssertEqual(interpolant.future, 0.0f, @"Future value should be 0.0");
}

- (void)testInitWithNegativeValue {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:-10.0f];

XCTAssertEqual(interpolant.present, -10.0f, @"Present value should handle negatives");
}

#pragma mark - Set Future Tests

- (void)testSetFutureWithUrgency {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:10.0f withUrgency:0.5f];

XCTAssertEqual(interpolant.future, 10.0f, @"Future should be set to 10.0");
XCTAssertEqual(interpolant.present, 0.0f, @"Present should still be 0.0 before tween");
}

- (void)testSetFutureHighUrgency {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:100.0f withUrgency:1.0f];

XCTAssertEqual(interpolant.future, 100.0f, @"Future should be 100.0");
// High urgency means faster convergence
}

#pragma mark - Tween Tests

- (void)testTweenConvergence {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:10.0f withUrgency:0.5f];

// Tween multiple times until convergence
for (int i = 0; i < 100; i++) {
[interpolant tween];
}

// After many iterations, present should approach future
XCTAssertEqualWithAccuracy(interpolant.present, 10.0f, 0.1f,
@"After many tweens, present should converge to future");
}

- (void)testTweenSingleStep {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:10.0f withUrgency:0.5f];

float before = interpolant.present;
[interpolant tween];
float after = interpolant.present;

XCTAssertGreaterThan(after, before, @"Single tween should move present toward future");
XCTAssertLessThan(after, 10.0f, @"Single tween should not reach future immediately");
}

- (void)testTweenWhenAtTarget {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:5.0f];
// Future already equals present

BOOL changed = [interpolant tween];

XCTAssertEqual(interpolant.present, 5.0f, @"Tween should maintain value when at target");
XCTAssertFalse(changed, @"Tween should return NO when at target");
}

- (void)testTweenNegativeDirection {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:10.0f];
[interpolant setFuture:0.0f withUrgency:0.5f];

[interpolant tween];

XCTAssertLessThan(interpolant.present, 10.0f, @"Present should decrease toward 0");
XCTAssertGreaterThan(interpolant.present, 0.0f, @"Present should not reach 0 immediately");
}

- (void)testTweenReturnsYesWhenMoving {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:10.0f withUrgency:0.5f];

BOOL changed = [interpolant tween];

XCTAssertTrue(changed, @"Tween should return YES when value changes");
}

#pragma mark - TweenAll Class Method Tests

- (void)testTweenAllWithMultipleInterpolants {
OWInterpolant *a = [[OWInterpolant alloc] initWithValue:0.0f];
OWInterpolant *b = [[OWInterpolant alloc] initWithValue:0.0f];
OWInterpolant *c = [[OWInterpolant alloc] initWithValue:0.0f];

[a setFuture:10.0f withUrgency:0.5f];
[b setFuture:20.0f withUrgency:0.5f];
[c setFuture:30.0f withUrgency:0.5f];

NSArray *interpolants = @[a, b, c];

for (int i = 0; i < 100; i++) {
[OWInterpolant tweenAll:interpolants];
}

XCTAssertEqualWithAccuracy(a.present, 10.0f, 0.1f, @"A should converge to 10");
XCTAssertEqualWithAccuracy(b.present, 20.0f, 0.1f, @"B should converge to 20");
XCTAssertEqualWithAccuracy(c.present, 30.0f, 0.1f, @"C should converge to 30");
}

- (void)testTweenAllWithEmptyArray {
// Should not crash with empty array
NSArray *empty = @[];
XCTAssertNoThrow([OWInterpolant tweenAll:empty], @"Should handle empty array");
}

- (void)testTweenAllReturnsYesWhenAnyChanges {
OWInterpolant *a = [[OWInterpolant alloc] initWithValue:0.0f];
OWInterpolant *b = [[OWInterpolant alloc] initWithValue:5.0f]; // Already at target

[a setFuture:10.0f withUrgency:0.5f];

NSArray *interpolants = @[a, b];
BOOL changed = [OWInterpolant tweenAll:interpolants];

XCTAssertTrue(changed, @"Should return YES if any interpolant changed");
}

#pragma mark - Bezier Point Tests

- (void)testBezierPointAtStart {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];

// At t=0, should return p0
float result = [interpolant bezierPoint:0.0f p0:0.0f p1:1.0f p2:2.0f p3:3.0f];

XCTAssertEqualWithAccuracy(result, 0.0f, 0.001f, @"At t=0, should return p0");
}

- (void)testBezierPointAtEnd {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];

// At t=1, should return p3
float result = [interpolant bezierPoint:1.0f p0:0.0f p1:1.0f p2:2.0f p3:3.0f];

XCTAssertEqualWithAccuracy(result, 3.0f, 0.001f, @"At t=1, should return p3");
}

- (void)testBezierPointAtMiddle {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];

// At t=0.5, linear case (0, 1, 2, 3) should give 1.5
float result = [interpolant bezierPoint:0.5f p0:0.0f p1:1.0f p2:2.0f p3:3.0f];

// Bezier at t=0.5 for these points: (1-t)^3*p0 + 3(1-t)^2*t*p1 + 3(1-t)*t^2*p2 + t^3*p3
// = 0.125*0 + 0.375*1 + 0.375*2 + 0.125*3 = 0 + 0.375 + 0.75 + 0.375 = 1.5
XCTAssertEqualWithAccuracy(result, 1.5f, 0.001f, @"At t=0.5, should be 1.5");
}

#pragma mark - Edge Cases

- (void)testVeryLargeValues {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:1000000.0f withUrgency:0.8f];

for (int i = 0; i < 200; i++) {
[interpolant tween];
}

XCTAssertEqualWithAccuracy(interpolant.present, 1000000.0f, 1000.0f,
@"Should handle large values");
}

- (void)testVerySmallChanges {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];
[interpolant setFuture:0.001f withUrgency:0.8f];

for (int i = 0; i < 100; i++) {
[interpolant tween];
}

XCTAssertEqualWithAccuracy(interpolant.present, 0.001f, 0.0001f,
@"Should handle small values");
}

- (void)testRapidFutureChanges {
OWInterpolant *interpolant = [[OWInterpolant alloc] initWithValue:0.0f];

// Change future rapidly
[interpolant setFuture:10.0f withUrgency:0.5f];
[interpolant tween];
[interpolant setFuture:5.0f withUrgency:0.5f]; // Change target mid-tween
[interpolant tween];

// Should be heading toward 5.0 now
XCTAssertEqual(interpolant.future, 5.0f, @"Future should be 5.0");
XCTAssertNotEqual(interpolant.present, 0.0f, @"Should have moved from 0");
}

- (void)testUrgencyAffectsSpeed {
OWInterpolant *slow = [[OWInterpolant alloc] initWithValue:0.0f];
OWInterpolant *fast = [[OWInterpolant alloc] initWithValue:0.0f];

[slow setFuture:10.0f withUrgency:0.1f]; // Low urgency
[fast setFuture:10.0f withUrgency:0.9f]; // High urgency

// Run same number of tweens
for (int i = 0; i < 10; i++) {
[slow tween];
[fast tween];
}

// Fast should be closer to 10 than slow
XCTAssertGreaterThan(fast.present, slow.present,
@"Higher urgency should converge faster");
}

@end
Loading