OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 6 #error "This file requires ARC support." |
| 7 #endif |
| 8 |
| 9 #import "remoting/ios/ui/cursor_texture.h" |
| 10 |
| 11 @implementation CursorTexture |
| 12 |
| 13 - (id)init { |
| 14 self = [super init]; |
| 15 if (self) { |
| 16 _needCursorRedraw = NO; |
| 17 _cursorDrawnToGL = webrtc::DesktopRect::MakeXYWH(0, 0, 0, 0); |
| 18 } |
| 19 return self; |
| 20 } |
| 21 |
| 22 - (const webrtc::DesktopSize&)textureSize { |
| 23 return _textureSize; |
| 24 } |
| 25 |
| 26 - (void)setTextureSize:(const webrtc::DesktopSize&)size { |
| 27 if (!_textureSize.equals(size)) { |
| 28 _textureSize.set(size.width(), size.height()); |
| 29 _needInitialize = true; |
| 30 } |
| 31 } |
| 32 |
| 33 - (const webrtc::MouseCursor&)cursor { |
| 34 return *_cursor.get(); |
| 35 } |
| 36 |
| 37 - (void)setCursor:(webrtc::MouseCursor*)cursor { |
| 38 _cursor.reset(cursor); |
| 39 |
| 40 if (_cursor.get() != NULL && _cursor->image().data()) { |
| 41 _needCursorRedraw = true; |
| 42 } |
| 43 } |
| 44 |
| 45 - (void)bindToEffect:(GLKEffectPropertyTexture*)effectProperty { |
| 46 glGenTextures(1, &_textureId); |
| 47 [Utility bindTextureForIOS:_textureId]; |
| 48 |
| 49 // This is the Cursor layer, and is stamped on top of Desktop as a |
| 50 // transparent image |
| 51 effectProperty.target = GLKTextureTarget2D; |
| 52 effectProperty.name = _textureId; |
| 53 effectProperty.envMode = GLKTextureEnvModeDecal; |
| 54 effectProperty.enabled = GL_TRUE; |
| 55 |
| 56 [Utility logGLErrorCode:@"CursorTexture bindToTexture"]; |
| 57 // Release context |
| 58 glBindTexture(GL_TEXTURE_2D, 0); |
| 59 } |
| 60 |
| 61 - (BOOL)needDrawAtPosition:(const webrtc::DesktopVector&)position { |
| 62 return (_cursor.get() != NULL && |
| 63 (_needInitialize || _needCursorRedraw == YES || |
| 64 _cursorDrawnToGL.left() != position.x() - _cursor->hotspot().x() || |
| 65 _cursorDrawnToGL.top() != position.y() - _cursor->hotspot().y())); |
| 66 } |
| 67 |
| 68 - (void)drawWithMousePosition:(const webrtc::DesktopVector&)position { |
| 69 if (_textureSize.height() == 0 && _textureSize.width() == 0) { |
| 70 return; |
| 71 } |
| 72 |
| 73 [Utility bindTextureForIOS:_textureId]; |
| 74 |
| 75 if (_needInitialize) { |
| 76 glTexImage2D(GL_TEXTURE_2D, |
| 77 0, |
| 78 GL_RGBA, |
| 79 _textureSize.width(), |
| 80 _textureSize.height(), |
| 81 0, |
| 82 GL_RGBA, |
| 83 GL_UNSIGNED_BYTE, |
| 84 NULL); |
| 85 |
| 86 [Utility logGLErrorCode:@"CursorTexture initializeTextureSurfaceWithSize"]; |
| 87 _needInitialize = false; |
| 88 } |
| 89 // When the cursor needs to be redraw in a different spot then we must clear |
| 90 // the previous area. |
| 91 |
| 92 DCHECK([self needDrawAtPosition:position]); |
| 93 |
| 94 if (_cursorDrawnToGL.width() > 0 && _cursorDrawnToGL.height() > 0) { |
| 95 webrtc::BasicDesktopFrame transparentCursor(_cursorDrawnToGL.size()); |
| 96 |
| 97 if (transparentCursor.data() != NULL) { |
| 98 DCHECK(transparentCursor.kBytesPerPixel == |
| 99 _cursor->image().kBytesPerPixel); |
| 100 memset(transparentCursor.data(), |
| 101 0, |
| 102 transparentCursor.stride() * transparentCursor.size().height()); |
| 103 |
| 104 [Utility drawSubRectToGLFromRectOfSize:_textureSize |
| 105 subRect:_cursorDrawnToGL |
| 106 data:transparentCursor.data()]; |
| 107 |
| 108 // there is no longer any cursor drawn to screen |
| 109 _cursorDrawnToGL = webrtc::DesktopRect::MakeXYWH(0, 0, 0, 0); |
| 110 } |
| 111 } |
| 112 |
| 113 if (_cursor.get() != NULL) { |
| 114 |
| 115 CGRect screen = |
| 116 CGRectMake(0.0, 0.0, _textureSize.width(), _textureSize.height()); |
| 117 CGRect cursor = CGRectMake(position.x() - _cursor->hotspot().x(), |
| 118 position.y() - _cursor->hotspot().y(), |
| 119 _cursor->image().size().width(), |
| 120 _cursor->image().size().height()); |
| 121 |
| 122 if (CGRectContainsRect(screen, cursor)) { |
| 123 _cursorDrawnToGL = webrtc::DesktopRect::MakeXYWH(cursor.origin.x, |
| 124 cursor.origin.y, |
| 125 cursor.size.width, |
| 126 cursor.size.height); |
| 127 |
| 128 [Utility drawSubRectToGLFromRectOfSize:_textureSize |
| 129 subRect:_cursorDrawnToGL |
| 130 data:_cursor->image().data()]; |
| 131 |
| 132 } else if (CGRectIntersectsRect(screen, cursor)) { |
| 133 // Some of the cursor falls off screen, need to clip it |
| 134 CGRect intersection = CGRectIntersection(screen, cursor); |
| 135 _cursorDrawnToGL = |
| 136 webrtc::DesktopRect::MakeXYWH(intersection.origin.x, |
| 137 intersection.origin.y, |
| 138 intersection.size.width, |
| 139 intersection.size.height); |
| 140 |
| 141 webrtc::BasicDesktopFrame partialCursor(_cursorDrawnToGL.size()); |
| 142 |
| 143 if (partialCursor.data()) { |
| 144 DCHECK(partialCursor.kBytesPerPixel == _cursor->image().kBytesPerPixel); |
| 145 |
| 146 uint32_t src_stride = _cursor->image().stride(); |
| 147 uint32_t dst_stride = partialCursor.stride(); |
| 148 |
| 149 uint8_t* source = _cursor->image().data(); |
| 150 source += abs((static_cast<int32_t>(cursor.origin.y) - |
| 151 _cursorDrawnToGL.top())) * |
| 152 src_stride; |
| 153 source += abs((static_cast<int32_t>(cursor.origin.x) - |
| 154 _cursorDrawnToGL.left())) * |
| 155 _cursor->image().kBytesPerPixel; |
| 156 uint8_t* dst = partialCursor.data(); |
| 157 |
| 158 for (uint32_t y = 0; y < _cursorDrawnToGL.height(); y++) { |
| 159 memcpy(dst, source, dst_stride); |
| 160 source += src_stride; |
| 161 dst += dst_stride; |
| 162 } |
| 163 |
| 164 [Utility drawSubRectToGLFromRectOfSize:_textureSize |
| 165 subRect:_cursorDrawnToGL |
| 166 data:partialCursor.data()]; |
| 167 } |
| 168 } |
| 169 } |
| 170 |
| 171 _needCursorRedraw = false; |
| 172 [Utility logGLErrorCode:@"CursorTexture drawWithMousePosition"]; |
| 173 // Release context |
| 174 glBindTexture(GL_TEXTURE_2D, 0); |
| 175 } |
| 176 |
| 177 - (void)releaseTexture { |
| 178 glDeleteTextures(1, &_textureId); |
| 179 } |
| 180 |
| 181 @end |
OLD | NEW |