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 |