Merge branch 'main' into externalmouse
This commit is contained in:
9 files changed
+162
-50
No files matched your search
@@ -178,6 +178,7 @@ public class GLFWInputImplementation implements InputImplementation {
|
||||
last_event_nanos = nanos;
|
||||
}
|
||||
public void putKeyboardEvent(int keycode, byte state, int ch, long nanos, boolean repeat) {
|
||||
System.out.println("LWJGL2: debug keyboard=" + keycode + ", state=" + state + ", repeat=" + repeat);
|
||||
key_down_buffer[keycode] = state;
|
||||
keyboardEvent.clear();
|
||||
keyboardEvent.putInt(keycode).put(state).putInt(ch).putLong(nanos).put(repeat ? (byte)1 : (byte)0);
|
||||
|
||||
@@ -19,5 +19,5 @@ target_link_libraries(pojavexec
|
||||
"-framework UIKit"
|
||||
"-framework MetalANGLE"
|
||||
"-framework CoreGraphics"
|
||||
"-framework SafariServices"
|
||||
"-framework AuthenticationServices"
|
||||
)
|
||||
@@ -66,17 +66,6 @@
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>net.kdt.pojavlaunch</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>ms-xal-00000000402b5328</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>MinimumOSVersion</key>
|
||||
|
||||
@@ -59,10 +59,6 @@ int launchJVM(int argc, char *argv[]) {
|
||||
setenv("LIBGL_NORMALIZE", "1", 1);
|
||||
|
||||
chdir("/var/mobile/Documents/minecraft");
|
||||
|
||||
if (chmod("/usr/lib/jvm/java-16-openjdk/bin/java", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
|
||||
debug("Warning: chmod +x java failed");
|
||||
}
|
||||
|
||||
char classpath[10000];
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#import <SafariServices/SafariServices.h>
|
||||
#import <AuthenticationServices/AuthenticationServices.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "LauncherViewController.h"
|
||||
@@ -39,7 +39,8 @@ void loginAccountInput(UINavigationController *controller, int type, const char*
|
||||
}
|
||||
}
|
||||
|
||||
@interface LoginViewController ()<SFSafariViewControllerDelegate>{
|
||||
#pragma mark - LoginViewController
|
||||
@interface LoginViewController () <ASWebAuthenticationPresentationContextProviding>{
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -170,9 +171,44 @@ void loginAccountInput(UINavigationController *controller, int type, const char*
|
||||
|
||||
- (void)loginMicrosoft {
|
||||
NSURL *url = [NSURL URLWithString:@"https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_url=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf"];
|
||||
SFSafariViewController *vc = [[SFSafariViewController alloc] initWithURL:url];
|
||||
vc.delegate = self;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
|
||||
ASWebAuthenticationSession *authVC =
|
||||
[[ASWebAuthenticationSession alloc] initWithURL:url
|
||||
callbackURLScheme:@"ms-xal-00000000402b5328://"
|
||||
completionHandler:^(NSURL * _Nullable callbackURL,
|
||||
NSError * _Nullable error) {
|
||||
if (callbackURL != nil) {
|
||||
NSString *urlString = [callbackURL absoluteString];
|
||||
NSLog(@"URL returned = %@", [callbackURL absoluteString]);
|
||||
|
||||
if ([urlString containsString:@"/auth/?code="] == YES) {
|
||||
NSArray *components = [urlString componentsSeparatedByString:@"/auth/?code="];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
|
||||
loginAccountInput(self.navigationController, TYPE_MICROSOFT, [components[1] UTF8String]);
|
||||
});
|
||||
} else {
|
||||
NSArray *components = [urlString componentsSeparatedByString:@"/auth/?error="];
|
||||
if ([components[1] hasPrefix:@"access_denied"] == NO) {
|
||||
NSString *outError = [components[1]
|
||||
stringByReplacingOccurrencesOfString:@"&error_description=" withString:@": "];
|
||||
outError = [outError stringByRemovingPercentEncoding];
|
||||
showDialog(self, @"Error", outError);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (error.code != ASWebAuthenticationSessionErrorCodeCanceledLogin) {
|
||||
showDialog(self, @"Error", error.localizedDescription);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
authVC.presentationContextProvider = self;
|
||||
}
|
||||
|
||||
if ([authVC start] == NO) {
|
||||
showDialog(self, @"Error", @"Unable to open Safari");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loginOffline {
|
||||
@@ -184,20 +220,6 @@ void loginAccountInput(UINavigationController *controller, int type, const char*
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller {
|
||||
[controller dismissViewControllerAnimated:true completion:nil];
|
||||
}
|
||||
|
||||
- (void)msaLoginCallback:(NSNotification *)notification {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
|
||||
NSDictionary *dict = [notification userInfo];
|
||||
NSURL *url = [dict objectForKey:@"url"];
|
||||
NSArray *components = [[url absoluteString] componentsSeparatedByString:@"?code="];
|
||||
// NSLog(@"URL returned = %@", components[1]);
|
||||
loginAccountInput(self.navigationController, TYPE_MICROSOFT, [components[1] UTF8String]);
|
||||
}
|
||||
|
||||
-(void)loginMojangWithUsername:(NSString*)input_username password:(NSString*)input_password {
|
||||
NSString *input_uuid = [[NSUUID UUID] UUIDString];
|
||||
|
||||
@@ -254,8 +276,14 @@ void loginAccountInput(UINavigationController *controller, int type, const char*
|
||||
[postDataTask resume];
|
||||
}
|
||||
|
||||
#pragma mark - ASWebAuthenticationPresentationContextProviding
|
||||
- (ASPresentationAnchor)presentationAnchorForWebAuthenticationSession:(ASWebAuthenticationSession *)session API_AVAILABLE(ios(13.0)){
|
||||
return UIApplication.sharedApplication.keyWindow;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - LoginListViewController
|
||||
@interface LoginListViewController () {
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES2/gl2ext.h"
|
||||
|
||||
// Debugging purposes
|
||||
// #define DEBUG_VISIBLE_TEXT_FIELD
|
||||
|
||||
#define ADD_BUTTON(NAME, KEY, RECT) \
|
||||
UIButton *button_##KEY = [UIButton buttonWithType:UIButtonTypeRoundedRect]; \
|
||||
button_##KEY.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth; \
|
||||
@@ -42,11 +45,19 @@
|
||||
|
||||
#define BTN_RECT 80.0, 30.0
|
||||
#define BTN_SQUARE 50.0, 50.0
|
||||
#define INPUT_SPACE_CHAR @" "
|
||||
#define INPUT_SPACE_LENGTH 20
|
||||
|
||||
int togglableVisibleButtonIndex = -1;
|
||||
UIButton* togglableVisibleButtons[100];
|
||||
|
||||
UIView *touchView;
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
UILabel *inputLengthView;
|
||||
#endif
|
||||
UITextField *inputView;
|
||||
int inputTextLength;
|
||||
|
||||
BOOL shouldTriggerClick = NO;
|
||||
int notchOffset;
|
||||
|
||||
@@ -108,9 +119,19 @@ int notchOffset;
|
||||
[touchView addGestureRecognizer:mouseWheelGesture];
|
||||
}
|
||||
|
||||
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputView = [[UITextField alloc] initWithFrame:CGRectMake(5 * 3 + 80 * 2, 5, BTN_RECT)];
|
||||
inputView.delegate = self;
|
||||
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
|
||||
#else
|
||||
inputView = [[UITextField alloc] initWithFrame:CGRectMake(5 * 3 + 80 * 2, 5 * 2 + 30, 200, 30)];
|
||||
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
|
||||
|
||||
inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + 80, 5 * 2 + 30, BTN_RECT)];
|
||||
inputLengthView.text = @"length=?";
|
||||
inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f];
|
||||
[self.view addSubview:inputLengthView];
|
||||
#endif
|
||||
inputView.delegate = self;
|
||||
[inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged];
|
||||
[inputView addTarget:self action:@selector(inputViewDidClick) forControlEvents:UIControlEventTouchDown];
|
||||
|
||||
@@ -283,6 +304,9 @@ BOOL isNotifRemoved;
|
||||
int hotbarItem = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale);
|
||||
|
||||
if (hotbarItem == -1) {
|
||||
inputView.text = INPUT_SPACE_CHAR;
|
||||
inputTextLength = 0;
|
||||
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL,
|
||||
isGrabbing == JNI_TRUE ? GLFW_MOUSE_BUTTON_RIGHT : GLFW_MOUSE_BUTTON_LEFT, 1, 0);
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL,
|
||||
@@ -317,6 +341,10 @@ BOOL isNotifRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
-(BOOL)prefersHomeIndicatorAutoHidden {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)surfaceOnLongpress:(UILongPressGestureRecognizer *)sender
|
||||
{
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
||||
@@ -324,6 +352,9 @@ BOOL isNotifRemoved;
|
||||
int hotbarItem = callback_SurfaceViewController_touchHotbar(location.x * screenScale, location.y * screenScale);
|
||||
if (sender.state == UIGestureRecognizerStateBegan) {
|
||||
if (hotbarItem == -1) {
|
||||
inputView.text = INPUT_SPACE_CHAR;
|
||||
inputTextLength = 0;
|
||||
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 1, 0);
|
||||
} else {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 1, 0);
|
||||
@@ -338,6 +369,9 @@ BOOL isNotifRemoved;
|
||||
|| sender.state == UIGestureRecognizerStateEnded)
|
||||
{
|
||||
if (hotbarItem == -1) {
|
||||
inputView.text = INPUT_SPACE_CHAR;
|
||||
inputTextLength = 0;
|
||||
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, 0, 0);
|
||||
} else {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_Q, 0, 0, 0);
|
||||
@@ -346,27 +380,86 @@ BOOL isNotifRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
NSString* inputStringBefore;
|
||||
-(void)inputViewDidChange {
|
||||
if ([inputView.text length] <= 1) {
|
||||
if ([inputView.text length] < INPUT_SPACE_LENGTH) {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0);
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0);
|
||||
} else {
|
||||
NSString *newText = [inputView.text substringFromIndex:2];
|
||||
inputView.text = [@" " stringByAppendingString:inputView.text];
|
||||
|
||||
if (inputTextLength > 0) {
|
||||
--inputTextLength;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
|
||||
inputTextLength];
|
||||
#endif
|
||||
} else if ([inputView.text length] > INPUT_SPACE_LENGTH) {
|
||||
NSString *newText = [inputView.text substringFromIndex:INPUT_SPACE_LENGTH];
|
||||
int charLength = [newText length];
|
||||
for (int i = 0; i < charLength; i++) {
|
||||
// Directly convert unichar to jchar which both are in UTF-16 encoding.
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [newText characterAtIndex:i] /* charText[i] */, /* mods */ 0);
|
||||
inputView.text = [inputView.text substringFromIndex:1];
|
||||
if (inputTextLength < INPUT_SPACE_LENGTH) {
|
||||
++inputTextLength;
|
||||
}
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
|
||||
inputTextLength];
|
||||
#endif
|
||||
}
|
||||
inputStringBefore = inputView.text;
|
||||
// [inputView.text substringFromIndex:inputTextLength - 1];
|
||||
} else {
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
NSLog(@"Compare \"%@\" vs \"%@\"", inputView.text, inputStringBefore);
|
||||
#endif
|
||||
for (int i = 0; i < INPUT_SPACE_LENGTH; i++) {
|
||||
if ([inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) {
|
||||
NSString *inputStringNow = [inputView.text substringFromIndex:i];
|
||||
/*
|
||||
inputView.text = [inputView.text substringToIndex:i];
|
||||
// self notify
|
||||
[self inputViewDidChange];
|
||||
|
||||
inputView.text = [inputView.text stringByAppendingString:inputStringNow];
|
||||
// self notify
|
||||
[self inputViewDidChange];
|
||||
*/
|
||||
|
||||
for (int i2 = 0; i2 < [inputStringNow length]; i2++) {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 1, 0);
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, GLFW_KEY_BACKSPACE, 0, 0, 0);
|
||||
}
|
||||
|
||||
for (int i2 = 0; i2 < [inputStringNow length]; i2++) {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendCharMods(NULL, NULL, (jchar) [inputStringNow characterAtIndex:i2], /* mods */ 0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputLengthView.text = @"length =";
|
||||
#endif
|
||||
inputStringBefore = inputView.text;
|
||||
// [inputView.text substringFromIndex:inputTextLength - 1];
|
||||
}
|
||||
|
||||
// Reset to default value
|
||||
inputView.text = @" ";
|
||||
// inputView.text = INPUT_SPACE_CHAR;
|
||||
}
|
||||
|
||||
-(void)inputViewDidClick {
|
||||
// Zero the input field so user will no longer able to select text inside.
|
||||
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputView.alpha = 0.0f;
|
||||
inputView.text = @" ";
|
||||
#endif
|
||||
inputView.text = INPUT_SPACE_CHAR;
|
||||
inputTextLength = 0;
|
||||
}
|
||||
|
||||
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
|
||||
@@ -384,8 +477,10 @@ ADD_BUTTON_DEF(special_togglebtn) {
|
||||
for (int i = 0; i < togglableVisibleButtonIndex + 1; i++) {
|
||||
togglableVisibleButtons[i].hidden = currentVisibility;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEBUG_VISIBLE_TEXT_FIELD
|
||||
inputView.hidden = currentVisibility;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ set -e
|
||||
CFLAGS="-fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -O3 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wno-float-conversion -Wno-non-literal-null-conversion -Wno-objc-literal-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wl,-rpath,/Applications/PojavLauncher.app/Frameworks -fobjc-arc -x objective-c -Fresources/Frameworks -Iresources/Frameworks/MetalANGLE.framework/Headers -isysroot /var/mobile/theos/sdks/iPhoneOS13.4.sdk"
|
||||
|
||||
clang -framework UIKit $CFLAGS -o PojavLauncher main.c log.m JavaLauncher.c
|
||||
clang -framework UIKit -framework MetalANGLE -framework CoreGraphics -framework SafariServices -dynamiclib $CFLAGS -o libpojavexec.dylib log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m egl_bridge.c input_bridge_v3.c utils.c -DGLES_TESTZ -DUSE_EGLZ
|
||||
clang -framework UIKit -framework MetalANGLE -framework CoreGraphics -framework AuthenticationServices -dynamiclib $CFLAGS -o libpojavexec.dylib log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m egl_bridge.c input_bridge_v3.c utils.c -DGLES_TESTZ -DUSE_EGLZ
|
||||
|
||||
ldid -S../entitlements.xml PojavLauncher
|
||||
ldid -S../entitlements.xml libpojavexec.dylib
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
# PojavLauncher_iOS
|
||||
Minecraft: Java Edition launcher for iOS, based on [PojavLauncher Android](https://github.com/PojavLauncherTeam/PojavLauncher).
|
||||
|
||||
This launcher is now available at Procursus repository, thanks to @Diatrus!
|
||||
|
||||
## Navigation
|
||||
- [Introduction](#introduction)
|
||||
- [Building](#building)
|
||||
@@ -21,7 +23,8 @@ Minecraft: Java Edition launcher for iOS, based on [PojavLauncher Android](https
|
||||
## Building
|
||||
Requirements:
|
||||
- Mac OS X (tested: 10.15)
|
||||
- XCode (tested: 11.7.0)
|
||||
- Xcode (tested: 11.7.0)
|
||||
- Minimum iOS SDK: 13.4.
|
||||
- JDK 8 installed
|
||||
- `gradle` to build Java part.
|
||||
- `cmake`, `wget`, `ldid`, `dpkg` and `fakeroot` to package.
|
||||
@@ -66,14 +69,13 @@ chmod 755 *.sh
|
||||
- Forge (1.13+), Fabric and OptiFine works well.
|
||||
|
||||
## Known issues
|
||||
- Mojang authentication might not work, but copying logged in account json from Android will work.
|
||||
- (Some versions) Camera position will be jumped to random location on first time touch.
|
||||
- It might crash sometimes, but try launch again until you get it works.
|
||||
|
||||
## Installing OpenJDK 16
|
||||
### For Chimera/Odyssey bootstrap
|
||||
- Add Procursus repository (https://apt.procurs.us).
|
||||
- Find and install `java-16-openjdk`.
|
||||
- Add Procursus repository (https://apt.procurs.us) (usually Sileo package manager already come with Procursus repo).
|
||||
- Find and install `openjdk-jre`.
|
||||
|
||||
### For other jailbreak bootstrap
|
||||
- Download [openjdk-16-jre.deb](https://github.com/PojavLauncherTeam/PojavLauncher_iOS/releases/tag/v16-openjdk).
|
||||
@@ -95,9 +97,9 @@ Contributions are welcome! We welcome any type of contribution, not only code. A
|
||||
|
||||
## Credits & Third party components and their licenses
|
||||
- [Contributors of PojavLauncher Android](https://github.com/PojavLauncherTeam/PojavLauncher/graphs/contributors) and here.
|
||||
- Apache Commons.
|
||||
- jsr305
|
||||
- org.json
|
||||
- [Apache Commons](https://commons.apache.org): [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt).
|
||||
- [jsr305](https://code.google.com/p/jsr-305): [3-Clause BSD License](http://opensource.org/licenses/BSD-3-Clause).
|
||||
- [org.json](https://github.com/stleary/JSON-java): [The JSON License](https://www.json.org/license.html).
|
||||
- [Boardwalk](https://github.com/zhuowei/Boardwalk) (JVM Launcher): Unknown License/[Apache License 2.0](https://github.com/zhuowei/Boardwalk/blob/master/LICENSE) or GNU GPLv2.
|
||||
- [GL4ES](https://github.com/ptitSeb/gl4es) by @lunixbochs @ptitSeb: [MIT License](https://github.com/ptitSeb/gl4es/blob/master/LICENSE).<br>
|
||||
- [MetalANGLE](https://github.com/kakashidinho/metalangle) by @kakashidinho and ANGLE team: [BSD License 2.0](https://github.com/kakashidinho/metalangle/blob/master/LICENSE).
|
||||
|
||||
Reference in new issue
Block a user