mirror of
https://github.com/alibaba/GCanvas.git
synced 2025-12-08 17:36:42 +00:00
352 lines
11 KiB
Plaintext
352 lines
11 KiB
Plaintext
/**
|
|
* Created by G-Canvas Open Source Team.
|
|
* Copyright (c) 2017, Alibaba, Inc. All rights reserved.
|
|
*
|
|
* This source code is licensed under the Apache Licence 2.0.
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "GCanvasPlugin.h"
|
|
#import "GCVCommon.h"
|
|
#import "GCVFont.h"
|
|
#import "GCVLog.h"
|
|
|
|
#include "GCanvasWeex.hpp"
|
|
#include "GCanvas2dContext.h"
|
|
#include "GCanvasManager.h"
|
|
#include "Log.h"
|
|
|
|
|
|
@interface GCanvasPlugin()
|
|
|
|
@property(nonatomic, strong) NSString *componentId;
|
|
@property(nonatomic, assign) gcanvas::GCanvasWeex *gcanvas;
|
|
@property(nonatomic, assign) GCanvasContext *context;
|
|
@property(nonatomic, strong) NSMutableArray *renderCommandArray;
|
|
@property(nonatomic, strong) NSMutableDictionary *textureDict;
|
|
|
|
@property(nonatomic, weak) GLKView *glkview;
|
|
|
|
@end
|
|
|
|
@implementation GCanvasPlugin
|
|
|
|
+ (void)setLogLevel:(NSUInteger)logLevel{
|
|
if( logLevel < LOG_LEVEL_DEBUG || logLevel > LOG_LEVEL_FATAL ) return;
|
|
#ifdef DEBUG
|
|
[GCVLog sharedInstance].logLevel = (GCVLogLevel)logLevel;
|
|
#endif
|
|
SetLogLevel((LogLevel)logLevel);
|
|
}
|
|
|
|
+ (FetchPluginBlock)GetFetchPluginBlock{
|
|
static FetchPluginBlock gFetchPluginBlock;
|
|
return gFetchPluginBlock;
|
|
}
|
|
|
|
+ (void)setFetchPlugin:(FetchPluginBlock)block
|
|
{
|
|
FetchPluginBlock fetchPluginBlock = [self GetFetchPluginBlock];
|
|
fetchPluginBlock = block;
|
|
}
|
|
|
|
|
|
- (instancetype)initWithComponentId:(NSString*)componentId{
|
|
self = [super init];
|
|
if (self){
|
|
self.renderCommandArray = [[NSMutableArray alloc] init];
|
|
self.textureDict = NSMutableDictionary.dictionary;
|
|
|
|
self.gcanvasInited = NO;
|
|
self.componentId = componentId;
|
|
|
|
gcanvas::GCanvasManager* manager = gcanvas::GCanvasManager::GetManager();
|
|
std::string key = [componentId UTF8String];
|
|
|
|
self.gcanvas = manager->NewCanvasWeex(key);
|
|
self.context = self.gcanvas->GetGCanvasContext();
|
|
|
|
#ifdef DEBUG
|
|
SetLogLevel(LOG_LEVEL_DEBUG);
|
|
#else
|
|
SetLogLevel(LOG_LEVEL_INFO);
|
|
#endif
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc{
|
|
[self removeGCanvas];
|
|
}
|
|
|
|
- (void)setFrame:(CGRect)frame{
|
|
if( !self.gcanvas ) return;
|
|
if( !self.gcanvasInited ){
|
|
self.gcanvas->OnSurfaceChanged(0, 0, frame.size.width, frame.size.height);
|
|
self.gcanvasInited = YES;
|
|
}
|
|
}
|
|
|
|
- (void)setClearColor:(UIColor*)color{
|
|
if( !self.gcanvas ) return;
|
|
|
|
if( color ){
|
|
CGFloat r, g, b, a;
|
|
BOOL ret = [color getRed:&r green:&g blue:&b alpha:&a];
|
|
if( ret ){
|
|
GColorRGBA c;
|
|
c.rgba.r = r;
|
|
c.rgba.g = g;
|
|
c.rgba.b = b;
|
|
c.rgba.a = a;
|
|
self.gcanvas->SetClearColor(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)addCommands:(NSString*)commands{
|
|
if (commands){
|
|
@synchronized (self) {
|
|
[self.renderCommandArray addObject:commands];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)removeCommands{
|
|
@synchronized (self) {
|
|
[self.renderCommandArray removeAllObjects];
|
|
}
|
|
}
|
|
|
|
- (void)execCommands{
|
|
if( !self.gcanvas || !self.gcanvasInited ) return;
|
|
|
|
@synchronized (self) {
|
|
if(self.renderCommandArray.count == 0){
|
|
return;
|
|
}
|
|
NSString* cmd = self.renderCommandArray[0];
|
|
int cmdLen = (int)strlen(cmd.UTF8String);
|
|
GCVLOG_METHOD(@"execCommands, len:%d, command=%@", cmdLen, cmd);
|
|
self.gcanvas->Render(cmd.UTF8String, cmdLen);
|
|
[self.renderCommandArray removeObjectAtIndex:0];
|
|
}
|
|
}
|
|
|
|
- (void)releaseManager{
|
|
gcanvas::GCanvasManager::Release();
|
|
}
|
|
|
|
- (void)removeGCanvas{
|
|
gcanvas::GCanvasManager* manager = gcanvas::GCanvasManager::GetManager();
|
|
manager->RemoveCanvas([self.componentId UTF8String]);
|
|
|
|
@synchronized(self){
|
|
[self.textureDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL * _Nonnull stop) {
|
|
GLuint tid = (GLuint)[value integerValue];
|
|
if(tid > 0){
|
|
glDeleteTextures(1, &tid);
|
|
}
|
|
}];
|
|
[self.textureDict removeAllObjects];
|
|
self.textureDict = nil;
|
|
}
|
|
|
|
self.gcanvas = nil;
|
|
}
|
|
|
|
- (GLuint)getTextureId:(NSUInteger)aid{
|
|
if( !self.gcanvas ) return 0;
|
|
|
|
@synchronized(self){
|
|
GLuint tid = (GLuint)([self.textureDict[@(aid)] integerValue]);
|
|
return tid;
|
|
}
|
|
}
|
|
|
|
- (void)addTextureId:(NSUInteger)tid withAppId:(NSUInteger)aid width:(NSUInteger)width height:(NSUInteger)height offscreen:(BOOL)offscreen{
|
|
if( !self.gcanvas ) return;
|
|
|
|
self.gcanvas->AddTexture((int)aid, (int)tid, (int)width, (int)height);
|
|
if( offscreen ){
|
|
self.gcanvas->AddOfflineTexture((int)aid, (int)tid);
|
|
}
|
|
@synchronized(self){
|
|
self.textureDict[@(aid)] = @(tid);
|
|
}
|
|
}
|
|
|
|
- (void)addTextureId:(NSUInteger)tid withAppId:(NSUInteger)aid width:(NSUInteger)width height:(NSUInteger)height{
|
|
[self addTextureId:tid withAppId:aid width:width height:height offscreen:NO];
|
|
}
|
|
|
|
- (void)setImageLoader:(id<GCVImageLoaderProtocol>)loader{
|
|
[GCVCommon sharedInstance].imageLoader = loader;
|
|
}
|
|
|
|
- (void)setDevicePixelRatio:(double)ratio{
|
|
if( !self.gcanvas ) return;
|
|
|
|
self.gcanvas->SetDevicePixelRatio(ratio);
|
|
}
|
|
|
|
- (void)setContextType:(GCVContextType)contextType{
|
|
if( !self.gcanvas ) return;
|
|
|
|
self.gcanvas->SetContextType((GCVContextTypeWebGL == contextType ) ? GCVContextTypeWebGL : GCVContextType2D);
|
|
|
|
//register function for GFont and WebGL texImage2D && texSubImage2D.
|
|
if( self.gcanvas->GetContextType() != 0 ){
|
|
self.context->SetGWebGLTxtImage2DFunc(iOS_GCanvas_GWebGLTxtImage2D);
|
|
self.context->SetGWebGLTxtSubImage2DFunc(iOS_GCanvas_GWebGLTxtSubImage2D);
|
|
self.context->SetGWebGLBindToGLKViewFunc(iOS_GCanvas_Bind_To_GLKView);
|
|
}
|
|
}
|
|
|
|
- (int)contextType{
|
|
if( !self.gcanvas ) return 0;
|
|
return self.gcanvas->GetContextType();
|
|
}
|
|
|
|
- (CGFloat)fps{
|
|
if( !self.gcanvas ) return 0;
|
|
return self.gcanvas->mFps;
|
|
}
|
|
|
|
- (GLuint)textureId{
|
|
if( !self.gcanvas ) return 0;
|
|
return self.gcanvas->GetFboTexture()->GetTextureID();
|
|
}
|
|
|
|
- (NSString*)getSyncResult{
|
|
if( !self.gcanvas ) return @"";
|
|
|
|
if( !self.gcanvas->mResult.empty() ){
|
|
NSString *retResult = [[NSString alloc] initWithUTF8String:self.gcanvas->mResult.c_str()];
|
|
self.gcanvas->setSyncResult("");
|
|
return retResult;
|
|
}
|
|
return @"";
|
|
}
|
|
|
|
- (void)setGLKView:(GLKView*)glkview{
|
|
self.glkview = glkview;
|
|
}
|
|
|
|
- (GLKView*)getGLKView{
|
|
return self.glkview;
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - iOS implementation of Font & texImage
|
|
/**
|
|
* Fetch GCVImageCache by image source, create texImage2D with imageData.
|
|
* create textImage2D success, while imageCache loaded.
|
|
*
|
|
* @param target texutre target to render
|
|
* @param level level
|
|
* @param internalformat internalformat
|
|
* @param format format
|
|
* @param type type
|
|
* @param src image src to loader
|
|
*
|
|
*/
|
|
void iOS_GCanvas_GWebGLTxtImage2D(GLenum target, GLint level, GLenum internalformat,
|
|
GLenum format, GLenum type, const char *src){
|
|
NSString *imageStr = [[NSString alloc] initWithUTF8String:src];
|
|
GCVImageCache *imageCache = [[GCVCommon sharedInstance] fetchLoadImage:imageStr];
|
|
|
|
void (^glTexImage2DBlock)(GCVImageCache*) = ^(GCVImageCache* cache){
|
|
LOG_D("width=%f, height=%f, image=%p", imageCache.width, imageCache.height, imageCache.image);
|
|
|
|
GLint width = imageCache.width;
|
|
GLint height = imageCache.height;
|
|
|
|
CGRect rect = CGRectMake(0, 0, width, height);
|
|
CGBitmapInfo info = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
|
|
NSMutableData *pixelData = [NSMutableData dataWithLength:width*height*4];
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
CGContextRef context = CGBitmapContextCreate(pixelData.mutableBytes, width, height, 8, 4 * width, colorSpace, info);
|
|
CGColorSpaceRelease(colorSpace);
|
|
CGContextClearRect(context, rect);
|
|
CGContextDrawImage(context, rect, imageCache.image.CGImage);
|
|
CGContextRelease(context);
|
|
|
|
glTexImage2D(target, level, internalformat, width, height, 0, format, type, pixelData.bytes);
|
|
};
|
|
|
|
if( imageCache ) {
|
|
glTexImage2DBlock(imageCache);
|
|
} else {
|
|
[[GCVCommon sharedInstance] addPreLoadImage:imageStr completion:^(GCVImageCache *imageCache, BOOL fromCache){
|
|
if( imageCache ){
|
|
glTexImage2DBlock(imageCache);
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fetch GCVImageCache by image source, create texImage2D with imageData.
|
|
* create textImage2D success, while imageCache loaded.
|
|
*
|
|
* @param target texutre target to render
|
|
* @param level level
|
|
* @param xoffset xoffset
|
|
* @param yoffset yoffset
|
|
* @param format format
|
|
* @param type type
|
|
* @param src image src to loader
|
|
*
|
|
*/
|
|
void iOS_GCanvas_GWebGLTxtSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
|
|
GLenum format, GLenum type, const char *src){
|
|
NSString *imageStr = [[NSString alloc] initWithUTF8String:src];
|
|
GCVImageCache *imageCache = [[GCVCommon sharedInstance] fetchLoadImage:imageStr];
|
|
|
|
void (^glTexSubImage2DBlock)(GCVImageCache*) = ^(GCVImageCache* cache){
|
|
LOG_D("width=%f, height=%f, image=%p", imageCache.width, imageCache.height, imageCache.image);
|
|
|
|
GLint width = imageCache.width;
|
|
GLint height = imageCache.height;
|
|
|
|
CGRect rect = CGRectMake(0, 0, width, height);
|
|
CGBitmapInfo info = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
|
|
NSMutableData *pixelData = [NSMutableData dataWithLength:width*height*4];
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
CGContextRef context = CGBitmapContextCreate(pixelData.mutableBytes, width, height, 8, 4 * width, colorSpace, info);
|
|
CGColorSpaceRelease(colorSpace);
|
|
CGContextClearRect(context, rect);
|
|
CGContextDrawImage(context, rect, imageCache.image.CGImage);
|
|
CGContextRelease(context);
|
|
|
|
glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData.bytes);
|
|
};
|
|
|
|
if( imageCache ){
|
|
glTexSubImage2DBlock(imageCache);
|
|
} else {
|
|
[[GCVCommon sharedInstance] addPreLoadImage:imageStr completion:^(GCVImageCache *imageCache, BOOL fromCache){
|
|
if( imageCache ){
|
|
glTexSubImage2DBlock(imageCache);
|
|
}
|
|
}];
|
|
}
|
|
}
|
|
|
|
void iOS_GCanvas_Bind_To_GLKView(std::string contextId){
|
|
if( [GCanvasPlugin GetFetchPluginBlock] ){
|
|
FetchPluginBlock block = [GCanvasPlugin GetFetchPluginBlock];
|
|
GCanvasPlugin *plugin = block([NSString stringWithUTF8String:contextId.c_str()]);
|
|
GLKView *glkview = [plugin getGLKView];
|
|
[glkview bindDrawable];
|
|
}
|
|
}
|
|
|
|
|
|
@end
|