Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a805106ed2 | |||
| e1b8812b25 | |||
| a130058c5d | |||
| 3f804634c5 | |||
| 8b39f68a48 | |||
| 1d7b1f7073 | |||
| 47f35058f3 | |||
| a1a7e9aeea | |||
| fabae8ddd8 | |||
| 12e1066cae | |||
| 05ca0f4f4b | |||
| 9e536d2291 | |||
| 7bb976d4ae | |||
| 934d3f29ad | |||
| 87b3244ba5 | |||
| 23824e2b74 | |||
| 71d68c3e6e | |||
| d9887180c3 | |||
| 30eac1282c | |||
| 77d6a5b85b | |||
| 73c9adeb71 | |||
| 7dcda23bf4 | |||
| aa4f259edc | |||
| bc5dcef3b7 | |||
| 782b0c3c71 | |||
| 34a2fdd3e2 | |||
| ae128ab66b | |||
| cb164ed1fe | |||
| c40b99c19a | |||
| 2a48333a9a | |||
| 3c0c2eecb8 | |||
| 442f04124d | |||
| c03bd61f37 | |||
| 161c0acd68 | |||
| b7be132a30 | |||
| d30aecc802 | |||
| b612be76bc | |||
| a322e2aa3f | |||
| b0e88e182a | |||
| 3ebd933b6c | |||
| db0814ca4c | |||
| 3a9e0efb73 | |||
| 7bcc82a03e | |||
| 293e021cf6 | |||
| 340ab086d2 | |||
| f025f807f4 | |||
| 90b086c7a3 | |||
| cf56d72598 | |||
| b22f61c4e2 | |||
| 7d1311311c | |||
| a508cecc32 | |||
| 7657d27854 | |||
| 7c3aae8003 | |||
| 8c2596c23e | |||
| 681b1cd107 | |||
| 13094108e3 | |||
| abd55c5511 | |||
| fc52abe7bd | |||
| fa10e28281 | |||
| c624fbe78c | |||
| 19a355e697 | |||
| 7799f0f613 | |||
| ecf3b557cf | |||
| 58d83ed0dc | |||
| b167bda396 | |||
| 336a6e2432 | |||
| 8acddcda90 | |||
| cf2fc51fea | |||
| 2b236b2a35 | |||
| e59699b7fd | |||
| e9f3c66a3b | |||
| dc1dc18824 | |||
| 014e73f44c | |||
| ee7c25727b | |||
| 79f0ba930b | |||
| c5edbfba8e | |||
| 91c689a41f |
+2
-2
@@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7
|
||||
xcode_project: LFLiveKit.xcodeproj
|
||||
xcode_project: FrameWork/LFLiveKit.xcodeproj
|
||||
xcode_scheme: LFLiveKit
|
||||
|
||||
script:
|
||||
- xctool -project LFLiveKit.xcodeproj -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
- xctool -project FrameWork/LFLiveKit.xcodeproj -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.1</string>
|
||||
<string>2.4.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -0,0 +1,894 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
84D003751DB8FE1000560583 /* LFLiveKitFramework-universal */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 84D003761DB8FE1000560583 /* Build configuration list for PBXAggregateTarget "LFLiveKitFramework-universal" */;
|
||||
buildPhases = (
|
||||
84D0037B1DB8FE1C00560583 /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
84D0037A1DB8FE1800560583 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "LFLiveKitFramework-universal";
|
||||
productName = "LFLiveKitFramework-universal";
|
||||
};
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8495F66F1DB8F14600542124 /* LFLiveKitFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6731DB8F1EE00542124 /* LFAudioCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5851D768B6E00752B56 /* LFAudioCapture.h */; };
|
||||
8495F6741DB8F1EE00542124 /* LFVideoCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5871D768B6E00752B56 /* LFVideoCapture.h */; };
|
||||
8495F6751DB8F1EE00542124 /* LFAVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */; };
|
||||
8495F6761DB8F1EE00542124 /* LFMP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */; };
|
||||
8495F6771DB8F1EE00542124 /* LFNALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5901D768B6E00752B56 /* LFNALUnit.h */; };
|
||||
8495F6781DB8F1EE00542124 /* LFVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */; };
|
||||
8495F6791DB8F1EE00542124 /* LFAudioEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */; };
|
||||
8495F67A1DB8F1EE00542124 /* LFH264VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */; };
|
||||
8495F67B1DB8F1EE00542124 /* LFHardwareAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */; };
|
||||
8495F67C1DB8F1EE00542124 /* LFHardwareVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */; };
|
||||
8495F67D1DB8F1EE00542124 /* LFVideoEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */; };
|
||||
8495F67E1DB8F1EE00542124 /* LFLiveAudioConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F67F1DB8F1EE00542124 /* LFLiveVideoConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6801DB8F1EE00542124 /* LFGPUImageBeautyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */; };
|
||||
8495F6811DB8F1EE00542124 /* LFGPUImageEmptyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */; };
|
||||
8495F6831DB8F1EE00542124 /* LFLiveSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A61D768B6E00752B56 /* LFLiveSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6841DB8F1EE00542124 /* LFAudioFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6851DB8F1EE00542124 /* LFFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AB1D768B6E00752B56 /* LFFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6861DB8F1EE00542124 /* LFLiveDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6871DB8F1EE00542124 /* LFLiveStreamInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6881DB8F1EE00542124 /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6891DB8F1EE00542124 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */; };
|
||||
8495F68A1DB8F1EE00542124 /* LFStreamRTMPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */; };
|
||||
8495F68B1DB8F1EE00542124 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */; };
|
||||
8495F68C1DB8F1EE00542124 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */; };
|
||||
8495F68D1DB8F27000542124 /* LFAudioCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5861D768B6E00752B56 /* LFAudioCapture.m */; };
|
||||
8495F68E1DB8F27000542124 /* LFVideoCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5881D768B6E00752B56 /* LFVideoCapture.m */; };
|
||||
8495F68F1DB8F27000542124 /* LFAVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */; };
|
||||
8495F6901DB8F27000542124 /* LFMP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */; };
|
||||
8495F6911DB8F27000542124 /* LFVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */; };
|
||||
8495F6921DB8F27000542124 /* LFH264VideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */; };
|
||||
8495F6931DB8F27000542124 /* LFHardwareAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */; };
|
||||
8495F6941DB8F27000542124 /* LFHardwareVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */; };
|
||||
8495F6951DB8F27000542124 /* LFLiveAudioConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */; };
|
||||
8495F6961DB8F27000542124 /* LFLiveVideoConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */; };
|
||||
8495F6971DB8F27000542124 /* LFGPUImageBeautyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */; };
|
||||
8495F6981DB8F27000542124 /* LFGPUImageEmptyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */; };
|
||||
8495F6991DB8F27000542124 /* LFLiveSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A71D768B6E00752B56 /* LFLiveSession.m */; };
|
||||
8495F69A1DB8F27000542124 /* LFAudioFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */; };
|
||||
8495F69B1DB8F27000542124 /* LFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AC1D768B6E00752B56 /* LFFrame.m */; };
|
||||
8495F69C1DB8F27000542124 /* LFLiveDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */; };
|
||||
8495F69D1DB8F27000542124 /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */; };
|
||||
8495F69E1DB8F27000542124 /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */; };
|
||||
8495F69F1DB8F27000542124 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */; };
|
||||
8495F6A01DB8F27000542124 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */; };
|
||||
8495F6A11DB8F27000542124 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */; };
|
||||
84D0036F1DB8F88F00560583 /* LFNALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */; };
|
||||
84D8B4BF1D757EB800752B56 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */; };
|
||||
84D8B4C11D757EBE00752B56 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */; };
|
||||
84D8B4C31D757EC400752B56 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C21D757EC400752B56 /* AVFoundation.framework */; };
|
||||
84D8B4C51D757EC800752B56 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C41D757EC800752B56 /* Foundation.framework */; };
|
||||
84D8B4C71D757ECC00752B56 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C61D757ECC00752B56 /* UIKit.framework */; };
|
||||
84D8B5BB1D768B6E00752B56 /* LFAudioCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5851D768B6E00752B56 /* LFAudioCapture.h */; };
|
||||
84D8B5BC1D768B6E00752B56 /* LFAudioCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5861D768B6E00752B56 /* LFAudioCapture.m */; };
|
||||
84D8B5BD1D768B6E00752B56 /* LFVideoCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5871D768B6E00752B56 /* LFVideoCapture.h */; };
|
||||
84D8B5BE1D768B6E00752B56 /* LFVideoCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5881D768B6E00752B56 /* LFVideoCapture.m */; };
|
||||
84D8B5BF1D768B6E00752B56 /* LFAVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */; };
|
||||
84D8B5C01D768B6E00752B56 /* LFAVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */; };
|
||||
84D8B5C11D768B6E00752B56 /* LFMP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */; };
|
||||
84D8B5C21D768B6E00752B56 /* LFMP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */; };
|
||||
84D8B5C31D768B6E00752B56 /* LFNALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */; };
|
||||
84D8B5C41D768B6E00752B56 /* LFNALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5901D768B6E00752B56 /* LFNALUnit.h */; };
|
||||
84D8B5C51D768B6E00752B56 /* LFVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */; };
|
||||
84D8B5C61D768B6E00752B56 /* LFVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */; };
|
||||
84D8B5C71D768B6E00752B56 /* LFAudioEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */; };
|
||||
84D8B5C81D768B6E00752B56 /* LFH264VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */; };
|
||||
84D8B5C91D768B6E00752B56 /* LFH264VideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */; };
|
||||
84D8B5CA1D768B6E00752B56 /* LFHardwareAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */; };
|
||||
84D8B5CB1D768B6E00752B56 /* LFHardwareAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */; };
|
||||
84D8B5CC1D768B6E00752B56 /* LFHardwareVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */; };
|
||||
84D8B5CD1D768B6E00752B56 /* LFHardwareVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */; };
|
||||
84D8B5CE1D768B6E00752B56 /* LFVideoEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */; };
|
||||
84D8B5CF1D768B6E00752B56 /* LFLiveAudioConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D01D768B6E00752B56 /* LFLiveAudioConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */; };
|
||||
84D8B5D11D768B6E00752B56 /* LFLiveVideoConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D21D768B6E00752B56 /* LFLiveVideoConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */; };
|
||||
84D8B5D31D768B6E00752B56 /* LFGPUImageBeautyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */; };
|
||||
84D8B5D41D768B6E00752B56 /* LFGPUImageBeautyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */; };
|
||||
84D8B5D51D768B6E00752B56 /* LFGPUImageEmptyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */; };
|
||||
84D8B5D61D768B6E00752B56 /* LFGPUImageEmptyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */; };
|
||||
84D8B5D71D768B6E00752B56 /* LFLiveKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A51D768B6E00752B56 /* LFLiveKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D81D768B6E00752B56 /* LFLiveSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A61D768B6E00752B56 /* LFLiveSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D91D768B6E00752B56 /* LFLiveSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A71D768B6E00752B56 /* LFLiveSession.m */; };
|
||||
84D8B5DA1D768B6E00752B56 /* LFAudioFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DB1D768B6E00752B56 /* LFAudioFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */; };
|
||||
84D8B5DC1D768B6E00752B56 /* LFFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AB1D768B6E00752B56 /* LFFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DD1D768B6E00752B56 /* LFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AC1D768B6E00752B56 /* LFFrame.m */; };
|
||||
84D8B5DE1D768B6E00752B56 /* LFLiveDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DF1D768B6E00752B56 /* LFLiveDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */; };
|
||||
84D8B5E01D768B6E00752B56 /* LFLiveStreamInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5E11D768B6E00752B56 /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */; };
|
||||
84D8B5E21D768B6E00752B56 /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5E31D768B6E00752B56 /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */; };
|
||||
84D8B5E41D768B6E00752B56 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */; };
|
||||
84D8B5E51D768B6E00752B56 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */; };
|
||||
84D8B5E61D768B6E00752B56 /* LFStreamRTMPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */; };
|
||||
84D8B5E71D768B6E00752B56 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */; };
|
||||
84D8B5E81D768B6E00752B56 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */; };
|
||||
84D8B5E91D768B6E00752B56 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */; };
|
||||
84D8B5EA1D768B6E00752B56 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
84D003791DB8FE1800560583 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84D8B3871D7574D600752B56 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8495F66A1DB8F14600542124;
|
||||
remoteInfo = LFLiveKitFramework;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8495F66B1DB8F14600542124 /* LFLiveKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LFLiveKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LFLiveKitFramework.h; sourceTree = "<group>"; };
|
||||
8495F66E1DB8F14600542124 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
84D8B3901D7574D600752B56 /* LFLiveKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LFLiveKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C21D757EC400752B56 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C41D757EC800752B56 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C61D757ECC00752B56 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C81D757ED100752B56 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
|
||||
84D8B4CA1D757ED600752B56 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
84D8B5851D768B6E00752B56 /* LFAudioCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioCapture.h; sourceTree = "<group>"; };
|
||||
84D8B5861D768B6E00752B56 /* LFAudioCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioCapture.m; sourceTree = "<group>"; };
|
||||
84D8B5871D768B6E00752B56 /* LFVideoCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoCapture.h; sourceTree = "<group>"; };
|
||||
84D8B5881D768B6E00752B56 /* LFVideoCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoCapture.m; sourceTree = "<group>"; };
|
||||
84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAVEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFAVEncoder.mm; sourceTree = "<group>"; };
|
||||
84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFMP4Atom.h; sourceTree = "<group>"; };
|
||||
84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFMP4Atom.m; sourceTree = "<group>"; };
|
||||
84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LFNALUnit.cpp; sourceTree = "<group>"; };
|
||||
84D8B5901D768B6E00752B56 /* LFNALUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFNALUnit.h; sourceTree = "<group>"; };
|
||||
84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioEncoding.h; sourceTree = "<group>"; };
|
||||
84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFH264VideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFH264VideoEncoder.mm; sourceTree = "<group>"; };
|
||||
84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareAudioEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareAudioEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareVideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareVideoEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoding.h; sourceTree = "<group>"; };
|
||||
84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveAudioConfiguration.h; sourceTree = "<group>"; };
|
||||
84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveAudioConfiguration.m; sourceTree = "<group>"; };
|
||||
84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveVideoConfiguration.h; sourceTree = "<group>"; };
|
||||
84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveVideoConfiguration.m; sourceTree = "<group>"; };
|
||||
84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageBeautyFilter.h; sourceTree = "<group>"; };
|
||||
84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageBeautyFilter.m; sourceTree = "<group>"; };
|
||||
84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageEmptyFilter.h; sourceTree = "<group>"; };
|
||||
84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageEmptyFilter.m; sourceTree = "<group>"; };
|
||||
84D8B5A51D768B6E00752B56 /* LFLiveKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveKit.h; sourceTree = "<group>"; };
|
||||
84D8B5A61D768B6E00752B56 /* LFLiveSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveSession.h; sourceTree = "<group>"; };
|
||||
84D8B5A71D768B6E00752B56 /* LFLiveSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveSession.m; sourceTree = "<group>"; };
|
||||
84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5AB1D768B6E00752B56 /* LFFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5AC1D768B6E00752B56 /* LFFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveDebug.h; sourceTree = "<group>"; };
|
||||
84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveDebug.m; sourceTree = "<group>"; };
|
||||
84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveStreamInfo.h; sourceTree = "<group>"; };
|
||||
84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveStreamInfo.m; sourceTree = "<group>"; };
|
||||
84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamingBuffer.h; sourceTree = "<group>"; };
|
||||
84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamingBuffer.m; sourceTree = "<group>"; };
|
||||
84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamRTMPSocket.h; sourceTree = "<group>"; };
|
||||
84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamRtmpSocket.m; sourceTree = "<group>"; };
|
||||
84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamSocket.h; sourceTree = "<group>"; };
|
||||
84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+LFAdd.h"; sourceTree = "<group>"; };
|
||||
84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+LFAdd.m"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8495F6671DB8F14600542124 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38C1D7574D600752B56 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B4C71D757ECC00752B56 /* UIKit.framework in Frameworks */,
|
||||
84D8B4C51D757EC800752B56 /* Foundation.framework in Frameworks */,
|
||||
84D8B4C31D757EC400752B56 /* AVFoundation.framework in Frameworks */,
|
||||
84D8B4C11D757EBE00752B56 /* AudioToolbox.framework in Frameworks */,
|
||||
84D8B4BF1D757EB800752B56 /* VideoToolbox.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
8495F66C1DB8F14600542124 /* LFLiveKitFramework */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */,
|
||||
8495F66E1DB8F14600542124 /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKitFramework;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B3861D7574D600752B56 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5831D768B6E00752B56 /* LFLiveKit */,
|
||||
84D8B4CA1D757ED600752B56 /* libz.tbd */,
|
||||
84D8B4C81D757ED100752B56 /* libstdc++.tbd */,
|
||||
84D8B4C61D757ECC00752B56 /* UIKit.framework */,
|
||||
84D8B4C41D757EC800752B56 /* Foundation.framework */,
|
||||
84D8B4C21D757EC400752B56 /* AVFoundation.framework */,
|
||||
84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */,
|
||||
84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */,
|
||||
8495F66C1DB8F14600542124 /* LFLiveKitFramework */,
|
||||
84D8B3911D7574D600752B56 /* Products */,
|
||||
9ABACAFFC334034AA0115426 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B3911D7574D600752B56 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B3901D7574D600752B56 /* LFLiveKit.framework */,
|
||||
8495F66B1DB8F14600542124 /* LFLiveKit.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5831D768B6E00752B56 /* LFLiveKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5841D768B6E00752B56 /* capture */,
|
||||
84D8B5891D768B6E00752B56 /* coder */,
|
||||
84D8B59B1D768B6E00752B56 /* configuration */,
|
||||
84D8B5A01D768B6E00752B56 /* filter */,
|
||||
84D8B5A51D768B6E00752B56 /* LFLiveKit.h */,
|
||||
84D8B5A61D768B6E00752B56 /* LFLiveSession.h */,
|
||||
84D8B5A71D768B6E00752B56 /* LFLiveSession.m */,
|
||||
84D8B5A81D768B6E00752B56 /* objects */,
|
||||
84D8B5B31D768B6E00752B56 /* publish */,
|
||||
);
|
||||
name = LFLiveKit;
|
||||
path = ../LFLiveKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5841D768B6E00752B56 /* capture */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5851D768B6E00752B56 /* LFAudioCapture.h */,
|
||||
84D8B5861D768B6E00752B56 /* LFAudioCapture.m */,
|
||||
84D8B5871D768B6E00752B56 /* LFVideoCapture.h */,
|
||||
84D8B5881D768B6E00752B56 /* LFVideoCapture.m */,
|
||||
);
|
||||
path = capture;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5891D768B6E00752B56 /* coder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B58A1D768B6E00752B56 /* H264 */,
|
||||
84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */,
|
||||
84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */,
|
||||
84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */,
|
||||
84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */,
|
||||
84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */,
|
||||
84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */,
|
||||
84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */,
|
||||
84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */,
|
||||
);
|
||||
path = coder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B58A1D768B6E00752B56 /* H264 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */,
|
||||
84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */,
|
||||
84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */,
|
||||
84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */,
|
||||
84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */,
|
||||
84D8B5901D768B6E00752B56 /* LFNALUnit.h */,
|
||||
84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */,
|
||||
84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */,
|
||||
);
|
||||
path = H264;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B59B1D768B6E00752B56 /* configuration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */,
|
||||
84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */,
|
||||
84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */,
|
||||
84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */,
|
||||
);
|
||||
path = configuration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5A01D768B6E00752B56 /* filter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */,
|
||||
84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */,
|
||||
84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */,
|
||||
84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */,
|
||||
);
|
||||
path = filter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5A81D768B6E00752B56 /* objects */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */,
|
||||
84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */,
|
||||
84D8B5AB1D768B6E00752B56 /* LFFrame.h */,
|
||||
84D8B5AC1D768B6E00752B56 /* LFFrame.m */,
|
||||
84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */,
|
||||
84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */,
|
||||
84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */,
|
||||
84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */,
|
||||
84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */,
|
||||
84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */,
|
||||
);
|
||||
path = objects;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5B31D768B6E00752B56 /* publish */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */,
|
||||
84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */,
|
||||
84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */,
|
||||
84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */,
|
||||
84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */,
|
||||
84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */,
|
||||
84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */,
|
||||
);
|
||||
path = publish;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9ABACAFFC334034AA0115426 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
8495F6681DB8F14600542124 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8495F6861DB8F1EE00542124 /* LFLiveDebug.h in Headers */,
|
||||
8495F6881DB8F1EE00542124 /* LFVideoFrame.h in Headers */,
|
||||
8495F6871DB8F1EE00542124 /* LFLiveStreamInfo.h in Headers */,
|
||||
8495F6851DB8F1EE00542124 /* LFFrame.h in Headers */,
|
||||
8495F6841DB8F1EE00542124 /* LFAudioFrame.h in Headers */,
|
||||
8495F67F1DB8F1EE00542124 /* LFLiveVideoConfiguration.h in Headers */,
|
||||
8495F67E1DB8F1EE00542124 /* LFLiveAudioConfiguration.h in Headers */,
|
||||
8495F6831DB8F1EE00542124 /* LFLiveSession.h in Headers */,
|
||||
8495F66F1DB8F14600542124 /* LFLiveKitFramework.h in Headers */,
|
||||
8495F6731DB8F1EE00542124 /* LFAudioCapture.h in Headers */,
|
||||
8495F6741DB8F1EE00542124 /* LFVideoCapture.h in Headers */,
|
||||
8495F6751DB8F1EE00542124 /* LFAVEncoder.h in Headers */,
|
||||
8495F6761DB8F1EE00542124 /* LFMP4Atom.h in Headers */,
|
||||
8495F6771DB8F1EE00542124 /* LFNALUnit.h in Headers */,
|
||||
8495F6781DB8F1EE00542124 /* LFVideoEncoder.h in Headers */,
|
||||
8495F6791DB8F1EE00542124 /* LFAudioEncoding.h in Headers */,
|
||||
8495F67A1DB8F1EE00542124 /* LFH264VideoEncoder.h in Headers */,
|
||||
8495F67B1DB8F1EE00542124 /* LFHardwareAudioEncoder.h in Headers */,
|
||||
8495F67C1DB8F1EE00542124 /* LFHardwareVideoEncoder.h in Headers */,
|
||||
8495F67D1DB8F1EE00542124 /* LFVideoEncoding.h in Headers */,
|
||||
8495F6801DB8F1EE00542124 /* LFGPUImageBeautyFilter.h in Headers */,
|
||||
8495F6811DB8F1EE00542124 /* LFGPUImageEmptyFilter.h in Headers */,
|
||||
8495F6891DB8F1EE00542124 /* LFStreamingBuffer.h in Headers */,
|
||||
8495F68A1DB8F1EE00542124 /* LFStreamRTMPSocket.h in Headers */,
|
||||
8495F68B1DB8F1EE00542124 /* LFStreamSocket.h in Headers */,
|
||||
8495F68C1DB8F1EE00542124 /* NSMutableArray+LFAdd.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38D1D7574D600752B56 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B5DE1D768B6E00752B56 /* LFLiveDebug.h in Headers */,
|
||||
84D8B5CF1D768B6E00752B56 /* LFLiveAudioConfiguration.h in Headers */,
|
||||
84D8B5DA1D768B6E00752B56 /* LFAudioFrame.h in Headers */,
|
||||
84D8B5E01D768B6E00752B56 /* LFLiveStreamInfo.h in Headers */,
|
||||
84D8B5D11D768B6E00752B56 /* LFLiveVideoConfiguration.h in Headers */,
|
||||
84D8B5DC1D768B6E00752B56 /* LFFrame.h in Headers */,
|
||||
84D8B5D71D768B6E00752B56 /* LFLiveKit.h in Headers */,
|
||||
84D8B5D81D768B6E00752B56 /* LFLiveSession.h in Headers */,
|
||||
84D8B5E21D768B6E00752B56 /* LFVideoFrame.h in Headers */,
|
||||
84D8B5BB1D768B6E00752B56 /* LFAudioCapture.h in Headers */,
|
||||
84D8B5E61D768B6E00752B56 /* LFStreamRTMPSocket.h in Headers */,
|
||||
84D8B5C11D768B6E00752B56 /* LFMP4Atom.h in Headers */,
|
||||
84D8B5D31D768B6E00752B56 /* LFGPUImageBeautyFilter.h in Headers */,
|
||||
84D8B5BF1D768B6E00752B56 /* LFAVEncoder.h in Headers */,
|
||||
84D8B5C51D768B6E00752B56 /* LFVideoEncoder.h in Headers */,
|
||||
84D8B5D51D768B6E00752B56 /* LFGPUImageEmptyFilter.h in Headers */,
|
||||
84D8B5C71D768B6E00752B56 /* LFAudioEncoding.h in Headers */,
|
||||
84D8B5E91D768B6E00752B56 /* NSMutableArray+LFAdd.h in Headers */,
|
||||
84D8B5CC1D768B6E00752B56 /* LFHardwareVideoEncoder.h in Headers */,
|
||||
84D8B5BD1D768B6E00752B56 /* LFVideoCapture.h in Headers */,
|
||||
84D8B5E81D768B6E00752B56 /* LFStreamSocket.h in Headers */,
|
||||
84D8B5C41D768B6E00752B56 /* LFNALUnit.h in Headers */,
|
||||
84D8B5CA1D768B6E00752B56 /* LFHardwareAudioEncoder.h in Headers */,
|
||||
84D8B5CE1D768B6E00752B56 /* LFVideoEncoding.h in Headers */,
|
||||
84D8B5E41D768B6E00752B56 /* LFStreamingBuffer.h in Headers */,
|
||||
84D8B5C81D768B6E00752B56 /* LFH264VideoEncoder.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8495F66A1DB8F14600542124 /* LFLiveKitFramework */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 8495F6701DB8F14600542124 /* Build configuration list for PBXNativeTarget "LFLiveKitFramework" */;
|
||||
buildPhases = (
|
||||
8495F6661DB8F14600542124 /* Sources */,
|
||||
8495F6671DB8F14600542124 /* Frameworks */,
|
||||
8495F6681DB8F14600542124 /* Headers */,
|
||||
8495F6691DB8F14600542124 /* Resources */,
|
||||
84D0037D1DB9023F00560583 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKitFramework;
|
||||
productName = LFLiveKitFramework;
|
||||
productReference = 8495F66B1DB8F14600542124 /* LFLiveKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
84D8B38F1D7574D600752B56 /* LFLiveKit */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 84D8B3981D7574D600752B56 /* Build configuration list for PBXNativeTarget "LFLiveKit" */;
|
||||
buildPhases = (
|
||||
84D8B38B1D7574D600752B56 /* Sources */,
|
||||
84D8B38C1D7574D600752B56 /* Frameworks */,
|
||||
84D8B38D1D7574D600752B56 /* Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKit;
|
||||
productName = LFLiveKit;
|
||||
productReference = 84D8B3901D7574D600752B56 /* LFLiveKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
84D8B3871D7574D600752B56 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = admin;
|
||||
TargetAttributes = {
|
||||
8495F66A1DB8F14600542124 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
84D003751DB8FE1000560583 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
DevelopmentTeam = G497YX6CBT;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
84D8B38F1D7574D600752B56 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 84D8B38A1D7574D600752B56 /* Build configuration list for PBXProject "LFLiveKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 84D8B3861D7574D600752B56;
|
||||
productRefGroup = 84D8B3911D7574D600752B56 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
84D8B38F1D7574D600752B56 /* LFLiveKit */,
|
||||
8495F66A1DB8F14600542124 /* LFLiveKitFramework */,
|
||||
84D003751DB8FE1000560583 /* LFLiveKitFramework-universal */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8495F6691DB8F14600542124 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
84D0037B1DB8FE1C00560583 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../scripts/build-universal-framework.sh\n";
|
||||
};
|
||||
84D0037D1DB9023F00560583 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"${env}\"";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8495F6661DB8F14600542124 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D0036F1DB8F88F00560583 /* LFNALUnit.cpp in Sources */,
|
||||
8495F68D1DB8F27000542124 /* LFAudioCapture.m in Sources */,
|
||||
8495F68E1DB8F27000542124 /* LFVideoCapture.m in Sources */,
|
||||
8495F68F1DB8F27000542124 /* LFAVEncoder.mm in Sources */,
|
||||
8495F6901DB8F27000542124 /* LFMP4Atom.m in Sources */,
|
||||
8495F6911DB8F27000542124 /* LFVideoEncoder.m in Sources */,
|
||||
8495F6921DB8F27000542124 /* LFH264VideoEncoder.mm in Sources */,
|
||||
8495F6931DB8F27000542124 /* LFHardwareAudioEncoder.m in Sources */,
|
||||
8495F6941DB8F27000542124 /* LFHardwareVideoEncoder.m in Sources */,
|
||||
8495F6951DB8F27000542124 /* LFLiveAudioConfiguration.m in Sources */,
|
||||
8495F6961DB8F27000542124 /* LFLiveVideoConfiguration.m in Sources */,
|
||||
8495F6971DB8F27000542124 /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
8495F6981DB8F27000542124 /* LFGPUImageEmptyFilter.m in Sources */,
|
||||
8495F6991DB8F27000542124 /* LFLiveSession.m in Sources */,
|
||||
8495F69A1DB8F27000542124 /* LFAudioFrame.m in Sources */,
|
||||
8495F69B1DB8F27000542124 /* LFFrame.m in Sources */,
|
||||
8495F69C1DB8F27000542124 /* LFLiveDebug.m in Sources */,
|
||||
8495F69D1DB8F27000542124 /* LFLiveStreamInfo.m in Sources */,
|
||||
8495F69E1DB8F27000542124 /* LFVideoFrame.m in Sources */,
|
||||
8495F69F1DB8F27000542124 /* LFStreamingBuffer.m in Sources */,
|
||||
8495F6A01DB8F27000542124 /* LFStreamRtmpSocket.m in Sources */,
|
||||
8495F6A11DB8F27000542124 /* NSMutableArray+LFAdd.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38B1D7574D600752B56 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B5D41D768B6E00752B56 /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
84D8B5DD1D768B6E00752B56 /* LFFrame.m in Sources */,
|
||||
84D8B5DF1D768B6E00752B56 /* LFLiveDebug.m in Sources */,
|
||||
84D8B5BE1D768B6E00752B56 /* LFVideoCapture.m in Sources */,
|
||||
84D8B5DB1D768B6E00752B56 /* LFAudioFrame.m in Sources */,
|
||||
84D8B5E11D768B6E00752B56 /* LFLiveStreamInfo.m in Sources */,
|
||||
84D8B5C31D768B6E00752B56 /* LFNALUnit.cpp in Sources */,
|
||||
84D8B5C01D768B6E00752B56 /* LFAVEncoder.mm in Sources */,
|
||||
84D8B5C21D768B6E00752B56 /* LFMP4Atom.m in Sources */,
|
||||
84D8B5D21D768B6E00752B56 /* LFLiveVideoConfiguration.m in Sources */,
|
||||
84D8B5C61D768B6E00752B56 /* LFVideoEncoder.m in Sources */,
|
||||
84D8B5D61D768B6E00752B56 /* LFGPUImageEmptyFilter.m in Sources */,
|
||||
84D8B5D91D768B6E00752B56 /* LFLiveSession.m in Sources */,
|
||||
84D8B5E71D768B6E00752B56 /* LFStreamRtmpSocket.m in Sources */,
|
||||
84D8B5D01D768B6E00752B56 /* LFLiveAudioConfiguration.m in Sources */,
|
||||
84D8B5CB1D768B6E00752B56 /* LFHardwareAudioEncoder.m in Sources */,
|
||||
84D8B5C91D768B6E00752B56 /* LFH264VideoEncoder.mm in Sources */,
|
||||
84D8B5E51D768B6E00752B56 /* LFStreamingBuffer.m in Sources */,
|
||||
84D8B5CD1D768B6E00752B56 /* LFHardwareVideoEncoder.m in Sources */,
|
||||
84D8B5E31D768B6E00752B56 /* LFVideoFrame.m in Sources */,
|
||||
84D8B5BC1D768B6E00752B56 /* LFAudioCapture.m in Sources */,
|
||||
84D8B5EA1D768B6E00752B56 /* NSMutableArray+LFAdd.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
84D0037A1DB8FE1800560583 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 8495F66A1DB8F14600542124 /* LFLiveKitFramework */;
|
||||
targetProxy = 84D003791DB8FE1800560583 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
8495F6711DB8F14600542124 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework/Headers\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework/Headers\"",
|
||||
);
|
||||
INFOPLIST_FILE = LFLiveKitFramework/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = LFLiveKit;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8495F6721DB8F14600542124 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework/Headers\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework/Headers\"",
|
||||
);
|
||||
INFOPLIST_FILE = LFLiveKitFramework/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = LFLiveKit;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D003771DB8FE1000560583 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D003781DB8FE1000560583 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D8B3961D7574D600752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B3971D7574D600752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D8B3991D7574D600752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitDemo/Pods\"/**",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B39A1D7574D600752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitDemo/Pods\"/**",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
8495F6701DB8F14600542124 /* Build configuration list for PBXNativeTarget "LFLiveKitFramework" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
8495F6711DB8F14600542124 /* Debug */,
|
||||
8495F6721DB8F14600542124 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D003761DB8FE1000560583 /* Build configuration list for PBXAggregateTarget "LFLiveKitFramework-universal" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D003771DB8FE1000560583 /* Debug */,
|
||||
84D003781DB8FE1000560583 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D8B38A1D7574D600752B56 /* Build configuration list for PBXProject "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B3961D7574D600752B56 /* Debug */,
|
||||
84D8B3971D7574D600752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D8B3981D7574D600752B56 /* Build configuration list for PBXNativeTarget "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B3991D7574D600752B56 /* Debug */,
|
||||
84D8B39A1D7574D600752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 84D8B3871D7574D600752B56 /* Project object */;
|
||||
}
|
||||
+17
-28
@@ -14,10 +14,10 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
@@ -29,20 +29,11 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
@@ -51,16 +42,15 @@
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
@@ -70,16 +60,15 @@
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B2D23E791D348F3D00B34CA8"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
@@ -13,12 +13,12 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<string>2.4.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// LFLiveKitFramework.h
|
||||
// LFLiveKitFramework
|
||||
//
|
||||
// Created by admin on 2016/10/20.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for LFLiveKitFramework.
|
||||
FOUNDATION_EXPORT double LFLiveKitFrameworkVersionNumber;
|
||||
|
||||
//! Project version string for LFLiveKitFramework.
|
||||
FOUNDATION_EXPORT const unsigned char LFLiveKitFrameworkVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <LFLiveKitFramework/PublicHeader.h>
|
||||
|
||||
#import <LFLiveKit/LFLiveSession.h>
|
||||
#import <LFLiveKit/LFLiveAudioConfiguration.h>
|
||||
#import <LFLiveKit/LFLiveVideoConfiguration.h>
|
||||
#import <LFLiveKit/LFAudioFrame.h>
|
||||
#import <LFLiveKit/LFFrame.h>
|
||||
#import <LFLiveKit/LFLiveStreamInfo.h>
|
||||
#import <LFLiveKit/LFVideoFrame.h>
|
||||
#import <LFLiveKit/LFLiveDebug.h>
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "LFLiveKit"
|
||||
s.version = "2.1"
|
||||
s.version = "2.4.3"
|
||||
s.summary = "LaiFeng ios Live. LFLiveKit."
|
||||
s.homepage = "https://github.com/chenliming777"
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
@@ -11,12 +11,12 @@ Pod::Spec.new do |s|
|
||||
s.ios.deployment_target = "7.0"
|
||||
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit.git", :tag => "#{s.version}" }
|
||||
s.source_files = "LFLiveKit/**/*.{h,m,mm,cpp,c}"
|
||||
#s.public_header_files = "LFLiveKit/**/*.h"
|
||||
s.public_header_files = ['LFLiveKit/*.h', 'LFLiveKit/objects/*.h', 'LFLiveKit/configuration/*.h']
|
||||
|
||||
s.frameworks = "VideoToolbox", "AudioToolbox","AVFoundation","Foundation","UIKit"
|
||||
s.libraries = "c++", "z"
|
||||
|
||||
s.requires_arc = true
|
||||
|
||||
s.dependency 'GPUImage'
|
||||
s.dependency 'pili-librtmp', '1.0.3.1'
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -1,155 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "48F687CDE9990BD471D7883061F7E5D4"
|
||||
BuildableName = "libCocoaAsyncSocket.a"
|
||||
BlueprintName = "CocoaAsyncSocket"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6610362E50A6DE8BACCA1F2885CD9157"
|
||||
BuildableName = "libGPUImage.a"
|
||||
BlueprintName = "GPUImage"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "7C2BDDF89D4243C7BCA44592D146DEED"
|
||||
BuildableName = "libPods-LFLiveKit.a"
|
||||
BlueprintName = "Pods-LFLiveKit"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F931D0015D10026C63F"
|
||||
BuildableName = "LFLiveKitTests.xctest"
|
||||
BlueprintName = "LFLiveKitTests"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F931D0015D10026C63F"
|
||||
BuildableName = "LFLiveKitTests.xctest"
|
||||
BlueprintName = "LFLiveKitTests"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>LFLiveKit.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>84001F891D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>84001F931D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?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>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>84001F891D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>84001F931D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -2,10 +2,13 @@
|
||||
// LFLiveKit.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by admin on 16/5/24.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LFLiveKit_h
|
||||
#define LFLiveKit_h
|
||||
|
||||
#import "LFLiveSession.h"
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
@@ -13,3 +16,7 @@
|
||||
#import "LFFrame.h"
|
||||
#import "LFLiveStreamInfo.h"
|
||||
#import "LFVideoFrame.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// LFLiveSession.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
//
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -15,6 +16,8 @@
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
|
||||
|
||||
typedef NS_ENUM(NSInteger,LFLiveCaptureType) {
|
||||
LFLiveCaptureAudio, //< capture only audio
|
||||
LFLiveCaptureVideo, //< capture onlt video
|
||||
@@ -113,7 +116,16 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
/*** The warterMarkView control whether the watermark is displayed or not ,if set ni,will remove watermark,otherwise add.
|
||||
set alpha represent mix.Position relative to outVideoSize.
|
||||
*.*/
|
||||
@property (nonatomic, strong) UIView *warterMarkView;
|
||||
@property (nonatomic, strong, nullable) UIView *warterMarkView;
|
||||
|
||||
/* The currentImage is videoCapture shot */
|
||||
@property (nonatomic, strong,readonly ,nullable) UIImage *currentImage;
|
||||
|
||||
/* The saveLocalVideo is save the local video */
|
||||
@property (nonatomic, assign) BOOL saveLocalVideo;
|
||||
|
||||
/* The saveLocalVideoPath is save the local video path */
|
||||
@property (nonatomic, strong, nullable) NSURL *saveLocalVideoPath;
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
@@ -126,7 +138,7 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration NS_DESIGNATED_INITIALIZER;
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
@@ -141,10 +153,10 @@ typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
- (void)stopLive;
|
||||
|
||||
/** support outer input yuv or rgb video(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer;
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer;
|
||||
|
||||
/** support outer input pcm audio(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList;
|
||||
- (void)pushAudio:(nullable NSData*)audioData;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+79
-31
@@ -2,8 +2,8 @@
|
||||
// LFLiveSession.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveSession.h"
|
||||
@@ -47,10 +47,10 @@
|
||||
@property (nonatomic, assign, readwrite) LFLiveState state;
|
||||
/// 当前直播type
|
||||
@property (nonatomic, assign, readwrite) LFLiveCaptureTypeMask captureType;
|
||||
|
||||
/// 时间戳锁
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
/** 时间戳 */
|
||||
@@ -59,16 +59,21 @@
|
||||
|
||||
@interface LFLiveSession ()
|
||||
|
||||
@property (nonatomic, assign) uint64_t timestamp;
|
||||
@property (nonatomic, assign) BOOL isFirstFrame;
|
||||
@property (nonatomic, assign) uint64_t currentTimestamp;
|
||||
/// 上传相对时间戳
|
||||
@property (nonatomic, assign) uint64_t relativeTimestamps;
|
||||
/// 音视频是否对齐
|
||||
@property (nonatomic, assign) BOOL AVAlignment;
|
||||
/// 当前是否采集到了音频
|
||||
@property (nonatomic, assign) BOOL hasCaptureAudio;
|
||||
/// 当前是否采集到了关键帧
|
||||
@property (nonatomic, assign) BOOL hasKeyFrameVideo;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFLiveSession
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
- (instancetype)initWithAudioConfiguration:(LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(LFLiveVideoConfiguration *)videoConfiguration {
|
||||
- (instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration {
|
||||
return [self initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration captureType:LFLiveCaptureDefaultMask];
|
||||
}
|
||||
|
||||
@@ -79,15 +84,14 @@
|
||||
_audioConfiguration = audioConfiguration;
|
||||
_videoConfiguration = videoConfiguration;
|
||||
_adaptiveBitrate = NO;
|
||||
_isFirstFrame = YES;
|
||||
_captureType = captureType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
self.videoCaptureSource.running = NO;
|
||||
self.audioCaptureSource.running = NO;
|
||||
_videoCaptureSource.running = NO;
|
||||
_audioCaptureSource.running = NO;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
@@ -96,7 +100,6 @@
|
||||
_streamInfo = streamInfo;
|
||||
_streamInfo.videoConfiguration = _videoConfiguration;
|
||||
_streamInfo.audioConfiguration = _audioConfiguration;
|
||||
_streamInfo.needDropFrame = (self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo) ? YES : NO;//< 有视频执行丢帧算法
|
||||
[self.socket start];
|
||||
}
|
||||
|
||||
@@ -106,42 +109,61 @@
|
||||
self.socket = nil;
|
||||
}
|
||||
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer{
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer{
|
||||
if(self.captureType & LFLiveInputMaskVideo){
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:NOW];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList{
|
||||
- (void)pushAudio:(nullable NSData*)audioData{
|
||||
if(self.captureType & LFLiveInputMaskAudio){
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioBufferList timeStamp:self.currentTimestamp];
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioData timeStamp:NOW];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- PrivateMethod
|
||||
- (void)pushSendBuffer:(LFFrame*)frame{
|
||||
if(self.relativeTimestamps == 0){
|
||||
self.relativeTimestamps = frame.timestamp;
|
||||
}
|
||||
frame.timestamp = [self uploadTimestamp:frame.timestamp];
|
||||
[self.socket sendFrame:frame];
|
||||
}
|
||||
|
||||
#pragma mark -- CaptureDelegate
|
||||
- (void)captureOutput:(nullable LFAudioCapture *)capture audioBuffer:(AudioBufferList)inBufferList {
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:inBufferList timeStamp:self.currentTimestamp];
|
||||
- (void)captureOutput:(nullable LFAudioCapture *)capture audioData:(nullable NSData*)audioData {
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioData timeStamp:NOW];
|
||||
}
|
||||
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVPixelBufferRef)pixelBuffer {
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:NOW];
|
||||
}
|
||||
|
||||
#pragma mark -- EncoderDelegate
|
||||
- (void)audioEncoder:(nullable id<LFAudioEncoding>)encoder audioFrame:(nullable LFAudioFrame *)frame {
|
||||
if (self.uploading) [self.socket sendFrame:frame]; //<上传
|
||||
//<上传 时间戳对齐
|
||||
if (self.uploading){
|
||||
self.hasCaptureAudio = YES;
|
||||
if(self.AVAlignment) [self pushSendBuffer:frame];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoEncoder:(nullable id<LFVideoEncoding>)encoder videoFrame:(nullable LFVideoFrame *)frame {
|
||||
if (self.uploading) [self.socket sendFrame:frame]; //<上传
|
||||
//<上传 时间戳对齐
|
||||
if (self.uploading){
|
||||
if(frame.isKeyFrame && self.hasCaptureAudio) self.hasKeyFrameVideo = YES;
|
||||
if(self.AVAlignment) [self pushSendBuffer:frame];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- LFStreamTcpSocketDelegate
|
||||
- (void)socketStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveState)status {
|
||||
if (status == LFLiveStart) {
|
||||
if (!self.uploading) {
|
||||
self.timestamp = 0;
|
||||
self.isFirstFrame = YES;
|
||||
self.AVAlignment = NO;
|
||||
self.hasCaptureAudio = NO;
|
||||
self.hasKeyFrameVideo = NO;
|
||||
self.relativeTimestamps = 0;
|
||||
self.uploading = YES;
|
||||
}
|
||||
} else if(status == LFLiveStop || status == LFLiveError){
|
||||
@@ -229,6 +251,23 @@
|
||||
[self didChangeValueForKey:@"beautyFace"];
|
||||
}
|
||||
|
||||
- (BOOL)saveLocalVideo{
|
||||
return self.videoCaptureSource.saveLocalVideo;
|
||||
}
|
||||
|
||||
- (void)setSaveLocalVideo:(BOOL)saveLocalVideo{
|
||||
[self.videoCaptureSource setSaveLocalVideo:saveLocalVideo];
|
||||
}
|
||||
|
||||
|
||||
- (NSURL*)saveLocalVideoPath{
|
||||
return self.videoCaptureSource.saveLocalVideoPath;
|
||||
}
|
||||
|
||||
- (void)setSaveLocalVideoPath:(NSURL*)saveLocalVideoPath{
|
||||
[self.videoCaptureSource setSaveLocalVideoPath:saveLocalVideoPath];
|
||||
}
|
||||
|
||||
- (BOOL)beautyFace {
|
||||
return self.videoCaptureSource.beautyFace;
|
||||
}
|
||||
@@ -297,10 +336,14 @@
|
||||
[self.videoCaptureSource setWarterMarkView:warterMarkView];
|
||||
}
|
||||
|
||||
- (UIView*)warterMarkView{
|
||||
- (nullable UIView*)warterMarkView{
|
||||
return self.videoCaptureSource.warterMarkView;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)currentImage{
|
||||
return self.videoCaptureSource.currentImage;
|
||||
}
|
||||
|
||||
- (LFAudioCapture *)audioCaptureSource {
|
||||
if (!_audioCaptureSource) {
|
||||
if(self.captureType & LFLiveCaptureMaskAudio){
|
||||
@@ -363,18 +406,23 @@
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (uint64_t)currentTimestamp {
|
||||
- (uint64_t)uploadTimestamp:(uint64_t)captureTimestamp{
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
uint64_t currentts = 0;
|
||||
if (_isFirstFrame) {
|
||||
_timestamp = NOW;
|
||||
_isFirstFrame = NO;
|
||||
currentts = 0;
|
||||
} else {
|
||||
currentts = NOW - _timestamp;
|
||||
}
|
||||
currentts = captureTimestamp - self.relativeTimestamps;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
return currentts;
|
||||
}
|
||||
|
||||
- (BOOL)AVAlignment{
|
||||
if((self.captureType & LFLiveCaptureMaskAudio || self.captureType & LFLiveInputMaskAudio) &&
|
||||
(self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo)
|
||||
){
|
||||
if(self.hasCaptureAudio && self.hasKeyFrameVideo) return YES;
|
||||
else return NO;
|
||||
}else{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-236
@@ -1,236 +0,0 @@
|
||||
// This is Jeff LaMarche's GLProgram OpenGL shader wrapper class from his OpenGL ES 2.0 book.
|
||||
// A description of this can be found at his page on the topic:
|
||||
// http://iphonedevelopment.blogspot.com/2010/11/opengl-es-20-for-ios-chapter-4.html
|
||||
|
||||
|
||||
#import "GLProgram.h"
|
||||
// START:typedefs
|
||||
#pragma mark Function Pointer Definitions
|
||||
typedef void (*GLInfoFunction)(GLuint program, GLenum pname, GLint* params);
|
||||
typedef void (*GLLogFunction) (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
|
||||
// END:typedefs
|
||||
#pragma mark -
|
||||
#pragma mark Private Extension Method Declaration
|
||||
// START:extension
|
||||
@interface GLProgram()
|
||||
|
||||
- (BOOL)compileShader:(GLuint *)shader
|
||||
type:(GLenum)type
|
||||
string:(NSString *)shaderString;
|
||||
@end
|
||||
// END:extension
|
||||
#pragma mark -
|
||||
|
||||
@implementation GLProgram
|
||||
// START:init
|
||||
|
||||
@synthesize initialized = _initialized;
|
||||
|
||||
- (id)initWithVertexShaderString:(NSString *)vShaderString
|
||||
fragmentShaderString:(NSString *)fShaderString;
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_initialized = NO;
|
||||
|
||||
attributes = [[NSMutableArray alloc] init];
|
||||
uniforms = [[NSMutableArray alloc] init];
|
||||
program = glCreateProgram();
|
||||
|
||||
if (![self compileShader:&vertShader
|
||||
type:GL_VERTEX_SHADER
|
||||
string:vShaderString])
|
||||
{
|
||||
NSLog(@"Failed to compile vertex shader");
|
||||
}
|
||||
|
||||
// Create and compile fragment shader
|
||||
if (![self compileShader:&fragShader
|
||||
type:GL_FRAGMENT_SHADER
|
||||
string:fShaderString])
|
||||
{
|
||||
NSLog(@"Failed to compile fragment shader");
|
||||
}
|
||||
|
||||
glAttachShader(program, vertShader);
|
||||
glAttachShader(program, fragShader);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithVertexShaderString:(NSString *)vShaderString
|
||||
fragmentShaderFilename:(NSString *)fShaderFilename;
|
||||
{
|
||||
NSString *fragShaderPathname = [[NSBundle mainBundle] pathForResource:fShaderFilename ofType:@"fsh"];
|
||||
NSString *fragmentShaderString = [NSString stringWithContentsOfFile:fragShaderPathname encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
if ((self = [self initWithVertexShaderString:vShaderString fragmentShaderString:fragmentShaderString]))
|
||||
{
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithVertexShaderFilename:(NSString *)vShaderFilename
|
||||
fragmentShaderFilename:(NSString *)fShaderFilename;
|
||||
{
|
||||
NSString *vertShaderPathname = [[NSBundle mainBundle] pathForResource:vShaderFilename ofType:@"vsh"];
|
||||
NSString *vertexShaderString = [NSString stringWithContentsOfFile:vertShaderPathname encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
NSString *fragShaderPathname = [[NSBundle mainBundle] pathForResource:fShaderFilename ofType:@"fsh"];
|
||||
NSString *fragmentShaderString = [NSString stringWithContentsOfFile:fragShaderPathname encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
if ((self = [self initWithVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString]))
|
||||
{
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
// END:init
|
||||
// START:compile
|
||||
- (BOOL)compileShader:(GLuint *)shader
|
||||
type:(GLenum)type
|
||||
string:(NSString *)shaderString
|
||||
{
|
||||
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
GLint status;
|
||||
const GLchar *source;
|
||||
|
||||
source =
|
||||
(GLchar *)[shaderString UTF8String];
|
||||
if (!source)
|
||||
{
|
||||
NSLog(@"Failed to load vertex shader");
|
||||
return NO;
|
||||
}
|
||||
|
||||
*shader = glCreateShader(type);
|
||||
glShaderSource(*shader, 1, &source, NULL);
|
||||
glCompileShader(*shader);
|
||||
|
||||
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (status != GL_TRUE)
|
||||
{
|
||||
GLint logLength;
|
||||
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0)
|
||||
{
|
||||
GLchar *log = (GLchar *)malloc(logLength);
|
||||
glGetShaderInfoLog(*shader, logLength, &logLength, log);
|
||||
if (shader == &vertShader)
|
||||
{
|
||||
self.vertexShaderLog = [NSString stringWithFormat:@"%s", log];
|
||||
}
|
||||
else
|
||||
{
|
||||
self.fragmentShaderLog = [NSString stringWithFormat:@"%s", log];
|
||||
}
|
||||
|
||||
free(log);
|
||||
}
|
||||
}
|
||||
|
||||
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
|
||||
// NSLog(@"Compiled in %f ms", linkTime * 1000.0);
|
||||
|
||||
return status == GL_TRUE;
|
||||
}
|
||||
// END:compile
|
||||
#pragma mark -
|
||||
// START:addattribute
|
||||
- (void)addAttribute:(NSString *)attributeName
|
||||
{
|
||||
if (![attributes containsObject:attributeName])
|
||||
{
|
||||
[attributes addObject:attributeName];
|
||||
glBindAttribLocation(program,
|
||||
(GLuint)[attributes indexOfObject:attributeName],
|
||||
[attributeName UTF8String]);
|
||||
}
|
||||
}
|
||||
// END:addattribute
|
||||
// START:indexmethods
|
||||
- (GLuint)attributeIndex:(NSString *)attributeName
|
||||
{
|
||||
return (GLuint)[attributes indexOfObject:attributeName];
|
||||
}
|
||||
- (GLuint)uniformIndex:(NSString *)uniformName
|
||||
{
|
||||
return glGetUniformLocation(program, [uniformName UTF8String]);
|
||||
}
|
||||
// END:indexmethods
|
||||
#pragma mark -
|
||||
// START:link
|
||||
- (BOOL)link
|
||||
{
|
||||
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
GLint status;
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
return NO;
|
||||
|
||||
if (vertShader)
|
||||
{
|
||||
glDeleteShader(vertShader);
|
||||
vertShader = 0;
|
||||
}
|
||||
if (fragShader)
|
||||
{
|
||||
glDeleteShader(fragShader);
|
||||
fragShader = 0;
|
||||
}
|
||||
|
||||
self.initialized = YES;
|
||||
|
||||
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
|
||||
// NSLog(@"Linked in %f ms", linkTime * 1000.0);
|
||||
|
||||
return YES;
|
||||
}
|
||||
// END:link
|
||||
// START:use
|
||||
- (void)use
|
||||
{
|
||||
glUseProgram(program);
|
||||
}
|
||||
// END:use
|
||||
#pragma mark -
|
||||
|
||||
- (void)validate;
|
||||
{
|
||||
GLint logLength;
|
||||
|
||||
glValidateProgram(program);
|
||||
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0)
|
||||
{
|
||||
GLchar *log = (GLchar *)malloc(logLength);
|
||||
glGetProgramInfoLog(program, logLength, &logLength, log);
|
||||
self.programLog = [NSString stringWithFormat:@"%s", log];
|
||||
free(log);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
// START:dealloc
|
||||
- (void)dealloc
|
||||
{
|
||||
if (vertShader)
|
||||
glDeleteShader(vertShader);
|
||||
|
||||
if (fragShader)
|
||||
glDeleteShader(fragShader);
|
||||
|
||||
if (program)
|
||||
glDeleteProgram(program);
|
||||
|
||||
}
|
||||
// END:dealloc
|
||||
@end
|
||||
@@ -1,128 +0,0 @@
|
||||
#import "GPUImage3x3ConvolutionFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImage3x3ConvolutionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mediump mat3 convolutionMatrix;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
mediump vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
mediump vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
mediump vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
mediump vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
mediump vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
mediump vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
|
||||
mediump vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
|
||||
resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
|
||||
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
|
||||
|
||||
gl_FragColor = vec4(resultColor, centerColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImage3x3ConvolutionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mat3 convolutionMatrix;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
|
||||
vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
|
||||
resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
|
||||
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
|
||||
|
||||
gl_FragColor = vec4(resultColor, centerColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImage3x3ConvolutionFilter
|
||||
|
||||
@synthesize convolutionKernel = _convolutionKernel;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithFragmentShaderFromString:kGPUImage3x3ConvolutionFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.convolutionKernel = (GPUMatrix3x3){
|
||||
{0.f, 0.f, 0.f},
|
||||
{0.f, 1.f, 0.f},
|
||||
{0.f, 0.f, 0.f}
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
convolutionMatrixUniform = [filterProgram uniformIndex:@"convolutionMatrix"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setConvolutionKernel:(GPUMatrix3x3)newValue;
|
||||
{
|
||||
_convolutionKernel = newValue;
|
||||
|
||||
[self setMatrix3f:_convolutionKernel forUniform:convolutionMatrixUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,121 +0,0 @@
|
||||
#import "GPUImage3x3TextureSamplingFilter.h"
|
||||
|
||||
// Override vertex shader to remove dependent texture reads
|
||||
NSString *const kGPUImageNearbyTexelSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidth;
|
||||
uniform float texelHeight;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 widthStep = vec2(texelWidth, 0.0);
|
||||
vec2 heightStep = vec2(0.0, texelHeight);
|
||||
vec2 widthHeightStep = vec2(texelWidth, texelHeight);
|
||||
vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);
|
||||
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;
|
||||
rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;
|
||||
|
||||
topTextureCoordinate = inputTextureCoordinate.xy - heightStep;
|
||||
topLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;
|
||||
topRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;
|
||||
|
||||
bottomTextureCoordinate = inputTextureCoordinate.xy + heightStep;
|
||||
bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;
|
||||
bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@implementation GPUImage3x3TextureSamplingFilter
|
||||
|
||||
@synthesize texelWidth = _texelWidth;
|
||||
@synthesize texelHeight = _texelHeight;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
texelWidthUniform = [filterProgram uniformIndex:@"texelWidth"];
|
||||
texelHeightUniform = [filterProgram uniformIndex:@"texelHeight"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [self initWithVertexShaderFromString:kGPUImageNearbyTexelSamplingVertexShaderString fragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
if (!hasOverriddenImageSizeFactor)
|
||||
{
|
||||
_texelWidth = 1.0 / filterFrameSize.width;
|
||||
_texelHeight = 1.0 / filterFrameSize.height;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
glUniform1f(texelWidthUniform, _texelHeight);
|
||||
glUniform1f(texelHeightUniform, _texelWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glUniform1f(texelWidthUniform, _texelWidth);
|
||||
glUniform1f(texelHeightUniform, _texelHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setTexelWidth:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelWidth = newValue;
|
||||
|
||||
[self setFloat:_texelWidth forUniform:texelWidthUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setTexelHeight:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelHeight = newValue;
|
||||
|
||||
[self setFloat:_texelHeight forUniform:texelHeightUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,100 +0,0 @@
|
||||
#import "GPUImageAdaptiveThresholdFilter.h"
|
||||
#import "GPUImageFilter.h"
|
||||
#import "GPUImageTwoInputFilter.h"
|
||||
#import "GPUImageGrayscaleFilter.h"
|
||||
#import "GPUImageBoxBlurFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageAdaptiveThresholdFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
highp float blurredInput = texture2D(inputImageTexture, textureCoordinate).r;
|
||||
highp float localLuminance = texture2D(inputImageTexture2, textureCoordinate2).r;
|
||||
highp float thresholdResult = step(blurredInput - 0.05, localLuminance);
|
||||
|
||||
gl_FragColor = vec4(vec3(thresholdResult), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageAdaptiveThresholdFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
float blurredInput = texture2D(inputImageTexture, textureCoordinate).r;
|
||||
float localLuminance = texture2D(inputImageTexture2, textureCoordinate2).r;
|
||||
float thresholdResult = step(blurredInput - 0.05, localLuminance);
|
||||
|
||||
gl_FragColor = vec4(vec3(thresholdResult), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@interface GPUImageAdaptiveThresholdFilter()
|
||||
{
|
||||
GPUImageBoxBlurFilter *boxBlurFilter;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GPUImageAdaptiveThresholdFilter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// First pass: reduce to luminance
|
||||
GPUImageGrayscaleFilter *luminanceFilter = [[GPUImageGrayscaleFilter alloc] init];
|
||||
[self addFilter:luminanceFilter];
|
||||
|
||||
// Second pass: perform a box blur
|
||||
boxBlurFilter = [[GPUImageBoxBlurFilter alloc] init];
|
||||
[self addFilter:boxBlurFilter];
|
||||
|
||||
// Third pass: compare the blurred background luminance to the local value
|
||||
GPUImageFilter *adaptiveThresholdFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromString:kGPUImageAdaptiveThresholdFragmentShaderString];
|
||||
[self addFilter:adaptiveThresholdFilter];
|
||||
|
||||
[luminanceFilter addTarget:boxBlurFilter];
|
||||
|
||||
[boxBlurFilter addTarget:adaptiveThresholdFilter];
|
||||
// To prevent double updating of this filter, disable updates from the sharp luminance image side
|
||||
[luminanceFilter addTarget:adaptiveThresholdFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObject:luminanceFilter];
|
||||
self.terminalFilter = adaptiveThresholdFilter;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
boxBlurFilter.blurRadiusInPixels = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurRadiusInPixels;
|
||||
{
|
||||
return boxBlurFilter.blurRadiusInPixels;
|
||||
}
|
||||
|
||||
@end
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
#import "GPUImageAddBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageAddBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
mediump float r;
|
||||
if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {
|
||||
r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
} else {
|
||||
r = overlay.r + base.r;
|
||||
}
|
||||
|
||||
mediump float g;
|
||||
if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {
|
||||
g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
} else {
|
||||
g = overlay.g + base.g;
|
||||
}
|
||||
|
||||
mediump float b;
|
||||
if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {
|
||||
b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
} else {
|
||||
b = overlay.b + base.b;
|
||||
}
|
||||
|
||||
mediump float a = overlay.a + base.a - overlay.a * base.a;
|
||||
|
||||
gl_FragColor = vec4(r, g, b, a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageAddBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
float r;
|
||||
if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {
|
||||
r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
} else {
|
||||
r = overlay.r + base.r;
|
||||
}
|
||||
|
||||
float g;
|
||||
if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {
|
||||
g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
} else {
|
||||
g = overlay.g + base.g;
|
||||
}
|
||||
|
||||
float b;
|
||||
if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {
|
||||
b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
} else {
|
||||
b = overlay.b + base.b;
|
||||
}
|
||||
|
||||
float a = overlay.a + base.a - overlay.a * base.a;
|
||||
|
||||
gl_FragColor = vec4(r, g, b, a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@implementation GPUImageAddBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageAddBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#import "GPUImageAlphaBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageAlphaBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
uniform lowp float mixturePercent;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * mixturePercent), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageAlphaBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
uniform float mixturePercent;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * mixturePercent), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageAlphaBlendFilter
|
||||
|
||||
@synthesize mix = _mix;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageAlphaBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
mixUniform = [filterProgram uniformIndex:@"mixturePercent"];
|
||||
self.mix = 0.5;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setMix:(CGFloat)newValue;
|
||||
{
|
||||
_mix = newValue;
|
||||
|
||||
[self setFloat:_mix forUniform:mixUniform program:filterProgram];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,38 +0,0 @@
|
||||
#import "GPUImageAmatorkaFilter.h"
|
||||
#import "GPUImagePicture.h"
|
||||
#import "GPUImageLookupFilter.h"
|
||||
|
||||
@implementation GPUImageAmatorkaFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
UIImage *image = [UIImage imageNamed:@"lookup_amatorka.png"];
|
||||
#else
|
||||
NSImage *image = [NSImage imageNamed:@"lookup_amatorka.png"];
|
||||
#endif
|
||||
|
||||
NSAssert(image, @"To use GPUImageAmatorkaFilter you need to add lookup_amatorka.png from GPUImage/framework/Resources to your application bundle.");
|
||||
|
||||
lookupImageSource = [[GPUImagePicture alloc] initWithImage:image];
|
||||
GPUImageLookupFilter *lookupFilter = [[GPUImageLookupFilter alloc] init];
|
||||
[self addFilter:lookupFilter];
|
||||
|
||||
[lookupImageSource addTarget:lookupFilter atTextureLocation:1];
|
||||
[lookupImageSource processImage];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:lookupFilter, nil];
|
||||
self.terminalFilter = lookupFilter;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
@end
|
||||
-204
@@ -1,204 +0,0 @@
|
||||
#import "GPUImageAverageColor.h"
|
||||
|
||||
NSString *const kGPUImageColorAveragingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidth;
|
||||
uniform float texelHeight;
|
||||
|
||||
varying vec2 upperLeftInputTextureCoordinate;
|
||||
varying vec2 upperRightInputTextureCoordinate;
|
||||
varying vec2 lowerLeftInputTextureCoordinate;
|
||||
varying vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
upperLeftInputTextureCoordinate = inputTextureCoordinate.xy + vec2(-texelWidth, -texelHeight);
|
||||
upperRightInputTextureCoordinate = inputTextureCoordinate.xy + vec2(texelWidth, -texelHeight);
|
||||
lowerLeftInputTextureCoordinate = inputTextureCoordinate.xy + vec2(-texelWidth, texelHeight);
|
||||
lowerRightInputTextureCoordinate = inputTextureCoordinate.xy + vec2(texelWidth, texelHeight);
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorAveragingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
varying highp vec2 outputTextureCoordinate;
|
||||
|
||||
varying highp vec2 upperLeftInputTextureCoordinate;
|
||||
varying highp vec2 upperRightInputTextureCoordinate;
|
||||
varying highp vec2 lowerLeftInputTextureCoordinate;
|
||||
varying highp vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec4 upperLeftColor = texture2D(inputImageTexture, upperLeftInputTextureCoordinate);
|
||||
highp vec4 upperRightColor = texture2D(inputImageTexture, upperRightInputTextureCoordinate);
|
||||
highp vec4 lowerLeftColor = texture2D(inputImageTexture, lowerLeftInputTextureCoordinate);
|
||||
highp vec4 lowerRightColor = texture2D(inputImageTexture, lowerRightInputTextureCoordinate);
|
||||
|
||||
gl_FragColor = 0.25 * (upperLeftColor + upperRightColor + lowerLeftColor + lowerRightColor);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorAveragingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
varying vec2 outputTextureCoordinate;
|
||||
|
||||
varying vec2 upperLeftInputTextureCoordinate;
|
||||
varying vec2 upperRightInputTextureCoordinate;
|
||||
varying vec2 lowerLeftInputTextureCoordinate;
|
||||
varying vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 upperLeftColor = texture2D(inputImageTexture, upperLeftInputTextureCoordinate);
|
||||
vec4 upperRightColor = texture2D(inputImageTexture, upperRightInputTextureCoordinate);
|
||||
vec4 lowerLeftColor = texture2D(inputImageTexture, lowerLeftInputTextureCoordinate);
|
||||
vec4 lowerRightColor = texture2D(inputImageTexture, lowerRightInputTextureCoordinate);
|
||||
|
||||
gl_FragColor = 0.25 * (upperLeftColor + upperRightColor + lowerLeftColor + lowerRightColor);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageAverageColor
|
||||
|
||||
@synthesize colorAverageProcessingFinishedBlock = _colorAverageProcessingFinishedBlock;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageColorAveragingVertexShaderString fragmentShaderFromString:kGPUImageColorAveragingFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
texelWidthUniform = [filterProgram uniformIndex:@"texelWidth"];
|
||||
texelHeightUniform = [filterProgram uniformIndex:@"texelHeight"];
|
||||
finalStageSize = CGSizeMake(1.0, 1.0);
|
||||
|
||||
__unsafe_unretained GPUImageAverageColor *weakSelf = self;
|
||||
[self setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime) {
|
||||
[weakSelf extractAverageColorAtFrameTime:frameTime];
|
||||
}];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
{
|
||||
if (rawImagePixels != NULL)
|
||||
{
|
||||
free(rawImagePixels);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Managing the display FBOs
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
[firstInputFramebuffer unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
outputFramebuffer = nil;
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
|
||||
GLuint currentTexture = [firstInputFramebuffer texture];
|
||||
|
||||
NSUInteger numberOfReductionsInX = floor(log(inputTextureSize.width) / log(4.0));
|
||||
NSUInteger numberOfReductionsInY = floor(log(inputTextureSize.height) / log(4.0));
|
||||
NSUInteger reductionsToHitSideLimit = MIN(numberOfReductionsInX, numberOfReductionsInY);
|
||||
for (NSUInteger currentReduction = 0; currentReduction < reductionsToHitSideLimit; currentReduction++)
|
||||
{
|
||||
CGSize currentStageSize = CGSizeMake(floor(inputTextureSize.width / pow(4.0, currentReduction + 1.0)), floor(inputTextureSize.height / pow(4.0, currentReduction + 1.0)));
|
||||
|
||||
[outputFramebuffer unlock];
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:currentStageSize textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, currentTexture);
|
||||
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
glUniform1f(texelWidthUniform, 0.25 / currentStageSize.width);
|
||||
glUniform1f(texelHeightUniform, 0.25 / currentStageSize.height);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
currentTexture = [outputFramebuffer texture];
|
||||
finalStageSize = currentStageSize;
|
||||
}
|
||||
|
||||
[firstInputFramebuffer unlock];
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
inputRotation = kGPUImageNoRotation;
|
||||
}
|
||||
|
||||
- (void)extractAverageColorAtFrameTime:(CMTime)frameTime;
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
// we need a normal color texture for averaging the color values
|
||||
NSAssert(self.outputTextureOptions.internalFormat == GL_RGBA, @"The output texture internal format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.outputTextureOptions.type == GL_UNSIGNED_BYTE, @"The type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
NSUInteger totalNumberOfPixels = round(finalStageSize.width * finalStageSize.height);
|
||||
|
||||
if (rawImagePixels == NULL)
|
||||
{
|
||||
rawImagePixels = (GLubyte *)malloc(totalNumberOfPixels * 4);
|
||||
}
|
||||
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
glReadPixels(0, 0, (int)finalStageSize.width, (int)finalStageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
|
||||
|
||||
NSUInteger redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
NSUInteger byteIndex = 0;
|
||||
for (NSUInteger currentPixel = 0; currentPixel < totalNumberOfPixels; currentPixel++)
|
||||
{
|
||||
redTotal += rawImagePixels[byteIndex++];
|
||||
greenTotal += rawImagePixels[byteIndex++];
|
||||
blueTotal += rawImagePixels[byteIndex++];
|
||||
alphaTotal += rawImagePixels[byteIndex++];
|
||||
}
|
||||
|
||||
CGFloat normalizedRedTotal = (CGFloat)redTotal / (CGFloat)totalNumberOfPixels / 255.0;
|
||||
CGFloat normalizedGreenTotal = (CGFloat)greenTotal / (CGFloat)totalNumberOfPixels / 255.0;
|
||||
CGFloat normalizedBlueTotal = (CGFloat)blueTotal / (CGFloat)totalNumberOfPixels / 255.0;
|
||||
CGFloat normalizedAlphaTotal = (CGFloat)alphaTotal / (CGFloat)totalNumberOfPixels / 255.0;
|
||||
|
||||
if (_colorAverageProcessingFinishedBlock != NULL)
|
||||
{
|
||||
_colorAverageProcessingFinishedBlock(normalizedRedTotal, normalizedGreenTotal, normalizedBlueTotal, normalizedAlphaTotal, frameTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,47 +0,0 @@
|
||||
#import "GPUImageAverageLuminanceThresholdFilter.h"
|
||||
#import "GPUImageLuminosity.h"
|
||||
#import "GPUImageLuminanceThresholdFilter.h"
|
||||
|
||||
@interface GPUImageAverageLuminanceThresholdFilter()
|
||||
{
|
||||
GPUImageLuminosity *luminosityFilter;
|
||||
GPUImageLuminanceThresholdFilter *luminanceThresholdFilter;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation GPUImageAverageLuminanceThresholdFilter
|
||||
|
||||
@synthesize thresholdMultiplier = _thresholdMultiplier;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.thresholdMultiplier = 1.0;
|
||||
|
||||
luminosityFilter = [[GPUImageLuminosity alloc] init];
|
||||
[self addFilter:luminosityFilter];
|
||||
|
||||
luminanceThresholdFilter = [[GPUImageLuminanceThresholdFilter alloc] init];
|
||||
[self addFilter:luminanceThresholdFilter];
|
||||
|
||||
__unsafe_unretained GPUImageAverageLuminanceThresholdFilter *weakSelf = self;
|
||||
__unsafe_unretained GPUImageLuminanceThresholdFilter *weakThreshold = luminanceThresholdFilter;
|
||||
|
||||
[luminosityFilter setLuminosityProcessingFinishedBlock:^(CGFloat luminosity, CMTime frameTime) {
|
||||
weakThreshold.threshold = luminosity * weakSelf.thresholdMultiplier;
|
||||
}];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:luminosityFilter, luminanceThresholdFilter, nil];
|
||||
self.terminalFilter = luminanceThresholdFilter;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
-231
@@ -1,231 +0,0 @@
|
||||
#import "GPUImageBilateralFilter.h"
|
||||
|
||||
NSString *const kGPUImageBilateralBlurVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
const int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
|
||||
// Calculate the positions for the blur
|
||||
int multiplier = 0;
|
||||
vec2 blurStep;
|
||||
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
for (int i = 0; i < GAUSSIAN_SAMPLES; i++)
|
||||
{
|
||||
multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));
|
||||
// Blur in x (horizontal)
|
||||
blurStep = float(multiplier) * singleStepOffset;
|
||||
blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageBilateralFilterFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const lowp int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
uniform mediump float distanceNormalizationFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 centralColor;
|
||||
lowp float gaussianWeightTotal;
|
||||
lowp vec4 sum;
|
||||
lowp vec4 sampleColor;
|
||||
lowp float distanceFromCentralColor;
|
||||
lowp float gaussianWeight;
|
||||
|
||||
centralColor = texture2D(inputImageTexture, blurCoordinates[4]);
|
||||
gaussianWeightTotal = 0.18;
|
||||
sum = centralColor * 0.18;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[1]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[2]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[3]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[5]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[6]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[7]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[8]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
gl_FragColor = sum / gaussianWeightTotal;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageBilateralFilterFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
uniform float distanceNormalizationFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 centralColor;
|
||||
float gaussianWeightTotal;
|
||||
vec4 sum;
|
||||
vec4 sampleColor;
|
||||
float distanceFromCentralColor;
|
||||
float gaussianWeight;
|
||||
|
||||
centralColor = texture2D(inputImageTexture, blurCoordinates[4]);
|
||||
gaussianWeightTotal = 0.18;
|
||||
sum = centralColor * 0.18;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[1]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[2]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[3]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[5]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[6]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[7]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
sampleColor = texture2D(inputImageTexture, blurCoordinates[8]);
|
||||
distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);
|
||||
gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);
|
||||
gaussianWeightTotal += gaussianWeight;
|
||||
sum += sampleColor * gaussianWeight;
|
||||
|
||||
gl_FragColor = sum / gaussianWeightTotal;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageBilateralFilter
|
||||
|
||||
@synthesize distanceNormalizationFactor = _distanceNormalizationFactor;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:kGPUImageBilateralBlurVertexShaderString
|
||||
firstStageFragmentShaderFromString:kGPUImageBilateralFilterFragmentShaderString
|
||||
secondStageVertexShaderFromString:kGPUImageBilateralBlurVertexShaderString
|
||||
secondStageFragmentShaderFromString:kGPUImageBilateralFilterFragmentShaderString])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
firstDistanceNormalizationFactorUniform = [filterProgram uniformIndex:@"distanceNormalizationFactor"];
|
||||
secondDistanceNormalizationFactorUniform = [filterProgram uniformIndex:@"distanceNormalizationFactor"];
|
||||
|
||||
self.texelSpacingMultiplier = 4.0;
|
||||
self.distanceNormalizationFactor = 8.0;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setDistanceNormalizationFactor:(CGFloat)newValue
|
||||
{
|
||||
_distanceNormalizationFactor = newValue;
|
||||
|
||||
[self setFloat:newValue
|
||||
forUniform:firstDistanceNormalizationFactorUniform
|
||||
program:filterProgram];
|
||||
|
||||
[self setFloat:newValue
|
||||
forUniform:secondDistanceNormalizationFactorUniform
|
||||
program:secondFilterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
-178
@@ -1,178 +0,0 @@
|
||||
#import "GPUImageBoxBlurFilter.h"
|
||||
|
||||
|
||||
@implementation GPUImageBoxBlurFilter
|
||||
|
||||
+ (NSString *)vertexShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImageVertexShaderString;
|
||||
}
|
||||
|
||||
// From these weights we calculate the offsets to read interpolated values from
|
||||
NSUInteger numberOfOptimizedOffsets = MIN(blurRadius / 2 + (blurRadius % 2), 7);
|
||||
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
// Header
|
||||
[shaderString appendFormat:@"\
|
||||
attribute vec4 position;\n\
|
||||
attribute vec4 inputTextureCoordinate;\n\
|
||||
\n\
|
||||
uniform float texelWidthOffset;\n\
|
||||
uniform float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
gl_Position = position;\n\
|
||||
\n\
|
||||
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n", (unsigned long)(1 + (numberOfOptimizedOffsets * 2))];
|
||||
|
||||
// Inner offset loop
|
||||
[shaderString appendString:@"blurCoordinates[0] = inputTextureCoordinate.xy;\n"];
|
||||
for (NSUInteger currentOptimizedOffset = 0; currentOptimizedOffset < numberOfOptimizedOffsets; currentOptimizedOffset++)
|
||||
{
|
||||
GLfloat optimizedOffset = (GLfloat)(currentOptimizedOffset * 2) + 1.5;
|
||||
|
||||
[shaderString appendFormat:@"\
|
||||
blurCoordinates[%lu] = inputTextureCoordinate.xy + singleStepOffset * %f;\n\
|
||||
blurCoordinates[%lu] = inputTextureCoordinate.xy - singleStepOffset * %f;\n", (unsigned long)((currentOptimizedOffset * 2) + 1), optimizedOffset, (unsigned long)((currentOptimizedOffset * 2) + 2), optimizedOffset];
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"}\n"];
|
||||
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
+ (NSString *)fragmentShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImagePassthroughFragmentShaderString;
|
||||
}
|
||||
|
||||
NSUInteger numberOfOptimizedOffsets = MIN(blurRadius / 2 + (blurRadius % 2), 7);
|
||||
NSUInteger trueNumberOfOptimizedOffsets = blurRadius / 2 + (blurRadius % 2);
|
||||
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
|
||||
// Header
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
uniform highp float texelWidthOffset;\n\
|
||||
uniform highp float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying highp vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
lowp vec4 sum = vec4(0.0);\n", (unsigned long)(1 + (numberOfOptimizedOffsets * 2)) ];
|
||||
#else
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
uniform float texelWidthOffset;\n\
|
||||
uniform float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 sum = vec4(0.0);\n", 1 + (numberOfOptimizedOffsets * 2) ];
|
||||
#endif
|
||||
|
||||
GLfloat boxWeight = 1.0 / (GLfloat)((blurRadius * 2) + 1);
|
||||
|
||||
// Inner texture loop
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0]) * %f;\n", boxWeight];
|
||||
|
||||
for (NSUInteger currentBlurCoordinateIndex = 0; currentBlurCoordinateIndex < numberOfOptimizedOffsets; currentBlurCoordinateIndex++)
|
||||
{
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 1), boxWeight * 2.0];
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 2), boxWeight * 2.0];
|
||||
}
|
||||
|
||||
// If the number of required samples exceeds the amount we can pass in via varyings, we have to do dependent texture reads in the fragment shader
|
||||
if (trueNumberOfOptimizedOffsets > numberOfOptimizedOffsets)
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[shaderString appendString:@"highp vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"];
|
||||
#else
|
||||
[shaderString appendString:@"vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"];
|
||||
#endif
|
||||
|
||||
for (NSUInteger currentOverlowTextureRead = numberOfOptimizedOffsets; currentOverlowTextureRead < trueNumberOfOptimizedOffsets; currentOverlowTextureRead++)
|
||||
{
|
||||
GLfloat optimizedOffset = (GLfloat)(currentOverlowTextureRead * 2) + 1.5;
|
||||
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] + singleStepOffset * %f) * %f;\n", optimizedOffset, boxWeight * 2.0];
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] - singleStepOffset * %f) * %f;\n", optimizedOffset, boxWeight * 2.0];
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"\
|
||||
gl_FragColor = sum;\n\
|
||||
}\n"];
|
||||
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
[super setupFilterForSize:filterFrameSize];
|
||||
|
||||
if (shouldResizeBlurRadiusWithImageSize == YES)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
// NSString *currentGaussianBlurVertexShader = [GPUImageGaussianBlurFilter vertexShaderForStandardGaussianOfRadius:4 sigma:2.0];
|
||||
// NSString *currentGaussianBlurFragmentShader = [GPUImageGaussianBlurFilter fragmentShaderForStandardGaussianOfRadius:4 sigma:2.0];
|
||||
|
||||
NSString *currentBoxBlurVertexShader = [[self class] vertexShaderForOptimizedBlurOfRadius:4 sigma:0.0];
|
||||
NSString *currentBoxBlurFragmentShader = [[self class] fragmentShaderForOptimizedBlurOfRadius:4 sigma:0.0];
|
||||
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:currentBoxBlurVertexShader firstStageFragmentShaderFromString:currentBoxBlurFragmentShader secondStageVertexShaderFromString:currentBoxBlurVertexShader secondStageFragmentShaderFromString:currentBoxBlurFragmentShader]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
_blurRadiusInPixels = 4.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
CGFloat newBlurRadius = round(round(newValue / 2.0) * 2.0); // For now, only do even radii
|
||||
|
||||
if (newBlurRadius != _blurRadiusInPixels)
|
||||
{
|
||||
_blurRadiusInPixels = newBlurRadius;
|
||||
|
||||
NSString *newGaussianBlurVertexShader = [[self class] vertexShaderForOptimizedBlurOfRadius:_blurRadiusInPixels sigma:0.0];
|
||||
NSString *newGaussianBlurFragmentShader = [[self class] fragmentShaderForOptimizedBlurOfRadius:_blurRadiusInPixels sigma:0.0];
|
||||
|
||||
// NSLog(@"Optimized vertex shader: \n%@", newGaussianBlurVertexShader);
|
||||
// NSLog(@"Optimized fragment shader: \n%@", newGaussianBlurFragmentShader);
|
||||
//
|
||||
[self switchToVertexShader:newGaussianBlurVertexShader fragmentShader:newGaussianBlurFragmentShader];
|
||||
}
|
||||
shouldResizeBlurRadiusWithImageSize = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#import "GPUImageBrightnessFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageBrightnessFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp float brightness;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageBrightnessFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float brightness;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageBrightnessFilter
|
||||
|
||||
@synthesize brightness = _brightness;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageBrightnessFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
brightnessUniform = [filterProgram uniformIndex:@"brightness"];
|
||||
self.brightness = 0.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBrightness:(CGFloat)newValue;
|
||||
{
|
||||
_brightness = newValue;
|
||||
|
||||
[self setFloat:_brightness forUniform:brightnessUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
#import "GPUImageBuffer.h"
|
||||
|
||||
@interface GPUImageBuffer()
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageBuffer
|
||||
|
||||
@synthesize bufferSize = _bufferSize;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithFragmentShaderFromString:kGPUImagePassthroughFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
bufferedFramebuffers = [[NSMutableArray alloc] init];
|
||||
// [bufferedTextures addObject:[NSNumber numberWithInt:outputTexture]];
|
||||
_bufferSize = 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
for (GPUImageFramebuffer *currentFramebuffer in bufferedFramebuffers)
|
||||
{
|
||||
[currentFramebuffer unlock];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if ([bufferedFramebuffers count] >= _bufferSize)
|
||||
{
|
||||
outputFramebuffer = [bufferedFramebuffers objectAtIndex:0];
|
||||
[bufferedFramebuffers removeObjectAtIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing yet in the buffer, so don't process further until the buffer is full
|
||||
outputFramebuffer = firstInputFramebuffer;
|
||||
[firstInputFramebuffer lock];
|
||||
}
|
||||
|
||||
[bufferedFramebuffers addObject:firstInputFramebuffer];
|
||||
|
||||
// Need to pass along rotation information, as we're just holding on to buffered framebuffers and not rotating them ourselves
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
if (currentTarget != self.targetToIgnoreForUpdates)
|
||||
{
|
||||
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
|
||||
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
|
||||
[currentTarget setInputRotation:inputRotation atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Let the downstream video elements see the previous frame from the buffer before rendering a new one into place
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
|
||||
// [self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]];
|
||||
}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
// No need to render to another texture anymore, since we'll be hanging on to the textures in our buffer
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBufferSize:(NSUInteger)newValue;
|
||||
{
|
||||
if ( (newValue == _bufferSize) || (newValue < 1) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue > _bufferSize)
|
||||
{
|
||||
NSUInteger texturesToAdd = newValue - _bufferSize;
|
||||
for (NSUInteger currentTextureIndex = 0; currentTextureIndex < texturesToAdd; currentTextureIndex++)
|
||||
{
|
||||
// TODO: Deal with the growth of the size of the buffer by rotating framebuffers, no textures
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSUInteger texturesToRemove = _bufferSize - newValue;
|
||||
for (NSUInteger currentTextureIndex = 0; currentTextureIndex < texturesToRemove; currentTextureIndex++)
|
||||
{
|
||||
GPUImageFramebuffer *lastFramebuffer = [bufferedFramebuffers lastObject];
|
||||
[bufferedFramebuffers removeObjectAtIndex:([bufferedFramebuffers count] - 1)];
|
||||
|
||||
[lastFramebuffer unlock];
|
||||
lastFramebuffer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
_bufferSize = newValue;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,174 +0,0 @@
|
||||
#import "GPUImageBulgeDistortionFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageBulgeDistortionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp float aspectRatio;
|
||||
uniform highp vec2 center;
|
||||
uniform highp float radius;
|
||||
uniform highp float scale;
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, ((textureCoordinate.y - center.y) * aspectRatio) + center.y);
|
||||
highp float dist = distance(center, textureCoordinateToUse);
|
||||
textureCoordinateToUse = textureCoordinate;
|
||||
|
||||
if (dist < radius)
|
||||
{
|
||||
textureCoordinateToUse -= center;
|
||||
highp float percent = 1.0 - ((radius - dist) / radius) * scale;
|
||||
percent = percent * percent;
|
||||
|
||||
textureCoordinateToUse = textureCoordinateToUse * percent;
|
||||
textureCoordinateToUse += center;
|
||||
}
|
||||
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageBulgeDistortionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform float aspectRatio;
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform float scale;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 textureCoordinateToUse = vec2(textureCoordinate.x, ((textureCoordinate.y - center.y) * aspectRatio) + center.y);
|
||||
float dist = distance(center, textureCoordinateToUse);
|
||||
textureCoordinateToUse = textureCoordinate;
|
||||
|
||||
if (dist < radius)
|
||||
{
|
||||
textureCoordinateToUse -= center;
|
||||
float percent = 1.0 - ((radius - dist) / radius) * scale;
|
||||
percent = percent * percent;
|
||||
|
||||
textureCoordinateToUse = textureCoordinateToUse * percent;
|
||||
textureCoordinateToUse += center;
|
||||
}
|
||||
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@interface GPUImageBulgeDistortionFilter ()
|
||||
|
||||
- (void)adjustAspectRatio;
|
||||
|
||||
@property (readwrite, nonatomic) CGFloat aspectRatio;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageBulgeDistortionFilter
|
||||
|
||||
@synthesize aspectRatio = _aspectRatio;
|
||||
@synthesize center = _center;
|
||||
@synthesize radius = _radius;
|
||||
@synthesize scale = _scale;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageBulgeDistortionFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
aspectRatioUniform = [filterProgram uniformIndex:@"aspectRatio"];
|
||||
radiusUniform = [filterProgram uniformIndex:@"radius"];
|
||||
scaleUniform = [filterProgram uniformIndex:@"scale"];
|
||||
centerUniform = [filterProgram uniformIndex:@"center"];
|
||||
|
||||
self.radius = 0.25;
|
||||
self.scale = 0.5;
|
||||
self.center = CGPointMake(0.5, 0.5);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)adjustAspectRatio;
|
||||
{
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
[self setAspectRatio:(inputTextureSize.width / inputTextureSize.height)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setAspectRatio:(inputTextureSize.height / inputTextureSize.width)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSize:(CGSize)frameSize;
|
||||
{
|
||||
[super forceProcessingAtSize:frameSize];
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
CGSize oldInputSize = inputTextureSize;
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
|
||||
if ( (!CGSizeEqualToSize(oldInputSize, inputTextureSize)) && (!CGSizeEqualToSize(newSize, CGSizeZero)) )
|
||||
{
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAspectRatio:(CGFloat)newValue;
|
||||
{
|
||||
_aspectRatio = newValue;
|
||||
|
||||
[self setFloat:_aspectRatio forUniform:aspectRatioUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
[super setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[self setCenter:self.center];
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
|
||||
- (void)setRadius:(CGFloat)newValue;
|
||||
{
|
||||
_radius = newValue;
|
||||
|
||||
[self setFloat:_radius forUniform:radiusUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setScale:(CGFloat)newValue;
|
||||
{
|
||||
_scale = newValue;
|
||||
|
||||
[self setFloat:_scale forUniform:scaleUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setCenter:(CGPoint)newValue;
|
||||
{
|
||||
_center = newValue;
|
||||
|
||||
CGPoint rotatedPoint = [self rotatedPoint:_center forRotation:inputRotation];
|
||||
|
||||
[self setPoint:rotatedPoint forUniform:centerUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,113 +0,0 @@
|
||||
//
|
||||
// GPUImageCGAColorspaceFilter.m
|
||||
//
|
||||
|
||||
#import "GPUImageCGAColorspaceFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageCGAColorspaceFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);
|
||||
//highp vec4 colorDivisor = vec4(colorDepth);
|
||||
|
||||
highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);
|
||||
highp vec4 color = texture2D(inputImageTexture, samplePos );
|
||||
|
||||
//gl_FragColor = texture2D(inputImageTexture, samplePos );
|
||||
mediump vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);
|
||||
mediump vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);
|
||||
mediump vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
mediump vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
mediump vec4 endColor;
|
||||
highp float blackDistance = distance(color, colorBlack);
|
||||
highp float whiteDistance = distance(color, colorWhite);
|
||||
highp float magentaDistance = distance(color, colorMagenta);
|
||||
highp float cyanDistance = distance(color, colorCyan);
|
||||
|
||||
mediump vec4 finalColor;
|
||||
|
||||
highp float colorDistance = min(magentaDistance, cyanDistance);
|
||||
colorDistance = min(colorDistance, whiteDistance);
|
||||
colorDistance = min(colorDistance, blackDistance);
|
||||
|
||||
if (colorDistance == blackDistance) {
|
||||
finalColor = colorBlack;
|
||||
} else if (colorDistance == whiteDistance) {
|
||||
finalColor = colorWhite;
|
||||
} else if (colorDistance == cyanDistance) {
|
||||
finalColor = colorCyan;
|
||||
} else {
|
||||
finalColor = colorMagenta;
|
||||
}
|
||||
|
||||
gl_FragColor = finalColor;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageCGAColorspaceFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);
|
||||
//highp vec4 colorDivisor = vec4(colorDepth);
|
||||
|
||||
vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);
|
||||
vec4 color = texture2D(inputImageTexture, samplePos );
|
||||
|
||||
//gl_FragColor = texture2D(inputImageTexture, samplePos );
|
||||
vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);
|
||||
vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);
|
||||
vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
vec4 endColor;
|
||||
float blackDistance = distance(color, colorBlack);
|
||||
float whiteDistance = distance(color, colorWhite);
|
||||
float magentaDistance = distance(color, colorMagenta);
|
||||
float cyanDistance = distance(color, colorCyan);
|
||||
|
||||
vec4 finalColor;
|
||||
|
||||
float colorDistance = min(magentaDistance, cyanDistance);
|
||||
colorDistance = min(colorDistance, whiteDistance);
|
||||
colorDistance = min(colorDistance, blackDistance);
|
||||
|
||||
if (colorDistance == blackDistance) {
|
||||
finalColor = colorBlack;
|
||||
} else if (colorDistance == whiteDistance) {
|
||||
finalColor = colorWhite;
|
||||
} else if (colorDistance == cyanDistance) {
|
||||
finalColor = colorCyan;
|
||||
} else {
|
||||
finalColor = colorMagenta;
|
||||
}
|
||||
|
||||
gl_FragColor = finalColor;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageCGAColorspaceFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageCGAColorspaceFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,125 +0,0 @@
|
||||
#import "GPUImageCannyEdgeDetectionFilter.h"
|
||||
|
||||
#import "GPUImageGrayscaleFilter.h"
|
||||
#import "GPUImageDirectionalSobelEdgeDetectionFilter.h"
|
||||
#import "GPUImageDirectionalNonMaximumSuppressionFilter.h"
|
||||
#import "GPUImageWeakPixelInclusionFilter.h"
|
||||
#import "GPUImageSingleComponentGaussianBlurFilter.h"
|
||||
|
||||
@implementation GPUImageCannyEdgeDetectionFilter
|
||||
|
||||
@synthesize upperThreshold;
|
||||
@synthesize lowerThreshold;
|
||||
@synthesize blurRadiusInPixels;
|
||||
@synthesize blurTexelSpacingMultiplier;
|
||||
@synthesize texelWidth;
|
||||
@synthesize texelHeight;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// First pass: convert image to luminance
|
||||
luminanceFilter = [[GPUImageGrayscaleFilter alloc] init];
|
||||
[self addFilter:luminanceFilter];
|
||||
|
||||
// Second pass: apply a variable Gaussian blur
|
||||
blurFilter = [[GPUImageSingleComponentGaussianBlurFilter alloc] init];
|
||||
[self addFilter:blurFilter];
|
||||
|
||||
// Third pass: run the Sobel edge detection, with calculated gradient directions, on this blurred image
|
||||
edgeDetectionFilter = [[GPUImageDirectionalSobelEdgeDetectionFilter alloc] init];
|
||||
[self addFilter:edgeDetectionFilter];
|
||||
|
||||
// Fourth pass: apply non-maximum suppression
|
||||
nonMaximumSuppressionFilter = [[GPUImageDirectionalNonMaximumSuppressionFilter alloc] init];
|
||||
[self addFilter:nonMaximumSuppressionFilter];
|
||||
|
||||
// Fifth pass: include weak pixels to complete edges
|
||||
weakPixelInclusionFilter = [[GPUImageWeakPixelInclusionFilter alloc] init];
|
||||
[self addFilter:weakPixelInclusionFilter];
|
||||
|
||||
[luminanceFilter addTarget:blurFilter];
|
||||
[blurFilter addTarget:edgeDetectionFilter];
|
||||
[edgeDetectionFilter addTarget:nonMaximumSuppressionFilter];
|
||||
[nonMaximumSuppressionFilter addTarget:weakPixelInclusionFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObject:luminanceFilter];
|
||||
// self.terminalFilter = nonMaximumSuppressionFilter;
|
||||
self.terminalFilter = weakPixelInclusionFilter;
|
||||
|
||||
self.blurRadiusInPixels = 2.0;
|
||||
self.blurTexelSpacingMultiplier = 1.0;
|
||||
self.upperThreshold = 0.4;
|
||||
self.lowerThreshold = 0.1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
blurFilter.blurRadiusInPixels = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurRadiusInPixels;
|
||||
{
|
||||
return blurFilter.blurRadiusInPixels;
|
||||
}
|
||||
|
||||
- (void)setBlurTexelSpacingMultiplier:(CGFloat)newValue;
|
||||
{
|
||||
blurFilter.texelSpacingMultiplier = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurTexelSpacingMultiplier;
|
||||
{
|
||||
return blurFilter.texelSpacingMultiplier;
|
||||
}
|
||||
|
||||
- (void)setTexelWidth:(CGFloat)newValue;
|
||||
{
|
||||
edgeDetectionFilter.texelWidth = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)texelWidth;
|
||||
{
|
||||
return edgeDetectionFilter.texelWidth;
|
||||
}
|
||||
|
||||
- (void)setTexelHeight:(CGFloat)newValue;
|
||||
{
|
||||
edgeDetectionFilter.texelHeight = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)texelHeight;
|
||||
{
|
||||
return edgeDetectionFilter.texelHeight;
|
||||
}
|
||||
|
||||
- (void)setUpperThreshold:(CGFloat)newValue;
|
||||
{
|
||||
nonMaximumSuppressionFilter.upperThreshold = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)upperThreshold;
|
||||
{
|
||||
return nonMaximumSuppressionFilter.upperThreshold;
|
||||
}
|
||||
|
||||
- (void)setLowerThreshold:(CGFloat)newValue;
|
||||
{
|
||||
nonMaximumSuppressionFilter.lowerThreshold = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)lowerThreshold;
|
||||
{
|
||||
return nonMaximumSuppressionFilter.lowerThreshold;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,117 +0,0 @@
|
||||
#import "GPUImageChromaKeyBlendFilter.h"
|
||||
|
||||
// Shader code based on Apple's CIChromaKeyFilter example: https://developer.apple.com/library/mac/#samplecode/CIChromaKeyFilter/Introduction/Intro.html
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageChromaKeyBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform float thresholdSensitivity;
|
||||
uniform float smoothing;
|
||||
uniform vec3 colorToReplace;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;
|
||||
float maskCr = 0.7132 * (colorToReplace.r - maskY);
|
||||
float maskCb = 0.5647 * (colorToReplace.b - maskY);
|
||||
|
||||
float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;
|
||||
float Cr = 0.7132 * (textureColor.r - Y);
|
||||
float Cb = 0.5647 * (textureColor.b - Y);
|
||||
|
||||
// float blendValue = 1.0 - smoothstep(thresholdSensitivity - smoothing, thresholdSensitivity , abs(Cr - maskCr) + abs(Cb - maskCb));
|
||||
float blendValue = 1.0 - smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));
|
||||
gl_FragColor = mix(textureColor, textureColor2, blendValue);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageChromaKeyBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform float thresholdSensitivity;
|
||||
uniform float smoothing;
|
||||
uniform vec3 colorToReplace;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;
|
||||
float maskCr = 0.7132 * (colorToReplace.r - maskY);
|
||||
float maskCb = 0.5647 * (colorToReplace.b - maskY);
|
||||
|
||||
float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;
|
||||
float Cr = 0.7132 * (textureColor.r - Y);
|
||||
float Cb = 0.5647 * (textureColor.b - Y);
|
||||
|
||||
// float blendValue = 1.0 - smoothstep(thresholdSensitivity - smoothing, thresholdSensitivity , abs(Cr - maskCr) + abs(Cb - maskCb));
|
||||
float blendValue = 1.0 - smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));
|
||||
gl_FragColor = mix(textureColor, textureColor2, blendValue);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageChromaKeyBlendFilter
|
||||
|
||||
@synthesize thresholdSensitivity = _thresholdSensitivity;
|
||||
@synthesize smoothing = _smoothing;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageChromaKeyBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
thresholdSensitivityUniform = [filterProgram uniformIndex:@"thresholdSensitivity"];
|
||||
smoothingUniform = [filterProgram uniformIndex:@"smoothing"];
|
||||
colorToReplaceUniform = [filterProgram uniformIndex:@"colorToReplace"];
|
||||
|
||||
self.thresholdSensitivity = 0.4;
|
||||
self.smoothing = 0.1;
|
||||
[self setColorToReplaceRed:0.0 green:1.0 blue:0.0];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 colorToReplace = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:colorToReplace forUniform:colorToReplaceUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setThresholdSensitivity:(CGFloat)newValue;
|
||||
{
|
||||
_thresholdSensitivity = newValue;
|
||||
|
||||
[self setFloat:(GLfloat)_thresholdSensitivity forUniform:thresholdSensitivityUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setSmoothing:(CGFloat)newValue;
|
||||
{
|
||||
_smoothing = newValue;
|
||||
|
||||
[self setFloat:(GLfloat)_smoothing forUniform:smoothingUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
#import "GPUImageChromaKeyFilter.h"
|
||||
|
||||
// Shader code based on Apple's CIChromaKeyFilter example: https://developer.apple.com/library/mac/#samplecode/CIChromaKeyFilter/Introduction/Intro.html
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageChromaKeyFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform float thresholdSensitivity;
|
||||
uniform float smoothing;
|
||||
uniform vec3 colorToReplace;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;
|
||||
float maskCr = 0.7132 * (colorToReplace.r - maskY);
|
||||
float maskCb = 0.5647 * (colorToReplace.b - maskY);
|
||||
|
||||
float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;
|
||||
float Cr = 0.7132 * (textureColor.r - Y);
|
||||
float Cb = 0.5647 * (textureColor.b - Y);
|
||||
|
||||
// float blendValue = 1.0 - smoothstep(thresholdSensitivity - smoothing, thresholdSensitivity , abs(Cr - maskCr) + abs(Cb - maskCb));
|
||||
float blendValue = smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));
|
||||
gl_FragColor = vec4(textureColor.rgb, textureColor.a * blendValue);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageChromaKeyFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform float thresholdSensitivity;
|
||||
uniform float smoothing;
|
||||
uniform vec3 colorToReplace;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;
|
||||
float maskCr = 0.7132 * (colorToReplace.r - maskY);
|
||||
float maskCb = 0.5647 * (colorToReplace.b - maskY);
|
||||
|
||||
float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;
|
||||
float Cr = 0.7132 * (textureColor.r - Y);
|
||||
float Cb = 0.5647 * (textureColor.b - Y);
|
||||
|
||||
// float blendValue = 1.0 - smoothstep(thresholdSensitivity - smoothing, thresholdSensitivity , abs(Cr - maskCr) + abs(Cb - maskCb));
|
||||
float blendValue = smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));
|
||||
gl_FragColor = vec4(textureColor.rgb, textureColor.a * blendValue);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageChromaKeyFilter
|
||||
|
||||
@synthesize thresholdSensitivity = _thresholdSensitivity;
|
||||
@synthesize smoothing = _smoothing;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageChromaKeyFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
thresholdSensitivityUniform = [filterProgram uniformIndex:@"thresholdSensitivity"];
|
||||
smoothingUniform = [filterProgram uniformIndex:@"smoothing"];
|
||||
colorToReplaceUniform = [filterProgram uniformIndex:@"colorToReplace"];
|
||||
|
||||
self.thresholdSensitivity = 0.4;
|
||||
self.smoothing = 0.1;
|
||||
[self setColorToReplaceRed:0.0 green:1.0 blue:0.0];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 colorToReplace = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:colorToReplace forUniform:colorToReplaceUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setThresholdSensitivity:(CGFloat)newValue;
|
||||
{
|
||||
_thresholdSensitivity = newValue;
|
||||
|
||||
[self setFloat:(GLfloat)_thresholdSensitivity forUniform:thresholdSensitivityUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setSmoothing:(CGFloat)newValue;
|
||||
{
|
||||
_smoothing = newValue;
|
||||
|
||||
[self setFloat:(GLfloat)_smoothing forUniform:smoothingUniform program:filterProgram];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,57 +0,0 @@
|
||||
#import "GPUImageClosingFilter.h"
|
||||
#import "GPUImageErosionFilter.h"
|
||||
#import "GPUImageDilationFilter.h"
|
||||
|
||||
@implementation GPUImageClosingFilter
|
||||
|
||||
@synthesize verticalTexelSpacing = _verticalTexelSpacing;
|
||||
@synthesize horizontalTexelSpacing = _horizontalTexelSpacing;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithRadius:1]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithRadius:(NSUInteger)radius;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// First pass: dilation
|
||||
dilationFilter = [[GPUImageDilationFilter alloc] initWithRadius:radius];
|
||||
[self addFilter:dilationFilter];
|
||||
|
||||
// Second pass: erosion
|
||||
erosionFilter = [[GPUImageErosionFilter alloc] initWithRadius:radius];
|
||||
[self addFilter:erosionFilter];
|
||||
|
||||
[dilationFilter addTarget:erosionFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:dilationFilter, nil];
|
||||
self.terminalFilter = erosionFilter;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setVerticalTexelSpacing:(CGFloat)newValue;
|
||||
{
|
||||
_verticalTexelSpacing = newValue;
|
||||
erosionFilter.verticalTexelSpacing = newValue;
|
||||
dilationFilter.verticalTexelSpacing = newValue;
|
||||
}
|
||||
|
||||
- (void)setHorizontalTexelSpacing:(CGFloat)newValue;
|
||||
{
|
||||
_horizontalTexelSpacing = newValue;
|
||||
erosionFilter.horizontalTexelSpacing = newValue;
|
||||
dilationFilter.horizontalTexelSpacing = newValue;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,113 +0,0 @@
|
||||
#import "GPUImageColorBlendFilter.h"
|
||||
|
||||
/**
|
||||
* Color blend mode based upon pseudo code from the PDF specification.
|
||||
*/
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
highp float lum(lowp vec3 c) {
|
||||
return dot(c, vec3(0.3, 0.59, 0.11));
|
||||
}
|
||||
|
||||
lowp vec3 clipcolor(lowp vec3 c) {
|
||||
highp float l = lum(c);
|
||||
lowp float n = min(min(c.r, c.g), c.b);
|
||||
lowp float x = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (n < 0.0) {
|
||||
c.r = l + ((c.r - l) * l) / (l - n);
|
||||
c.g = l + ((c.g - l) * l) / (l - n);
|
||||
c.b = l + ((c.b - l) * l) / (l - n);
|
||||
}
|
||||
if (x > 1.0) {
|
||||
c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);
|
||||
c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);
|
||||
c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
lowp vec3 setlum(lowp vec3 c, highp float l) {
|
||||
highp float d = l - lum(c);
|
||||
c = c + vec3(d);
|
||||
return clipcolor(c);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, baseColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
float lum(vec3 c) {
|
||||
return dot(c, vec3(0.3, 0.59, 0.11));
|
||||
}
|
||||
|
||||
vec3 clipcolor(vec3 c) {
|
||||
float l = lum(c);
|
||||
float n = min(min(c.r, c.g), c.b);
|
||||
float x = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (n < 0.0) {
|
||||
c.r = l + ((c.r - l) * l) / (l - n);
|
||||
c.g = l + ((c.g - l) * l) / (l - n);
|
||||
c.b = l + ((c.b - l) * l) / (l - n);
|
||||
}
|
||||
if (x > 1.0) {
|
||||
c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);
|
||||
c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);
|
||||
c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3 setlum(vec3 c, float l) {
|
||||
float d = l - lum(c);
|
||||
c = c + vec3(d);
|
||||
return clipcolor(c);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, baseColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageColorBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageColorBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,52 +0,0 @@
|
||||
#import "GPUImageColorBurnBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorBurnBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
mediump vec4 whiteColor = vec4(1.0);
|
||||
gl_FragColor = whiteColor - (whiteColor - textureColor) / textureColor2;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorBurnBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
vec4 whiteColor = vec4(1.0);
|
||||
gl_FragColor = whiteColor - (whiteColor - textureColor) / textureColor2;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageColorBurnBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageColorBurnBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
#import "GPUImageFilter.h"
|
||||
|
||||
// Color Conversion Constants (YUV to RGB) including adjustment from 16-235/16-240 (video range)
|
||||
|
||||
// BT.601, which is the standard for SDTV.
|
||||
GLfloat kColorConversion601Default[] = {
|
||||
1.164, 1.164, 1.164,
|
||||
0.0, -0.392, 2.017,
|
||||
1.596, -0.813, 0.0,
|
||||
};
|
||||
|
||||
// BT.601 full range (ref: http://www.equasys.de/colorconversion.html)
|
||||
GLfloat kColorConversion601FullRangeDefault[] = {
|
||||
1.0, 1.0, 1.0,
|
||||
0.0, -0.343, 1.765,
|
||||
1.4, -0.711, 0.0,
|
||||
};
|
||||
|
||||
// BT.709, which is the standard for HDTV.
|
||||
GLfloat kColorConversion709Default[] = {
|
||||
1.164, 1.164, 1.164,
|
||||
0.0, -0.213, 2.112,
|
||||
1.793, -0.533, 0.0,
|
||||
};
|
||||
|
||||
|
||||
GLfloat *kColorConversion601 = kColorConversion601Default;
|
||||
GLfloat *kColorConversion601FullRange = kColorConversion601FullRangeDefault;
|
||||
GLfloat *kColorConversion709 = kColorConversion709Default;
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageYUVVideoRangeConversionForRGFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D luminanceTexture;
|
||||
uniform sampler2D chrominanceTexture;
|
||||
uniform mediump mat3 colorConversionMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 yuv;
|
||||
lowp vec3 rgb;
|
||||
|
||||
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
|
||||
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).rg - vec2(0.5, 0.5);
|
||||
rgb = colorConversionMatrix * yuv;
|
||||
|
||||
gl_FragColor = vec4(rgb, 1);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageYUVVideoRangeConversionForRGFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D luminanceTexture;
|
||||
uniform sampler2D chrominanceTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 yuv;
|
||||
vec3 rgb;
|
||||
|
||||
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
|
||||
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).rg - vec2(0.5, 0.5);
|
||||
|
||||
// BT.601, which is the standard for SDTV is provided as a reference
|
||||
/*
|
||||
rgb = mat3( 1, 1, 1,
|
||||
0, -.39465, 2.03211,
|
||||
1.13983, -.58060, 0) * yuv;
|
||||
*/
|
||||
|
||||
// Using BT.709 which is the standard for HDTV
|
||||
rgb = mat3( 1, 1, 1,
|
||||
0, -.21482, 2.12798,
|
||||
1.28033, -.38059, 0) * yuv;
|
||||
|
||||
gl_FragColor = vec4(rgb, 1);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
NSString *const kGPUImageYUVFullRangeConversionForLAFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D luminanceTexture;
|
||||
uniform sampler2D chrominanceTexture;
|
||||
uniform mediump mat3 colorConversionMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 yuv;
|
||||
lowp vec3 rgb;
|
||||
|
||||
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
|
||||
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).ra - vec2(0.5, 0.5);
|
||||
rgb = colorConversionMatrix * yuv;
|
||||
|
||||
gl_FragColor = vec4(rgb, 1);
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D luminanceTexture;
|
||||
uniform sampler2D chrominanceTexture;
|
||||
uniform mediump mat3 colorConversionMatrix;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 yuv;
|
||||
lowp vec3 rgb;
|
||||
|
||||
yuv.x = texture2D(luminanceTexture, textureCoordinate).r - (16.0/255.0);
|
||||
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).ra - vec2(0.5, 0.5);
|
||||
rgb = colorConversionMatrix * yuv;
|
||||
|
||||
gl_FragColor = vec4(rgb, 1);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageYUVVideoRangeConversionForLAFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D luminanceTexture;
|
||||
uniform sampler2D chrominanceTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 yuv;
|
||||
vec3 rgb;
|
||||
|
||||
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
|
||||
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).ra - vec2(0.5, 0.5);
|
||||
|
||||
// BT.601, which is the standard for SDTV is provided as a reference
|
||||
/*
|
||||
rgb = mat3( 1, 1, 1,
|
||||
0, -.39465, 2.03211,
|
||||
1.13983, -.58060, 0) * yuv;
|
||||
*/
|
||||
|
||||
// Using BT.709 which is the standard for HDTV
|
||||
rgb = mat3( 1, 1, 1,
|
||||
0, -.21482, 2.12798,
|
||||
1.28033, -.38059, 0) * yuv;
|
||||
|
||||
gl_FragColor = vec4(rgb, 1);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#import "GPUImageColorDodgeBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorDodgeBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
|
||||
precision mediump float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
vec3 baseOverlayAlphaProduct = vec3(overlay.a * base.a);
|
||||
vec3 rightHandProduct = overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a);
|
||||
|
||||
vec3 firstBlendColor = baseOverlayAlphaProduct + rightHandProduct;
|
||||
vec3 overlayRGB = clamp((overlay.rgb / clamp(overlay.a, 0.01, 1.0)) * step(0.0, overlay.a), 0.0, 0.99);
|
||||
|
||||
vec3 secondBlendColor = (base.rgb * overlay.a) / (1.0 - overlayRGB) + rightHandProduct;
|
||||
|
||||
vec3 colorChoice = step((overlay.rgb * base.a + base.rgb * overlay.a), baseOverlayAlphaProduct);
|
||||
|
||||
gl_FragColor = vec4(mix(firstBlendColor, secondBlendColor, colorChoice), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorDodgeBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
vec3 baseOverlayAlphaProduct = vec3(overlay.a * base.a);
|
||||
vec3 rightHandProduct = overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a);
|
||||
|
||||
vec3 firstBlendColor = baseOverlayAlphaProduct + rightHandProduct;
|
||||
vec3 overlayRGB = clamp((overlay.rgb / clamp(overlay.a, 0.01, 1.0)) * step(0.0, overlay.a), 0.0, 0.99);
|
||||
|
||||
vec3 secondBlendColor = (base.rgb * overlay.a) / (1.0 - overlayRGB) + rightHandProduct;
|
||||
|
||||
vec3 colorChoice = step((overlay.rgb * base.a + base.rgb * overlay.a), baseOverlayAlphaProduct);
|
||||
|
||||
gl_FragColor = vec4(mix(firstBlendColor, secondBlendColor, colorChoice), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageColorDodgeBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageColorDodgeBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#import "GPUImageColorInvertFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageInvertFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageInvertFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageColorInvertFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageInvertFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
#import "GPUImageColorLocalBinaryPatternFilter.h"
|
||||
|
||||
// This is based on "Accelerating image recognition on mobile devices using GPGPU" by Miguel Bordallo Lopez, Henri Nykanen, Jari Hannuksela, Olli Silven and Markku Vehvilainen
|
||||
// http://www.ee.oulu.fi/~jhannuks/publications/SPIE2011a.pdf
|
||||
|
||||
// Right pixel is the most significant bit, traveling clockwise to get to the upper right, which is the least significant
|
||||
// If the external pixel is greater than or equal to the center, set to 1, otherwise 0
|
||||
//
|
||||
// 2 1 0
|
||||
// 3 7
|
||||
// 4 5 6
|
||||
|
||||
// 01101101
|
||||
// 76543210
|
||||
|
||||
@implementation GPUImageColorLocalBinaryPatternFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorLocalBinaryPatternFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec3 centerColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
lowp vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
lowp vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
lowp vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
lowp vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
lowp vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
lowp vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
lowp vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
lowp vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
|
||||
lowp float redByteTally = 1.0 / 255.0 * step(centerColor.r, topRightColor.r);
|
||||
redByteTally += 2.0 / 255.0 * step(centerColor.r, topColor.r);
|
||||
redByteTally += 4.0 / 255.0 * step(centerColor.r, topLeftColor.r);
|
||||
redByteTally += 8.0 / 255.0 * step(centerColor.r, leftColor.r);
|
||||
redByteTally += 16.0 / 255.0 * step(centerColor.r, bottomLeftColor.r);
|
||||
redByteTally += 32.0 / 255.0 * step(centerColor.r, bottomColor.r);
|
||||
redByteTally += 64.0 / 255.0 * step(centerColor.r, bottomRightColor.r);
|
||||
redByteTally += 128.0 / 255.0 * step(centerColor.r, rightColor.r);
|
||||
|
||||
lowp float blueByteTally = 1.0 / 255.0 * step(centerColor.b, topRightColor.b);
|
||||
blueByteTally += 2.0 / 255.0 * step(centerColor.b, topColor.b);
|
||||
blueByteTally += 4.0 / 255.0 * step(centerColor.b, topLeftColor.b);
|
||||
blueByteTally += 8.0 / 255.0 * step(centerColor.b, leftColor.b);
|
||||
blueByteTally += 16.0 / 255.0 * step(centerColor.b, bottomLeftColor.b);
|
||||
blueByteTally += 32.0 / 255.0 * step(centerColor.b, bottomColor.b);
|
||||
blueByteTally += 64.0 / 255.0 * step(centerColor.b, bottomRightColor.b);
|
||||
blueByteTally += 128.0 / 255.0 * step(centerColor.b, rightColor.b);
|
||||
|
||||
lowp float greenByteTally = 1.0 / 255.0 * step(centerColor.g, topRightColor.g);
|
||||
greenByteTally += 2.0 / 255.0 * step(centerColor.g, topColor.g);
|
||||
greenByteTally += 4.0 / 255.0 * step(centerColor.g, topLeftColor.g);
|
||||
greenByteTally += 8.0 / 255.0 * step(centerColor.g, leftColor.g);
|
||||
greenByteTally += 16.0 / 255.0 * step(centerColor.g, bottomLeftColor.g);
|
||||
greenByteTally += 32.0 / 255.0 * step(centerColor.g, bottomColor.g);
|
||||
greenByteTally += 64.0 / 255.0 * step(centerColor.g, bottomRightColor.g);
|
||||
greenByteTally += 128.0 / 255.0 * step(centerColor.g, rightColor.g);
|
||||
|
||||
// TODO: Replace the above with a dot product and two vec4s
|
||||
// TODO: Apply step to a matrix, rather than individually
|
||||
|
||||
gl_FragColor = vec4(redByteTally, blueByteTally, greenByteTally, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorLocalBinaryPatternFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 centerColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
|
||||
float redByteTally = 1.0 / 255.0 * step(centerColor.r, topRightColor.r);
|
||||
redByteTally += 2.0 / 255.0 * step(centerColor.r, topColor.r);
|
||||
redByteTally += 4.0 / 255.0 * step(centerColor.r, topLeftColor.r);
|
||||
redByteTally += 8.0 / 255.0 * step(centerColor.r, leftColor.r);
|
||||
redByteTally += 16.0 / 255.0 * step(centerColor.r, bottomLeftColor.r);
|
||||
redByteTally += 32.0 / 255.0 * step(centerColor.r, bottomColor.r);
|
||||
redByteTally += 64.0 / 255.0 * step(centerColor.r, bottomRightColor.r);
|
||||
redByteTally += 128.0 / 255.0 * step(centerColor.r, rightColor.r);
|
||||
|
||||
float blueByteTally = 1.0 / 255.0 * step(centerColor.b, topRightColor.b);
|
||||
blueByteTally += 2.0 / 255.0 * step(centerColor.b, topColor.b);
|
||||
blueByteTally += 4.0 / 255.0 * step(centerColor.b, topLeftColor.b);
|
||||
blueByteTally += 8.0 / 255.0 * step(centerColor.b, leftColor.b);
|
||||
blueByteTally += 16.0 / 255.0 * step(centerColor.b, bottomLeftColor.b);
|
||||
blueByteTally += 32.0 / 255.0 * step(centerColor.b, bottomColor.b);
|
||||
blueByteTally += 64.0 / 255.0 * step(centerColor.b, bottomRightColor.b);
|
||||
blueByteTally += 128.0 / 255.0 * step(centerColor.b, rightColor.b);
|
||||
|
||||
float greenByteTally = 1.0 / 255.0 * step(centerColor.g, topRightColor.g);
|
||||
greenByteTally += 2.0 / 255.0 * step(centerColor.g, topColor.g);
|
||||
greenByteTally += 4.0 / 255.0 * step(centerColor.g, topLeftColor.g);
|
||||
greenByteTally += 8.0 / 255.0 * step(centerColor.g, leftColor.g);
|
||||
greenByteTally += 16.0 / 255.0 * step(centerColor.g, bottomLeftColor.g);
|
||||
greenByteTally += 32.0 / 255.0 * step(centerColor.g, bottomColor.g);
|
||||
greenByteTally += 64.0 / 255.0 * step(centerColor.g, bottomRightColor.g);
|
||||
greenByteTally += 128.0 / 255.0 * step(centerColor.g, rightColor.g);
|
||||
|
||||
// TODO: Replace the above with a dot product and two vec4s
|
||||
// TODO: Apply step to a matrix, rather than individually
|
||||
|
||||
gl_FragColor = vec4(redByteTally, blueByteTally, greenByteTally, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageColorLocalBinaryPatternFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,87 +0,0 @@
|
||||
#import "GPUImageColorMatrixFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorMatrixFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform lowp mat4 colorMatrix;
|
||||
uniform lowp float intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 outputColor = textureColor * colorMatrix;
|
||||
|
||||
gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorMatrixFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mat4 colorMatrix;
|
||||
uniform float intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 outputColor = textureColor * colorMatrix;
|
||||
|
||||
gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageColorMatrixFilter
|
||||
|
||||
@synthesize intensity = _intensity;
|
||||
@synthesize colorMatrix = _colorMatrix;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageColorMatrixFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
colorMatrixUniform = [filterProgram uniformIndex:@"colorMatrix"];
|
||||
intensityUniform = [filterProgram uniformIndex:@"intensity"];
|
||||
|
||||
self.intensity = 1.f;
|
||||
self.colorMatrix = (GPUMatrix4x4){
|
||||
{1.f, 0.f, 0.f, 0.f},
|
||||
{0.f, 1.f, 0.f, 0.f},
|
||||
{0.f, 0.f, 1.f, 0.f},
|
||||
{0.f, 0.f, 0.f, 1.f}
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setIntensity:(CGFloat)newIntensity;
|
||||
{
|
||||
_intensity = newIntensity;
|
||||
|
||||
[self setFloat:_intensity forUniform:intensityUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setColorMatrix:(GPUMatrix4x4)newColorMatrix;
|
||||
{
|
||||
_colorMatrix = newColorMatrix;
|
||||
|
||||
[self setMatrix4f:_colorMatrix forUniform:colorMatrixUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,139 +0,0 @@
|
||||
#import "GPUImageColorPackingFilter.h"
|
||||
|
||||
NSString *const kGPUImageColorPackingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidth;
|
||||
uniform float texelHeight;
|
||||
|
||||
varying vec2 upperLeftInputTextureCoordinate;
|
||||
varying vec2 upperRightInputTextureCoordinate;
|
||||
varying vec2 lowerLeftInputTextureCoordinate;
|
||||
varying vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
upperLeftInputTextureCoordinate = inputTextureCoordinate.xy + vec2(-texelWidth, -texelHeight);
|
||||
upperRightInputTextureCoordinate = inputTextureCoordinate.xy + vec2(texelWidth, -texelHeight);
|
||||
lowerLeftInputTextureCoordinate = inputTextureCoordinate.xy + vec2(-texelWidth, texelHeight);
|
||||
lowerRightInputTextureCoordinate = inputTextureCoordinate.xy + vec2(texelWidth, texelHeight);
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColorPackingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mediump mat3 convolutionMatrix;
|
||||
|
||||
varying highp vec2 outputTextureCoordinate;
|
||||
|
||||
varying highp vec2 upperLeftInputTextureCoordinate;
|
||||
varying highp vec2 upperRightInputTextureCoordinate;
|
||||
varying highp vec2 lowerLeftInputTextureCoordinate;
|
||||
varying highp vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
float upperLeftIntensity = texture2D(inputImageTexture, upperLeftInputTextureCoordinate).r;
|
||||
float upperRightIntensity = texture2D(inputImageTexture, upperRightInputTextureCoordinate).r;
|
||||
float lowerLeftIntensity = texture2D(inputImageTexture, lowerLeftInputTextureCoordinate).r;
|
||||
float lowerRightIntensity = texture2D(inputImageTexture, lowerRightInputTextureCoordinate).r;
|
||||
|
||||
gl_FragColor = vec4(upperLeftIntensity, upperRightIntensity, lowerLeftIntensity, lowerRightIntensity);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColorPackingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mat3 convolutionMatrix;
|
||||
|
||||
varying vec2 outputTextureCoordinate;
|
||||
|
||||
varying vec2 upperLeftInputTextureCoordinate;
|
||||
varying vec2 upperRightInputTextureCoordinate;
|
||||
varying vec2 lowerLeftInputTextureCoordinate;
|
||||
varying vec2 lowerRightInputTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
float upperLeftIntensity = texture2D(inputImageTexture, upperLeftInputTextureCoordinate).r;
|
||||
float upperRightIntensity = texture2D(inputImageTexture, upperRightInputTextureCoordinate).r;
|
||||
float lowerLeftIntensity = texture2D(inputImageTexture, lowerLeftInputTextureCoordinate).r;
|
||||
float lowerRightIntensity = texture2D(inputImageTexture, lowerRightInputTextureCoordinate).r;
|
||||
|
||||
gl_FragColor = vec4(upperLeftIntensity, upperRightIntensity, lowerLeftIntensity, lowerRightIntensity);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageColorPackingFilter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageColorPackingVertexShaderString fragmentShaderFromString:kGPUImageColorPackingFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
texelWidthUniform = [filterProgram uniformIndex:@"texelWidth"];
|
||||
texelHeightUniform = [filterProgram uniformIndex:@"texelHeight"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
texelWidth = 0.5 / inputTextureSize.width;
|
||||
texelHeight = 0.5 / inputTextureSize.height;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
glUniform1f(texelWidthUniform, texelWidth);
|
||||
glUniform1f(texelHeightUniform, texelHeight);
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Managing the display FBOs
|
||||
|
||||
- (CGSize)sizeOfFBO;
|
||||
{
|
||||
CGSize outputSize = [self maximumOutputSize];
|
||||
if ( (CGSizeEqualToSize(outputSize, CGSizeZero)) || (inputTextureSize.width < outputSize.width) )
|
||||
{
|
||||
CGSize quarterSize;
|
||||
quarterSize.width = inputTextureSize.width / 2.0;
|
||||
quarterSize.height = inputTextureSize.height / 2.0;
|
||||
return quarterSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return outputSize;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (CGSize)outputFrameSize;
|
||||
{
|
||||
CGSize quarterSize;
|
||||
quarterSize.width = inputTextureSize.width / 2.0;
|
||||
quarterSize.height = inputTextureSize.height / 2.0;
|
||||
return quarterSize;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,48 +0,0 @@
|
||||
#import "GPUImageColourFASTFeatureDetector.h"
|
||||
#import "GPUImageColourFASTSamplingOperation.h"
|
||||
#import "GPUImageBoxBlurFilter.h"
|
||||
|
||||
@implementation GPUImageColourFASTFeatureDetector
|
||||
|
||||
@synthesize blurRadiusInPixels;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// First pass: apply a variable Gaussian blur
|
||||
blurFilter = [[GPUImageBoxBlurFilter alloc] init];
|
||||
[self addFilter:blurFilter];
|
||||
|
||||
// Second pass: combine the blurred image with the original sharp one
|
||||
colourFASTSamplingOperation = [[GPUImageColourFASTSamplingOperation alloc] init];
|
||||
[self addFilter:colourFASTSamplingOperation];
|
||||
|
||||
// Texture location 0 needs to be the sharp image for both the blur and the second stage processing
|
||||
[blurFilter addTarget:colourFASTSamplingOperation atTextureLocation:1];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:blurFilter, colourFASTSamplingOperation, nil];
|
||||
self.terminalFilter = colourFASTSamplingOperation;
|
||||
|
||||
self.blurRadiusInPixels = 3.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
blurFilter.blurRadiusInPixels = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurRadiusInPixels;
|
||||
{
|
||||
return blurFilter.blurRadiusInPixels;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,204 +0,0 @@
|
||||
#import "GPUImageColourFASTSamplingOperation.h"
|
||||
|
||||
NSString *const kGPUImageColourFASTSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
attribute vec4 inputTextureCoordinate2;
|
||||
|
||||
uniform float texelWidth;
|
||||
uniform float texelHeight;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 pointATextureCoordinate;
|
||||
varying vec2 pointBTextureCoordinate;
|
||||
varying vec2 pointCTextureCoordinate;
|
||||
varying vec2 pointDTextureCoordinate;
|
||||
varying vec2 pointETextureCoordinate;
|
||||
varying vec2 pointFTextureCoordinate;
|
||||
varying vec2 pointGTextureCoordinate;
|
||||
varying vec2 pointHTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
float tripleTexelWidth = 3.0 * texelWidth;
|
||||
float tripleTexelHeight = 3.0 * texelHeight;
|
||||
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
|
||||
pointATextureCoordinate = vec2(textureCoordinate.x + tripleTexelWidth, textureCoordinate.y + texelHeight);
|
||||
pointBTextureCoordinate = vec2(textureCoordinate.x + texelWidth, textureCoordinate.y + tripleTexelHeight);
|
||||
pointCTextureCoordinate = vec2(textureCoordinate.x - texelWidth, textureCoordinate.y + tripleTexelHeight);
|
||||
pointDTextureCoordinate = vec2(textureCoordinate.x - tripleTexelWidth, textureCoordinate.y + texelHeight);
|
||||
pointETextureCoordinate = vec2(textureCoordinate.x - tripleTexelWidth, textureCoordinate.y - texelHeight);
|
||||
pointFTextureCoordinate = vec2(textureCoordinate.x - texelWidth, textureCoordinate.y - tripleTexelHeight);
|
||||
pointGTextureCoordinate = vec2(textureCoordinate.x + texelWidth, textureCoordinate.y - tripleTexelHeight);
|
||||
pointHTextureCoordinate = vec2(textureCoordinate.x + tripleTexelWidth, textureCoordinate.y - texelHeight);
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageColourFASTSamplingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 pointATextureCoordinate;
|
||||
varying vec2 pointBTextureCoordinate;
|
||||
varying vec2 pointCTextureCoordinate;
|
||||
varying vec2 pointDTextureCoordinate;
|
||||
varying vec2 pointETextureCoordinate;
|
||||
varying vec2 pointFTextureCoordinate;
|
||||
varying vec2 pointGTextureCoordinate;
|
||||
varying vec2 pointHTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
const float PITwo = 6.2832;
|
||||
const float PI = 3.1416;
|
||||
void main()
|
||||
{
|
||||
vec3 centerColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
|
||||
vec3 pointAColor = texture2D(inputImageTexture, pointATextureCoordinate).rgb;
|
||||
vec3 pointBColor = texture2D(inputImageTexture, pointBTextureCoordinate).rgb;
|
||||
vec3 pointCColor = texture2D(inputImageTexture, pointCTextureCoordinate).rgb;
|
||||
vec3 pointDColor = texture2D(inputImageTexture, pointDTextureCoordinate).rgb;
|
||||
vec3 pointEColor = texture2D(inputImageTexture, pointETextureCoordinate).rgb;
|
||||
vec3 pointFColor = texture2D(inputImageTexture, pointFTextureCoordinate).rgb;
|
||||
vec3 pointGColor = texture2D(inputImageTexture, pointGTextureCoordinate).rgb;
|
||||
vec3 pointHColor = texture2D(inputImageTexture, pointHTextureCoordinate).rgb;
|
||||
|
||||
vec3 colorComparison = ((pointAColor + pointBColor + pointCColor + pointDColor + pointEColor + pointFColor + pointGColor + pointHColor) * 0.125) - centerColor;
|
||||
|
||||
// Direction calculation drawn from Appendix B of Seth Hall's Ph.D. thesis
|
||||
|
||||
vec3 dirX = (pointAColor*0.94868) + (pointBColor*0.316227) - (pointCColor*0.316227) - (pointDColor*0.94868) - (pointEColor*0.94868) - (pointFColor*0.316227) + (pointGColor*0.316227) + (pointHColor*0.94868);
|
||||
vec3 dirY = (pointAColor*0.316227) + (pointBColor*0.94868) + (pointCColor*0.94868) + (pointDColor*0.316227) - (pointEColor*0.316227) - (pointFColor*0.94868) - (pointGColor*0.94868) - (pointHColor*0.316227);
|
||||
vec3 absoluteDifference = abs(colorComparison);
|
||||
float componentLength = length(colorComparison);
|
||||
float avgX = dot(absoluteDifference, dirX) / componentLength;
|
||||
float avgY = dot(absoluteDifference, dirY) / componentLength;
|
||||
float angle = atan(avgY, avgX);
|
||||
|
||||
vec3 normalizedColorComparison = (colorComparison + 1.0) * 0.5;
|
||||
|
||||
gl_FragColor = vec4(normalizedColorComparison, (angle+PI)/PITwo);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageColourFASTSamplingFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 pointATextureCoordinate;
|
||||
varying vec2 pointBTextureCoordinate;
|
||||
varying vec2 pointCTextureCoordinate;
|
||||
varying vec2 pointDTextureCoordinate;
|
||||
varying vec2 pointETextureCoordinate;
|
||||
varying vec2 pointFTextureCoordinate;
|
||||
varying vec2 pointGTextureCoordinate;
|
||||
varying vec2 pointHTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
const float PITwo = 6.2832;
|
||||
const float PI = 3.1416;
|
||||
void main()
|
||||
{
|
||||
vec3 centerColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
|
||||
vec3 pointAColor = texture2D(inputImageTexture, pointATextureCoordinate).rgb;
|
||||
vec3 pointBColor = texture2D(inputImageTexture, pointBTextureCoordinate).rgb;
|
||||
vec3 pointCColor = texture2D(inputImageTexture, pointCTextureCoordinate).rgb;
|
||||
vec3 pointDColor = texture2D(inputImageTexture, pointDTextureCoordinate).rgb;
|
||||
vec3 pointEColor = texture2D(inputImageTexture, pointETextureCoordinate).rgb;
|
||||
vec3 pointFColor = texture2D(inputImageTexture, pointFTextureCoordinate).rgb;
|
||||
vec3 pointGColor = texture2D(inputImageTexture, pointGTextureCoordinate).rgb;
|
||||
vec3 pointHColor = texture2D(inputImageTexture, pointHTextureCoordinate).rgb;
|
||||
|
||||
vec3 colorComparison = ((pointAColor + pointBColor + pointCColor + pointDColor + pointEColor + pointFColor + pointGColor + pointHColor) * 0.125) - centerColor;
|
||||
|
||||
// Direction calculation drawn from Appendix B of Seth Hall's Ph.D. thesis
|
||||
|
||||
vec3 dirX = (pointAColor*0.94868) + (pointBColor*0.316227) - (pointCColor*0.316227) - (pointDColor*0.94868) - (pointEColor*0.94868) - (pointFColor*0.316227) + (pointGColor*0.316227) + (pointHColor*0.94868);
|
||||
vec3 dirY = (pointAColor*0.316227) + (pointBColor*0.94868) + (pointCColor*0.94868) + (pointDColor*0.316227) - (pointEColor*0.316227) - (pointFColor*0.94868) - (pointGColor*0.94868) - (pointHColor*0.316227);
|
||||
vec3 absoluteDifference = abs(colorComparison);
|
||||
float componentLength = length(colorComparison);
|
||||
float avgX = dot(absoluteDifference, dirX) / componentLength;
|
||||
float avgY = dot(absoluteDifference, dirY) / componentLength;
|
||||
float angle = atan(avgY, avgX);
|
||||
|
||||
vec3 normalizedColorComparison = (colorComparison + 1.0) * 0.5;
|
||||
|
||||
gl_FragColor = vec4(normalizedColorComparison, (angle+PI)/PITwo);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageColourFASTSamplingOperation
|
||||
|
||||
@synthesize texelWidth = _texelWidth;
|
||||
@synthesize texelHeight = _texelHeight;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageColourFASTSamplingVertexShaderString fragmentShaderFromString:kGPUImageColourFASTSamplingFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
texelWidthUniform = [filterProgram uniformIndex:@"texelWidth"];
|
||||
texelHeightUniform = [filterProgram uniformIndex:@"texelHeight"];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
if (!hasOverriddenImageSizeFactor)
|
||||
{
|
||||
_texelWidth = 1.0 / filterFrameSize.width;
|
||||
_texelHeight = 1.0 / filterFrameSize.height;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
glUniform1f(texelWidthUniform, _texelHeight);
|
||||
glUniform1f(texelHeightUniform, _texelWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
glUniform1f(texelWidthUniform, _texelWidth);
|
||||
glUniform1f(texelHeightUniform, _texelHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setTexelWidth:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelWidth = newValue;
|
||||
|
||||
[self setFloat:_texelWidth forUniform:texelWidthUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setTexelHeight:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelHeight = newValue;
|
||||
|
||||
[self setFloat:_texelHeight forUniform:texelHeightUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,66 +0,0 @@
|
||||
#import "GPUImageContrastFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageContrastFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp float contrast;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageContrastFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float contrast;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageContrastFilter
|
||||
|
||||
@synthesize contrast = _contrast;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageContrastFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
contrastUniform = [filterProgram uniformIndex:@"contrast"];
|
||||
self.contrast = 1.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setContrast:(CGFloat)newValue;
|
||||
{
|
||||
_contrast = newValue;
|
||||
|
||||
[self setFloat:_contrast forUniform:contrastUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-274
@@ -1,274 +0,0 @@
|
||||
#import "GPUImageCropFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageCropFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageCropFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@interface GPUImageCropFilter ()
|
||||
|
||||
- (void)calculateCropTextureCoordinates;
|
||||
|
||||
@end
|
||||
|
||||
@interface GPUImageCropFilter()
|
||||
{
|
||||
CGSize originallySuppliedInputSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageCropFilter
|
||||
|
||||
@synthesize cropRegion = _cropRegion;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithCropRegion:(CGRect)newCropRegion;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageCropFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.cropRegion = newCropRegion;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithCropRegion:CGRectMake(0.0, 0.0, 1.0, 1.0)]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if (overrideInputSize)
|
||||
// {
|
||||
// if (CGSizeEqualToSize(forcedMaximumSize, CGSizeZero))
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(newSize, CGRectMake(0.0, 0.0, forcedMaximumSize.width, forcedMaximumSize.height));
|
||||
// inputTextureSize = insetRect.size;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
CGSize rotatedSize = [self rotatedSize:newSize forIndex:textureIndex];
|
||||
originallySuppliedInputSize = rotatedSize;
|
||||
|
||||
CGSize scaledSize;
|
||||
scaledSize.width = rotatedSize.width * _cropRegion.size.width;
|
||||
scaledSize.height = rotatedSize.height * _cropRegion.size.height;
|
||||
|
||||
|
||||
if (CGSizeEqualToSize(scaledSize, CGSizeZero))
|
||||
{
|
||||
inputTextureSize = scaledSize;
|
||||
}
|
||||
else if (!CGSizeEqualToSize(inputTextureSize, scaledSize))
|
||||
{
|
||||
inputTextureSize = scaledSize;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput
|
||||
|
||||
- (void)calculateCropTextureCoordinates;
|
||||
{
|
||||
CGFloat minX = _cropRegion.origin.x;
|
||||
CGFloat minY = _cropRegion.origin.y;
|
||||
CGFloat maxX = CGRectGetMaxX(_cropRegion);
|
||||
CGFloat maxY = CGRectGetMaxY(_cropRegion);
|
||||
|
||||
switch(inputRotation)
|
||||
{
|
||||
case kGPUImageNoRotation: // Works
|
||||
{
|
||||
cropTextureCoordinates[0] = minX; // 0,0
|
||||
cropTextureCoordinates[1] = minY;
|
||||
|
||||
cropTextureCoordinates[2] = maxX; // 1,0
|
||||
cropTextureCoordinates[3] = minY;
|
||||
|
||||
cropTextureCoordinates[4] = minX; // 0,1
|
||||
cropTextureCoordinates[5] = maxY;
|
||||
|
||||
cropTextureCoordinates[6] = maxX; // 1,1
|
||||
cropTextureCoordinates[7] = maxY;
|
||||
}; break;
|
||||
case kGPUImageRotateLeft: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxY; // 1,0
|
||||
cropTextureCoordinates[1] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[2] = maxY; // 1,1
|
||||
cropTextureCoordinates[3] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[4] = minY; // 0,0
|
||||
cropTextureCoordinates[5] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[6] = minY; // 0,1
|
||||
cropTextureCoordinates[7] = 1.0 - minX;
|
||||
}; break;
|
||||
case kGPUImageRotateRight: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = minY; // 0,1
|
||||
cropTextureCoordinates[1] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[2] = minY; // 0,0
|
||||
cropTextureCoordinates[3] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[4] = maxY; // 1,1
|
||||
cropTextureCoordinates[5] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[6] = maxY; // 1,0
|
||||
cropTextureCoordinates[7] = 1.0 - maxX;
|
||||
}; break;
|
||||
case kGPUImageFlipVertical: // Works for me
|
||||
{
|
||||
cropTextureCoordinates[0] = minX; // 0,1
|
||||
cropTextureCoordinates[1] = maxY;
|
||||
|
||||
cropTextureCoordinates[2] = maxX; // 1,1
|
||||
cropTextureCoordinates[3] = maxY;
|
||||
|
||||
cropTextureCoordinates[4] = minX; // 0,0
|
||||
cropTextureCoordinates[5] = minY;
|
||||
|
||||
cropTextureCoordinates[6] = maxX; // 1,0
|
||||
cropTextureCoordinates[7] = minY;
|
||||
}; break;
|
||||
case kGPUImageFlipHorizonal: // Works for me
|
||||
{
|
||||
cropTextureCoordinates[0] = maxX; // 1,0
|
||||
cropTextureCoordinates[1] = minY;
|
||||
|
||||
cropTextureCoordinates[2] = minX; // 0,0
|
||||
cropTextureCoordinates[3] = minY;
|
||||
|
||||
cropTextureCoordinates[4] = maxX; // 1,1
|
||||
cropTextureCoordinates[5] = maxY;
|
||||
|
||||
cropTextureCoordinates[6] = minX; // 0,1
|
||||
cropTextureCoordinates[7] = maxY;
|
||||
}; break;
|
||||
case kGPUImageRotate180: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxX; // 1,1
|
||||
cropTextureCoordinates[1] = maxY;
|
||||
|
||||
cropTextureCoordinates[2] = minX; // 0,1
|
||||
cropTextureCoordinates[3] = maxY;
|
||||
|
||||
cropTextureCoordinates[4] = maxX; // 1,0
|
||||
cropTextureCoordinates[5] = minY;
|
||||
|
||||
cropTextureCoordinates[6] = minX; // 0,0
|
||||
cropTextureCoordinates[7] = minY;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipVertical: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = minY; // 0,0
|
||||
cropTextureCoordinates[1] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[2] = minY; // 0,1
|
||||
cropTextureCoordinates[3] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[4] = maxY; // 1,0
|
||||
cropTextureCoordinates[5] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[6] = maxY; // 1,1
|
||||
cropTextureCoordinates[7] = 1.0 - minX;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipHorizontal: // Fixed
|
||||
{
|
||||
cropTextureCoordinates[0] = maxY; // 1,1
|
||||
cropTextureCoordinates[1] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[2] = maxY; // 1,0
|
||||
cropTextureCoordinates[3] = 1.0 - maxX;
|
||||
|
||||
cropTextureCoordinates[4] = minY; // 0,1
|
||||
cropTextureCoordinates[5] = 1.0 - minX;
|
||||
|
||||
cropTextureCoordinates[6] = minY; // 0,0
|
||||
cropTextureCoordinates[7] = 1.0 - maxX;
|
||||
}; break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
static const GLfloat cropSquareVertices[] = {
|
||||
-1.0f, -1.0f,
|
||||
1.0f, -1.0f,
|
||||
-1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
[self renderToTextureWithVertices:cropSquareVertices textureCoordinates:cropTextureCoordinates];
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setCropRegion:(CGRect)newValue;
|
||||
{
|
||||
NSParameterAssert(newValue.origin.x >= 0 && newValue.origin.x <= 1 &&
|
||||
newValue.origin.y >= 0 && newValue.origin.y <= 1 &&
|
||||
newValue.size.width >= 0 && newValue.size.width <= 1 &&
|
||||
newValue.size.height >= 0 && newValue.size.height <= 1);
|
||||
|
||||
_cropRegion = newValue;
|
||||
[self calculateCropTextureCoordinates];
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
[super setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[self calculateCropTextureCoordinates];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,139 +0,0 @@
|
||||
#import "GPUImageCrosshairGenerator.h"
|
||||
|
||||
NSString *const kGPUImageCrosshairVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
uniform float crosshairWidth;
|
||||
|
||||
varying vec2 centerLocation;
|
||||
varying float pointSpacing;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(((position.xy * 2.0) - 1.0), 0.0, 1.0);
|
||||
gl_PointSize = crosshairWidth + 1.0;
|
||||
pointSpacing = 1.0 / crosshairWidth;
|
||||
centerLocation = vec2(pointSpacing * ceil(crosshairWidth / 2.0), pointSpacing * ceil(crosshairWidth / 2.0));
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageCrosshairFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform lowp vec3 crosshairColor;
|
||||
|
||||
varying highp vec2 centerLocation;
|
||||
varying highp float pointSpacing;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec2 distanceFromCenter = abs(centerLocation - gl_PointCoord.xy);
|
||||
lowp float axisTest = step(pointSpacing, gl_PointCoord.y) * step(distanceFromCenter.x, 0.09) + step(pointSpacing, gl_PointCoord.x) * step(distanceFromCenter.y, 0.09);
|
||||
|
||||
gl_FragColor = vec4(crosshairColor * axisTest, axisTest);
|
||||
// gl_FragColor = vec4(distanceFromCenterInX, distanceFromCenterInY, 0.0, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageCrosshairFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
GPUImageEscapedHashIdentifier(version 120)\n
|
||||
|
||||
uniform vec3 crosshairColor;
|
||||
|
||||
varying vec2 centerLocation;
|
||||
varying float pointSpacing;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 distanceFromCenter = abs(centerLocation - gl_PointCoord.xy);
|
||||
float axisTest = step(pointSpacing, gl_PointCoord.y) * step(distanceFromCenter.x, 0.09) + step(pointSpacing, gl_PointCoord.x) * step(distanceFromCenter.y, 0.09);
|
||||
|
||||
gl_FragColor = vec4(crosshairColor * axisTest, axisTest);
|
||||
// gl_FragColor = vec4(distanceFromCenterInX, distanceFromCenterInY, 0.0, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageCrosshairGenerator
|
||||
|
||||
@synthesize crosshairWidth = _crosshairWidth;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageCrosshairVertexShaderString fragmentShaderFromString:kGPUImageCrosshairFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
crosshairWidthUniform = [filterProgram uniformIndex:@"crosshairWidth"];
|
||||
crosshairColorUniform = [filterProgram uniformIndex:@"crosshairColor"];
|
||||
|
||||
self.crosshairWidth = 5.0;
|
||||
[self setCrosshairColorRed:0.0 green:1.0 blue:0.0];
|
||||
});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)renderCrosshairsFromArray:(GLfloat *)crosshairCoordinates count:(NSUInteger)numberOfCrosshairs frameTime:(CMTime)frameTime;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#else
|
||||
glEnable(GL_POINT_SPRITE);
|
||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
#endif
|
||||
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, crosshairCoordinates);
|
||||
|
||||
glDrawArrays(GL_POINTS, 0, (GLsizei)numberOfCrosshairs);
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
// Prevent rendering of the frame by normal means
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setCrosshairWidth:(CGFloat)newValue;
|
||||
{
|
||||
_crosshairWidth = newValue;
|
||||
|
||||
[self setFloat:_crosshairWidth forUniform:crosshairWidthUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setCrosshairColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 crosshairColor = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:crosshairColor forUniform:crosshairColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,163 +0,0 @@
|
||||
#import "GPUImageCrosshatchFilter.h"
|
||||
|
||||
// Shader code based on http://machinesdontcare.wordpress.com/
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageCrosshatchFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp float crossHatchSpacing;
|
||||
uniform highp float lineWidth;
|
||||
|
||||
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
highp float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W);
|
||||
|
||||
lowp vec4 colorToDisplay = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
if (luminance < 1.00)
|
||||
{
|
||||
if (mod(textureCoordinate.x + textureCoordinate.y, crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.75)
|
||||
{
|
||||
if (mod(textureCoordinate.x - textureCoordinate.y, crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.50)
|
||||
{
|
||||
if (mod(textureCoordinate.x + textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.3)
|
||||
{
|
||||
if (mod(textureCoordinate.x - textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = colorToDisplay;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageCrosshatchFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform float crossHatchSpacing;
|
||||
uniform float lineWidth;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W);
|
||||
|
||||
vec4 colorToDisplay = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
if (luminance < 1.00)
|
||||
{
|
||||
if (mod(textureCoordinate.x + textureCoordinate.y, crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.75)
|
||||
{
|
||||
if (mod(textureCoordinate.x - textureCoordinate.y, crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.50)
|
||||
{
|
||||
if (mod(textureCoordinate.x + textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
if (luminance < 0.3)
|
||||
{
|
||||
if (mod(textureCoordinate.x - textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)
|
||||
{
|
||||
colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = colorToDisplay;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageCrosshatchFilter
|
||||
|
||||
@synthesize crossHatchSpacing = _crossHatchSpacing;
|
||||
@synthesize lineWidth = _lineWidth;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageCrosshatchFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
crossHatchSpacingUniform = [filterProgram uniformIndex:@"crossHatchSpacing"];
|
||||
lineWidthUniform = [filterProgram uniformIndex:@"lineWidth"];
|
||||
|
||||
self.crossHatchSpacing = 0.03;
|
||||
self.lineWidth = 0.003;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setCrossHatchSpacing:(CGFloat)newValue;
|
||||
{
|
||||
CGFloat singlePixelSpacing;
|
||||
if (inputTextureSize.width != 0.0)
|
||||
{
|
||||
singlePixelSpacing = 1.0 / inputTextureSize.width;
|
||||
}
|
||||
else
|
||||
{
|
||||
singlePixelSpacing = 1.0 / 2048.0;
|
||||
}
|
||||
|
||||
if (newValue < singlePixelSpacing)
|
||||
{
|
||||
_crossHatchSpacing = singlePixelSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
_crossHatchSpacing = newValue;
|
||||
}
|
||||
|
||||
[self setFloat:_crossHatchSpacing forUniform:crossHatchSpacingUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setLineWidth:(CGFloat)newValue;
|
||||
{
|
||||
_lineWidth = newValue;
|
||||
|
||||
[self setFloat:_lineWidth forUniform:lineWidthUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,52 +0,0 @@
|
||||
#import "GPUImageDarkenBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDarkenBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(min(overlayer.rgb * base.a, base.rgb * overlayer.a) + overlayer.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlayer.a), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDarkenBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(min(overlayer.rgb * base.a, base.rgb * overlayer.a) + overlayer.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlayer.a), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageDarkenBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDarkenBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#import "GPUImageDifferenceBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDifferenceBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
gl_FragColor = vec4(abs(textureColor2.rgb - textureColor.rgb), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDifferenceBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
gl_FragColor = vec4(abs(textureColor2.rgb - textureColor.rgb), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageDifferenceBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDifferenceBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-431
@@ -1,431 +0,0 @@
|
||||
#import "GPUImageDilationFilter.h"
|
||||
|
||||
@implementation GPUImageDilationFilter
|
||||
|
||||
NSString *const kGPUImageDilationRadiusOneVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec2 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 offset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
centerTextureCoordinate = inputTextureCoordinate;
|
||||
oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;
|
||||
oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusTwoVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec2 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 offset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
centerTextureCoordinate = inputTextureCoordinate;
|
||||
oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;
|
||||
oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;
|
||||
twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);
|
||||
twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusThreeVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec2 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 offset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
centerTextureCoordinate = inputTextureCoordinate;
|
||||
oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;
|
||||
oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;
|
||||
twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);
|
||||
twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);
|
||||
threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);
|
||||
threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusFourVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec2 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
varying vec2 fourStepsPositiveTextureCoordinate;
|
||||
varying vec2 fourStepsNegativeTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 offset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
centerTextureCoordinate = inputTextureCoordinate;
|
||||
oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;
|
||||
oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;
|
||||
twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);
|
||||
twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);
|
||||
threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);
|
||||
threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);
|
||||
fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);
|
||||
fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDilationRadiusOneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusTwoFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusThreeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, threeStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, threeStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusFourFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
varying vec2 fourStepsPositiveTextureCoordinate;
|
||||
varying vec2 fourStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;
|
||||
float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, threeStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, threeStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, fourStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, fourStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDilationRadiusOneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
|
||||
float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusTwoFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusThreeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, threeStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, threeStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageDilationRadiusFourFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
varying vec2 fourStepsPositiveTextureCoordinate;
|
||||
varying vec2 fourStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;
|
||||
float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float maxValue = max(centerIntensity, oneStepPositiveIntensity);
|
||||
maxValue = max(maxValue, oneStepNegativeIntensity);
|
||||
maxValue = max(maxValue, twoStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, twoStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, threeStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, threeStepsNegativeIntensity);
|
||||
maxValue = max(maxValue, fourStepsPositiveIntensity);
|
||||
maxValue = max(maxValue, fourStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(maxValue), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithRadius:(NSUInteger)dilationRadius;
|
||||
{
|
||||
NSString *fragmentShaderForThisRadius = nil;
|
||||
NSString *vertexShaderForThisRadius = nil;
|
||||
|
||||
switch (dilationRadius)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusOneVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageDilationRadiusOneFragmentShaderString;
|
||||
}; break;
|
||||
case 2:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusTwoVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageDilationRadiusTwoFragmentShaderString;
|
||||
}; break;
|
||||
case 3:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusThreeVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageDilationRadiusThreeFragmentShaderString;
|
||||
}; break;
|
||||
case 4:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusFourVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageDilationRadiusFourFragmentShaderString;
|
||||
}; break;
|
||||
default:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusFourVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageDilationRadiusFourFragmentShaderString;
|
||||
}; break;
|
||||
}
|
||||
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:vertexShaderForThisRadius firstStageFragmentShaderFromString:fragmentShaderForThisRadius secondStageVertexShaderFromString:vertexShaderForThisRadius secondStageFragmentShaderFromString:fragmentShaderForThisRadius]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithRadius:1]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,141 +0,0 @@
|
||||
#import "GPUImageDirectionalNonMaximumSuppressionFilter.h"
|
||||
|
||||
@implementation GPUImageDirectionalNonMaximumSuppressionFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDirectionalNonmaximumSuppressionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision mediump float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform highp float texelWidth;
|
||||
uniform highp float texelHeight;
|
||||
uniform mediump float upperThreshold;
|
||||
uniform mediump float lowerThreshold;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 currentGradientAndDirection = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
vec2 gradientDirection = ((currentGradientAndDirection.gb * 2.0) - 1.0) * vec2(texelWidth, texelHeight);
|
||||
|
||||
float firstSampledGradientMagnitude = texture2D(inputImageTexture, textureCoordinate + gradientDirection).r;
|
||||
float secondSampledGradientMagnitude = texture2D(inputImageTexture, textureCoordinate - gradientDirection).r;
|
||||
|
||||
float multiplier = step(firstSampledGradientMagnitude, currentGradientAndDirection.r);
|
||||
multiplier = multiplier * step(secondSampledGradientMagnitude, currentGradientAndDirection.r);
|
||||
|
||||
float thresholdCompliance = smoothstep(lowerThreshold, upperThreshold, currentGradientAndDirection.r);
|
||||
multiplier = multiplier * thresholdCompliance;
|
||||
|
||||
gl_FragColor = vec4(multiplier, multiplier, multiplier, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDirectionalNonmaximumSuppressionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float texelWidth;
|
||||
uniform float texelHeight;
|
||||
uniform float upperThreshold;
|
||||
uniform float lowerThreshold;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 currentGradientAndDirection = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
vec2 gradientDirection = ((currentGradientAndDirection.gb * 2.0) - 1.0) * vec2(texelWidth, texelHeight);
|
||||
|
||||
float firstSampledGradientMagnitude = texture2D(inputImageTexture, textureCoordinate + gradientDirection).r;
|
||||
float secondSampledGradientMagnitude = texture2D(inputImageTexture, textureCoordinate - gradientDirection).r;
|
||||
|
||||
float multiplier = step(firstSampledGradientMagnitude, currentGradientAndDirection.r);
|
||||
multiplier = multiplier * step(secondSampledGradientMagnitude, currentGradientAndDirection.r);
|
||||
|
||||
float thresholdCompliance = smoothstep(lowerThreshold, upperThreshold, currentGradientAndDirection.r);
|
||||
multiplier = multiplier * thresholdCompliance;
|
||||
|
||||
gl_FragColor = vec4(multiplier, multiplier, multiplier, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@synthesize texelWidth = _texelWidth;
|
||||
@synthesize texelHeight = _texelHeight;
|
||||
@synthesize upperThreshold = _upperThreshold;
|
||||
@synthesize lowerThreshold = _lowerThreshold;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDirectionalNonmaximumSuppressionFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
texelWidthUniform = [filterProgram uniformIndex:@"texelWidth"];
|
||||
texelHeightUniform = [filterProgram uniformIndex:@"texelHeight"];
|
||||
upperThresholdUniform = [filterProgram uniformIndex:@"upperThreshold"];
|
||||
lowerThresholdUniform = [filterProgram uniformIndex:@"lowerThreshold"];
|
||||
|
||||
self.upperThreshold = 0.5;
|
||||
self.lowerThreshold = 0.1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
if (!hasOverriddenImageSizeFactor)
|
||||
{
|
||||
_texelWidth = 1.0 / filterFrameSize.width;
|
||||
_texelHeight = 1.0 / filterFrameSize.height;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
glUniform1f(texelWidthUniform, _texelWidth);
|
||||
glUniform1f(texelHeightUniform, _texelHeight);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setTexelWidth:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelWidth = newValue;
|
||||
|
||||
[self setFloat:_texelWidth forUniform:texelWidthUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setTexelHeight:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenImageSizeFactor = YES;
|
||||
_texelHeight = newValue;
|
||||
|
||||
[self setFloat:_texelHeight forUniform:texelHeightUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setLowerThreshold:(CGFloat)newValue;
|
||||
{
|
||||
_lowerThreshold = newValue;
|
||||
|
||||
[self setFloat:_lowerThreshold forUniform:lowerThresholdUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setUpperThreshold:(CGFloat)newValue;
|
||||
{
|
||||
_upperThreshold = newValue;
|
||||
|
||||
[self setFloat:_upperThreshold forUniform:upperThresholdUniform program:filterProgram];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,103 +0,0 @@
|
||||
#import "GPUImageDirectionalSobelEdgeDetectionFilter.h"
|
||||
|
||||
@implementation GPUImageDirectionalSobelEdgeDetectionFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDirectionalSobelEdgeDetectionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
|
||||
float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;
|
||||
float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
|
||||
float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
|
||||
float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
|
||||
float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
|
||||
float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
|
||||
float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
|
||||
|
||||
vec2 gradientDirection;
|
||||
gradientDirection.x = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;
|
||||
gradientDirection.y = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;
|
||||
|
||||
float gradientMagnitude = length(gradientDirection);
|
||||
vec2 normalizedDirection = normalize(gradientDirection);
|
||||
normalizedDirection = sign(normalizedDirection) * floor(abs(normalizedDirection) + 0.617316); // Offset by 1-sin(pi/8) to set to 0 if near axis, 1 if away
|
||||
normalizedDirection = (normalizedDirection + 1.0) * 0.5; // Place -1.0 - 1.0 within 0 - 1.0
|
||||
|
||||
gl_FragColor = vec4(gradientMagnitude, normalizedDirection.x, normalizedDirection.y, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDirectionalSobelEdgeDetectionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
|
||||
float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;
|
||||
float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
|
||||
float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
|
||||
float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
|
||||
float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
|
||||
float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
|
||||
float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
|
||||
|
||||
vec2 gradientDirection;
|
||||
gradientDirection.x = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;
|
||||
gradientDirection.y = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;
|
||||
|
||||
float gradientMagnitude = length(gradientDirection);
|
||||
vec2 normalizedDirection = normalize(gradientDirection);
|
||||
normalizedDirection = sign(normalizedDirection) * floor(abs(normalizedDirection) + 0.617316); // Offset by 1-sin(pi/8) to set to 0 if near axis, 1 if away
|
||||
normalizedDirection = (normalizedDirection + 1.0) * 0.5; // Place -1.0 - 1.0 within 0 - 1.0
|
||||
|
||||
gl_FragColor = vec4(gradientMagnitude, normalizedDirection.x, normalizedDirection.y, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDirectionalSobelEdgeDetectionFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,72 +0,0 @@
|
||||
#import "GPUImageDissolveBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDissolveBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
uniform lowp float mixturePercent;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = mix(textureColor, textureColor2, mixturePercent);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDissolveBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
uniform float mixturePercent;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = mix(textureColor, textureColor2, mixturePercent);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageDissolveBlendFilter
|
||||
|
||||
@synthesize mix = _mix;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDissolveBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
mixUniform = [filterProgram uniformIndex:@"mixturePercent"];
|
||||
self.mix = 0.5;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setMix:(CGFloat)newValue;
|
||||
{
|
||||
_mix = newValue;
|
||||
|
||||
[self setFloat:_mix forUniform:mixUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#import "GPUImageDivideBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageDivideBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
mediump float ra;
|
||||
if (overlay.a == 0.0 || ((base.r / overlay.r) > (base.a / overlay.a)))
|
||||
ra = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
else
|
||||
ra = (base.r * overlay.a * overlay.a) / overlay.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
|
||||
|
||||
mediump float ga;
|
||||
if (overlay.a == 0.0 || ((base.g / overlay.g) > (base.a / overlay.a)))
|
||||
ga = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
else
|
||||
ga = (base.g * overlay.a * overlay.a) / overlay.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
|
||||
|
||||
mediump float ba;
|
||||
if (overlay.a == 0.0 || ((base.b / overlay.b) > (base.a / overlay.a)))
|
||||
ba = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
else
|
||||
ba = (base.b * overlay.a * overlay.a) / overlay.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
|
||||
mediump float a = overlay.a + base.a - overlay.a * base.a;
|
||||
|
||||
gl_FragColor = vec4(ra, ga, ba, a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageDivideBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
float ra;
|
||||
if (overlay.a == 0.0 || ((base.r / overlay.r) > (base.a / overlay.a)))
|
||||
ra = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
else
|
||||
ra = (base.r * overlay.a * overlay.a) / overlay.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
|
||||
|
||||
float ga;
|
||||
if (overlay.a == 0.0 || ((base.g / overlay.g) > (base.a / overlay.a)))
|
||||
ga = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
else
|
||||
ga = (base.g * overlay.a * overlay.a) / overlay.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
|
||||
|
||||
float ba;
|
||||
if (overlay.a == 0.0 || ((base.b / overlay.b) > (base.a / overlay.a)))
|
||||
ba = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
else
|
||||
ba = (base.b * overlay.a * overlay.a) / overlay.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
|
||||
float a = overlay.a + base.a - overlay.a * base.a;
|
||||
|
||||
gl_FragColor = vec4(ra, ga, ba, a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageDivideBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageDivideBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#import "GPUImageEmbossFilter.h"
|
||||
|
||||
@implementation GPUImageEmbossFilter
|
||||
|
||||
@synthesize intensity = _intensity;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.intensity = 1.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setIntensity:(CGFloat)newValue;
|
||||
{
|
||||
// [(GPUImage3x3ConvolutionFilter *)filter setConvolutionMatrix:(GPUMatrix3x3){
|
||||
// {-2.0f, -1.0f, 0.0f},
|
||||
// {-1.0f, 1.0f, 1.0f},
|
||||
// { 0.0f, 1.0f, 2.0f}
|
||||
// }];
|
||||
|
||||
_intensity = newValue;
|
||||
|
||||
GPUMatrix3x3 newConvolutionMatrix;
|
||||
newConvolutionMatrix.one.one = _intensity * (-2.0);
|
||||
newConvolutionMatrix.one.two = -_intensity;
|
||||
newConvolutionMatrix.one.three = 0.0f;
|
||||
|
||||
newConvolutionMatrix.two.one = -_intensity;
|
||||
newConvolutionMatrix.two.two = 1.0;
|
||||
newConvolutionMatrix.two.three = _intensity;
|
||||
|
||||
newConvolutionMatrix.three.one = 0.0f;
|
||||
newConvolutionMatrix.three.two = _intensity;
|
||||
newConvolutionMatrix.three.three = _intensity * 2.0;
|
||||
|
||||
self.convolutionKernel = newConvolutionMatrix;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
-312
@@ -1,312 +0,0 @@
|
||||
#import "GPUImageErosionFilter.h"
|
||||
#import "GPUImageDilationFilter.h"
|
||||
|
||||
@implementation GPUImageErosionFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageErosionRadiusOneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusTwoFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusThreeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
minValue = min(minValue, threeStepsPositiveIntensity);
|
||||
minValue = min(minValue, threeStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusFourFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
varying vec2 fourStepsPositiveTextureCoordinate;
|
||||
varying vec2 fourStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;
|
||||
float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;
|
||||
|
||||
lowp float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
minValue = min(minValue, threeStepsPositiveIntensity);
|
||||
minValue = min(minValue, threeStepsNegativeIntensity);
|
||||
minValue = min(minValue, fourStepsPositiveIntensity);
|
||||
minValue = min(minValue, fourStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageErosionRadiusOneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
|
||||
float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusTwoFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusThreeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
minValue = min(minValue, threeStepsPositiveIntensity);
|
||||
minValue = min(minValue, threeStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageErosionRadiusFourFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepPositiveTextureCoordinate;
|
||||
varying vec2 oneStepNegativeTextureCoordinate;
|
||||
varying vec2 twoStepsPositiveTextureCoordinate;
|
||||
varying vec2 twoStepsNegativeTextureCoordinate;
|
||||
varying vec2 threeStepsPositiveTextureCoordinate;
|
||||
varying vec2 threeStepsNegativeTextureCoordinate;
|
||||
varying vec2 fourStepsPositiveTextureCoordinate;
|
||||
varying vec2 fourStepsNegativeTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;
|
||||
float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;
|
||||
float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;
|
||||
float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;
|
||||
float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;
|
||||
float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;
|
||||
float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;
|
||||
float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;
|
||||
float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;
|
||||
|
||||
float minValue = min(centerIntensity, oneStepPositiveIntensity);
|
||||
minValue = min(minValue, oneStepNegativeIntensity);
|
||||
minValue = min(minValue, twoStepsPositiveIntensity);
|
||||
minValue = min(minValue, twoStepsNegativeIntensity);
|
||||
minValue = min(minValue, threeStepsPositiveIntensity);
|
||||
minValue = min(minValue, threeStepsNegativeIntensity);
|
||||
minValue = min(minValue, fourStepsPositiveIntensity);
|
||||
minValue = min(minValue, fourStepsNegativeIntensity);
|
||||
|
||||
gl_FragColor = vec4(vec3(minValue), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithRadius:(NSUInteger)dilationRadius;
|
||||
{
|
||||
NSString *fragmentShaderForThisRadius = nil;
|
||||
NSString *vertexShaderForThisRadius = nil;
|
||||
|
||||
switch (dilationRadius)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusOneVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageErosionRadiusOneFragmentShaderString;
|
||||
}; break;
|
||||
case 2:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusTwoVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageErosionRadiusTwoFragmentShaderString;
|
||||
}; break;
|
||||
case 3:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusThreeVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageErosionRadiusThreeFragmentShaderString;
|
||||
}; break;
|
||||
case 4:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusFourVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageErosionRadiusFourFragmentShaderString;
|
||||
}; break;
|
||||
default:
|
||||
{
|
||||
vertexShaderForThisRadius = kGPUImageDilationRadiusFourVertexShaderString;
|
||||
fragmentShaderForThisRadius = kGPUImageErosionRadiusFourFragmentShaderString;
|
||||
}; break;
|
||||
}
|
||||
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:vertexShaderForThisRadius firstStageFragmentShaderFromString:fragmentShaderForThisRadius secondStageVertexShaderFromString:vertexShaderForThisRadius secondStageFragmentShaderFromString:fragmentShaderForThisRadius]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithRadius:1]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,56 +0,0 @@
|
||||
#import "GPUImageExclusionBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageExclusionBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
// Dca = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
|
||||
|
||||
gl_FragColor = vec4((overlay.rgb * base.a + base.rgb * overlay.a - 2.0 * overlay.rgb * base.rgb) + overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a), base.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageExclusionBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
// Dca = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
|
||||
|
||||
gl_FragColor = vec4((overlay.rgb * base.a + base.rgb * overlay.a - 2.0 * overlay.rgb * base.rgb) + overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a), base.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageExclusionBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageExclusionBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#import "GPUImageExposureFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageExposureFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform highp float exposure;
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageExposureFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float exposure;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageExposureFilter
|
||||
|
||||
@synthesize exposure = _exposure;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageExposureFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
exposureUniform = [filterProgram uniformIndex:@"exposure"];
|
||||
self.exposure = 0.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setExposure:(CGFloat)newValue;
|
||||
{
|
||||
_exposure = newValue;
|
||||
|
||||
[self setFloat:_exposure forUniform:exposureUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
#import "GPUImageFASTCornerDetectionFilter.h"
|
||||
|
||||
#import "GPUImageGrayscaleFilter.h"
|
||||
#import "GPUImage3x3TextureSamplingFilter.h"
|
||||
#import "GPUImageNonMaximumSuppressionFilter.h"
|
||||
|
||||
// 14 total texture coordinates from vertex shader for non-dependent reads
|
||||
// 3 texture coordinates for dependent reads, then
|
||||
|
||||
NSString *const kGPUImageFASTDetectorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D lookupTable;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp float centerIntensity = texture2D(inputImageTexture, textureCoordinate).r;
|
||||
lowp float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
|
||||
lowp float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;
|
||||
lowp float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
|
||||
lowp float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
|
||||
lowp float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
|
||||
lowp float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
|
||||
lowp float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
|
||||
lowp float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
|
||||
|
||||
lowp float byteTally = 1.0 / 255.0 * step(centerIntensity, topRightIntensity);
|
||||
byteTally += 2.0 / 255.0 * step(centerIntensity, topIntensity);
|
||||
byteTally += 4.0 / 255.0 * step(centerIntensity, topLeftIntensity);
|
||||
byteTally += 8.0 / 255.0 * step(centerIntensity, leftIntensity);
|
||||
byteTally += 16.0 / 255.0 * step(centerIntensity, bottomLeftIntensity);
|
||||
byteTally += 32.0 / 255.0 * step(centerIntensity, bottomIntensity);
|
||||
byteTally += 64.0 / 255.0 * step(centerIntensity, bottomRightIntensity);
|
||||
byteTally += 128.0 / 255.0 * step(centerIntensity, rightIntensity);
|
||||
|
||||
// TODO: Replace the above with a dot product and two vec4s
|
||||
// TODO: Apply step to a matrix, rather than individually
|
||||
|
||||
gl_FragColor = vec4(byteTally, byteTally, byteTally, 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@implementation GPUImageFASTCornerDetectionFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithFASTDetectorVariant:kGPUImageFAST12ContiguousNonMaximumSuppressed]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFASTDetectorVariant:(GPUImageFASTDetectorType)detectorType;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// [derivativeFilter addTarget:blurFilter];
|
||||
// [blurFilter addTarget:harrisCornerDetectionFilter];
|
||||
// [harrisCornerDetectionFilter addTarget:nonMaximumSuppressionFilter];
|
||||
// [simpleThresholdFilter addTarget:colorPackingFilter];
|
||||
|
||||
// self.initialFilters = [NSArray arrayWithObjects:derivativeFilter, nil];
|
||||
// self.terminalFilter = colorPackingFilter;
|
||||
// self.terminalFilter = nonMaximumSuppressionFilter;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,101 +0,0 @@
|
||||
#import "GPUImageFalseColorFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUFalseColorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float intensity;
|
||||
uniform vec3 firstColor;
|
||||
uniform vec3 secondColor;
|
||||
|
||||
const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, luminanceWeighting);
|
||||
|
||||
gl_FragColor = vec4( mix(firstColor.rgb, secondColor.rgb, luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUFalseColorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float intensity;
|
||||
uniform vec3 firstColor;
|
||||
uniform vec3 secondColor;
|
||||
|
||||
const vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, luminanceWeighting);
|
||||
|
||||
gl_FragColor = vec4( mix(firstColor.rgb, secondColor.rgb, luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageFalseColorFilter
|
||||
|
||||
@synthesize secondColor = _secondColor;
|
||||
@synthesize firstColor = _firstColor;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUFalseColorFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
firstColorUniform = [filterProgram uniformIndex:@"firstColor"];
|
||||
secondColorUniform = [filterProgram uniformIndex:@"secondColor"];
|
||||
|
||||
self.firstColor = (GPUVector4){0.0f, 0.0f, 0.5f, 1.0f};
|
||||
self.secondColor = (GPUVector4){1.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setFirstColor:(GPUVector4)newValue;
|
||||
{
|
||||
_firstColor = newValue;
|
||||
|
||||
[self setFirstColorRed:_firstColor.one green:_firstColor.two blue:_firstColor.three];
|
||||
}
|
||||
|
||||
- (void)setSecondColor:(GPUVector4)newValue;
|
||||
{
|
||||
_secondColor = newValue;
|
||||
|
||||
[self setSecondColorRed:_secondColor.one green:_secondColor.two blue:_secondColor.three];
|
||||
}
|
||||
|
||||
- (void)setFirstColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 firstColor = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:firstColor forUniform:firstColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setSecondColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 secondColor = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:secondColor forUniform:secondColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
-753
@@ -1,753 +0,0 @@
|
||||
#import "GPUImageFilter.h"
|
||||
#import "GPUImagePicture.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
// Hardcode the vertex shader for standard filters, but this can be overridden
|
||||
NSString *const kGPUImageVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
|
||||
NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
);
|
||||
|
||||
#else
|
||||
|
||||
NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageFilter
|
||||
|
||||
@synthesize preventRendering = _preventRendering;
|
||||
@synthesize currentlyReceivingMonochromeInput;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
uniformStateRestorationBlocks = [NSMutableDictionary dictionaryWithCapacity:10];
|
||||
_preventRendering = NO;
|
||||
currentlyReceivingMonochromeInput = NO;
|
||||
inputRotation = kGPUImageNoRotation;
|
||||
backgroundColorRed = 0.0;
|
||||
backgroundColorGreen = 0.0;
|
||||
backgroundColorBlue = 0.0;
|
||||
backgroundColorAlpha = 0.0;
|
||||
imageCaptureSemaphore = dispatch_semaphore_create(0);
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
filterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString];
|
||||
|
||||
if (!filterProgram.initialized)
|
||||
{
|
||||
[self initializeAttributes];
|
||||
|
||||
if (![filterProgram link])
|
||||
{
|
||||
NSString *progLog = [filterProgram programLog];
|
||||
NSLog(@"Program link log: %@", progLog);
|
||||
NSString *fragLog = [filterProgram fragmentShaderLog];
|
||||
NSLog(@"Fragment shader compile log: %@", fragLog);
|
||||
NSString *vertLog = [filterProgram vertexShaderLog];
|
||||
NSLog(@"Vertex shader compile log: %@", vertLog);
|
||||
filterProgram = nil;
|
||||
NSAssert(NO, @"Filter shader link failed");
|
||||
}
|
||||
}
|
||||
|
||||
filterPositionAttribute = [filterProgram attributeIndex:@"position"];
|
||||
filterTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate"];
|
||||
filterInputTextureUniform = [filterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
glEnableVertexAttribArray(filterPositionAttribute);
|
||||
glEnableVertexAttribArray(filterTextureCoordinateAttribute);
|
||||
});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [self initWithVertexShaderFromString:kGPUImageVertexShaderString fragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFragmentShaderFromFile:(NSString *)fragmentShaderFilename;
|
||||
{
|
||||
NSString *fragmentShaderPathname = [[NSBundle mainBundle] pathForResource:fragmentShaderFilename ofType:@"fsh"];
|
||||
NSString *fragmentShaderString = [NSString stringWithContentsOfFile:fragmentShaderPathname encoding:NSUTF8StringEncoding error:nil];
|
||||
|
||||
if (!(self = [self initWithFragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithFragmentShaderFromString:kGPUImagePassthroughFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initializeAttributes;
|
||||
{
|
||||
[filterProgram addAttribute:@"position"];
|
||||
[filterProgram addAttribute:@"inputTextureCoordinate"];
|
||||
|
||||
// Override this, calling back to this super method, in order to add new attributes to your vertex shader
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
// This is where you can override to provide some custom setup, if your filter has a size-dependent element
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if !OS_OBJECT_USE_OBJC
|
||||
if (imageCaptureSemaphore != NULL)
|
||||
{
|
||||
dispatch_release(imageCaptureSemaphore);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Still image processing
|
||||
|
||||
- (void)useNextFrameForImageCapture;
|
||||
{
|
||||
usingNextFrameForImageCapture = YES;
|
||||
|
||||
// Set the semaphore high, if it isn't already
|
||||
if (dispatch_semaphore_wait(imageCaptureSemaphore, DISPATCH_TIME_NOW) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput
|
||||
{
|
||||
// Give it three seconds to process, then abort if they forgot to set up the image capture properly
|
||||
double timeoutForImageCapture = 3.0;
|
||||
dispatch_time_t convertedTimeout = dispatch_time(DISPATCH_TIME_NOW, timeoutForImageCapture * NSEC_PER_SEC);
|
||||
|
||||
if (dispatch_semaphore_wait(imageCaptureSemaphore, convertedTimeout) != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GPUImageFramebuffer* framebuffer = [self framebufferForOutput];
|
||||
|
||||
usingNextFrameForImageCapture = NO;
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
|
||||
CGImageRef image = [framebuffer newCGImageFromFramebufferContents];
|
||||
return image;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Managing the display FBOs
|
||||
|
||||
- (CGSize)sizeOfFBO;
|
||||
{
|
||||
CGSize outputSize = [self maximumOutputSize];
|
||||
if ( (CGSizeEqualToSize(outputSize, CGSizeZero)) || (inputTextureSize.width < outputSize.width) )
|
||||
{
|
||||
return inputTextureSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return outputSize;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
|
||||
{
|
||||
static const GLfloat noRotationTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateLeftTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat verticalFlipTextureCoordinates[] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat horizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightVerticalFlipTextureCoordinates[] = {
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotateRightHorizontalFlipTextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
static const GLfloat rotate180TextureCoordinates[] = {
|
||||
1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
};
|
||||
|
||||
switch(rotationMode)
|
||||
{
|
||||
case kGPUImageNoRotation: return noRotationTextureCoordinates;
|
||||
case kGPUImageRotateLeft: return rotateLeftTextureCoordinates;
|
||||
case kGPUImageRotateRight: return rotateRightTextureCoordinates;
|
||||
case kGPUImageFlipVertical: return verticalFlipTextureCoordinates;
|
||||
case kGPUImageFlipHorizonal: return horizontalFlipTextureCoordinates;
|
||||
case kGPUImageRotateRightFlipVertical: return rotateRightVerticalFlipTextureCoordinates;
|
||||
case kGPUImageRotateRightFlipHorizontal: return rotateRightHorizontalFlipTextureCoordinates;
|
||||
case kGPUImageRotate180: return rotate180TextureCoordinates;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
[firstInputFramebuffer unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
[outputFramebuffer lock];
|
||||
}
|
||||
|
||||
[self setUniformsForProgramAtIndex:0];
|
||||
|
||||
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
|
||||
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
[firstInputFramebuffer unlock];
|
||||
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
|
||||
{
|
||||
if (self.frameProcessingCompletionBlock != NULL)
|
||||
{
|
||||
self.frameProcessingCompletionBlock(self, frameTime);
|
||||
}
|
||||
|
||||
// Get all targets the framebuffer so they can grab a lock on it
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
if (currentTarget != self.targetToIgnoreForUpdates)
|
||||
{
|
||||
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
|
||||
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
|
||||
[self setInputFramebufferForTarget:currentTarget atIndex:textureIndex];
|
||||
[currentTarget setInputSize:[self outputFrameSize] atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Release our hold so it can return to the cache immediately upon processing
|
||||
[[self framebufferForOutput] unlock];
|
||||
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
// usingNextFrameForImageCapture = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self removeOutputFramebuffer];
|
||||
}
|
||||
|
||||
// Trigger processing last, so that our unlock comes first in serial execution, avoiding the need for a callback
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
if (currentTarget != self.targetToIgnoreForUpdates)
|
||||
{
|
||||
NSInteger indexOfObject = [targets indexOfObject:currentTarget];
|
||||
NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
[currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)outputFrameSize;
|
||||
{
|
||||
return inputTextureSize;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Input parameters
|
||||
|
||||
- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
{
|
||||
backgroundColorRed = redComponent;
|
||||
backgroundColorGreen = greenComponent;
|
||||
backgroundColorBlue = blueComponent;
|
||||
backgroundColorAlpha = alphaComponent;
|
||||
}
|
||||
|
||||
- (void)setInteger:(GLint)newInteger forUniformName:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setInteger:newInteger forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setFloat:(GLfloat)newFloat forUniformName:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setFloat:newFloat forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setSize:(CGSize)newSize forUniformName:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setSize:newSize forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setPoint:(CGPoint)newPoint forUniformName:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setPoint:newPoint forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setFloatVec3:(GPUVector3)newVec3 forUniformName:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setVec3:newVec3 forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setFloatVec4:(GPUVector4)newVec4 forUniform:(NSString *)uniformName;
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
[self setVec4:newVec4 forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setFloatArray:(GLfloat *)array length:(GLsizei)count forUniform:(NSString*)uniformName
|
||||
{
|
||||
GLint uniformIndex = [filterProgram uniformIndex:uniformName];
|
||||
|
||||
[self setFloatArray:array length:count forUniform:uniformIndex program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setMatrix3f:(GPUMatrix3x3)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniformMatrix3fv(uniform, 1, GL_FALSE, (GLfloat *)&matrix);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setMatrix4f:(GPUMatrix4x4)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniformMatrix4fv(uniform, 1, GL_FALSE, (GLfloat *)&matrix);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setFloat:(GLfloat)floatValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniform1f(uniform, floatValue);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setPoint:(CGPoint)pointValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
GLfloat positionArray[2];
|
||||
positionArray[0] = pointValue.x;
|
||||
positionArray[1] = pointValue.y;
|
||||
|
||||
glUniform2fv(uniform, 1, positionArray);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setSize:(CGSize)sizeValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
GLfloat sizeArray[2];
|
||||
sizeArray[0] = sizeValue.width;
|
||||
sizeArray[1] = sizeValue.height;
|
||||
|
||||
glUniform2fv(uniform, 1, sizeArray);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setVec3:(GPUVector3)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniform3fv(uniform, 1, (GLfloat *)&vectorValue);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setVec4:(GPUVector4)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniform4fv(uniform, 1, (GLfloat *)&vectorValue);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setFloatArray:(GLfloat *)arrayValue length:(GLsizei)arrayLength forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
// Make a copy of the data, so it doesn't get overwritten before async call executes
|
||||
NSData* arrayData = [NSData dataWithBytes:arrayValue length:arrayLength * sizeof(arrayValue[0])];
|
||||
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniform1fv(uniform, arrayLength, [arrayData bytes]);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setInteger:(GLint)intValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:shaderProgram];
|
||||
|
||||
[self setAndExecuteUniformStateCallbackAtIndex:uniform forProgram:shaderProgram toBlock:^{
|
||||
glUniform1i(uniform, intValue);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)setAndExecuteUniformStateCallbackAtIndex:(GLint)uniform forProgram:(GLProgram *)shaderProgram toBlock:(dispatch_block_t)uniformStateBlock;
|
||||
{
|
||||
[uniformStateRestorationBlocks setObject:[uniformStateBlock copy] forKey:[NSNumber numberWithInt:uniform]];
|
||||
uniformStateBlock();
|
||||
}
|
||||
|
||||
- (void)setUniformsForProgramAtIndex:(NSUInteger)programIndex;
|
||||
{
|
||||
[uniformStateRestorationBlocks enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
|
||||
dispatch_block_t currentBlock = obj;
|
||||
currentBlock();
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
static const GLfloat imageVertices[] = {
|
||||
-1.0f, -1.0f,
|
||||
1.0f, -1.0f,
|
||||
-1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]];
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
}
|
||||
|
||||
- (NSInteger)nextAvailableTextureIndex;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
firstInputFramebuffer = newInputFramebuffer;
|
||||
[firstInputFramebuffer lock];
|
||||
}
|
||||
|
||||
- (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
CGSize rotatedSize = sizeToRotate;
|
||||
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
rotatedSize.width = sizeToRotate.height;
|
||||
rotatedSize.height = sizeToRotate.width;
|
||||
}
|
||||
|
||||
return rotatedSize;
|
||||
}
|
||||
|
||||
- (CGPoint)rotatedPoint:(CGPoint)pointToRotate forRotation:(GPUImageRotationMode)rotation;
|
||||
{
|
||||
CGPoint rotatedPoint;
|
||||
switch(rotation)
|
||||
{
|
||||
case kGPUImageNoRotation: return pointToRotate; break;
|
||||
case kGPUImageFlipHorizonal:
|
||||
{
|
||||
rotatedPoint.x = 1.0 - pointToRotate.x;
|
||||
rotatedPoint.y = pointToRotate.y;
|
||||
}; break;
|
||||
case kGPUImageFlipVertical:
|
||||
{
|
||||
rotatedPoint.x = pointToRotate.x;
|
||||
rotatedPoint.y = 1.0 - pointToRotate.y;
|
||||
}; break;
|
||||
case kGPUImageRotateLeft:
|
||||
{
|
||||
rotatedPoint.x = 1.0 - pointToRotate.y;
|
||||
rotatedPoint.y = pointToRotate.x;
|
||||
}; break;
|
||||
case kGPUImageRotateRight:
|
||||
{
|
||||
rotatedPoint.x = pointToRotate.y;
|
||||
rotatedPoint.y = 1.0 - pointToRotate.x;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipVertical:
|
||||
{
|
||||
rotatedPoint.x = pointToRotate.y;
|
||||
rotatedPoint.y = pointToRotate.x;
|
||||
}; break;
|
||||
case kGPUImageRotateRightFlipHorizontal:
|
||||
{
|
||||
rotatedPoint.x = 1.0 - pointToRotate.y;
|
||||
rotatedPoint.y = 1.0 - pointToRotate.x;
|
||||
}; break;
|
||||
case kGPUImageRotate180:
|
||||
{
|
||||
rotatedPoint.x = 1.0 - pointToRotate.x;
|
||||
rotatedPoint.y = 1.0 - pointToRotate.y;
|
||||
}; break;
|
||||
}
|
||||
|
||||
return rotatedPoint;
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (overrideInputSize)
|
||||
{
|
||||
if (CGSizeEqualToSize(forcedMaximumSize, CGSizeZero))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(newSize, CGRectMake(0.0, 0.0, forcedMaximumSize.width, forcedMaximumSize.height));
|
||||
inputTextureSize = insetRect.size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CGSize rotatedSize = [self rotatedSize:newSize forIndex:textureIndex];
|
||||
|
||||
if (CGSizeEqualToSize(rotatedSize, CGSizeZero))
|
||||
{
|
||||
inputTextureSize = rotatedSize;
|
||||
}
|
||||
else if (!CGSizeEqualToSize(inputTextureSize, rotatedSize))
|
||||
{
|
||||
inputTextureSize = rotatedSize;
|
||||
}
|
||||
}
|
||||
|
||||
[self setupFilterForSize:[self sizeOfFBO]];
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
inputRotation = newInputRotation;
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSize:(CGSize)frameSize;
|
||||
{
|
||||
if (CGSizeEqualToSize(frameSize, CGSizeZero))
|
||||
{
|
||||
overrideInputSize = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
overrideInputSize = YES;
|
||||
inputTextureSize = frameSize;
|
||||
forcedMaximumSize = CGSizeZero;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSizeRespectingAspectRatio:(CGSize)frameSize;
|
||||
{
|
||||
if (CGSizeEqualToSize(frameSize, CGSizeZero))
|
||||
{
|
||||
overrideInputSize = NO;
|
||||
inputTextureSize = CGSizeZero;
|
||||
forcedMaximumSize = CGSizeZero;
|
||||
}
|
||||
else
|
||||
{
|
||||
overrideInputSize = YES;
|
||||
forcedMaximumSize = frameSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)maximumOutputSize;
|
||||
{
|
||||
// I'm temporarily disabling adjustments for smaller output sizes until I figure out how to make this work better
|
||||
return CGSizeZero;
|
||||
|
||||
/*
|
||||
if (CGSizeEqualToSize(cachedMaximumOutputSize, CGSizeZero))
|
||||
{
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
if ([currentTarget maximumOutputSize].width > cachedMaximumOutputSize.width)
|
||||
{
|
||||
cachedMaximumOutputSize = [currentTarget maximumOutputSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cachedMaximumOutputSize;
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)endProcessing
|
||||
{
|
||||
if (!isEndProcessing)
|
||||
{
|
||||
isEndProcessing = YES;
|
||||
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
[currentTarget endProcessing];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)wantsMonochromeInput;
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
@end
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
#import "GPUImageFilterGroup.h"
|
||||
#import "GPUImagePicture.h"
|
||||
|
||||
@implementation GPUImageFilterGroup
|
||||
|
||||
@synthesize terminalFilter = _terminalFilter;
|
||||
@synthesize initialFilters = _initialFilters;
|
||||
@synthesize inputFilterToIgnoreForUpdates = _inputFilterToIgnoreForUpdates;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
filters = [[NSMutableArray alloc] init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Filter management
|
||||
|
||||
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)newFilter;
|
||||
{
|
||||
[filters addObject:newFilter];
|
||||
}
|
||||
|
||||
- (GPUImageOutput<GPUImageInput> *)filterAtIndex:(NSUInteger)filterIndex;
|
||||
{
|
||||
return [filters objectAtIndex:filterIndex];
|
||||
}
|
||||
|
||||
- (NSUInteger)filterCount;
|
||||
{
|
||||
return [filters count];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Still image processing
|
||||
|
||||
- (void)useNextFrameForImageCapture;
|
||||
{
|
||||
[self.terminalFilter useNextFrameForImageCapture];
|
||||
}
|
||||
|
||||
- (CGImageRef)newCGImageFromCurrentlyProcessedOutput;
|
||||
{
|
||||
return [self.terminalFilter newCGImageFromCurrentlyProcessedOutput];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageOutput overrides
|
||||
|
||||
- (void)setTargetToIgnoreForUpdates:(id<GPUImageInput>)targetToIgnoreForUpdates;
|
||||
{
|
||||
[_terminalFilter setTargetToIgnoreForUpdates:targetToIgnoreForUpdates];
|
||||
}
|
||||
|
||||
- (void)addTarget:(id<GPUImageInput>)newTarget atTextureLocation:(NSInteger)textureLocation;
|
||||
{
|
||||
[_terminalFilter addTarget:newTarget atTextureLocation:textureLocation];
|
||||
}
|
||||
|
||||
- (void)removeTarget:(id<GPUImageInput>)targetToRemove;
|
||||
{
|
||||
[_terminalFilter removeTarget:targetToRemove];
|
||||
}
|
||||
|
||||
- (void)removeAllTargets;
|
||||
{
|
||||
[_terminalFilter removeAllTargets];
|
||||
}
|
||||
|
||||
- (NSArray *)targets;
|
||||
{
|
||||
return [_terminalFilter targets];
|
||||
}
|
||||
|
||||
- (void)setFrameProcessingCompletionBlock:(void (^)(GPUImageOutput *, CMTime))frameProcessingCompletionBlock;
|
||||
{
|
||||
[_terminalFilter setFrameProcessingCompletionBlock:frameProcessingCompletionBlock];
|
||||
}
|
||||
|
||||
- (void (^)(GPUImageOutput *, CMTime))frameProcessingCompletionBlock;
|
||||
{
|
||||
return [_terminalFilter frameProcessingCompletionBlock];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput protocol
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
if (currentFilter != self.inputFilterToIgnoreForUpdates)
|
||||
{
|
||||
[currentFilter newFrameReadyAtTime:frameTime atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
[currentFilter setInputFramebuffer:newInputFramebuffer atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)nextAvailableTextureIndex;
|
||||
{
|
||||
// if ([_initialFilters count] > 0)
|
||||
// {
|
||||
// return [[_initialFilters objectAtIndex:0] nextAvailableTextureIndex];
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
[currentFilter setInputSize:newSize atIndex:textureIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
[currentFilter setInputRotation:newInputRotation atIndex:(NSInteger)textureIndex];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSize:(CGSize)frameSize;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in filters)
|
||||
{
|
||||
[currentFilter forceProcessingAtSize:frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSizeRespectingAspectRatio:(CGSize)frameSize;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in filters)
|
||||
{
|
||||
[currentFilter forceProcessingAtSizeRespectingAspectRatio:frameSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)maximumOutputSize;
|
||||
{
|
||||
// I'm temporarily disabling adjustments for smaller output sizes until I figure out how to make this work better
|
||||
return CGSizeZero;
|
||||
|
||||
/*
|
||||
if (CGSizeEqualToSize(cachedMaximumOutputSize, CGSizeZero))
|
||||
{
|
||||
for (id<GPUImageInput> currentTarget in _initialFilters)
|
||||
{
|
||||
if ([currentTarget maximumOutputSize].width > cachedMaximumOutputSize.width)
|
||||
{
|
||||
cachedMaximumOutputSize = [currentTarget maximumOutputSize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cachedMaximumOutputSize;
|
||||
*/
|
||||
}
|
||||
|
||||
- (void)endProcessing;
|
||||
{
|
||||
if (!isEndProcessing)
|
||||
{
|
||||
isEndProcessing = YES;
|
||||
|
||||
for (id<GPUImageInput> currentTarget in _initialFilters)
|
||||
{
|
||||
[currentTarget endProcessing];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)wantsMonochromeInput;
|
||||
{
|
||||
BOOL allInputsWantMonochromeInput = YES;
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
allInputsWantMonochromeInput = allInputsWantMonochromeInput && [currentFilter wantsMonochromeInput];
|
||||
}
|
||||
|
||||
return allInputsWantMonochromeInput;
|
||||
}
|
||||
|
||||
- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
|
||||
{
|
||||
for (GPUImageOutput<GPUImageInput> *currentFilter in _initialFilters)
|
||||
{
|
||||
[currentFilter setCurrentlyReceivingMonochromeInput:newValue];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
-218
@@ -1,218 +0,0 @@
|
||||
#import "GPUImageFilterPipeline.h"
|
||||
|
||||
@interface GPUImageFilterPipeline ()
|
||||
|
||||
- (BOOL)_parseConfiguration:(NSDictionary *)configuration;
|
||||
|
||||
- (void)_refreshFilters;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageFilterPipeline
|
||||
|
||||
@synthesize filters = _filters, input = _input, output = _output;
|
||||
|
||||
#pragma mark Config file init
|
||||
|
||||
- (id)initWithConfiguration:(NSDictionary *)configuration input:(GPUImageOutput *)input output:(id <GPUImageInput>)output {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.input = input;
|
||||
self.output = output;
|
||||
if (![self _parseConfiguration:configuration]) {
|
||||
NSLog(@"Sorry, a parsing error occurred.");
|
||||
abort();
|
||||
}
|
||||
[self _refreshFilters];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithConfigurationFile:(NSURL *)configuration input:(GPUImageOutput *)input output:(id <GPUImageInput>)output {
|
||||
return [self initWithConfiguration:[NSDictionary dictionaryWithContentsOfURL:configuration] input:input output:output];
|
||||
}
|
||||
|
||||
- (BOOL)_parseConfiguration:(NSDictionary *)configuration {
|
||||
NSArray *filters = [configuration objectForKey:@"Filters"];
|
||||
if (!filters) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSError *regexError = nil;
|
||||
NSRegularExpression *parsingRegex = [NSRegularExpression regularExpressionWithPattern:@"(float|CGPoint|NSString)\\((.*?)(?:,\\s*(.*?))*\\)"
|
||||
options:0
|
||||
error:®exError];
|
||||
|
||||
// It's faster to put them into an array and then pass it to the filters property than it is to call [self addFilter:] every time
|
||||
NSMutableArray *orderedFilters = [NSMutableArray arrayWithCapacity:[filters count]];
|
||||
for (NSDictionary *filter in filters) {
|
||||
NSString *filterName = [filter objectForKey:@"FilterName"];
|
||||
Class theClass = NSClassFromString(filterName);
|
||||
GPUImageOutput<GPUImageInput> *genericFilter = [[theClass alloc] init];
|
||||
// Set up the properties
|
||||
NSDictionary *filterAttributes;
|
||||
if ((filterAttributes = [filter objectForKey:@"Attributes"])) {
|
||||
for (NSString *propertyKey in filterAttributes) {
|
||||
// Set up the selector
|
||||
SEL theSelector = NSSelectorFromString(propertyKey);
|
||||
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[theClass instanceMethodSignatureForSelector:theSelector]];
|
||||
[inv setSelector:theSelector];
|
||||
[inv setTarget:genericFilter];
|
||||
|
||||
// check selector given with parameter
|
||||
if ([propertyKey hasSuffix:@":"]) {
|
||||
|
||||
stringValue = nil;
|
||||
|
||||
// Then parse the arguments
|
||||
NSMutableArray *parsedArray;
|
||||
if ([[filterAttributes objectForKey:propertyKey] isKindOfClass:[NSArray class]]) {
|
||||
NSArray *array = [filterAttributes objectForKey:propertyKey];
|
||||
parsedArray = [NSMutableArray arrayWithCapacity:[array count]];
|
||||
for (NSString *string in array) {
|
||||
NSTextCheckingResult *parse = [parsingRegex firstMatchInString:string
|
||||
options:0
|
||||
range:NSMakeRange(0, [string length])];
|
||||
|
||||
NSString *modifier = [string substringWithRange:[parse rangeAtIndex:1]];
|
||||
if ([modifier isEqualToString:@"float"]) {
|
||||
// Float modifier, one argument
|
||||
CGFloat value = [[string substringWithRange:[parse rangeAtIndex:2]] floatValue];
|
||||
[parsedArray addObject:[NSNumber numberWithFloat:value]];
|
||||
[inv setArgument:&value atIndex:2];
|
||||
} else if ([modifier isEqualToString:@"CGPoint"]) {
|
||||
// CGPoint modifier, two float arguments
|
||||
CGFloat x = [[string substringWithRange:[parse rangeAtIndex:2]] floatValue];
|
||||
CGFloat y = [[string substringWithRange:[parse rangeAtIndex:3]] floatValue];
|
||||
CGPoint value = CGPointMake(x, y);
|
||||
[parsedArray addObject:[NSValue valueWithCGPoint:value]];
|
||||
} else if ([modifier isEqualToString:@"NSString"]) {
|
||||
// NSString modifier, one string argument
|
||||
stringValue = [[string substringWithRange:[parse rangeAtIndex:2]] copy];
|
||||
[inv setArgument:&stringValue atIndex:2];
|
||||
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
[inv setArgument:&parsedArray atIndex:2];
|
||||
} else {
|
||||
NSString *string = [filterAttributes objectForKey:propertyKey];
|
||||
NSTextCheckingResult *parse = [parsingRegex firstMatchInString:string
|
||||
options:0
|
||||
range:NSMakeRange(0, [string length])];
|
||||
|
||||
NSString *modifier = [string substringWithRange:[parse rangeAtIndex:1]];
|
||||
if ([modifier isEqualToString:@"float"]) {
|
||||
// Float modifier, one argument
|
||||
CGFloat value = [[string substringWithRange:[parse rangeAtIndex:2]] floatValue];
|
||||
[inv setArgument:&value atIndex:2];
|
||||
} else if ([modifier isEqualToString:@"CGPoint"]) {
|
||||
// CGPoint modifier, two float arguments
|
||||
CGFloat x = [[string substringWithRange:[parse rangeAtIndex:2]] floatValue];
|
||||
CGFloat y = [[string substringWithRange:[parse rangeAtIndex:3]] floatValue];
|
||||
CGPoint value = CGPointMake(x, y);
|
||||
[inv setArgument:&value atIndex:2];
|
||||
} else if ([modifier isEqualToString:@"NSString"]) {
|
||||
// NSString modifier, one string argument
|
||||
stringValue = [[string substringWithRange:[parse rangeAtIndex:2]] copy];
|
||||
[inv setArgument:&stringValue atIndex:2];
|
||||
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[inv invoke];
|
||||
}
|
||||
}
|
||||
[orderedFilters addObject:genericFilter];
|
||||
}
|
||||
self.filters = orderedFilters;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark Regular init
|
||||
|
||||
- (id)initWithOrderedFilters:(NSArray *)filters input:(GPUImageOutput *)input output:(id <GPUImageInput>)output {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.input = input;
|
||||
self.output = output;
|
||||
self.filters = [NSMutableArray arrayWithArray:filters];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)filter atIndex:(NSUInteger)insertIndex {
|
||||
[self.filters insertObject:filter atIndex:insertIndex];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)addFilter:(GPUImageOutput<GPUImageInput> *)filter {
|
||||
[self.filters addObject:filter];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)replaceFilterAtIndex:(NSUInteger)index withFilter:(GPUImageOutput<GPUImageInput> *)filter {
|
||||
[self.filters replaceObjectAtIndex:index withObject:filter];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void) removeFilter:(GPUImageOutput<GPUImageInput> *)filter;
|
||||
{
|
||||
[self.filters removeObject:filter];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)removeFilterAtIndex:(NSUInteger)index {
|
||||
[self.filters removeObjectAtIndex:index];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)removeAllFilters {
|
||||
[self.filters removeAllObjects];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)replaceAllFilters:(NSArray *)newFilters {
|
||||
self.filters = [NSMutableArray arrayWithArray:newFilters];
|
||||
[self _refreshFilters];
|
||||
}
|
||||
|
||||
- (void)_refreshFilters {
|
||||
|
||||
id prevFilter = self.input;
|
||||
GPUImageOutput<GPUImageInput> *theFilter = nil;
|
||||
|
||||
for (int i = 0; i < [self.filters count]; i++) {
|
||||
theFilter = [self.filters objectAtIndex:i];
|
||||
[prevFilter removeAllTargets];
|
||||
[prevFilter addTarget:theFilter];
|
||||
prevFilter = theFilter;
|
||||
}
|
||||
|
||||
[prevFilter removeAllTargets];
|
||||
|
||||
if (self.output != nil) {
|
||||
[prevFilter addTarget:self.output];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)currentFilteredFrame {
|
||||
return [(GPUImageOutput<GPUImageInput> *)[_filters lastObject] imageFromCurrentFramebuffer];
|
||||
}
|
||||
|
||||
- (UIImage *)currentFilteredFrameWithOrientation:(UIImageOrientation)imageOrientation {
|
||||
return [(GPUImageOutput<GPUImageInput> *)[_filters lastObject] imageFromCurrentFramebufferWithOrientation:imageOrientation];
|
||||
}
|
||||
|
||||
- (CGImageRef)newCGImageFromCurrentFilteredFrame {
|
||||
return [(GPUImageOutput<GPUImageInput> *)[_filters lastObject] newCGImageFromCurrentlyProcessedOutput];
|
||||
}
|
||||
|
||||
@end
|
||||
-401
@@ -1,401 +0,0 @@
|
||||
#import "GPUImageFourInputFilter.h"
|
||||
|
||||
|
||||
NSString *const kGPUImageFourInputTextureVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
attribute vec4 inputTextureCoordinate2;
|
||||
attribute vec4 inputTextureCoordinate3;
|
||||
attribute vec4 inputTextureCoordinate4;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
varying vec2 textureCoordinate3;
|
||||
varying vec2 textureCoordinate4;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
textureCoordinate2 = inputTextureCoordinate2.xy;
|
||||
textureCoordinate3 = inputTextureCoordinate3.xy;
|
||||
textureCoordinate4 = inputTextureCoordinate4.xy;
|
||||
}
|
||||
);
|
||||
|
||||
@implementation GPUImageFourInputFilter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [self initWithVertexShaderFromString:kGPUImageFourInputTextureVertexShaderString fragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
inputRotation4 = kGPUImageNoRotation;
|
||||
|
||||
hasSetThirdTexture = NO;
|
||||
|
||||
hasReceivedFourthFrame = NO;
|
||||
fourthFrameWasVideo = NO;
|
||||
fourthFrameCheckDisabled = NO;
|
||||
|
||||
fourthFrameTime = kCMTimeInvalid;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
filterFourthTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate4"];
|
||||
|
||||
filterInputTextureUniform4 = [filterProgram uniformIndex:@"inputImageTexture4"]; // This does assume a name of "inputImageTexture3" for the third input texture in the fragment shader
|
||||
glEnableVertexAttribArray(filterFourthTextureCoordinateAttribute);
|
||||
});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initializeAttributes;
|
||||
{
|
||||
[super initializeAttributes];
|
||||
[filterProgram addAttribute:@"inputTextureCoordinate4"];
|
||||
}
|
||||
|
||||
- (void)disableFourthFrameCheck;
|
||||
{
|
||||
fourthFrameCheckDisabled = YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
[firstInputFramebuffer unlock];
|
||||
[secondInputFramebuffer unlock];
|
||||
[thirdInputFramebuffer unlock];
|
||||
[fourthInputFramebuffer unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
[outputFramebuffer lock];
|
||||
}
|
||||
|
||||
[self setUniformsForProgramAtIndex:0];
|
||||
|
||||
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]);
|
||||
glUniform1i(filterInputTextureUniform2, 3);
|
||||
|
||||
glActiveTexture(GL_TEXTURE4);
|
||||
glBindTexture(GL_TEXTURE_2D, [thirdInputFramebuffer texture]);
|
||||
glUniform1i(filterInputTextureUniform3, 4);
|
||||
|
||||
glActiveTexture(GL_TEXTURE5);
|
||||
glBindTexture(GL_TEXTURE_2D, [fourthInputFramebuffer texture]);
|
||||
glUniform1i(filterInputTextureUniform4, 5);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation2]);
|
||||
glVertexAttribPointer(filterThirdTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation3]);
|
||||
glVertexAttribPointer(filterFourthTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation4]);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
[firstInputFramebuffer unlock];
|
||||
[secondInputFramebuffer unlock];
|
||||
[thirdInputFramebuffer unlock];
|
||||
[fourthInputFramebuffer unlock];
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark GPUImageInput
|
||||
|
||||
- (NSInteger)nextAvailableTextureIndex;
|
||||
{
|
||||
if (hasSetThirdTexture)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else if (hasSetSecondTexture)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (hasSetFirstTexture)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (textureIndex == 0)
|
||||
{
|
||||
firstInputFramebuffer = newInputFramebuffer;
|
||||
hasSetFirstTexture = YES;
|
||||
[firstInputFramebuffer lock];
|
||||
}
|
||||
else if (textureIndex == 1)
|
||||
{
|
||||
secondInputFramebuffer = newInputFramebuffer;
|
||||
hasSetSecondTexture = YES;
|
||||
[secondInputFramebuffer lock];
|
||||
}
|
||||
else if (textureIndex == 2)
|
||||
{
|
||||
thirdInputFramebuffer = newInputFramebuffer;
|
||||
hasSetThirdTexture = YES;
|
||||
[thirdInputFramebuffer lock];
|
||||
}
|
||||
else
|
||||
{
|
||||
fourthInputFramebuffer = newInputFramebuffer;
|
||||
[fourthInputFramebuffer lock];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (textureIndex == 0)
|
||||
{
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
|
||||
if (CGSizeEqualToSize(newSize, CGSizeZero))
|
||||
{
|
||||
hasSetFirstTexture = NO;
|
||||
}
|
||||
}
|
||||
else if (textureIndex == 1)
|
||||
{
|
||||
if (CGSizeEqualToSize(newSize, CGSizeZero))
|
||||
{
|
||||
hasSetSecondTexture = NO;
|
||||
}
|
||||
}
|
||||
else if (textureIndex == 2)
|
||||
{
|
||||
if (CGSizeEqualToSize(newSize, CGSizeZero))
|
||||
{
|
||||
hasSetThirdTexture = NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (textureIndex == 0)
|
||||
{
|
||||
inputRotation = newInputRotation;
|
||||
}
|
||||
else if (textureIndex == 1)
|
||||
{
|
||||
inputRotation2 = newInputRotation;
|
||||
}
|
||||
else if (textureIndex == 2)
|
||||
{
|
||||
inputRotation3 = newInputRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputRotation4 = newInputRotation;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
CGSize rotatedSize = sizeToRotate;
|
||||
|
||||
GPUImageRotationMode rotationToCheck;
|
||||
if (textureIndex == 0)
|
||||
{
|
||||
rotationToCheck = inputRotation;
|
||||
}
|
||||
else if (textureIndex == 1)
|
||||
{
|
||||
rotationToCheck = inputRotation2;
|
||||
}
|
||||
else if (textureIndex == 2)
|
||||
{
|
||||
rotationToCheck = inputRotation3;
|
||||
}
|
||||
else
|
||||
{
|
||||
rotationToCheck = inputRotation4;
|
||||
}
|
||||
|
||||
if (GPUImageRotationSwapsWidthAndHeight(rotationToCheck))
|
||||
{
|
||||
rotatedSize.width = sizeToRotate.height;
|
||||
rotatedSize.height = sizeToRotate.width;
|
||||
}
|
||||
|
||||
return rotatedSize;
|
||||
}
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
// You can set up infinite update loops, so this helps to short circuit them
|
||||
if (hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL updatedMovieFrameOppositeStillImage = NO;
|
||||
|
||||
if (textureIndex == 0)
|
||||
{
|
||||
hasReceivedFirstFrame = YES;
|
||||
firstFrameTime = frameTime;
|
||||
if (secondFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedSecondFrame = YES;
|
||||
}
|
||||
if (thirdFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedThirdFrame = YES;
|
||||
}
|
||||
if (fourthFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedThirdFrame = YES;
|
||||
}
|
||||
|
||||
if (!CMTIME_IS_INDEFINITE(frameTime))
|
||||
{
|
||||
if CMTIME_IS_INDEFINITE(secondFrameTime)
|
||||
{
|
||||
updatedMovieFrameOppositeStillImage = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (textureIndex == 1)
|
||||
{
|
||||
hasReceivedSecondFrame = YES;
|
||||
secondFrameTime = frameTime;
|
||||
if (firstFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedFirstFrame = YES;
|
||||
}
|
||||
if (thirdFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedThirdFrame = YES;
|
||||
}
|
||||
if (fourthFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedFourthFrame = YES;
|
||||
}
|
||||
|
||||
if (!CMTIME_IS_INDEFINITE(frameTime))
|
||||
{
|
||||
if CMTIME_IS_INDEFINITE(firstFrameTime)
|
||||
{
|
||||
updatedMovieFrameOppositeStillImage = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (textureIndex == 2)
|
||||
{
|
||||
hasReceivedThirdFrame = YES;
|
||||
thirdFrameTime = frameTime;
|
||||
if (firstFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedFirstFrame = YES;
|
||||
}
|
||||
if (secondFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedSecondFrame = YES;
|
||||
}
|
||||
if (fourthFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedFourthFrame = YES;
|
||||
}
|
||||
|
||||
if (!CMTIME_IS_INDEFINITE(frameTime))
|
||||
{
|
||||
if CMTIME_IS_INDEFINITE(firstFrameTime)
|
||||
{
|
||||
updatedMovieFrameOppositeStillImage = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hasReceivedFourthFrame = YES;
|
||||
fourthFrameTime = frameTime;
|
||||
if (firstFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedFirstFrame = YES;
|
||||
}
|
||||
if (secondFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedSecondFrame = YES;
|
||||
}
|
||||
if (thirdFrameCheckDisabled)
|
||||
{
|
||||
hasReceivedThirdFrame = YES;
|
||||
}
|
||||
|
||||
if (!CMTIME_IS_INDEFINITE(frameTime))
|
||||
{
|
||||
if CMTIME_IS_INDEFINITE(firstFrameTime)
|
||||
{
|
||||
updatedMovieFrameOppositeStillImage = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// || (hasReceivedFirstFrame && secondFrameCheckDisabled) || (hasReceivedSecondFrame && firstFrameCheckDisabled)
|
||||
if ((hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame && hasReceivedFourthFrame) || updatedMovieFrameOppositeStillImage)
|
||||
{
|
||||
static const GLfloat imageVertices[] = {
|
||||
-1.0f, -1.0f,
|
||||
1.0f, -1.0f,
|
||||
-1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
};
|
||||
|
||||
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]];
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
|
||||
hasReceivedFirstFrame = NO;
|
||||
hasReceivedSecondFrame = NO;
|
||||
hasReceivedThirdFrame = NO;
|
||||
hasReceivedFourthFrame = NO;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
-457
@@ -1,457 +0,0 @@
|
||||
#import "GPUImageFramebuffer.h"
|
||||
#import "GPUImageOutput.h"
|
||||
|
||||
@interface GPUImageFramebuffer()
|
||||
{
|
||||
GLuint framebuffer;
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
CVPixelBufferRef renderTarget;
|
||||
CVOpenGLESTextureRef renderTexture;
|
||||
NSUInteger readLockCount;
|
||||
#else
|
||||
#endif
|
||||
NSUInteger framebufferReferenceCount;
|
||||
BOOL referenceCountingDisabled;
|
||||
}
|
||||
|
||||
- (void)generateFramebuffer;
|
||||
- (void)generateTexture;
|
||||
- (void)destroyFramebuffer;
|
||||
|
||||
@end
|
||||
|
||||
void dataProviderReleaseCallback (void *info, const void *data, size_t size);
|
||||
void dataProviderUnlockCallback (void *info, const void *data, size_t size);
|
||||
|
||||
@implementation GPUImageFramebuffer
|
||||
|
||||
@synthesize size = _size;
|
||||
@synthesize textureOptions = _textureOptions;
|
||||
@synthesize texture = _texture;
|
||||
@synthesize missingFramebuffer = _missingFramebuffer;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
_textureOptions = fboTextureOptions;
|
||||
_size = framebufferSize;
|
||||
framebufferReferenceCount = 0;
|
||||
referenceCountingDisabled = NO;
|
||||
_missingFramebuffer = onlyGenerateTexture;
|
||||
|
||||
if (_missingFramebuffer)
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
[self generateTexture];
|
||||
framebuffer = 0;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
[self generateFramebuffer];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
GPUTextureOptions defaultTextureOptions;
|
||||
defaultTextureOptions.minFilter = GL_LINEAR;
|
||||
defaultTextureOptions.magFilter = GL_LINEAR;
|
||||
defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.internalFormat = GL_RGBA;
|
||||
defaultTextureOptions.format = GL_BGRA;
|
||||
defaultTextureOptions.type = GL_UNSIGNED_BYTE;
|
||||
|
||||
_textureOptions = defaultTextureOptions;
|
||||
_size = framebufferSize;
|
||||
framebufferReferenceCount = 0;
|
||||
referenceCountingDisabled = YES;
|
||||
|
||||
_texture = inputTexture;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithSize:(CGSize)framebufferSize;
|
||||
{
|
||||
GPUTextureOptions defaultTextureOptions;
|
||||
defaultTextureOptions.minFilter = GL_LINEAR;
|
||||
defaultTextureOptions.magFilter = GL_LINEAR;
|
||||
defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.internalFormat = GL_RGBA;
|
||||
defaultTextureOptions.format = GL_BGRA;
|
||||
defaultTextureOptions.type = GL_UNSIGNED_BYTE;
|
||||
|
||||
if (!(self = [self initWithSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:NO]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self destroyFramebuffer];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Internal
|
||||
|
||||
- (void)generateTexture;
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glGenTextures(1, &_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _textureOptions.minFilter);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _textureOptions.magFilter);
|
||||
// This is necessary for non-power-of-two textures
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureOptions.wrapS);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);
|
||||
|
||||
// TODO: Handle mipmaps
|
||||
}
|
||||
|
||||
- (void)generateFramebuffer;
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
// By default, all framebuffers on iOS 5.0+ devices are backed by texture caches, using one shared cache
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
CVOpenGLESTextureCacheRef coreVideoTextureCache = [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache];
|
||||
// Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/
|
||||
|
||||
CFDictionaryRef empty; // empty value for attr value.
|
||||
CFMutableDictionaryRef attrs;
|
||||
empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary
|
||||
attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
|
||||
|
||||
CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, (int)_size.width, (int)_size.height, kCVPixelFormatType_32BGRA, attrs, &renderTarget);
|
||||
if (err)
|
||||
{
|
||||
NSLog(@"FBO size: %f, %f", _size.width, _size.height);
|
||||
NSAssert(NO, @"Error at CVPixelBufferCreate %d", err);
|
||||
}
|
||||
|
||||
err = CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, coreVideoTextureCache, renderTarget,
|
||||
NULL, // texture attributes
|
||||
GL_TEXTURE_2D,
|
||||
_textureOptions.internalFormat, // opengl format
|
||||
(int)_size.width,
|
||||
(int)_size.height,
|
||||
_textureOptions.format, // native iOS format
|
||||
_textureOptions.type,
|
||||
0,
|
||||
&renderTexture);
|
||||
if (err)
|
||||
{
|
||||
NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
|
||||
}
|
||||
|
||||
CFRelease(attrs);
|
||||
CFRelease(empty);
|
||||
|
||||
glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));
|
||||
_texture = CVOpenGLESTextureGetName(renderTexture);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureOptions.wrapS);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
[self generateTexture];
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, _textureOptions.internalFormat, (int)_size.width, (int)_size.height, 0, _textureOptions.format, _textureOptions.type, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
}
|
||||
|
||||
#ifndef NS_BLOCK_ASSERTIONS
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
NSAssert(status == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", status);
|
||||
#endif
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)destroyFramebuffer;
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
if (framebuffer)
|
||||
{
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
framebuffer = 0;
|
||||
}
|
||||
|
||||
|
||||
if ([GPUImageContext supportsFastTextureUpload] && (!_missingFramebuffer))
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
if (renderTarget)
|
||||
{
|
||||
CFRelease(renderTarget);
|
||||
renderTarget = NULL;
|
||||
}
|
||||
|
||||
if (renderTexture)
|
||||
{
|
||||
CFRelease(renderTexture);
|
||||
renderTexture = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteTextures(1, &_texture);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Usage
|
||||
|
||||
- (void)activateFramebuffer;
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
glViewport(0, 0, (int)_size.width, (int)_size.height);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reference counting
|
||||
|
||||
- (void)lock;
|
||||
{
|
||||
if (referenceCountingDisabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
framebufferReferenceCount++;
|
||||
}
|
||||
|
||||
- (void)unlock;
|
||||
{
|
||||
if (referenceCountingDisabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");
|
||||
framebufferReferenceCount--;
|
||||
if (framebufferReferenceCount < 1)
|
||||
{
|
||||
[[GPUImageContext sharedFramebufferCache] returnFramebufferToCache:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearAllLocks;
|
||||
{
|
||||
framebufferReferenceCount = 0;
|
||||
}
|
||||
|
||||
- (void)disableReferenceCounting;
|
||||
{
|
||||
referenceCountingDisabled = YES;
|
||||
}
|
||||
|
||||
- (void)enableReferenceCounting;
|
||||
{
|
||||
referenceCountingDisabled = NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Image capture
|
||||
|
||||
void dataProviderReleaseCallback (void *info, const void *data, size_t size)
|
||||
{
|
||||
free((void *)data);
|
||||
}
|
||||
|
||||
void dataProviderUnlockCallback (void *info, const void *data, size_t size)
|
||||
{
|
||||
GPUImageFramebuffer *framebuffer = (__bridge_transfer GPUImageFramebuffer*)info;
|
||||
|
||||
[framebuffer restoreRenderTarget];
|
||||
[framebuffer unlock];
|
||||
[[GPUImageContext sharedFramebufferCache] removeFramebufferFromActiveImageCaptureList:framebuffer];
|
||||
}
|
||||
|
||||
- (CGImageRef)newCGImageFromFramebufferContents;
|
||||
{
|
||||
// a CGImage can only be created from a 'normal' color texture
|
||||
NSAssert(self.textureOptions.internalFormat == GL_RGBA, @"For conversion to a CGImage the output texture format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.textureOptions.type == GL_UNSIGNED_BYTE, @"For conversion to a CGImage the type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
__block CGImageRef cgImageFromBytes;
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
NSUInteger totalBytesForImage = (int)_size.width * (int)_size.height * 4;
|
||||
// It appears that the width of a texture must be padded out to be a multiple of 8 (32 bytes) if reading from it using a texture cache
|
||||
|
||||
GLubyte *rawImagePixels;
|
||||
|
||||
CGDataProviderRef dataProvider = NULL;
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4.0;
|
||||
NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * 4;
|
||||
|
||||
glFinish();
|
||||
CFRetain(renderTarget); // I need to retain the pixel buffer here and release in the data source callback to prevent its bytes from being prematurely deallocated during a photo write operation
|
||||
[self lockForReading];
|
||||
rawImagePixels = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
|
||||
dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, rawImagePixels, paddedBytesForImage, dataProviderUnlockCallback);
|
||||
[[GPUImageContext sharedFramebufferCache] addFramebufferToActiveImageCaptureList:self]; // In case the framebuffer is swapped out on the filter, need to have a strong reference to it somewhere for it to hang on while the image is in existence
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
[self activateFramebuffer];
|
||||
rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
|
||||
glReadPixels(0, 0, (int)_size.width, (int)_size.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
|
||||
dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels, totalBytesForImage, dataProviderReleaseCallback);
|
||||
[self unlock]; // Don't need to keep this around anymore
|
||||
}
|
||||
|
||||
CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
}
|
||||
|
||||
// Capture image with current device orientation
|
||||
CGDataProviderRelease(dataProvider);
|
||||
CGColorSpaceRelease(defaultRGBColorSpace);
|
||||
|
||||
});
|
||||
|
||||
return cgImageFromBytes;
|
||||
}
|
||||
|
||||
- (void)restoreRenderTarget;
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[self unlockAfterReading];
|
||||
CFRelease(renderTarget);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Raw data bytes
|
||||
|
||||
- (void)lockForReading
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
if (readLockCount == 0)
|
||||
{
|
||||
CVPixelBufferLockBaseAddress(renderTarget, 0);
|
||||
}
|
||||
readLockCount++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)unlockAfterReading
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
NSAssert(readLockCount > 0, @"Unbalanced call to -[GPUImageFramebuffer unlockAfterReading]");
|
||||
readLockCount--;
|
||||
if (readLockCount == 0)
|
||||
{
|
||||
CVPixelBufferUnlockBaseAddress(renderTarget, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSUInteger)bytesPerRow;
|
||||
{
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
return CVPixelBufferGetBytesPerRow(renderTarget);
|
||||
#else
|
||||
return _size.width * 4; // TODO: do more with this on the non-texture-cache side
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return _size.width * 4;
|
||||
}
|
||||
}
|
||||
|
||||
- (GLubyte *)byteBuffer;
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[self lockForReading];
|
||||
GLubyte * bufferBytes = CVPixelBufferGetBaseAddress(renderTarget);
|
||||
[self unlockAfterReading];
|
||||
return bufferBytes;
|
||||
#else
|
||||
return NULL; // TODO: do more with this on the non-texture-cache side
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CVPixelBufferRef )pixelBuffer;
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
return renderTarget;
|
||||
#else
|
||||
return NULL; // TODO: do more with this on the non-texture-cache side
|
||||
#endif
|
||||
}
|
||||
|
||||
- (GLuint)texture;
|
||||
{
|
||||
// NSLog(@"Accessing texture: %d from FB: %@", _texture, self);
|
||||
return _texture;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,190 +0,0 @@
|
||||
#import "GPUImageFramebufferCache.h"
|
||||
#import "GPUImageContext.h"
|
||||
#import "GPUImageOutput.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#endif
|
||||
|
||||
@interface GPUImageFramebufferCache()
|
||||
{
|
||||
// NSCache *framebufferCache;
|
||||
NSMutableDictionary *framebufferCache;
|
||||
NSMutableDictionary *framebufferTypeCounts;
|
||||
NSMutableArray *activeImageCaptureList; // Where framebuffers that may be lost by a filter, but which are still needed for a UIImage, etc., are stored
|
||||
id memoryWarningObserver;
|
||||
|
||||
dispatch_queue_t framebufferCacheQueue;
|
||||
}
|
||||
|
||||
- (NSString *)hashForSize:(CGSize)size textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation GPUImageFramebufferCache
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
__unsafe_unretained __typeof__ (self) weakSelf = self;
|
||||
memoryWarningObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
||||
__typeof__ (self) strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf purgeAllUnassignedFramebuffers];
|
||||
}
|
||||
}];
|
||||
#else
|
||||
#endif
|
||||
|
||||
// framebufferCache = [[NSCache alloc] init];
|
||||
framebufferCache = [[NSMutableDictionary alloc] init];
|
||||
framebufferTypeCounts = [[NSMutableDictionary alloc] init];
|
||||
activeImageCaptureList = [[NSMutableArray alloc] init];
|
||||
framebufferCacheQueue = dispatch_queue_create("com.sunsetlakesoftware.GPUImage.framebufferCacheQueue", GPUImageDefaultQueueAttribute());
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Framebuffer management
|
||||
|
||||
- (NSString *)hashForSize:(CGSize)size textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
|
||||
{
|
||||
if (onlyTexture)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%.1fx%.1f-%d:%d:%d:%d:%d:%d:%d-NOFB", size.width, size.height, textureOptions.minFilter, textureOptions.magFilter, textureOptions.wrapS, textureOptions.wrapT, textureOptions.internalFormat, textureOptions.format, textureOptions.type];
|
||||
}
|
||||
else
|
||||
{
|
||||
return [NSString stringWithFormat:@"%.1fx%.1f-%d:%d:%d:%d:%d:%d:%d", size.width, size.height, textureOptions.minFilter, textureOptions.magFilter, textureOptions.wrapS, textureOptions.wrapT, textureOptions.internalFormat, textureOptions.format, textureOptions.type];
|
||||
}
|
||||
}
|
||||
|
||||
- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture;
|
||||
{
|
||||
__block GPUImageFramebuffer *framebufferFromCache = nil;
|
||||
// dispatch_sync(framebufferCacheQueue, ^{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
|
||||
NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
|
||||
NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];
|
||||
|
||||
if ([numberOfMatchingTexturesInCache integerValue] < 1)
|
||||
{
|
||||
// Nothing in the cache, create a new framebuffer to use
|
||||
framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something found, pull the old framebuffer and decrement the count
|
||||
NSInteger currentTextureID = (numberOfMatchingTextures - 1);
|
||||
while ((framebufferFromCache == nil) && (currentTextureID >= 0))
|
||||
{
|
||||
NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)currentTextureID];
|
||||
framebufferFromCache = [framebufferCache objectForKey:textureHash];
|
||||
// Test the values in the cache first, to see if they got invalidated behind our back
|
||||
if (framebufferFromCache != nil)
|
||||
{
|
||||
// Withdraw this from the cache while it's in use
|
||||
[framebufferCache removeObjectForKey:textureHash];
|
||||
}
|
||||
currentTextureID--;
|
||||
}
|
||||
|
||||
currentTextureID++;
|
||||
|
||||
[framebufferTypeCounts setObject:[NSNumber numberWithInteger:currentTextureID] forKey:lookupHash];
|
||||
|
||||
if (framebufferFromCache == nil)
|
||||
{
|
||||
framebufferFromCache = [[GPUImageFramebuffer alloc] initWithSize:framebufferSize textureOptions:textureOptions onlyTexture:onlyTexture];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
[framebufferFromCache lock];
|
||||
return framebufferFromCache;
|
||||
}
|
||||
|
||||
- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture;
|
||||
{
|
||||
GPUTextureOptions defaultTextureOptions;
|
||||
defaultTextureOptions.minFilter = GL_LINEAR;
|
||||
defaultTextureOptions.magFilter = GL_LINEAR;
|
||||
defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
|
||||
defaultTextureOptions.internalFormat = GL_RGBA;
|
||||
defaultTextureOptions.format = GL_BGRA;
|
||||
defaultTextureOptions.type = GL_UNSIGNED_BYTE;
|
||||
|
||||
return [self fetchFramebufferForSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:onlyTexture];
|
||||
}
|
||||
|
||||
- (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer;
|
||||
{
|
||||
[framebuffer clearAllLocks];
|
||||
|
||||
// dispatch_async(framebufferCacheQueue, ^{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
CGSize framebufferSize = framebuffer.size;
|
||||
GPUTextureOptions framebufferTextureOptions = framebuffer.textureOptions;
|
||||
NSString *lookupHash = [self hashForSize:framebufferSize textureOptions:framebufferTextureOptions onlyTexture:framebuffer.missingFramebuffer];
|
||||
NSNumber *numberOfMatchingTexturesInCache = [framebufferTypeCounts objectForKey:lookupHash];
|
||||
NSInteger numberOfMatchingTextures = [numberOfMatchingTexturesInCache integerValue];
|
||||
|
||||
NSString *textureHash = [NSString stringWithFormat:@"%@-%ld", lookupHash, (long)numberOfMatchingTextures];
|
||||
|
||||
// [framebufferCache setObject:framebuffer forKey:textureHash cost:round(framebufferSize.width * framebufferSize.height * 4.0)];
|
||||
[framebufferCache setObject:framebuffer forKey:textureHash];
|
||||
[framebufferTypeCounts setObject:[NSNumber numberWithInteger:(numberOfMatchingTextures + 1)] forKey:lookupHash];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)purgeAllUnassignedFramebuffers;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
// dispatch_async(framebufferCacheQueue, ^{
|
||||
[framebufferCache removeAllObjects];
|
||||
[framebufferTypeCounts removeAllObjects];
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
CVOpenGLESTextureCacheFlush([[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], 0);
|
||||
#else
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
- (void)addFramebufferToActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
// dispatch_async(framebufferCacheQueue, ^{
|
||||
[activeImageCaptureList addObject:framebuffer];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)removeFramebufferFromActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer;
|
||||
{
|
||||
runAsynchronouslyOnVideoProcessingQueue(^{
|
||||
// dispatch_async(framebufferCacheQueue, ^{
|
||||
[activeImageCaptureList removeObject:framebuffer];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
#import "GPUImageGammaFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageGammaFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp float gamma;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageGammaFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float gamma;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageGammaFilter
|
||||
|
||||
@synthesize gamma = _gamma;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageGammaFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
gammaUniform = [filterProgram uniformIndex:@"gamma"];
|
||||
self.gamma = 1.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setGamma:(CGFloat)newValue;
|
||||
{
|
||||
_gamma = newValue;
|
||||
|
||||
[self setFloat:_gamma forUniform:gammaUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,513 +0,0 @@
|
||||
#import "GPUImageGaussianBlurFilter.h"
|
||||
|
||||
@implementation GPUImageGaussianBlurFilter
|
||||
|
||||
@synthesize texelSpacingMultiplier = _texelSpacingMultiplier;
|
||||
@synthesize blurRadiusInPixels = _blurRadiusInPixels;
|
||||
@synthesize blurRadiusAsFractionOfImageWidth = _blurRadiusAsFractionOfImageWidth;
|
||||
@synthesize blurRadiusAsFractionOfImageHeight = _blurRadiusAsFractionOfImageHeight;
|
||||
@synthesize blurPasses = _blurPasses;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShaderString firstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString secondStageVertexShaderFromString:(NSString *)secondStageVertexShaderString secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString
|
||||
{
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:firstStageVertexShaderString firstStageFragmentShaderFromString:firstStageFragmentShaderString secondStageVertexShaderFromString:secondStageVertexShaderString secondStageFragmentShaderFromString:secondStageFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.texelSpacingMultiplier = 1.0;
|
||||
_blurRadiusInPixels = 2.0;
|
||||
shouldResizeBlurRadiusWithImageSize = NO;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
NSString *currentGaussianBlurVertexShader = [[self class] vertexShaderForOptimizedBlurOfRadius:4 sigma:2.0];
|
||||
NSString *currentGaussianBlurFragmentShader = [[self class] fragmentShaderForOptimizedBlurOfRadius:4 sigma:2.0];
|
||||
|
||||
return [self initWithFirstStageVertexShaderFromString:currentGaussianBlurVertexShader firstStageFragmentShaderFromString:currentGaussianBlurFragmentShader secondStageVertexShaderFromString:currentGaussianBlurVertexShader secondStageFragmentShaderFromString:currentGaussianBlurFragmentShader];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Auto-generation of optimized Gaussian shaders
|
||||
|
||||
// "Implementation limit of 32 varying components exceeded" - Max number of varyings for these GPUs
|
||||
|
||||
+ (NSString *)vertexShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImageVertexShaderString;
|
||||
}
|
||||
|
||||
// NSLog(@"Max varyings: %d", [GPUImageContext maximumVaryingVectorsForThisDevice]);
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
|
||||
// Header
|
||||
[shaderString appendFormat:@"\
|
||||
attribute vec4 position;\n\
|
||||
attribute vec4 inputTextureCoordinate;\n\
|
||||
\n\
|
||||
uniform float texelWidthOffset;\n\
|
||||
uniform float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
gl_Position = position;\n\
|
||||
\n\
|
||||
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n", (unsigned long)(blurRadius * 2 + 1) ];
|
||||
|
||||
// Inner offset loop
|
||||
for (NSUInteger currentBlurCoordinateIndex = 0; currentBlurCoordinateIndex < (blurRadius * 2 + 1); currentBlurCoordinateIndex++)
|
||||
{
|
||||
NSInteger offsetFromCenter = currentBlurCoordinateIndex - blurRadius;
|
||||
if (offsetFromCenter < 0)
|
||||
{
|
||||
[shaderString appendFormat:@"blurCoordinates[%ld] = inputTextureCoordinate.xy - singleStepOffset * %f;\n", (unsigned long)currentBlurCoordinateIndex, (GLfloat)(-offsetFromCenter)];
|
||||
}
|
||||
else if (offsetFromCenter > 0)
|
||||
{
|
||||
[shaderString appendFormat:@"blurCoordinates[%ld] = inputTextureCoordinate.xy + singleStepOffset * %f;\n", (unsigned long)currentBlurCoordinateIndex, (GLfloat)(offsetFromCenter)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[shaderString appendFormat:@"blurCoordinates[%ld] = inputTextureCoordinate.xy;\n", (unsigned long)currentBlurCoordinateIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"}\n"];
|
||||
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
+ (NSString *)fragmentShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImagePassthroughFragmentShaderString;
|
||||
}
|
||||
|
||||
// First, generate the normal Gaussian weights for a given sigma
|
||||
GLfloat *standardGaussianWeights = calloc(blurRadius + 1, sizeof(GLfloat));
|
||||
GLfloat sumOfWeights = 0.0;
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = (1.0 / sqrt(2.0 * M_PI * pow(sigma, 2.0))) * exp(-pow(currentGaussianWeightIndex, 2.0) / (2.0 * pow(sigma, 2.0)));
|
||||
|
||||
if (currentGaussianWeightIndex == 0)
|
||||
{
|
||||
sumOfWeights += standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
sumOfWeights += 2.0 * standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Next, normalize these weights to prevent the clipping of the Gaussian curve at the end of the discrete samples from reducing luminance
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = standardGaussianWeights[currentGaussianWeightIndex] / sumOfWeights;
|
||||
}
|
||||
|
||||
// Finally, generate the shader from these weights
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
|
||||
// Header
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
\n\
|
||||
varying highp vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
lowp vec4 sum = vec4(0.0);\n", (unsigned long)(blurRadius * 2 + 1) ];
|
||||
#else
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 sum = vec4(0.0);\n", (blurRadius * 2 + 1) ];
|
||||
#endif
|
||||
|
||||
// Inner texture loop
|
||||
for (NSUInteger currentBlurCoordinateIndex = 0; currentBlurCoordinateIndex < (blurRadius * 2 + 1); currentBlurCoordinateIndex++)
|
||||
{
|
||||
NSInteger offsetFromCenter = currentBlurCoordinateIndex - blurRadius;
|
||||
if (offsetFromCenter < 0)
|
||||
{
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)currentBlurCoordinateIndex, standardGaussianWeights[-offsetFromCenter]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)currentBlurCoordinateIndex, standardGaussianWeights[offsetFromCenter]];
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"\
|
||||
gl_FragColor = sum;\n\
|
||||
}\n"];
|
||||
|
||||
free(standardGaussianWeights);
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
+ (NSString *)vertexShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImageVertexShaderString;
|
||||
}
|
||||
|
||||
// First, generate the normal Gaussian weights for a given sigma
|
||||
GLfloat *standardGaussianWeights = calloc(blurRadius + 1, sizeof(GLfloat));
|
||||
GLfloat sumOfWeights = 0.0;
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = (1.0 / sqrt(2.0 * M_PI * pow(sigma, 2.0))) * exp(-pow(currentGaussianWeightIndex, 2.0) / (2.0 * pow(sigma, 2.0)));
|
||||
|
||||
if (currentGaussianWeightIndex == 0)
|
||||
{
|
||||
sumOfWeights += standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
sumOfWeights += 2.0 * standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Next, normalize these weights to prevent the clipping of the Gaussian curve at the end of the discrete samples from reducing luminance
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = standardGaussianWeights[currentGaussianWeightIndex] / sumOfWeights;
|
||||
}
|
||||
|
||||
// From these weights we calculate the offsets to read interpolated values from
|
||||
NSUInteger numberOfOptimizedOffsets = MIN(blurRadius / 2 + (blurRadius % 2), 7);
|
||||
GLfloat *optimizedGaussianOffsets = calloc(numberOfOptimizedOffsets, sizeof(GLfloat));
|
||||
|
||||
for (NSUInteger currentOptimizedOffset = 0; currentOptimizedOffset < numberOfOptimizedOffsets; currentOptimizedOffset++)
|
||||
{
|
||||
GLfloat firstWeight = standardGaussianWeights[currentOptimizedOffset*2 + 1];
|
||||
GLfloat secondWeight = standardGaussianWeights[currentOptimizedOffset*2 + 2];
|
||||
|
||||
GLfloat optimizedWeight = firstWeight + secondWeight;
|
||||
|
||||
optimizedGaussianOffsets[currentOptimizedOffset] = (firstWeight * (currentOptimizedOffset*2 + 1) + secondWeight * (currentOptimizedOffset*2 + 2)) / optimizedWeight;
|
||||
}
|
||||
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
// Header
|
||||
[shaderString appendFormat:@"\
|
||||
attribute vec4 position;\n\
|
||||
attribute vec4 inputTextureCoordinate;\n\
|
||||
\n\
|
||||
uniform float texelWidthOffset;\n\
|
||||
uniform float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
gl_Position = position;\n\
|
||||
\n\
|
||||
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n", (unsigned long)(1 + (numberOfOptimizedOffsets * 2))];
|
||||
|
||||
// Inner offset loop
|
||||
[shaderString appendString:@"blurCoordinates[0] = inputTextureCoordinate.xy;\n"];
|
||||
for (NSUInteger currentOptimizedOffset = 0; currentOptimizedOffset < numberOfOptimizedOffsets; currentOptimizedOffset++)
|
||||
{
|
||||
[shaderString appendFormat:@"\
|
||||
blurCoordinates[%lu] = inputTextureCoordinate.xy + singleStepOffset * %f;\n\
|
||||
blurCoordinates[%lu] = inputTextureCoordinate.xy - singleStepOffset * %f;\n", (unsigned long)((currentOptimizedOffset * 2) + 1), optimizedGaussianOffsets[currentOptimizedOffset], (unsigned long)((currentOptimizedOffset * 2) + 2), optimizedGaussianOffsets[currentOptimizedOffset]];
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"}\n"];
|
||||
|
||||
free(optimizedGaussianOffsets);
|
||||
free(standardGaussianWeights);
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
+ (NSString *)fragmentShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma;
|
||||
{
|
||||
if (blurRadius < 1)
|
||||
{
|
||||
return kGPUImagePassthroughFragmentShaderString;
|
||||
}
|
||||
|
||||
// First, generate the normal Gaussian weights for a given sigma
|
||||
GLfloat *standardGaussianWeights = calloc(blurRadius + 1, sizeof(GLfloat));
|
||||
GLfloat sumOfWeights = 0.0;
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = (1.0 / sqrt(2.0 * M_PI * pow(sigma, 2.0))) * exp(-pow(currentGaussianWeightIndex, 2.0) / (2.0 * pow(sigma, 2.0)));
|
||||
|
||||
if (currentGaussianWeightIndex == 0)
|
||||
{
|
||||
sumOfWeights += standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
sumOfWeights += 2.0 * standardGaussianWeights[currentGaussianWeightIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Next, normalize these weights to prevent the clipping of the Gaussian curve at the end of the discrete samples from reducing luminance
|
||||
for (NSUInteger currentGaussianWeightIndex = 0; currentGaussianWeightIndex < blurRadius + 1; currentGaussianWeightIndex++)
|
||||
{
|
||||
standardGaussianWeights[currentGaussianWeightIndex] = standardGaussianWeights[currentGaussianWeightIndex] / sumOfWeights;
|
||||
}
|
||||
|
||||
// From these weights we calculate the offsets to read interpolated values from
|
||||
NSUInteger numberOfOptimizedOffsets = MIN(blurRadius / 2 + (blurRadius % 2), 7);
|
||||
NSUInteger trueNumberOfOptimizedOffsets = blurRadius / 2 + (blurRadius % 2);
|
||||
|
||||
NSMutableString *shaderString = [[NSMutableString alloc] init];
|
||||
|
||||
// Header
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
uniform highp float texelWidthOffset;\n\
|
||||
uniform highp float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying highp vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
lowp vec4 sum = vec4(0.0);\n", (unsigned long)(1 + (numberOfOptimizedOffsets * 2)) ];
|
||||
#else
|
||||
[shaderString appendFormat:@"\
|
||||
uniform sampler2D inputImageTexture;\n\
|
||||
uniform float texelWidthOffset;\n\
|
||||
uniform float texelHeightOffset;\n\
|
||||
\n\
|
||||
varying vec2 blurCoordinates[%lu];\n\
|
||||
\n\
|
||||
void main()\n\
|
||||
{\n\
|
||||
vec4 sum = vec4(0.0);\n", 1 + (numberOfOptimizedOffsets * 2) ];
|
||||
#endif
|
||||
|
||||
// Inner texture loop
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0]) * %f;\n", standardGaussianWeights[0]];
|
||||
|
||||
for (NSUInteger currentBlurCoordinateIndex = 0; currentBlurCoordinateIndex < numberOfOptimizedOffsets; currentBlurCoordinateIndex++)
|
||||
{
|
||||
GLfloat firstWeight = standardGaussianWeights[currentBlurCoordinateIndex * 2 + 1];
|
||||
GLfloat secondWeight = standardGaussianWeights[currentBlurCoordinateIndex * 2 + 2];
|
||||
GLfloat optimizedWeight = firstWeight + secondWeight;
|
||||
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 1), optimizedWeight];
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[%lu]) * %f;\n", (unsigned long)((currentBlurCoordinateIndex * 2) + 2), optimizedWeight];
|
||||
}
|
||||
|
||||
// If the number of required samples exceeds the amount we can pass in via varyings, we have to do dependent texture reads in the fragment shader
|
||||
if (trueNumberOfOptimizedOffsets > numberOfOptimizedOffsets)
|
||||
{
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
[shaderString appendString:@"highp vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"];
|
||||
#else
|
||||
[shaderString appendString:@"vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);\n"];
|
||||
#endif
|
||||
|
||||
for (NSUInteger currentOverlowTextureRead = numberOfOptimizedOffsets; currentOverlowTextureRead < trueNumberOfOptimizedOffsets; currentOverlowTextureRead++)
|
||||
{
|
||||
GLfloat firstWeight = standardGaussianWeights[currentOverlowTextureRead * 2 + 1];
|
||||
GLfloat secondWeight = standardGaussianWeights[currentOverlowTextureRead * 2 + 2];
|
||||
|
||||
GLfloat optimizedWeight = firstWeight + secondWeight;
|
||||
GLfloat optimizedOffset = (firstWeight * (currentOverlowTextureRead * 2 + 1) + secondWeight * (currentOverlowTextureRead * 2 + 2)) / optimizedWeight;
|
||||
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] + singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
|
||||
[shaderString appendFormat:@"sum += texture2D(inputImageTexture, blurCoordinates[0] - singleStepOffset * %f) * %f;\n", optimizedOffset, optimizedWeight];
|
||||
}
|
||||
}
|
||||
|
||||
// Footer
|
||||
[shaderString appendString:@"\
|
||||
gl_FragColor = sum;\n\
|
||||
}\n"];
|
||||
|
||||
free(standardGaussianWeights);
|
||||
return shaderString;
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
[super setupFilterForSize:filterFrameSize];
|
||||
|
||||
if (shouldResizeBlurRadiusWithImageSize)
|
||||
{
|
||||
if (self.blurRadiusAsFractionOfImageWidth > 0)
|
||||
{
|
||||
self.blurRadiusInPixels = filterFrameSize.width * self.blurRadiusAsFractionOfImageWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.blurRadiusInPixels = filterFrameSize.height * self.blurRadiusAsFractionOfImageHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
[super renderToTextureWithVertices:vertices textureCoordinates:textureCoordinates];
|
||||
|
||||
for (NSUInteger currentAdditionalBlurPass = 1; currentAdditionalBlurPass < _blurPasses; currentAdditionalBlurPass++)
|
||||
{
|
||||
[super renderToTextureWithVertices:vertices textureCoordinates:[[self class] textureCoordinatesForRotation:kGPUImageNoRotation]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)switchToVertexShader:(NSString *)newVertexShader fragmentShader:(NSString *)newFragmentShader;
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
filterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:newVertexShader fragmentShaderString:newFragmentShader];
|
||||
|
||||
if (!filterProgram.initialized)
|
||||
{
|
||||
[self initializeAttributes];
|
||||
|
||||
if (![filterProgram link])
|
||||
{
|
||||
NSString *progLog = [filterProgram programLog];
|
||||
NSLog(@"Program link log: %@", progLog);
|
||||
NSString *fragLog = [filterProgram fragmentShaderLog];
|
||||
NSLog(@"Fragment shader compile log: %@", fragLog);
|
||||
NSString *vertLog = [filterProgram vertexShaderLog];
|
||||
NSLog(@"Vertex shader compile log: %@", vertLog);
|
||||
filterProgram = nil;
|
||||
NSAssert(NO, @"Filter shader link failed");
|
||||
}
|
||||
}
|
||||
|
||||
filterPositionAttribute = [filterProgram attributeIndex:@"position"];
|
||||
filterTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate"];
|
||||
filterInputTextureUniform = [filterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader
|
||||
verticalPassTexelWidthOffsetUniform = [filterProgram uniformIndex:@"texelWidthOffset"];
|
||||
verticalPassTexelHeightOffsetUniform = [filterProgram uniformIndex:@"texelHeightOffset"];
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
glEnableVertexAttribArray(filterPositionAttribute);
|
||||
glEnableVertexAttribArray(filterTextureCoordinateAttribute);
|
||||
|
||||
secondFilterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:newVertexShader fragmentShaderString:newFragmentShader];
|
||||
|
||||
if (!secondFilterProgram.initialized)
|
||||
{
|
||||
[self initializeSecondaryAttributes];
|
||||
|
||||
if (![secondFilterProgram link])
|
||||
{
|
||||
NSString *progLog = [secondFilterProgram programLog];
|
||||
NSLog(@"Program link log: %@", progLog);
|
||||
NSString *fragLog = [secondFilterProgram fragmentShaderLog];
|
||||
NSLog(@"Fragment shader compile log: %@", fragLog);
|
||||
NSString *vertLog = [secondFilterProgram vertexShaderLog];
|
||||
NSLog(@"Vertex shader compile log: %@", vertLog);
|
||||
secondFilterProgram = nil;
|
||||
NSAssert(NO, @"Filter shader link failed");
|
||||
}
|
||||
}
|
||||
|
||||
secondFilterPositionAttribute = [secondFilterProgram attributeIndex:@"position"];
|
||||
secondFilterTextureCoordinateAttribute = [secondFilterProgram attributeIndex:@"inputTextureCoordinate"];
|
||||
secondFilterInputTextureUniform = [secondFilterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader
|
||||
secondFilterInputTextureUniform2 = [secondFilterProgram uniformIndex:@"inputImageTexture2"]; // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader
|
||||
horizontalPassTexelWidthOffsetUniform = [secondFilterProgram uniformIndex:@"texelWidthOffset"];
|
||||
horizontalPassTexelHeightOffsetUniform = [secondFilterProgram uniformIndex:@"texelHeightOffset"];
|
||||
[GPUImageContext setActiveShaderProgram:secondFilterProgram];
|
||||
|
||||
glEnableVertexAttribArray(secondFilterPositionAttribute);
|
||||
glEnableVertexAttribArray(secondFilterTextureCoordinateAttribute);
|
||||
|
||||
[self setupFilterForSize:[self sizeOfFBO]];
|
||||
glFinish();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setTexelSpacingMultiplier:(CGFloat)newValue;
|
||||
{
|
||||
_texelSpacingMultiplier = newValue;
|
||||
|
||||
_verticalTexelSpacing = _texelSpacingMultiplier;
|
||||
_horizontalTexelSpacing = _texelSpacingMultiplier;
|
||||
|
||||
[self setupFilterForSize:[self sizeOfFBO]];
|
||||
}
|
||||
|
||||
// inputRadius for Core Image's CIGaussianBlur is really sigma in the Gaussian equation, so I'm using that for my blur radius, to be consistent
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
// 7.0 is the limit for blur size for hardcoded varying offsets
|
||||
|
||||
if (round(newValue) != _blurRadiusInPixels)
|
||||
{
|
||||
_blurRadiusInPixels = round(newValue); // For now, only do integral sigmas
|
||||
|
||||
NSUInteger calculatedSampleRadius = 0;
|
||||
if (_blurRadiusInPixels >= 1) // Avoid a divide-by-zero error here
|
||||
{
|
||||
// Calculate the number of pixels to sample from by setting a bottom limit for the contribution of the outermost pixel
|
||||
CGFloat minimumWeightToFindEdgeOfSamplingArea = 1.0/256.0;
|
||||
calculatedSampleRadius = floor(sqrt(-2.0 * pow(_blurRadiusInPixels, 2.0) * log(minimumWeightToFindEdgeOfSamplingArea * sqrt(2.0 * M_PI * pow(_blurRadiusInPixels, 2.0))) ));
|
||||
calculatedSampleRadius += calculatedSampleRadius % 2; // There's nothing to gain from handling odd radius sizes, due to the optimizations I use
|
||||
}
|
||||
|
||||
// NSLog(@"Blur radius: %f, calculated sample radius: %d", _blurRadiusInPixels, calculatedSampleRadius);
|
||||
//
|
||||
NSString *newGaussianBlurVertexShader = [[self class] vertexShaderForOptimizedBlurOfRadius:calculatedSampleRadius sigma:_blurRadiusInPixels];
|
||||
NSString *newGaussianBlurFragmentShader = [[self class] fragmentShaderForOptimizedBlurOfRadius:calculatedSampleRadius sigma:_blurRadiusInPixels];
|
||||
|
||||
// NSLog(@"Optimized vertex shader: \n%@", newGaussianBlurVertexShader);
|
||||
// NSLog(@"Optimized fragment shader: \n%@", newGaussianBlurFragmentShader);
|
||||
//
|
||||
[self switchToVertexShader:newGaussianBlurVertexShader fragmentShader:newGaussianBlurFragmentShader];
|
||||
}
|
||||
shouldResizeBlurRadiusWithImageSize = NO;
|
||||
}
|
||||
|
||||
- (void)setBlurRadiusAsFractionOfImageWidth:(CGFloat)blurRadiusAsFractionOfImageWidth
|
||||
{
|
||||
if (blurRadiusAsFractionOfImageWidth < 0) return;
|
||||
|
||||
shouldResizeBlurRadiusWithImageSize = _blurRadiusAsFractionOfImageWidth != blurRadiusAsFractionOfImageWidth && blurRadiusAsFractionOfImageWidth > 0;
|
||||
_blurRadiusAsFractionOfImageWidth = blurRadiusAsFractionOfImageWidth;
|
||||
_blurRadiusAsFractionOfImageHeight = 0;
|
||||
}
|
||||
|
||||
- (void)setBlurRadiusAsFractionOfImageHeight:(CGFloat)blurRadiusAsFractionOfImageHeight
|
||||
{
|
||||
if (blurRadiusAsFractionOfImageHeight < 0) return;
|
||||
|
||||
shouldResizeBlurRadiusWithImageSize = _blurRadiusAsFractionOfImageHeight != blurRadiusAsFractionOfImageHeight && blurRadiusAsFractionOfImageHeight > 0;
|
||||
_blurRadiusAsFractionOfImageHeight = blurRadiusAsFractionOfImageHeight;
|
||||
_blurRadiusAsFractionOfImageWidth = 0;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,232 +0,0 @@
|
||||
#import "GPUImageGaussianBlurPositionFilter.h"
|
||||
|
||||
NSString *const kGPUImageGaussianBlurPositionVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
const int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
|
||||
// Calculate the positions for the blur
|
||||
int multiplier = 0;
|
||||
vec2 blurStep;
|
||||
vec2 singleStepOffset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
|
||||
for (int i = 0; i < GAUSSIAN_SAMPLES; i++) {
|
||||
multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));
|
||||
// Blur in x (horizontal)
|
||||
blurStep = float(multiplier) * singleStepOffset;
|
||||
blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageGaussianBlurPositionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const lowp int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
uniform highp float aspectRatio;
|
||||
uniform lowp vec2 blurCenter;
|
||||
uniform highp float blurRadius;
|
||||
|
||||
void main() {
|
||||
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
highp float dist = distance(blurCenter, textureCoordinateToUse);
|
||||
|
||||
if (dist < blurRadius)
|
||||
{
|
||||
lowp vec4 sum = vec4(0.0);
|
||||
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[0]) * 0.05;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[1]) * 0.09;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[2]) * 0.12;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[3]) * 0.15;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[4]) * 0.18;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[5]) * 0.15;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[6]) * 0.12;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[7]) * 0.09;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[8]) * 0.05;
|
||||
|
||||
gl_FragColor = sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageGaussianBlurPositionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const int GAUSSIAN_SAMPLES = 9;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];
|
||||
|
||||
uniform float aspectRatio;
|
||||
uniform vec2 blurCenter;
|
||||
uniform float blurRadius;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
float dist = distance(blurCenter, textureCoordinateToUse);
|
||||
|
||||
if (dist < blurRadius)
|
||||
{
|
||||
vec4 sum = vec4(0.0);
|
||||
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[0]) * 0.05;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[1]) * 0.09;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[2]) * 0.12;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[3]) * 0.15;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[4]) * 0.18;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[5]) * 0.15;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[6]) * 0.12;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[7]) * 0.09;
|
||||
sum += texture2D(inputImageTexture, blurCoordinates[8]) * 0.05;
|
||||
|
||||
gl_FragColor = sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
}
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@interface GPUImageGaussianBlurPositionFilter ()
|
||||
|
||||
- (void)adjustAspectRatio;
|
||||
|
||||
@property (readwrite, nonatomic) CGFloat aspectRatio;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageGaussianBlurPositionFilter
|
||||
|
||||
@synthesize blurSize = _blurSize;
|
||||
@synthesize blurCenter = _blurCenter;
|
||||
@synthesize aspectRatio = _aspectRatio;
|
||||
|
||||
- (id) initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShaderString
|
||||
firstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString
|
||||
secondStageVertexShaderFromString:(NSString *)secondStageVertexShaderString
|
||||
secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString {
|
||||
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:firstStageVertexShaderString ? firstStageVertexShaderString : kGPUImageGaussianBlurPositionVertexShaderString
|
||||
firstStageFragmentShaderFromString:firstStageFragmentShaderString ? firstStageFragmentShaderString : kGPUImageGaussianBlurPositionFragmentShaderString
|
||||
secondStageVertexShaderFromString:secondStageVertexShaderString ? secondStageVertexShaderString : kGPUImageGaussianBlurPositionVertexShaderString
|
||||
secondStageFragmentShaderFromString:secondStageFragmentShaderString ? secondStageFragmentShaderString : kGPUImageGaussianBlurPositionFragmentShaderString])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
aspectRatioUniform = [secondFilterProgram uniformIndex:@"aspectRatio"];
|
||||
blurCenterUniform = [secondFilterProgram uniformIndex:@"blurCenter"];
|
||||
blurRadiusUniform = [secondFilterProgram uniformIndex:@"blurRadius"];
|
||||
|
||||
self.blurSize = 1.0;
|
||||
self.blurRadius = 1.0;
|
||||
self.blurCenter = CGPointMake(0.5, 0.5);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
return [self initWithFirstStageVertexShaderFromString:nil
|
||||
firstStageFragmentShaderFromString:nil
|
||||
secondStageVertexShaderFromString:nil
|
||||
secondStageFragmentShaderFromString:nil];
|
||||
}
|
||||
|
||||
- (void)adjustAspectRatio;
|
||||
{
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
[self setAspectRatio:(inputTextureSize.width / inputTextureSize.height)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setAspectRatio:(inputTextureSize.height / inputTextureSize.width)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)forceProcessingAtSize:(CGSize)frameSize;
|
||||
{
|
||||
[super forceProcessingAtSize:frameSize];
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
CGSize oldInputSize = inputTextureSize;
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
|
||||
if ( (!CGSizeEqualToSize(oldInputSize, inputTextureSize)) && (!CGSizeEqualToSize(newSize, CGSizeZero)) )
|
||||
{
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
[super setInputRotation:newInputRotation atIndex:textureIndex];
|
||||
[self setBlurCenter:self.blurCenter];
|
||||
[self adjustAspectRatio];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurSize:(CGFloat)newValue;
|
||||
{
|
||||
_blurSize = newValue;
|
||||
|
||||
_verticalTexelSpacing = _blurSize;
|
||||
_horizontalTexelSpacing = _blurSize;
|
||||
|
||||
[self setupFilterForSize:[self sizeOfFBO]];
|
||||
}
|
||||
|
||||
- (void) setBlurCenter:(CGPoint)blurCenter;
|
||||
{
|
||||
_blurCenter = blurCenter;
|
||||
CGPoint rotatedPoint = [self rotatedPoint:blurCenter forRotation:inputRotation];
|
||||
[self setPoint:rotatedPoint forUniform:blurCenterUniform program:secondFilterProgram];
|
||||
}
|
||||
|
||||
- (void) setBlurRadius:(CGFloat)blurRadius;
|
||||
{
|
||||
_blurRadius = blurRadius;
|
||||
|
||||
[self setFloat:_blurRadius forUniform:blurRadiusUniform program:secondFilterProgram];
|
||||
}
|
||||
|
||||
- (void) setAspectRatio:(CGFloat)newValue;
|
||||
{
|
||||
_aspectRatio = newValue;
|
||||
|
||||
[self setFloat:_aspectRatio forUniform:aspectRatioUniform program:secondFilterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,147 +0,0 @@
|
||||
#import "GPUImageGaussianSelectiveBlurFilter.h"
|
||||
#import "GPUImageGaussianBlurFilter.h"
|
||||
#import "GPUImageTwoInputFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageGaussianSelectiveBlurFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
uniform lowp float excludeCircleRadius;
|
||||
uniform lowp vec2 excludeCirclePoint;
|
||||
uniform lowp float excludeBlurSize;
|
||||
uniform highp float aspectRatio;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 sharpImageColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 blurredImageColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
highp vec2 textureCoordinateToUse = vec2(textureCoordinate2.x, (textureCoordinate2.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
highp float distanceFromCenter = distance(excludeCirclePoint, textureCoordinateToUse);
|
||||
|
||||
gl_FragColor = mix(sharpImageColor, blurredImageColor, smoothstep(excludeCircleRadius - excludeBlurSize, excludeCircleRadius, distanceFromCenter));
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageGaussianSelectiveBlurFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
uniform float excludeCircleRadius;
|
||||
uniform vec2 excludeCirclePoint;
|
||||
uniform float excludeBlurSize;
|
||||
uniform float aspectRatio;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 sharpImageColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 blurredImageColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
vec2 textureCoordinateToUse = vec2(textureCoordinate2.x, (textureCoordinate2.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
float distanceFromCenter = distance(excludeCirclePoint, textureCoordinateToUse);
|
||||
|
||||
gl_FragColor = mix(sharpImageColor, blurredImageColor, smoothstep(excludeCircleRadius - excludeBlurSize, excludeCircleRadius, distanceFromCenter));
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageGaussianSelectiveBlurFilter
|
||||
|
||||
@synthesize excludeCirclePoint = _excludeCirclePoint, excludeCircleRadius = _excludeCircleRadius, excludeBlurSize = _excludeBlurSize;
|
||||
@synthesize blurRadiusInPixels = _blurRadiusInPixels;
|
||||
@synthesize aspectRatio = _aspectRatio;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
hasOverriddenAspectRatio = NO;
|
||||
|
||||
// First pass: apply a variable Gaussian blur
|
||||
blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
|
||||
[self addFilter:blurFilter];
|
||||
|
||||
// Second pass: combine the blurred image with the original sharp one
|
||||
selectiveFocusFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromString:kGPUImageGaussianSelectiveBlurFragmentShaderString];
|
||||
[self addFilter:selectiveFocusFilter];
|
||||
|
||||
// Texture location 0 needs to be the sharp image for both the blur and the second stage processing
|
||||
[blurFilter addTarget:selectiveFocusFilter atTextureLocation:1];
|
||||
|
||||
// To prevent double updating of this filter, disable updates from the sharp image side
|
||||
self.initialFilters = [NSArray arrayWithObjects:blurFilter, selectiveFocusFilter, nil];
|
||||
self.terminalFilter = selectiveFocusFilter;
|
||||
|
||||
self.blurRadiusInPixels = 5.0;
|
||||
|
||||
self.excludeCircleRadius = 60.0/320.0;
|
||||
self.excludeCirclePoint = CGPointMake(0.5f, 0.5f);
|
||||
self.excludeBlurSize = 30.0/320.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
CGSize oldInputSize = inputTextureSize;
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
inputTextureSize = newSize;
|
||||
|
||||
if ( (!CGSizeEqualToSize(oldInputSize, inputTextureSize)) && (!hasOverriddenAspectRatio) && (!CGSizeEqualToSize(newSize, CGSizeZero)) )
|
||||
{
|
||||
_aspectRatio = (inputTextureSize.width / inputTextureSize.height);
|
||||
[selectiveFocusFilter setFloat:_aspectRatio forUniformName:@"aspectRatio"];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
blurFilter.blurRadiusInPixels = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurRadiusInPixels;
|
||||
{
|
||||
return blurFilter.blurRadiusInPixels;
|
||||
}
|
||||
|
||||
- (void)setExcludeCirclePoint:(CGPoint)newValue;
|
||||
{
|
||||
_excludeCirclePoint = newValue;
|
||||
[selectiveFocusFilter setPoint:newValue forUniformName:@"excludeCirclePoint"];
|
||||
}
|
||||
|
||||
- (void)setExcludeCircleRadius:(CGFloat)newValue;
|
||||
{
|
||||
_excludeCircleRadius = newValue;
|
||||
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeCircleRadius"];
|
||||
}
|
||||
|
||||
- (void)setExcludeBlurSize:(CGFloat)newValue;
|
||||
{
|
||||
_excludeBlurSize = newValue;
|
||||
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeBlurSize"];
|
||||
}
|
||||
|
||||
- (void)setAspectRatio:(CGFloat)newValue;
|
||||
{
|
||||
hasOverriddenAspectRatio = YES;
|
||||
_aspectRatio = newValue;
|
||||
[selectiveFocusFilter setFloat:_aspectRatio forUniformName:@"aspectRatio"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,106 +0,0 @@
|
||||
#import "GPUImageGlassSphereFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageGlassSphereFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp vec2 center;
|
||||
uniform highp float radius;
|
||||
uniform highp float aspectRatio;
|
||||
uniform highp float refractiveIndex;
|
||||
// uniform vec3 lightPosition;
|
||||
const highp vec3 lightPosition = vec3(-0.5, 0.5, 1.0);
|
||||
const highp vec3 ambientLightPosition = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
highp float distanceFromCenter = distance(center, textureCoordinateToUse);
|
||||
lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);
|
||||
|
||||
distanceFromCenter = distanceFromCenter / radius;
|
||||
|
||||
highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);
|
||||
highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));
|
||||
|
||||
highp vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);
|
||||
refractedVector.xy = -refractedVector.xy;
|
||||
|
||||
highp vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5).rgb;
|
||||
|
||||
// Grazing angle lighting
|
||||
highp float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition, sphereNormal), 0.0, 1.0), 0.25));
|
||||
finalSphereColor += lightingIntensity;
|
||||
|
||||
// Specular lighting
|
||||
lightingIntensity = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);
|
||||
lightingIntensity = pow(lightingIntensity, 15.0);
|
||||
finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;
|
||||
|
||||
gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageGlassSphereFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform float aspectRatio;
|
||||
uniform float refractiveIndex;
|
||||
// uniform vec3 lightPosition;
|
||||
const vec3 lightPosition = vec3(-0.5, 0.5, 1.0);
|
||||
const vec3 ambientLightPosition = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
float distanceFromCenter = distance(center, textureCoordinateToUse);
|
||||
float checkForPresenceWithinSphere = step(distanceFromCenter, radius);
|
||||
|
||||
distanceFromCenter = distanceFromCenter / radius;
|
||||
|
||||
float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);
|
||||
vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));
|
||||
|
||||
vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);
|
||||
refractedVector.xy = -refractedVector.xy;
|
||||
|
||||
vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5).rgb;
|
||||
|
||||
// Grazing angle lighting
|
||||
float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition, sphereNormal), 0.0, 1.0), 0.25));
|
||||
finalSphereColor += lightingIntensity;
|
||||
|
||||
// Specular lighting
|
||||
lightingIntensity = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);
|
||||
lightingIntensity = pow(lightingIntensity, 15.0);
|
||||
finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;
|
||||
|
||||
gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageGlassSphereFilter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageGlassSphereFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
#import "GPUImageGrayscaleFilter.h"
|
||||
|
||||
@implementation GPUImageGrayscaleFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLuminanceFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, W);
|
||||
|
||||
gl_FragColor = vec4(vec3(luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLuminanceFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, W);
|
||||
|
||||
gl_FragColor = vec4(vec3(luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
if (!currentlyReceivingMonochromeInput)
|
||||
{
|
||||
[super renderToTextureWithVertices:vertices textureCoordinates:textureCoordinates];
|
||||
}
|
||||
}
|
||||
|
||||
//- (void)setInputTexture:(GLuint)newInputTexture atIndex:(NSInteger)textureIndex;
|
||||
//{
|
||||
// [super setInputTexture:newInputTexture atIndex:textureIndex];
|
||||
// if (currentlyReceivingMonochromeInput)
|
||||
// {
|
||||
// [self notifyTargetsAboutNewOutputTexture];
|
||||
// }
|
||||
//}
|
||||
|
||||
//- (GLuint)textureForOutput;
|
||||
//{
|
||||
// if (currentlyReceivingMonochromeInput)
|
||||
// {
|
||||
// return filterSourceTexture;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return outputTexture;
|
||||
// }
|
||||
//}
|
||||
|
||||
- (BOOL)wantsMonochromeInput;
|
||||
{
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)providesMonochromeOutput;
|
||||
{
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
// TODO: Rewrite this based on the new GPUImageFilter implementation
|
||||
//- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
|
||||
//{
|
||||
// if (self.frameProcessingCompletionBlock != NULL)
|
||||
// {
|
||||
// self.frameProcessingCompletionBlock(self, frameTime);
|
||||
// }
|
||||
//
|
||||
// for (id<GPUImageInput> currentTarget in targets)
|
||||
// {
|
||||
// if (currentTarget != self.targetToIgnoreForUpdates)
|
||||
// {
|
||||
// NSInteger indexOfObject = [targets indexOfObject:currentTarget];
|
||||
// NSInteger textureIndex = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
//
|
||||
// if ([GPUImageContext supportsFastTextureUpload] && preparedToCaptureImage)
|
||||
// {
|
||||
// [self setInputTextureForTarget:currentTarget atIndex:textureIndex];
|
||||
// }
|
||||
//
|
||||
// if (currentlyReceivingMonochromeInput)
|
||||
// {
|
||||
// [currentTarget setInputRotation:inputRotation atIndex:textureIndex];
|
||||
//
|
||||
// CGSize sizeToRotate = [self outputFrameSize];
|
||||
// CGSize rotatedSize = sizeToRotate;
|
||||
// if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
// {
|
||||
// rotatedSize.width = sizeToRotate.height;
|
||||
// rotatedSize.height = sizeToRotate.width;
|
||||
// }
|
||||
// [currentTarget setInputSize:rotatedSize atIndex:textureIndex];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// [currentTarget setInputSize:[self outputFrameSize] atIndex:textureIndex];
|
||||
// }
|
||||
// [currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndex];
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLuminanceFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
-414
@@ -1,414 +0,0 @@
|
||||
#import "GPUImageHSBFilter.h"
|
||||
|
||||
@implementation GPUImageHSBFilter {
|
||||
float matrix[4][4];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self reset];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
identmat(matrix);
|
||||
[self _updateColorMatrix];
|
||||
}
|
||||
|
||||
- (void)rotateHue:(float)h {
|
||||
huerotatemat(matrix, h);
|
||||
[self _updateColorMatrix];
|
||||
}
|
||||
|
||||
- (void)adjustSaturation:(float)s {
|
||||
saturatemat(matrix, s);
|
||||
[self _updateColorMatrix];
|
||||
}
|
||||
|
||||
- (void)adjustBrightness:(float)b {
|
||||
cscalemat(matrix, b, b, b);
|
||||
[self _updateColorMatrix];
|
||||
}
|
||||
|
||||
- (void)_updateColorMatrix {
|
||||
GPUMatrix4x4 gpuMatrix;
|
||||
gpuMatrix.one.one = matrix[0][0];
|
||||
gpuMatrix.one.two = matrix[1][0];
|
||||
gpuMatrix.one.three = matrix[2][0];
|
||||
gpuMatrix.one.four = matrix[3][0];
|
||||
gpuMatrix.two.one = matrix[0][1];
|
||||
gpuMatrix.two.two = matrix[1][1];
|
||||
gpuMatrix.two.three = matrix[2][1];
|
||||
gpuMatrix.two.four = matrix[3][1];
|
||||
gpuMatrix.three.one = matrix[0][2];
|
||||
gpuMatrix.three.two = matrix[1][2];
|
||||
gpuMatrix.three.three = matrix[2][2];
|
||||
gpuMatrix.three.four = matrix[3][2];
|
||||
gpuMatrix.four.one = matrix[0][3];
|
||||
gpuMatrix.four.two = matrix[1][3];
|
||||
gpuMatrix.four.three = matrix[2][3];
|
||||
gpuMatrix.four.four = matrix[3][3];
|
||||
self.colorMatrix = gpuMatrix;
|
||||
}
|
||||
|
||||
#pragma mark - Matrix algorithms
|
||||
|
||||
/* Matrix algorithms adapted from http://www.graficaobscura.com/matrix/index.html
|
||||
|
||||
Note about luminance vector values below from that page:
|
||||
Where rwgt is 0.3086, gwgt is 0.6094, and bwgt is 0.0820. This is the luminance vector. Notice here that we do not use the standard NTSC weights of 0.299, 0.587, and 0.114. The NTSC weights are only applicable to RGB colors in a gamma 2.2 color space. For linear RGB colors the values above are better.
|
||||
*/
|
||||
//#define RLUM (0.3086f)
|
||||
//#define GLUM (0.6094f)
|
||||
//#define BLUM (0.0820f)
|
||||
|
||||
/* This is the vector value from the PDF specification, and may be closer to what Photoshop uses */
|
||||
#define RLUM (0.3f)
|
||||
#define GLUM (0.59f)
|
||||
#define BLUM (0.11f)
|
||||
|
||||
/*
|
||||
* matrixmult -
|
||||
* multiply two matricies
|
||||
*/
|
||||
static void matrixmult(a,b,c)
|
||||
float a[4][4], b[4][4], c[4][4];
|
||||
{
|
||||
int x, y;
|
||||
float temp[4][4];
|
||||
|
||||
for(y=0; y<4 ; y++)
|
||||
for(x=0 ; x<4 ; x++) {
|
||||
temp[y][x] = b[y][0] * a[0][x]
|
||||
+ b[y][1] * a[1][x]
|
||||
+ b[y][2] * a[2][x]
|
||||
+ b[y][3] * a[3][x];
|
||||
}
|
||||
for(y=0; y<4; y++)
|
||||
for(x=0; x<4; x++)
|
||||
c[y][x] = temp[y][x];
|
||||
}
|
||||
|
||||
/*
|
||||
* identmat -
|
||||
* make an identity matrix
|
||||
*/
|
||||
static void identmat(matrix)
|
||||
float matrix[4][4];
|
||||
{
|
||||
memset(matrix, 0, sizeof(float[4][4]));
|
||||
matrix[0][0] = 1.0f;
|
||||
matrix[1][1] = 1.0f;
|
||||
matrix[2][2] = 1.0f;
|
||||
matrix[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
* xformpnt -
|
||||
* transform a 3D point using a matrix
|
||||
*/
|
||||
static void xformpnt(matrix,x,y,z,tx,ty,tz)
|
||||
float matrix[4][4];
|
||||
float x,y,z;
|
||||
float *tx,*ty,*tz;
|
||||
{
|
||||
*tx = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + matrix[3][0];
|
||||
*ty = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + matrix[3][1];
|
||||
*tz = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + matrix[3][2];
|
||||
}
|
||||
|
||||
/*
|
||||
* cscalemat -
|
||||
* make a color scale marix
|
||||
*/
|
||||
static void cscalemat(mat,rscale,gscale,bscale)
|
||||
float mat[4][4];
|
||||
float rscale, gscale, bscale;
|
||||
{
|
||||
float mmat[4][4];
|
||||
|
||||
mmat[0][0] = rscale;
|
||||
mmat[0][1] = 0.0;
|
||||
mmat[0][2] = 0.0;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = 0.0;
|
||||
mmat[1][1] = gscale;
|
||||
mmat[1][2] = 0.0;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
|
||||
mmat[2][0] = 0.0;
|
||||
mmat[2][1] = 0.0;
|
||||
mmat[2][2] = bscale;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* saturatemat -
|
||||
* make a saturation marix
|
||||
*/
|
||||
static void saturatemat(mat,sat)
|
||||
float mat[4][4];
|
||||
float sat;
|
||||
{
|
||||
float mmat[4][4];
|
||||
float a, b, c, d, e, f, g, h, i;
|
||||
float rwgt, gwgt, bwgt;
|
||||
|
||||
rwgt = RLUM;
|
||||
gwgt = GLUM;
|
||||
bwgt = BLUM;
|
||||
|
||||
a = (1.0-sat)*rwgt + sat;
|
||||
b = (1.0-sat)*rwgt;
|
||||
c = (1.0-sat)*rwgt;
|
||||
d = (1.0-sat)*gwgt;
|
||||
e = (1.0-sat)*gwgt + sat;
|
||||
f = (1.0-sat)*gwgt;
|
||||
g = (1.0-sat)*bwgt;
|
||||
h = (1.0-sat)*bwgt;
|
||||
i = (1.0-sat)*bwgt + sat;
|
||||
mmat[0][0] = a;
|
||||
mmat[0][1] = b;
|
||||
mmat[0][2] = c;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = d;
|
||||
mmat[1][1] = e;
|
||||
mmat[1][2] = f;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
mmat[2][0] = g;
|
||||
mmat[2][1] = h;
|
||||
mmat[2][2] = i;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* xrotate -
|
||||
* rotate about the x (red) axis
|
||||
*/
|
||||
static void xrotatemat(mat,rs,rc)
|
||||
float mat[4][4];
|
||||
float rs, rc;
|
||||
{
|
||||
float mmat[4][4];
|
||||
|
||||
mmat[0][0] = 1.0;
|
||||
mmat[0][1] = 0.0;
|
||||
mmat[0][2] = 0.0;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = 0.0;
|
||||
mmat[1][1] = rc;
|
||||
mmat[1][2] = rs;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
mmat[2][0] = 0.0;
|
||||
mmat[2][1] = -rs;
|
||||
mmat[2][2] = rc;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* yrotate -
|
||||
* rotate about the y (green) axis
|
||||
*/
|
||||
static void yrotatemat(mat,rs,rc)
|
||||
float mat[4][4];
|
||||
float rs, rc;
|
||||
{
|
||||
float mmat[4][4];
|
||||
|
||||
mmat[0][0] = rc;
|
||||
mmat[0][1] = 0.0;
|
||||
mmat[0][2] = -rs;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = 0.0;
|
||||
mmat[1][1] = 1.0;
|
||||
mmat[1][2] = 0.0;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
mmat[2][0] = rs;
|
||||
mmat[2][1] = 0.0;
|
||||
mmat[2][2] = rc;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* zrotate -
|
||||
* rotate about the z (blue) axis
|
||||
*/
|
||||
static void zrotatemat(mat,rs,rc)
|
||||
float mat[4][4];
|
||||
float rs, rc;
|
||||
{
|
||||
float mmat[4][4];
|
||||
|
||||
mmat[0][0] = rc;
|
||||
mmat[0][1] = rs;
|
||||
mmat[0][2] = 0.0;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = -rs;
|
||||
mmat[1][1] = rc;
|
||||
mmat[1][2] = 0.0;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
mmat[2][0] = 0.0;
|
||||
mmat[2][1] = 0.0;
|
||||
mmat[2][2] = 1.0;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* zshear -
|
||||
* shear z using x and y.
|
||||
*/
|
||||
static void zshearmat(mat,dx,dy)
|
||||
float mat[4][4];
|
||||
float dx, dy;
|
||||
{
|
||||
float mmat[4][4];
|
||||
|
||||
mmat[0][0] = 1.0;
|
||||
mmat[0][1] = 0.0;
|
||||
mmat[0][2] = dx;
|
||||
mmat[0][3] = 0.0;
|
||||
|
||||
mmat[1][0] = 0.0;
|
||||
mmat[1][1] = 1.0;
|
||||
mmat[1][2] = dy;
|
||||
mmat[1][3] = 0.0;
|
||||
|
||||
mmat[2][0] = 0.0;
|
||||
mmat[2][1] = 0.0;
|
||||
mmat[2][2] = 1.0;
|
||||
mmat[2][3] = 0.0;
|
||||
|
||||
mmat[3][0] = 0.0;
|
||||
mmat[3][1] = 0.0;
|
||||
mmat[3][2] = 0.0;
|
||||
mmat[3][3] = 1.0;
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
/*
|
||||
* simplehuerotatemat -
|
||||
* simple hue rotation. This changes luminance
|
||||
*/
|
||||
//static void simplehuerotatemat(mat,rot)
|
||||
//float mat[4][4];
|
||||
//float rot;
|
||||
//{
|
||||
// float mag;
|
||||
// float xrs, xrc;
|
||||
// float yrs, yrc;
|
||||
// float zrs, zrc;
|
||||
//
|
||||
// /* rotate the grey vector into positive Z */
|
||||
// mag = sqrt(2.0);
|
||||
// xrs = 1.0/mag;
|
||||
// xrc = 1.0/mag;
|
||||
// xrotatemat(mat,xrs,xrc);
|
||||
//
|
||||
// mag = sqrt(3.0);
|
||||
// yrs = -1.0/mag;
|
||||
// yrc = sqrt(2.0)/mag;
|
||||
// yrotatemat(mat,yrs,yrc);
|
||||
//
|
||||
// /* rotate the hue */
|
||||
// zrs = sin(rot*M_PI/180.0);
|
||||
// zrc = cos(rot*M_PI/180.0);
|
||||
// zrotatemat(mat,zrs,zrc);
|
||||
//
|
||||
// /* rotate the grey vector back into place */
|
||||
// yrotatemat(mat,-yrs,yrc);
|
||||
// xrotatemat(mat,-xrs,xrc);
|
||||
//}
|
||||
|
||||
/*
|
||||
* huerotatemat -
|
||||
* rotate the hue, while maintaining luminance.
|
||||
*/
|
||||
static void huerotatemat(mat,rot)
|
||||
float mat[4][4];
|
||||
float rot;
|
||||
{
|
||||
float mmat[4][4];
|
||||
float mag;
|
||||
float lx, ly, lz;
|
||||
float xrs, xrc;
|
||||
float yrs, yrc;
|
||||
float zrs, zrc;
|
||||
float zsx, zsy;
|
||||
|
||||
identmat(mmat);
|
||||
|
||||
/* rotate the grey vector into positive Z */
|
||||
mag = sqrt(2.0);
|
||||
xrs = 1.0/mag;
|
||||
xrc = 1.0/mag;
|
||||
xrotatemat(mmat,xrs,xrc);
|
||||
mag = sqrt(3.0);
|
||||
yrs = -1.0/mag;
|
||||
yrc = sqrt(2.0)/mag;
|
||||
yrotatemat(mmat,yrs,yrc);
|
||||
|
||||
/* shear the space to make the luminance plane horizontal */
|
||||
xformpnt(mmat,RLUM,GLUM,BLUM,&lx,&ly,&lz);
|
||||
zsx = lx/lz;
|
||||
zsy = ly/lz;
|
||||
zshearmat(mmat,zsx,zsy);
|
||||
|
||||
/* rotate the hue */
|
||||
zrs = sin(rot*M_PI/180.0);
|
||||
zrc = cos(rot*M_PI/180.0);
|
||||
zrotatemat(mmat,zrs,zrc);
|
||||
|
||||
/* unshear the space to put the luminance plane back */
|
||||
zshearmat(mmat,-zsx,-zsy);
|
||||
|
||||
/* rotate the grey vector back into place */
|
||||
yrotatemat(mmat,-yrs,yrc);
|
||||
xrotatemat(mmat,-xrs,xrc);
|
||||
|
||||
matrixmult(mmat,mat,mat);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,79 +0,0 @@
|
||||
#import "GPUImageHalftoneFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHalftoneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp float fractionalWidthOfPixel;
|
||||
uniform highp float aspectRatio;
|
||||
uniform highp float dotScaling;
|
||||
|
||||
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec2 sampleDivisor = vec2(fractionalWidthOfPixel, fractionalWidthOfPixel / aspectRatio);
|
||||
|
||||
highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor) + 0.5 * sampleDivisor;
|
||||
highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
highp vec2 adjustedSamplePos = vec2(samplePos.x, (samplePos.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
highp float distanceFromSamplePoint = distance(adjustedSamplePos, textureCoordinateToUse);
|
||||
|
||||
lowp vec3 sampledColor = texture2D(inputImageTexture, samplePos ).rgb;
|
||||
highp float dotScaling = 1.0 - dot(sampledColor, W);
|
||||
|
||||
lowp float checkForPresenceWithinDot = 1.0 - step(distanceFromSamplePoint, (fractionalWidthOfPixel * 0.5) * dotScaling);
|
||||
|
||||
gl_FragColor = vec4(vec3(checkForPresenceWithinDot), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHalftoneFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform float fractionalWidthOfPixel;
|
||||
uniform float aspectRatio;
|
||||
uniform float dotScaling;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 sampleDivisor = vec2(fractionalWidthOfPixel, fractionalWidthOfPixel / aspectRatio);
|
||||
|
||||
vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor) + 0.5 * sampleDivisor;
|
||||
vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
vec2 adjustedSamplePos = vec2(samplePos.x, (samplePos.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
|
||||
float distanceFromSamplePoint = distance(adjustedSamplePos, textureCoordinateToUse);
|
||||
|
||||
vec3 sampledColor = texture2D(inputImageTexture, samplePos ).rgb;
|
||||
float dotScaling = 1.0 - dot(sampledColor, W);
|
||||
|
||||
float checkForPresenceWithinDot = 1.0 - step(distanceFromSamplePoint, (fractionalWidthOfPixel * 0.5) * dotScaling);
|
||||
|
||||
gl_FragColor = vec4(vec3(checkForPresenceWithinDot), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHalftoneFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageHalftoneFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.fractionalWidthOfAPixel = 0.01;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,99 +0,0 @@
|
||||
#import "GPUImageHardLightBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHardLightBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
highp float ra;
|
||||
if (2.0 * overlay.r < overlay.a) {
|
||||
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
} else {
|
||||
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
highp float ga;
|
||||
if (2.0 * overlay.g < overlay.a) {
|
||||
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
} else {
|
||||
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
highp float ba;
|
||||
if (2.0 * overlay.b < overlay.a) {
|
||||
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
} else {
|
||||
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(ra, ga, ba, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHardLightBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 base = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
float ra;
|
||||
if (2.0 * overlay.r < overlay.a) {
|
||||
ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
} else {
|
||||
ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
float ga;
|
||||
if (2.0 * overlay.g < overlay.a) {
|
||||
ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
} else {
|
||||
ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
float ba;
|
||||
if (2.0 * overlay.b < overlay.a) {
|
||||
ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
} else {
|
||||
ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(ra, ga, ba, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageHardLightBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageHardLightBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
#import "GPUImageHarrisCornerDetectionFilter.h"
|
||||
#import "GPUImageGaussianBlurFilter.h"
|
||||
#import "GPUImageXYDerivativeFilter.h"
|
||||
#import "GPUImageGrayscaleFilter.h"
|
||||
#import "GPUImageThresholdedNonMaximumSuppressionFilter.h"
|
||||
#import "GPUImageColorPackingFilter.h"
|
||||
#import "GPUImageGaussianBlurFilter.h"
|
||||
|
||||
@interface GPUImageHarrisCornerDetectionFilter()
|
||||
|
||||
- (void)extractCornerLocationsFromImageAtFrameTime:(CMTime)frameTime;
|
||||
|
||||
@end
|
||||
|
||||
// This is the Harris corner detector, as described in
|
||||
// C. Harris and M. Stephens. A Combined Corner and Edge Detector. Proc. Alvey Vision Conf., Univ. Manchester, pp. 147-151, 1988.
|
||||
|
||||
@implementation GPUImageHarrisCornerDetectionFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHarrisCornerDetectionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp float sensitivity;
|
||||
|
||||
const mediump float harrisConstant = 0.04;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
|
||||
mediump float derivativeSum = derivativeElements.x + derivativeElements.y;
|
||||
|
||||
mediump float zElement = (derivativeElements.z * 2.0) - 1.0;
|
||||
|
||||
// R = Ix^2 * Iy^2 - Ixy * Ixy - k * (Ix^2 + Iy^2)^2
|
||||
mediump float cornerness = derivativeElements.x * derivativeElements.y - (zElement * zElement) - harrisConstant * derivativeSum * derivativeSum;
|
||||
|
||||
gl_FragColor = vec4(vec3(cornerness * sensitivity), 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHarrisCornerDetectionFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float sensitivity;
|
||||
|
||||
const float harrisConstant = 0.04;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 derivativeElements = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
|
||||
float derivativeSum = derivativeElements.x + derivativeElements.y;
|
||||
|
||||
float zElement = (derivativeElements.z * 2.0) - 1.0;
|
||||
|
||||
// R = Ix^2 * Iy^2 - Ixy * Ixy - k * (Ix^2 + Iy^2)^2
|
||||
float cornerness = derivativeElements.x * derivativeElements.y - (zElement * zElement) - harrisConstant * derivativeSum * derivativeSum;
|
||||
|
||||
gl_FragColor = vec4(vec3(cornerness * sensitivity), 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@synthesize blurRadiusInPixels;
|
||||
@synthesize cornersDetectedBlock;
|
||||
@synthesize sensitivity = _sensitivity;
|
||||
@synthesize threshold = _threshold;
|
||||
@synthesize intermediateImages = _intermediateImages;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithCornerDetectionFragmentShader:kGPUImageHarrisCornerDetectionFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCornerDetectionFragmentShader:(NSString *)cornerDetectionFragmentShader;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
#ifdef DEBUGFEATUREDETECTION
|
||||
_intermediateImages = [[NSMutableArray alloc] init];
|
||||
#endif
|
||||
|
||||
// First pass: reduce to luminance and take the derivative of the luminance texture
|
||||
derivativeFilter = [[GPUImageXYDerivativeFilter alloc] init];
|
||||
[self addFilter:derivativeFilter];
|
||||
|
||||
#ifdef DEBUGFEATUREDETECTION
|
||||
__unsafe_unretained NSMutableArray *weakIntermediateImages = _intermediateImages;
|
||||
__unsafe_unretained GPUImageFilter *weakFilter = derivativeFilter;
|
||||
[derivativeFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
UIImage *intermediateImage = [weakFilter imageFromCurrentlyProcessedOutput];
|
||||
[weakIntermediateImages addObject:intermediateImage];
|
||||
}];
|
||||
#endif
|
||||
|
||||
// Second pass: blur the derivative
|
||||
blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
|
||||
[self addFilter:blurFilter];
|
||||
|
||||
#ifdef DEBUGFEATUREDETECTION
|
||||
weakFilter = blurFilter;
|
||||
[blurFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
UIImage *intermediateImage = [weakFilter imageFromCurrentlyProcessedOutput];
|
||||
[weakIntermediateImages addObject:intermediateImage];
|
||||
}];
|
||||
#endif
|
||||
|
||||
// Third pass: apply the Harris corner detection calculation
|
||||
harrisCornerDetectionFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromString:cornerDetectionFragmentShader];
|
||||
[self addFilter:harrisCornerDetectionFilter];
|
||||
|
||||
#ifdef DEBUGFEATUREDETECTION
|
||||
weakFilter = harrisCornerDetectionFilter;
|
||||
[harrisCornerDetectionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
UIImage *intermediateImage = [weakFilter imageFromCurrentlyProcessedOutput];
|
||||
[weakIntermediateImages addObject:intermediateImage];
|
||||
}];
|
||||
#endif
|
||||
|
||||
// Fourth pass: apply non-maximum suppression and thresholding to find the local maxima
|
||||
nonMaximumSuppressionFilter = [[GPUImageThresholdedNonMaximumSuppressionFilter alloc] init];
|
||||
[self addFilter:nonMaximumSuppressionFilter];
|
||||
|
||||
__unsafe_unretained GPUImageHarrisCornerDetectionFilter *weakSelf = self;
|
||||
#ifdef DEBUGFEATUREDETECTION
|
||||
weakFilter = nonMaximumSuppressionFilter;
|
||||
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
UIImage *intermediateImage = [weakFilter imageFromCurrentlyProcessedOutput];
|
||||
[weakIntermediateImages addObject:intermediateImage];
|
||||
|
||||
[weakSelf extractCornerLocationsFromImageAtFrameTime:frameTime];
|
||||
}];
|
||||
#else
|
||||
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime) {
|
||||
[weakSelf extractCornerLocationsFromImageAtFrameTime:frameTime];
|
||||
}];
|
||||
#endif
|
||||
|
||||
// Sixth pass: compress the thresholded points into the RGBA channels
|
||||
// colorPackingFilter = [[GPUImageColorPackingFilter alloc] init];
|
||||
// [self addFilter:colorPackingFilter];
|
||||
//
|
||||
//
|
||||
//#ifdef DEBUGFEATUREDETECTION
|
||||
// __unsafe_unretained GPUImageHarrisCornerDetectionFilter *weakSelf = self;
|
||||
// weakFilter = colorPackingFilter;
|
||||
// [colorPackingFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
// NSLog(@"Triggered response from compaction filter");
|
||||
//
|
||||
// UIImage *intermediateImage = [weakFilter imageFromCurrentlyProcessedOutput];
|
||||
// [weakIntermediateImages addObject:intermediateImage];
|
||||
//
|
||||
// [weakSelf extractCornerLocationsFromImageAtFrameTime:frameTime];
|
||||
// }];
|
||||
//#else
|
||||
// __unsafe_unretained GPUImageHarrisCornerDetectionFilter *weakSelf = self;
|
||||
// [colorPackingFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime) {
|
||||
// [weakSelf extractCornerLocationsFromImageAtFrameTime:frameTime];
|
||||
// }];
|
||||
//#endif
|
||||
|
||||
[derivativeFilter addTarget:blurFilter];
|
||||
[blurFilter addTarget:harrisCornerDetectionFilter];
|
||||
[harrisCornerDetectionFilter addTarget:nonMaximumSuppressionFilter];
|
||||
// [simpleThresholdFilter addTarget:colorPackingFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:derivativeFilter, nil];
|
||||
// self.terminalFilter = colorPackingFilter;
|
||||
self.terminalFilter = nonMaximumSuppressionFilter;
|
||||
|
||||
self.blurRadiusInPixels = 2.0;
|
||||
self.sensitivity = 5.0;
|
||||
self.threshold = 0.20;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
{
|
||||
free(rawImagePixels);
|
||||
free(cornersArray);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Corner extraction
|
||||
|
||||
- (void)extractCornerLocationsFromImageAtFrameTime:(CMTime)frameTime;
|
||||
{
|
||||
// we need a normal color texture for this filter
|
||||
NSAssert(self.outputTextureOptions.internalFormat == GL_RGBA, @"The output texture format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.outputTextureOptions.type == GL_UNSIGNED_BYTE, @"The type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
NSUInteger numberOfCorners = 0;
|
||||
CGSize imageSize = nonMaximumSuppressionFilter.outputFrameSize;
|
||||
|
||||
unsigned int imageByteSize = imageSize.width * imageSize.height * 4;
|
||||
|
||||
if (rawImagePixels == NULL)
|
||||
{
|
||||
rawImagePixels = (GLubyte *)malloc(imageByteSize);
|
||||
cornersArray = calloc(512 * 2, sizeof(GLfloat));
|
||||
}
|
||||
|
||||
glReadPixels(0, 0, (int)imageSize.width, (int)imageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
|
||||
|
||||
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
unsigned int imageWidth = imageSize.width * 4;
|
||||
|
||||
unsigned int currentByte = 0;
|
||||
unsigned int cornerStorageIndex = 0;
|
||||
while (currentByte < imageByteSize)
|
||||
{
|
||||
GLubyte colorByte = rawImagePixels[currentByte];
|
||||
|
||||
if (colorByte > 0)
|
||||
{
|
||||
unsigned int xCoordinate = currentByte % imageWidth;
|
||||
unsigned int yCoordinate = currentByte / imageWidth;
|
||||
|
||||
cornersArray[cornerStorageIndex++] = (CGFloat)(xCoordinate / 4) / imageSize.width;
|
||||
cornersArray[cornerStorageIndex++] = (CGFloat)(yCoordinate) / imageSize.height;
|
||||
numberOfCorners++;
|
||||
|
||||
numberOfCorners = MIN(numberOfCorners, 511);
|
||||
cornerStorageIndex = MIN(cornerStorageIndex, 1021);
|
||||
}
|
||||
currentByte +=4;
|
||||
}
|
||||
|
||||
CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
|
||||
NSLog(@"Processing time : %f ms", 1000.0 * currentFrameTime);
|
||||
|
||||
if (cornersDetectedBlock != NULL)
|
||||
{
|
||||
cornersDetectedBlock(cornersArray, numberOfCorners, frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)wantsMonochromeInput;
|
||||
{
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
|
||||
{
|
||||
blurFilter.blurRadiusInPixels = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)blurRadiusInPixels;
|
||||
{
|
||||
return blurFilter.blurRadiusInPixels;
|
||||
}
|
||||
|
||||
- (void)setSensitivity:(CGFloat)newValue;
|
||||
{
|
||||
_sensitivity = newValue;
|
||||
[harrisCornerDetectionFilter setFloat:newValue forUniformName:@"sensitivity"];
|
||||
}
|
||||
|
||||
- (void)setThreshold:(CGFloat)newValue;
|
||||
{
|
||||
nonMaximumSuppressionFilter.threshold = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)threshold;
|
||||
{
|
||||
return nonMaximumSuppressionFilter.threshold;
|
||||
}
|
||||
|
||||
@end
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
#import "GPUImageHazeFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHazeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform lowp float hazeDistance;
|
||||
uniform highp float slope;
|
||||
|
||||
void main()
|
||||
{
|
||||
//todo reconsider precision modifiers
|
||||
highp vec4 color = vec4(1.0);//todo reimplement as a parameter
|
||||
|
||||
highp float d = textureCoordinate.y * slope + hazeDistance;
|
||||
|
||||
highp vec4 c = texture2D(inputImageTexture, textureCoordinate) ; // consider using unpremultiply
|
||||
|
||||
c = (c - d * color) / (1.0 -d);
|
||||
|
||||
gl_FragColor = c; //consider using premultiply(c);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHazeFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform float hazeDistance;
|
||||
uniform float slope;
|
||||
|
||||
void main()
|
||||
{
|
||||
//todo reconsider precision modifiers
|
||||
vec4 color = vec4(1.0);//todo reimplement as a parameter
|
||||
|
||||
float d = textureCoordinate.y * slope + hazeDistance;
|
||||
|
||||
vec4 c = texture2D(inputImageTexture, textureCoordinate) ; // consider using unpremultiply
|
||||
|
||||
c = (c - d * color) / (1.0 -d);
|
||||
|
||||
gl_FragColor = c; //consider using premultiply(c);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation GPUImageHazeFilter
|
||||
|
||||
@synthesize distance = _distance;
|
||||
@synthesize slope = _slope;
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageHazeFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
distanceUniform = [filterProgram uniformIndex:@"hazeDistance"];
|
||||
slopeUniform = [filterProgram uniformIndex:@"slope"];
|
||||
|
||||
self.distance = 0.2;
|
||||
self.slope = 0.0;
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setDistance:(CGFloat)newValue;
|
||||
{
|
||||
_distance = newValue;
|
||||
|
||||
[self setFloat:_distance forUniform:distanceUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setSlope:(CGFloat)newValue;
|
||||
{
|
||||
_slope = newValue;
|
||||
|
||||
[self setFloat:_slope forUniform:slopeUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#import "GPUImageHighPassFilter.h"
|
||||
|
||||
@implementation GPUImageHighPassFilter
|
||||
|
||||
@synthesize filterStrength;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Start with a low pass filter to define the component to be removed
|
||||
lowPassFilter = [[GPUImageLowPassFilter alloc] init];
|
||||
[self addFilter:lowPassFilter];
|
||||
|
||||
// Take the difference of the current frame from the low pass filtered result to get the high pass
|
||||
differenceBlendFilter = [[GPUImageDifferenceBlendFilter alloc] init];
|
||||
[self addFilter:differenceBlendFilter];
|
||||
|
||||
// Texture location 0 needs to be the original image for the difference blend
|
||||
[lowPassFilter addTarget:differenceBlendFilter atTextureLocation:1];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:lowPassFilter, differenceBlendFilter, nil];
|
||||
self.terminalFilter = differenceBlendFilter;
|
||||
|
||||
self.filterStrength = 0.5;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setFilterStrength:(CGFloat)newValue;
|
||||
{
|
||||
lowPassFilter.filterStrength = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)filterStrength;
|
||||
{
|
||||
return lowPassFilter.filterStrength;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,93 +0,0 @@
|
||||
#import "GPUImageHighlightShadowFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHighlightShadowFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform lowp float shadows;
|
||||
uniform lowp float highlights;
|
||||
|
||||
const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump float luminance = dot(source.rgb, luminanceWeighting);
|
||||
|
||||
mediump float shadow = clamp((pow(luminance, 1.0/(shadows+1.0)) + (-0.76)*pow(luminance, 2.0/(shadows+1.0))) - luminance, 0.0, 1.0);
|
||||
mediump float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);
|
||||
lowp vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));
|
||||
|
||||
gl_FragColor = vec4(result.rgb, source.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHighlightShadowFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform float shadows;
|
||||
uniform float highlights;
|
||||
|
||||
const vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 source = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(source.rgb, luminanceWeighting);
|
||||
|
||||
float shadow = clamp((pow(luminance, 1.0/(shadows+1.0)) + (-0.76)*pow(luminance, 2.0/(shadows+1.0))) - luminance, 0.0, 1.0);
|
||||
float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);
|
||||
vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));
|
||||
|
||||
gl_FragColor = vec4(result.rgb, source.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHighlightShadowFilter
|
||||
|
||||
@synthesize shadows = _shadows;
|
||||
@synthesize highlights = _highlights;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageHighlightShadowFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
shadowsUniform = [filterProgram uniformIndex:@"shadows"];
|
||||
highlightsUniform = [filterProgram uniformIndex:@"highlights"];
|
||||
|
||||
self.shadows = 0.0;
|
||||
self.highlights = 1.0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setShadows:(CGFloat)newValue;
|
||||
{
|
||||
_shadows = newValue;
|
||||
|
||||
[self setFloat:_shadows forUniform:shadowsUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setHighlights:(CGFloat)newValue;
|
||||
{
|
||||
_highlights = newValue;
|
||||
|
||||
[self setFloat:_highlights forUniform:highlightsUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// GPUImageHighlightShadowTintFilter.h
|
||||
//
|
||||
//
|
||||
// Created by github.com/r3mus on 8/14/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import "GPUImageFilter.h"
|
||||
|
||||
@interface GPUImageHighlightShadowTintFilter : GPUImageFilter
|
||||
{
|
||||
GLint shadowTintIntensityUniform, highlightTintIntensityUniform, shadowTintColorUniform, highlightTintColorUniform;
|
||||
}
|
||||
|
||||
// The shadowTint and highlightTint colors specify what colors replace the dark and light areas of the image, respectively. The defaults for shadows are black, highlighs white.
|
||||
@property(readwrite, nonatomic) GLfloat shadowTintIntensity;
|
||||
@property(readwrite, nonatomic) GPUVector4 shadowTintColor;
|
||||
@property(readwrite, nonatomic) GLfloat highlightTintIntensity;
|
||||
@property(readwrite, nonatomic) GPUVector4 highlightTintColor;
|
||||
|
||||
- (void)setShadowTintColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
- (void)setHighlightTintColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
|
||||
@end
|
||||
@@ -1,136 +0,0 @@
|
||||
//
|
||||
// GPUImageHighlightShadowTintFilter.m
|
||||
//
|
||||
// Created by github.com/r3mus on 8/14/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import "GPUImageHighlightShadowTintFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUHighlightShadowTintFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision lowp float;
|
||||
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp float shadowTintIntensity;
|
||||
uniform lowp float highlightTintIntensity;
|
||||
uniform highp vec4 shadowTintColor;
|
||||
uniform highp vec4 highlightTintColor;
|
||||
|
||||
const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
highp float luminance = dot(textureColor.rgb, luminanceWeighting);
|
||||
|
||||
highp vec4 shadowResult = mix(textureColor, max(textureColor, vec4( mix(shadowTintColor.rgb, textureColor.rgb, luminance), textureColor.a)), shadowTintIntensity);
|
||||
highp vec4 highlightResult = mix(textureColor, min(shadowResult, vec4( mix(shadowResult.rgb, highlightTintColor.rgb, luminance), textureColor.a)), highlightTintIntensity);
|
||||
|
||||
gl_FragColor = vec4( mix(shadowResult.rgb, highlightResult.rgb, luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUHighlightShadowTintFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float shadowTintIntensity;
|
||||
uniform float highlightTintIntensity;
|
||||
uniform vec3 shadowTintColor;
|
||||
uniform vec3 highlightTintColor;
|
||||
|
||||
const vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, luminanceWeighting);
|
||||
|
||||
vec4 shadowResult = mix(textureColor, max(textureColor, vec4( mix(shadowTintColor.rgb, textureColor.rgb, luminance), textureColor.a)), shadowTintIntensity);
|
||||
vec4 highlightResult = mix(textureColor, min(shadowResult, vec4( mix(shadowResult.rgb, highlightTintColor.rgb, luminance), textureColor.a)), highlightTintIntensity);
|
||||
|
||||
gl_FragColor = vec4( mix(shadowResult.rgb, highlightResult.rgb, luminance), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
@implementation GPUImageHighlightShadowTintFilter
|
||||
|
||||
@synthesize shadowTintIntensity = _shadowTintIntensity;
|
||||
@synthesize highlightTintIntensity = _highlightTintIntensity;
|
||||
@synthesize shadowTintColor = _shadowTintColor;
|
||||
@synthesize highlightTintColor = _highlightTintColor;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUHighlightShadowTintFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
shadowTintIntensityUniform = [filterProgram uniformIndex:@"shadowTintIntensity"];
|
||||
highlightTintIntensityUniform = [filterProgram uniformIndex:@"highlightTintIntensity"];
|
||||
shadowTintColorUniform = [filterProgram uniformIndex:@"shadowTintColor"];
|
||||
highlightTintColorUniform = [filterProgram uniformIndex:@"highlightTintColor"];
|
||||
|
||||
self.shadowTintIntensity = 0.0f;
|
||||
self.highlightTintIntensity = 0.0f;
|
||||
self.shadowTintColor = (GPUVector4){1.0f, 0.0f, 0.0f, 1.0f};
|
||||
self.highlightTintColor = (GPUVector4){0.0f, 0.0f, 1.0f, 1.0f};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setShadowTintIntensity:(GLfloat)newValue
|
||||
{
|
||||
_shadowTintIntensity = newValue;
|
||||
|
||||
[self setFloat:_shadowTintIntensity forUniform:shadowTintIntensityUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setHighlightTintIntensity:(GLfloat)newValue
|
||||
{
|
||||
_highlightTintIntensity = newValue;
|
||||
|
||||
[self setFloat:_highlightTintIntensity forUniform:highlightTintIntensityUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setShadowTintColor:(GPUVector4)newValue;
|
||||
{
|
||||
_shadowTintColor = newValue;
|
||||
|
||||
[self setShadowTintColorRed:_shadowTintColor.one green:_shadowTintColor.two blue:_shadowTintColor.three alpha:_shadowTintColor.four];
|
||||
}
|
||||
|
||||
- (void)setHighlightTintColor:(GPUVector4)newValue;
|
||||
{
|
||||
_highlightTintColor = newValue;
|
||||
|
||||
[self setHighlightTintColorRed:_highlightTintColor.one green:_highlightTintColor.two blue:_highlightTintColor.three alpha:_highlightTintColor.four];
|
||||
}
|
||||
|
||||
- (void)setShadowTintColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
{
|
||||
GPUVector4 shadowTintColor = {redComponent, greenComponent, blueComponent, alphaComponent};
|
||||
|
||||
[self setVec4:shadowTintColor forUniform:shadowTintColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
- (void)setHighlightTintColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
{
|
||||
GPUVector4 highlightTintColor = {redComponent, greenComponent, blueComponent, alphaComponent};
|
||||
|
||||
[self setVec4:highlightTintColor forUniform:highlightTintColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,307 +0,0 @@
|
||||
//
|
||||
// GPUImageHistogramEqualizationFilter.m
|
||||
// FilterShowcase
|
||||
//
|
||||
// Created by Adam Marcus on 19/08/2014.
|
||||
// Copyright (c) 2014 Sunset Lake Software LLC. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GPUImageHistogramEqualizationFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageRedHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;
|
||||
|
||||
gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageRedHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;
|
||||
|
||||
gl_FragColor = vec4(redCurveValue, textureColor.g, textureColor.b, textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageGreenHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;
|
||||
|
||||
gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageGreenHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;
|
||||
|
||||
gl_FragColor = vec4(textureColor.r, greenCurveValue, textureColor.b, textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageBlueHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;
|
||||
|
||||
gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageBlueHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;
|
||||
|
||||
gl_FragColor = vec4(textureColor.r, textureColor.g, blueCurveValue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageRGBHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;
|
||||
lowp float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;
|
||||
lowp float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;
|
||||
|
||||
gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageRGBHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float redCurveValue = texture2D(inputImageTexture2, vec2(textureColor.r, 0.0)).r;
|
||||
float greenCurveValue = texture2D(inputImageTexture2, vec2(textureColor.g, 0.0)).g;
|
||||
float blueCurveValue = texture2D(inputImageTexture2, vec2(textureColor.b, 0.0)).b;
|
||||
|
||||
gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLuminanceHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
const lowp vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp float luminance = dot(textureColor.rgb, W);
|
||||
lowp float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r;
|
||||
lowp float deltaLuminance = newLuminance - luminance;
|
||||
|
||||
lowp float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0);
|
||||
lowp float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0);
|
||||
lowp float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0);
|
||||
|
||||
gl_FragColor = vec4(red, green, blue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLuminanceHistogramEqualizationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
float luminance = dot(textureColor.rgb, W);
|
||||
float newLuminance = texture2D(inputImageTexture2, vec2(luminance, 0.0)).r;
|
||||
float deltaLuminance = newLuminance - luminance;
|
||||
|
||||
float red = clamp(textureColor.r + deltaLuminance, 0.0, 1.0);
|
||||
float green = clamp(textureColor.g + deltaLuminance, 0.0, 1.0);
|
||||
float blue = clamp(textureColor.b + deltaLuminance, 0.0, 1.0);
|
||||
|
||||
gl_FragColor = vec4(red, green, blue, textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHistogramEqualizationFilter
|
||||
|
||||
@synthesize downsamplingFactor = _downsamplingFactor;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithHistogramType:kGPUImageHistogramRGB]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithHistogramType:(GPUImageHistogramType)newHistogramType
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
histogramFilter = [[GPUImageHistogramFilter alloc] initWithHistogramType:newHistogramType];
|
||||
[self addFilter:histogramFilter];
|
||||
|
||||
GLubyte dummyInput[4 * 256]; // NB: No way to initialise GPUImageRawDataInput without providing bytes
|
||||
rawDataInputFilter = [[GPUImageRawDataInput alloc] initWithBytes:dummyInput size:CGSizeMake(256.0, 1.0) pixelFormat:GPUPixelFormatBGRA type:GPUPixelTypeUByte];
|
||||
rawDataOutputFilter = [[GPUImageRawDataOutput alloc] initWithImageSize:CGSizeMake(256.0, 3.0) resultsInBGRAFormat:YES];
|
||||
|
||||
__unsafe_unretained GPUImageRawDataOutput *_rawDataOutputFilter = rawDataOutputFilter;
|
||||
__unsafe_unretained GPUImageRawDataInput *_rawDataInputFilter = rawDataInputFilter;
|
||||
[rawDataOutputFilter setNewFrameAvailableBlock:^{
|
||||
|
||||
unsigned int histogramBins[3][256];
|
||||
|
||||
[_rawDataOutputFilter lockFramebufferForReading];
|
||||
|
||||
GLubyte *data = [_rawDataOutputFilter rawBytesForImage];
|
||||
data += [_rawDataOutputFilter bytesPerRowInOutput];
|
||||
|
||||
histogramBins[0][0] = *data++;
|
||||
histogramBins[1][0] = *data++;
|
||||
histogramBins[2][0] = *data++;
|
||||
data++;
|
||||
|
||||
for (unsigned int x = 1; x < 256; x++) {
|
||||
histogramBins[0][x] = histogramBins[0][x-1] + *data++;
|
||||
histogramBins[1][x] = histogramBins[1][x-1] + *data++;
|
||||
histogramBins[2][x] = histogramBins[2][x-1] + *data++;
|
||||
data++;
|
||||
}
|
||||
|
||||
[_rawDataOutputFilter unlockFramebufferAfterReading];
|
||||
|
||||
GLubyte colorMapping[4 * 256];
|
||||
GLubyte *_colorMapping = colorMapping;
|
||||
|
||||
for (unsigned int x = 0; x < 256; x++) {
|
||||
*_colorMapping++ = (GLubyte) (((histogramBins[0][x] - histogramBins[0][0]) * 255) / histogramBins[0][255]);
|
||||
*_colorMapping++ = (GLubyte) (((histogramBins[1][x] - histogramBins[1][0]) * 255) / histogramBins[1][255]);
|
||||
*_colorMapping++ = (GLubyte) (((histogramBins[2][x] - histogramBins[2][0]) * 255) / histogramBins[2][255]);
|
||||
*_colorMapping++ = 255;
|
||||
}
|
||||
|
||||
_colorMapping = colorMapping;
|
||||
[_rawDataInputFilter updateDataFromBytes:_colorMapping size:CGSizeMake(256.0, 1.0)];
|
||||
[_rawDataInputFilter processData];
|
||||
}];
|
||||
[histogramFilter addTarget:rawDataOutputFilter];
|
||||
|
||||
NSString *fragmentShader = nil;
|
||||
switch (newHistogramType) {
|
||||
case kGPUImageHistogramRed:
|
||||
fragmentShader = kGPUImageRedHistogramEqualizationFragmentShaderString;
|
||||
break;
|
||||
case kGPUImageHistogramGreen:
|
||||
fragmentShader = kGPUImageGreenHistogramEqualizationFragmentShaderString;
|
||||
break;
|
||||
case kGPUImageHistogramBlue:
|
||||
fragmentShader = kGPUImageBlueHistogramEqualizationFragmentShaderString;
|
||||
break;
|
||||
default:
|
||||
case kGPUImageHistogramRGB:
|
||||
fragmentShader = kGPUImageRGBHistogramEqualizationFragmentShaderString;
|
||||
break;
|
||||
case kGPUImageHistogramLuminance:
|
||||
fragmentShader = kGPUImageLuminanceHistogramEqualizationFragmentShaderString;
|
||||
break;
|
||||
}
|
||||
GPUImageFilter *equalizationFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromString:fragmentShader];
|
||||
[rawDataInputFilter addTarget:equalizationFilter atTextureLocation:1];
|
||||
|
||||
[self addFilter:equalizationFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:histogramFilter, equalizationFilter, nil];
|
||||
self.terminalFilter = equalizationFilter;
|
||||
|
||||
self.downsamplingFactor = 16;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setDownsamplingFactor:(NSUInteger)newValue;
|
||||
{
|
||||
if (_downsamplingFactor != newValue)
|
||||
{
|
||||
_downsamplingFactor = newValue;
|
||||
histogramFilter.downsamplingFactor = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
-341
@@ -1,341 +0,0 @@
|
||||
#import "GPUImageHistogramFilter.h"
|
||||
|
||||
// Unlike other filters, this one uses a grid of GL_POINTs to sample the incoming image in a grid. A custom vertex shader reads the color in the texture at its position
|
||||
// and outputs a bin position in the final histogram as the vertex position. That point is then written into the image of the histogram using translucent pixels.
|
||||
// The degree of translucency is controlled by the scalingFactor, which lets you adjust the dynamic range of the histogram. The histogram can only be generated for one
|
||||
// color channel or luminance value at a time.
|
||||
//
|
||||
// This is based on this implementation: http://www.shaderwrangler.com/publications/histogram/histogram_cameraready.pdf
|
||||
//
|
||||
// Or at least that's how it would work if iOS could read from textures in a vertex shader, which it can't. Therefore, I read the texture data down from the
|
||||
// incoming frame and process the texture colors as vertices.
|
||||
|
||||
NSString *const kGPUImageRedHistogramSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
varying vec3 colorFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
colorFactor = vec3(1.0, 0.0, 0.0);
|
||||
gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);
|
||||
gl_PointSize = 1.0;
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageGreenHistogramSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
varying vec3 colorFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
colorFactor = vec3(0.0, 1.0, 0.0);
|
||||
gl_Position = vec4(-1.0 + (position.y * 0.0078125), 0.0, 0.0, 1.0);
|
||||
gl_PointSize = 1.0;
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageBlueHistogramSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
varying vec3 colorFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
colorFactor = vec3(0.0, 0.0, 1.0);
|
||||
gl_Position = vec4(-1.0 + (position.z * 0.0078125), 0.0, 0.0, 1.0);
|
||||
gl_PointSize = 1.0;
|
||||
}
|
||||
);
|
||||
|
||||
NSString *const kGPUImageLuminanceHistogramSamplingVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
varying vec3 colorFactor;
|
||||
|
||||
const vec3 W = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
void main()
|
||||
{
|
||||
float luminance = dot(position.xyz, W);
|
||||
|
||||
colorFactor = vec3(1.0, 1.0, 1.0);
|
||||
gl_Position = vec4(-1.0 + (luminance * 0.0078125), 0.0, 0.0, 1.0);
|
||||
gl_PointSize = 1.0;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHistogramAccumulationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
const lowp float scalingFactor = 1.0 / 256.0;
|
||||
|
||||
varying lowp vec3 colorFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(colorFactor * scalingFactor , 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHistogramAccumulationFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
const float scalingFactor = 1.0 / 256.0;
|
||||
|
||||
varying vec3 colorFactor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(colorFactor * scalingFactor , 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHistogramFilter
|
||||
|
||||
@synthesize downsamplingFactor = _downsamplingFactor;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)initWithHistogramType:(GPUImageHistogramType)newHistogramType;
|
||||
{
|
||||
switch (newHistogramType)
|
||||
{
|
||||
case kGPUImageHistogramRed:
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageRedHistogramSamplingVertexShaderString fragmentShaderFromString:kGPUImageHistogramAccumulationFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}; break;
|
||||
case kGPUImageHistogramGreen:
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageGreenHistogramSamplingVertexShaderString fragmentShaderFromString:kGPUImageHistogramAccumulationFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}; break;
|
||||
case kGPUImageHistogramBlue:
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageBlueHistogramSamplingVertexShaderString fragmentShaderFromString:kGPUImageHistogramAccumulationFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}; break;
|
||||
case kGPUImageHistogramLuminance:
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageLuminanceHistogramSamplingVertexShaderString fragmentShaderFromString:kGPUImageHistogramAccumulationFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}; break;
|
||||
case kGPUImageHistogramRGB:
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageRedHistogramSamplingVertexShaderString fragmentShaderFromString:kGPUImageHistogramAccumulationFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
secondFilterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageGreenHistogramSamplingVertexShaderString fragmentShaderString:kGPUImageHistogramAccumulationFragmentShaderString];
|
||||
thirdFilterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageBlueHistogramSamplingVertexShaderString fragmentShaderString:kGPUImageHistogramAccumulationFragmentShaderString];
|
||||
|
||||
if (!secondFilterProgram.initialized)
|
||||
{
|
||||
[self initializeSecondaryAttributes];
|
||||
|
||||
if (![secondFilterProgram link])
|
||||
{
|
||||
NSString *progLog = [secondFilterProgram programLog];
|
||||
NSLog(@"Program link log: %@", progLog);
|
||||
NSString *fragLog = [secondFilterProgram fragmentShaderLog];
|
||||
NSLog(@"Fragment shader compile log: %@", fragLog);
|
||||
NSString *vertLog = [secondFilterProgram vertexShaderLog];
|
||||
NSLog(@"Vertex shader compile log: %@", vertLog);
|
||||
filterProgram = nil;
|
||||
NSAssert(NO, @"Filter shader link failed");
|
||||
|
||||
}
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:secondFilterProgram];
|
||||
|
||||
glEnableVertexAttribArray(secondFilterPositionAttribute);
|
||||
|
||||
if (![thirdFilterProgram link])
|
||||
{
|
||||
NSString *progLog = [secondFilterProgram programLog];
|
||||
NSLog(@"Program link log: %@", progLog);
|
||||
NSString *fragLog = [secondFilterProgram fragmentShaderLog];
|
||||
NSLog(@"Fragment shader compile log: %@", fragLog);
|
||||
NSString *vertLog = [secondFilterProgram vertexShaderLog];
|
||||
NSLog(@"Vertex shader compile log: %@", vertLog);
|
||||
filterProgram = nil;
|
||||
NSAssert(NO, @"Filter shader link failed");
|
||||
}
|
||||
}
|
||||
|
||||
secondFilterPositionAttribute = [secondFilterProgram attributeIndex:@"position"];
|
||||
|
||||
|
||||
thirdFilterPositionAttribute = [thirdFilterProgram attributeIndex:@"position"];
|
||||
[GPUImageContext setActiveShaderProgram:thirdFilterProgram];
|
||||
|
||||
glEnableVertexAttribArray(thirdFilterPositionAttribute);
|
||||
});
|
||||
}; break;
|
||||
}
|
||||
|
||||
histogramType = newHistogramType;
|
||||
|
||||
self.downsamplingFactor = 16;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [self initWithHistogramType:kGPUImageHistogramRGB]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initializeSecondaryAttributes;
|
||||
{
|
||||
[secondFilterProgram addAttribute:@"position"];
|
||||
[thirdFilterProgram addAttribute:@"position"];
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
{
|
||||
if (vertexSamplingCoordinates != NULL && ![GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
free(vertexSamplingCoordinates);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (CGSize)sizeOfFBO;
|
||||
{
|
||||
return CGSizeMake(256.0, 3.0);
|
||||
}
|
||||
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
[self renderToTextureWithVertices:NULL textureCoordinates:NULL];
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
}
|
||||
|
||||
- (CGSize)outputFrameSize;
|
||||
{
|
||||
return [self sizeOfFBO];
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
inputTextureSize = newSize;
|
||||
}
|
||||
|
||||
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
inputRotation = kGPUImageNoRotation;
|
||||
}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
// we need a normal color texture for this filter
|
||||
NSAssert(self.outputTextureOptions.internalFormat == GL_RGBA, @"The output texture format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.outputTextureOptions.type == GL_UNSIGNED_BYTE, @"The type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
if (self.preventRendering)
|
||||
{
|
||||
[firstInputFramebuffer unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
[GPUImageContext useImageProcessingContext];
|
||||
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
glFinish();
|
||||
vertexSamplingCoordinates = [firstInputFramebuffer byteBuffer];
|
||||
} else {
|
||||
if (vertexSamplingCoordinates == NULL)
|
||||
{
|
||||
vertexSamplingCoordinates = calloc(inputTextureSize.width * inputTextureSize.height * 4, sizeof(GLubyte));
|
||||
}
|
||||
glReadPixels(0, 0, inputTextureSize.width, inputTextureSize.height, GL_RGBA, GL_UNSIGNED_BYTE, vertexSamplingCoordinates);
|
||||
}
|
||||
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
[outputFramebuffer lock];
|
||||
}
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 4, GL_UNSIGNED_BYTE, 0, ((unsigned int)_downsamplingFactor - 1) * 4, vertexSamplingCoordinates);
|
||||
glDrawArrays(GL_POINTS, 0, inputTextureSize.width * inputTextureSize.height / (CGFloat)_downsamplingFactor);
|
||||
|
||||
if (histogramType == kGPUImageHistogramRGB)
|
||||
{
|
||||
[GPUImageContext setActiveShaderProgram:secondFilterProgram];
|
||||
|
||||
glVertexAttribPointer(secondFilterPositionAttribute, 4, GL_UNSIGNED_BYTE, 0, ((unsigned int)_downsamplingFactor - 1) * 4, vertexSamplingCoordinates);
|
||||
glDrawArrays(GL_POINTS, 0, inputTextureSize.width * inputTextureSize.height / (CGFloat)_downsamplingFactor);
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:thirdFilterProgram];
|
||||
|
||||
glVertexAttribPointer(thirdFilterPositionAttribute, 4, GL_UNSIGNED_BYTE, 0, ((unsigned int)_downsamplingFactor - 1) * 4, vertexSamplingCoordinates);
|
||||
glDrawArrays(GL_POINTS, 0, inputTextureSize.width * inputTextureSize.height / (CGFloat)_downsamplingFactor);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
[firstInputFramebuffer unlock];
|
||||
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
//- (void)setScalingFactor:(CGFloat)newValue;
|
||||
//{
|
||||
// _scalingFactor = newValue;
|
||||
//
|
||||
// [GPUImageContext useImageProcessingContext];
|
||||
// [filterProgram use];
|
||||
// glUniform1f(scalingFactorUniform, _scalingFactor);
|
||||
//}
|
||||
|
||||
@end
|
||||
@@ -1,87 +0,0 @@
|
||||
#import "GPUImageHistogramGenerator.h"
|
||||
|
||||
NSString *const kGPUImageHistogramGeneratorVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying float height;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
textureCoordinate = vec2(inputTextureCoordinate.x, 0.5);
|
||||
height = 1.0 - inputTextureCoordinate.y;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHistogramGeneratorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp float height;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform lowp vec4 backgroundColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec3 colorChannels = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
lowp vec4 heightTest = vec4(step(height, colorChannels), 1.0);
|
||||
gl_FragColor = mix(backgroundColor, heightTest, heightTest.r + heightTest.g + heightTest.b);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHistogramGeneratorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying float height;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform vec4 backgroundColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 colorChannels = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
vec4 heightTest = vec4(step(height, colorChannels), 1.0);
|
||||
gl_FragColor = mix(backgroundColor, heightTest, heightTest.r + heightTest.g + heightTest.b);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHistogramGenerator
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageHistogramGeneratorVertexShaderString fragmentShaderFromString:kGPUImageHistogramGeneratorFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
backgroundColorUniform = [filterProgram uniformIndex:@"backgroundColor"];
|
||||
|
||||
[self setBackgroundColorRed:0.0 green:0.0 blue:0.0 alpha:0.0];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
|
||||
{
|
||||
// GLfloat backgroundColor[4];
|
||||
// backgroundColor[0] = redComponent;
|
||||
// backgroundColor[1] = greenComponent;
|
||||
// backgroundColor[2] = blueComponent;
|
||||
// backgroundColor[3] = alphaComponent;
|
||||
GPUVector4 backgroundColor = {redComponent, greenComponent, blueComponent, alphaComponent};
|
||||
|
||||
[self setVec4:backgroundColor forUniform:backgroundColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,241 +0,0 @@
|
||||
#import "GPUImageHoughTransformLineDetector.h"
|
||||
|
||||
@interface GPUImageHoughTransformLineDetector()
|
||||
|
||||
- (void)extractLineParametersFromImageAtFrameTime:(CMTime)frameTime;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageHoughTransformLineDetector
|
||||
|
||||
@synthesize linesDetectedBlock;
|
||||
@synthesize edgeThreshold;
|
||||
@synthesize lineDetectionThreshold;
|
||||
@synthesize intermediateImages = _intermediateImages;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// First pass: do edge detection and threshold that to just have white pixels for edges
|
||||
// if ([GPUImageContext deviceSupportsFramebufferReads])
|
||||
// if ([GPUImageContext deviceSupportsFramebufferReads])
|
||||
// {
|
||||
// thresholdEdgeDetectionFilter = [[GPUImageThresholdEdgeDetectionFilter alloc] init];
|
||||
// thresholdEdgeDetectionFilter = [[GPUImageSobelEdgeDetectionFilter alloc] init];
|
||||
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setThreshold:0.07];
|
||||
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setEdgeStrength:0.25];
|
||||
// [(GPUImageThresholdEdgeDetectionFilter *)thresholdEdgeDetectionFilter setEdgeStrength:1.0];
|
||||
// thresholdEdgeDetectionFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
thresholdEdgeDetectionFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
|
||||
// }
|
||||
[self addFilter:thresholdEdgeDetectionFilter];
|
||||
|
||||
// Second pass: extract the white points and draw representative lines in parallel coordinate space
|
||||
parallelCoordinateLineTransformFilter = [[GPUImageParallelCoordinateLineTransformFilter alloc] init];
|
||||
[self addFilter:parallelCoordinateLineTransformFilter];
|
||||
|
||||
// Third pass: apply non-maximum suppression
|
||||
if ([GPUImageContext deviceSupportsFramebufferReads])
|
||||
{
|
||||
nonMaximumSuppressionFilter = [[GPUImageThresholdedNonMaximumSuppressionFilter alloc] initWithPackedColorspace:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
nonMaximumSuppressionFilter = [[GPUImageThresholdedNonMaximumSuppressionFilter alloc] initWithPackedColorspace:NO];
|
||||
}
|
||||
[self addFilter:nonMaximumSuppressionFilter];
|
||||
|
||||
__unsafe_unretained GPUImageHoughTransformLineDetector *weakSelf = self;
|
||||
#ifdef DEBUGLINEDETECTION
|
||||
_intermediateImages = [[NSMutableArray alloc] init];
|
||||
__unsafe_unretained NSMutableArray *weakIntermediateImages = _intermediateImages;
|
||||
|
||||
// __unsafe_unretained GPUImageOutput<GPUImageInput> *weakEdgeDetectionFilter = thresholdEdgeDetectionFilter;
|
||||
// [thresholdEdgeDetectionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
// [weakIntermediateImages removeAllObjects];
|
||||
// UIImage *intermediateImage = [weakEdgeDetectionFilter imageFromCurrentFramebuffer];
|
||||
// [weakIntermediateImages addObject:intermediateImage];
|
||||
// }];
|
||||
//
|
||||
// __unsafe_unretained GPUImageOutput<GPUImageInput> *weakParallelCoordinateLineTransformFilter = parallelCoordinateLineTransformFilter;
|
||||
// [parallelCoordinateLineTransformFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
// UIImage *intermediateImage = [weakParallelCoordinateLineTransformFilter imageFromCurrentFramebuffer];
|
||||
// [weakIntermediateImages addObject:intermediateImage];
|
||||
// }];
|
||||
|
||||
__unsafe_unretained GPUImageOutput<GPUImageInput> *weakNonMaximumSuppressionFilter = nonMaximumSuppressionFilter;
|
||||
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime){
|
||||
UIImage *intermediateImage = [weakNonMaximumSuppressionFilter imageFromCurrentFramebuffer];
|
||||
[weakIntermediateImages addObject:intermediateImage];
|
||||
|
||||
[weakSelf extractLineParametersFromImageAtFrameTime:frameTime];
|
||||
}];
|
||||
#else
|
||||
[nonMaximumSuppressionFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *filter, CMTime frameTime) {
|
||||
[weakSelf extractLineParametersFromImageAtFrameTime:frameTime];
|
||||
}];
|
||||
#endif
|
||||
|
||||
[thresholdEdgeDetectionFilter addTarget:parallelCoordinateLineTransformFilter];
|
||||
[parallelCoordinateLineTransformFilter addTarget:nonMaximumSuppressionFilter];
|
||||
|
||||
self.initialFilters = [NSArray arrayWithObjects:thresholdEdgeDetectionFilter, nil];
|
||||
// self.terminalFilter = colorPackingFilter;
|
||||
self.terminalFilter = nonMaximumSuppressionFilter;
|
||||
|
||||
// self.edgeThreshold = 0.95;
|
||||
self.lineDetectionThreshold = 0.12;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc;
|
||||
{
|
||||
free(rawImagePixels);
|
||||
free(linesArray);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Corner extraction
|
||||
|
||||
- (void)extractLineParametersFromImageAtFrameTime:(CMTime)frameTime;
|
||||
{
|
||||
// we need a normal color texture for this filter
|
||||
NSAssert(self.outputTextureOptions.internalFormat == GL_RGBA, @"The output texture format for this filter must be GL_RGBA.");
|
||||
NSAssert(self.outputTextureOptions.type == GL_UNSIGNED_BYTE, @"The type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
|
||||
|
||||
NSUInteger numberOfLines = 0;
|
||||
CGSize imageSize = nonMaximumSuppressionFilter.outputFrameSize;
|
||||
|
||||
unsigned int imageByteSize = imageSize.width * imageSize.height * 4;
|
||||
|
||||
if (rawImagePixels == NULL)
|
||||
{
|
||||
rawImagePixels = (GLubyte *)malloc(imageByteSize);
|
||||
linesArray = calloc(1024 * 2, sizeof(GLfloat));
|
||||
}
|
||||
|
||||
glReadPixels(0, 0, (int)imageSize.width, (int)imageSize.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
|
||||
|
||||
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
|
||||
unsigned int imageWidth = imageSize.width * 4;
|
||||
|
||||
unsigned int currentByte = 0;
|
||||
unsigned int cornerStorageIndex = 0;
|
||||
unsigned long lineStrengthCounter = 0;
|
||||
while (currentByte < imageByteSize)
|
||||
{
|
||||
GLubyte colorByte = rawImagePixels[currentByte];
|
||||
// NSLog(@"(%d,%d): [%d,%d,%d,%d]", xCoordinate, yCoordinate, rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
|
||||
// NSLog(@"[%d,%d,%d,%d]", rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
|
||||
|
||||
if (colorByte > 0)
|
||||
{
|
||||
unsigned int xCoordinate = currentByte % imageWidth;
|
||||
unsigned int yCoordinate = currentByte / imageWidth;
|
||||
|
||||
lineStrengthCounter += colorByte;
|
||||
// NSLog(@"(%d,%d): [%d,%d,%d,%d]", xCoordinate, yCoordinate, rawImagePixels[currentByte], rawImagePixels[currentByte+1], rawImagePixels[currentByte+2], rawImagePixels[currentByte+3]);
|
||||
|
||||
CGFloat normalizedXCoordinate = -1.0 + 2.0 * (CGFloat)(xCoordinate / 4) / imageSize.width;
|
||||
CGFloat normalizedYCoordinate = -1.0 + 2.0 * (CGFloat)(yCoordinate) / imageSize.height;
|
||||
|
||||
if (normalizedXCoordinate < 0.0)
|
||||
{
|
||||
// T space
|
||||
// m = -1 - d/u
|
||||
// b = d * v/u
|
||||
if (normalizedXCoordinate > -0.05) // Test for the case right near the X axis, stamp the X intercept instead of the Y
|
||||
{
|
||||
linesArray[cornerStorageIndex++] = 100000.0;
|
||||
linesArray[cornerStorageIndex++] = normalizedYCoordinate;
|
||||
}
|
||||
else
|
||||
{
|
||||
linesArray[cornerStorageIndex++] = -1.0 - 1.0 / normalizedXCoordinate;
|
||||
linesArray[cornerStorageIndex++] = 1.0 * normalizedYCoordinate / normalizedXCoordinate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// S space
|
||||
// m = 1 - d/u
|
||||
// b = d * v/u
|
||||
if (normalizedXCoordinate < 0.05) // Test for the case right near the X axis, stamp the X intercept instead of the Y
|
||||
{
|
||||
linesArray[cornerStorageIndex++] = 100000.0;
|
||||
linesArray[cornerStorageIndex++] = normalizedYCoordinate;
|
||||
}
|
||||
else
|
||||
{
|
||||
linesArray[cornerStorageIndex++] = 1.0 - 1.0 / normalizedXCoordinate;
|
||||
linesArray[cornerStorageIndex++] = 1.0 * normalizedYCoordinate / normalizedXCoordinate;
|
||||
}
|
||||
}
|
||||
|
||||
numberOfLines++;
|
||||
|
||||
numberOfLines = MIN(numberOfLines, 1023);
|
||||
cornerStorageIndex = MIN(cornerStorageIndex, 2040);
|
||||
}
|
||||
currentByte +=4;
|
||||
}
|
||||
|
||||
// CFAbsoluteTime currentFrameTime = (CFAbsoluteTimeGetCurrent() - startTime);
|
||||
// NSLog(@"Processing time : %f ms", 1000.0 * currentFrameTime);
|
||||
|
||||
if (linesDetectedBlock != NULL)
|
||||
{
|
||||
linesDetectedBlock(linesArray, numberOfLines, frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)wantsMonochromeInput;
|
||||
{
|
||||
// return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
//- (void)setEdgeThreshold:(CGFloat)newValue;
|
||||
//{
|
||||
// [(GPUImageCannyEdgeDetectionFilter *)thresholdEdgeDetectionFilter setThreshold:newValue];
|
||||
//}
|
||||
//
|
||||
//- (CGFloat)edgeThreshold;
|
||||
//{
|
||||
// return [(GPUImageCannyEdgeDetectionFilter *)thresholdEdgeDetectionFilter threshold];
|
||||
//}
|
||||
|
||||
- (void)setLineDetectionThreshold:(CGFloat)newValue;
|
||||
{
|
||||
nonMaximumSuppressionFilter.threshold = newValue;
|
||||
}
|
||||
|
||||
- (CGFloat)lineDetectionThreshold;
|
||||
{
|
||||
return nonMaximumSuppressionFilter.threshold;
|
||||
}
|
||||
|
||||
#ifdef DEBUGLINEDETECTION
|
||||
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
// [thresholdEdgeDetectionFilter useNextFrameForImageCapture];
|
||||
// [parallelCoordinateLineTransformFilter useNextFrameForImageCapture];
|
||||
[nonMaximumSuppressionFilter useNextFrameForImageCapture];
|
||||
|
||||
[super newFrameReadyAtTime:frameTime atIndex:textureIndex];
|
||||
}
|
||||
#endif
|
||||
|
||||
@end
|
||||
-212
@@ -1,212 +0,0 @@
|
||||
#import "GPUImageHueBlendFilter.h"
|
||||
|
||||
/**
|
||||
* Hue blend mode based upon pseudo code from the PDF specification.
|
||||
*/
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHueBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
highp float lum(lowp vec3 c) {
|
||||
return dot(c, vec3(0.3, 0.59, 0.11));
|
||||
}
|
||||
|
||||
lowp vec3 clipcolor(lowp vec3 c) {
|
||||
highp float l = lum(c);
|
||||
lowp float n = min(min(c.r, c.g), c.b);
|
||||
lowp float x = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (n < 0.0) {
|
||||
c.r = l + ((c.r - l) * l) / (l - n);
|
||||
c.g = l + ((c.g - l) * l) / (l - n);
|
||||
c.b = l + ((c.b - l) * l) / (l - n);
|
||||
}
|
||||
if (x > 1.0) {
|
||||
c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);
|
||||
c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);
|
||||
c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
lowp vec3 setlum(lowp vec3 c, highp float l) {
|
||||
highp float d = l - lum(c);
|
||||
c = c + vec3(d);
|
||||
return clipcolor(c);
|
||||
}
|
||||
|
||||
highp float sat(lowp vec3 c) {
|
||||
lowp float n = min(min(c.r, c.g), c.b);
|
||||
lowp float x = max(max(c.r, c.g), c.b);
|
||||
return x - n;
|
||||
}
|
||||
|
||||
lowp float mid(lowp float cmin, lowp float cmid, lowp float cmax, highp float s) {
|
||||
return ((cmid - cmin) * s) / (cmax - cmin);
|
||||
}
|
||||
|
||||
lowp vec3 setsat(lowp vec3 c, highp float s) {
|
||||
if (c.r > c.g) {
|
||||
if (c.r > c.b) {
|
||||
if (c.g > c.b) {
|
||||
/* g is mid, b is min */
|
||||
c.g = mid(c.b, c.g, c.r, s);
|
||||
c.b = 0.0;
|
||||
} else {
|
||||
/* b is mid, g is min */
|
||||
c.b = mid(c.g, c.b, c.r, s);
|
||||
c.g = 0.0;
|
||||
}
|
||||
c.r = s;
|
||||
} else {
|
||||
/* b is max, r is mid, g is min */
|
||||
c.r = mid(c.g, c.r, c.b, s);
|
||||
c.b = s;
|
||||
c.r = 0.0;
|
||||
}
|
||||
} else if (c.r > c.b) {
|
||||
/* g is max, r is mid, b is min */
|
||||
c.r = mid(c.b, c.r, c.g, s);
|
||||
c.g = s;
|
||||
c.b = 0.0;
|
||||
} else if (c.g > c.b) {
|
||||
/* g is max, b is mid, r is min */
|
||||
c.b = mid(c.r, c.b, c.g, s);
|
||||
c.g = s;
|
||||
c.r = 0.0;
|
||||
} else if (c.b > c.g) {
|
||||
/* b is max, g is mid, r is min */
|
||||
c.g = mid(c.r, c.g, c.b, s);
|
||||
c.b = s;
|
||||
c.r = 0.0;
|
||||
} else {
|
||||
c = vec3(0.0);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(setsat(overlayColor.rgb, sat(baseColor.rgb)), lum(baseColor.rgb)) * overlayColor.a, baseColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHueBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
float lum(vec3 c) {
|
||||
return dot(c, vec3(0.3, 0.59, 0.11));
|
||||
}
|
||||
|
||||
vec3 clipcolor(vec3 c) {
|
||||
float l = lum(c);
|
||||
float n = min(min(c.r, c.g), c.b);
|
||||
float x = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (n < 0.0) {
|
||||
c.r = l + ((c.r - l) * l) / (l - n);
|
||||
c.g = l + ((c.g - l) * l) / (l - n);
|
||||
c.b = l + ((c.b - l) * l) / (l - n);
|
||||
}
|
||||
if (x > 1.0) {
|
||||
c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);
|
||||
c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);
|
||||
c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3 setlum(vec3 c, float l) {
|
||||
float d = l - lum(c);
|
||||
c = c + vec3(d);
|
||||
return clipcolor(c);
|
||||
}
|
||||
|
||||
float sat(vec3 c) {
|
||||
float n = min(min(c.r, c.g), c.b);
|
||||
float x = max(max(c.r, c.g), c.b);
|
||||
return x - n;
|
||||
}
|
||||
|
||||
float mid(float cmin, float cmid, float cmax, float s) {
|
||||
return ((cmid - cmin) * s) / (cmax - cmin);
|
||||
}
|
||||
|
||||
vec3 setsat(vec3 c, float s) {
|
||||
if (c.r > c.g) {
|
||||
if (c.r > c.b) {
|
||||
if (c.g > c.b) {
|
||||
/* g is mid, b is min */
|
||||
c.g = mid(c.b, c.g, c.r, s);
|
||||
c.b = 0.0;
|
||||
} else {
|
||||
/* b is mid, g is min */
|
||||
c.b = mid(c.g, c.b, c.r, s);
|
||||
c.g = 0.0;
|
||||
}
|
||||
c.r = s;
|
||||
} else {
|
||||
/* b is max, r is mid, g is min */
|
||||
c.r = mid(c.g, c.r, c.b, s);
|
||||
c.b = s;
|
||||
c.r = 0.0;
|
||||
}
|
||||
} else if (c.r > c.b) {
|
||||
/* g is max, r is mid, b is min */
|
||||
c.r = mid(c.b, c.r, c.g, s);
|
||||
c.g = s;
|
||||
c.b = 0.0;
|
||||
} else if (c.g > c.b) {
|
||||
/* g is max, b is mid, r is min */
|
||||
c.b = mid(c.r, c.b, c.g, s);
|
||||
c.g = s;
|
||||
c.r = 0.0;
|
||||
} else if (c.b > c.g) {
|
||||
/* b is max, g is mid, r is min */
|
||||
c.g = mid(c.r, c.g, c.b, s);
|
||||
c.b = s;
|
||||
c.r = 0.0;
|
||||
} else {
|
||||
c = vec3(0.0);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(setsat(overlayColor.rgb, sat(baseColor.rgb)), lum(baseColor.rgb)) * overlayColor.a, baseColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHueBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageHueBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
-123
@@ -1,123 +0,0 @@
|
||||
|
||||
#import "GPUImageHueFilter.h"
|
||||
|
||||
// Adapted from http://stackoverflow.com/questions/9234724/how-to-change-hue-of-a-texture-with-glsl - see for code and discussion
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageHueFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform mediump float hueAdjust;
|
||||
const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
|
||||
const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
|
||||
const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);
|
||||
|
||||
const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
|
||||
const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
|
||||
const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);
|
||||
|
||||
void main ()
|
||||
{
|
||||
// Sample the input pixel
|
||||
highp vec4 color = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
// Convert to YIQ
|
||||
highp float YPrime = dot (color, kRGBToYPrime);
|
||||
highp float I = dot (color, kRGBToI);
|
||||
highp float Q = dot (color, kRGBToQ);
|
||||
|
||||
// Calculate the hue and chroma
|
||||
highp float hue = atan (Q, I);
|
||||
highp float chroma = sqrt (I * I + Q * Q);
|
||||
|
||||
// Make the user's adjustments
|
||||
hue += (-hueAdjust); //why negative rotation?
|
||||
|
||||
// Convert back to YIQ
|
||||
Q = chroma * sin (hue);
|
||||
I = chroma * cos (hue);
|
||||
|
||||
// Convert back to RGB
|
||||
highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
|
||||
color.r = dot (yIQ, kYIQToR);
|
||||
color.g = dot (yIQ, kYIQToG);
|
||||
color.b = dot (yIQ, kYIQToB);
|
||||
|
||||
// Save the result
|
||||
gl_FragColor = color;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageHueFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform float hueAdjust;
|
||||
const vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
|
||||
const vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);
|
||||
const vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);
|
||||
|
||||
const vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);
|
||||
const vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);
|
||||
const vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);
|
||||
|
||||
void main ()
|
||||
{
|
||||
// Sample the input pixel
|
||||
vec4 color = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
// Convert to YIQ
|
||||
float YPrime = dot (color, kRGBToYPrime);
|
||||
float I = dot (color, kRGBToI);
|
||||
float Q = dot (color, kRGBToQ);
|
||||
|
||||
// Calculate the hue and chroma
|
||||
float hue = atan (Q, I);
|
||||
float chroma = sqrt (I * I + Q * Q);
|
||||
|
||||
// Make the user's adjustments
|
||||
hue += (-hueAdjust); //why negative rotation?
|
||||
|
||||
// Convert back to YIQ
|
||||
Q = chroma * sin (hue);
|
||||
I = chroma * cos (hue);
|
||||
|
||||
// Convert back to RGB
|
||||
vec4 yIQ = vec4 (YPrime, I, Q, 0.0);
|
||||
color.r = dot (yIQ, kYIQToR);
|
||||
color.g = dot (yIQ, kYIQToG);
|
||||
color.b = dot (yIQ, kYIQToB);
|
||||
|
||||
// Save the result
|
||||
gl_FragColor = color;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageHueFilter
|
||||
@synthesize hue;
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if(! (self = [super initWithFragmentShaderFromString:kGPUImageHueFragmentShaderString]) )
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
hueAdjustUniform = [filterProgram uniformIndex:@"hueAdjust"];
|
||||
self.hue = 90;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setHue:(CGFloat)newHue
|
||||
{
|
||||
// Convert degrees to radians for hue rotation
|
||||
hue = fmodf(newHue, 360.0) * M_PI/180;
|
||||
[self setFloat:hue forUniform:hueAdjustUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,446 +0,0 @@
|
||||
// adapted from unitzeroone - http://unitzeroone.com/labs/jfavoronoi/
|
||||
|
||||
#import "GPUImageJFAVoronoiFilter.h"
|
||||
|
||||
// The shaders are mostly taken from UnitZeroOne's WebGL example here:
|
||||
// http://unitzeroone.com/blog/2011/03/22/jump-flood-voronoi-for-webgl/
|
||||
|
||||
NSString *const kGPUImageJFAVoronoiVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec4 inputTextureCoordinate;
|
||||
|
||||
uniform float sampleStep;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 widthStep = vec2(sampleStep, 0.0);
|
||||
vec2 heightStep = vec2(0.0, sampleStep);
|
||||
vec2 widthHeightStep = vec2(sampleStep);
|
||||
vec2 widthNegativeHeightStep = vec2(sampleStep, -sampleStep);
|
||||
|
||||
textureCoordinate = inputTextureCoordinate.xy;
|
||||
leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;
|
||||
rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;
|
||||
|
||||
topTextureCoordinate = inputTextureCoordinate.xy - heightStep;
|
||||
topLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;
|
||||
topRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;
|
||||
|
||||
bottomTextureCoordinate = inputTextureCoordinate.xy + heightStep;
|
||||
bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;
|
||||
bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageJFAVoronoiFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform vec2 size;
|
||||
//varying vec2 textureCoordinate;
|
||||
//uniform float sampleStep;
|
||||
|
||||
vec2 getCoordFromColor(vec4 color)
|
||||
{
|
||||
float z = color.z * 256.0;
|
||||
float yoff = floor(z / 8.0);
|
||||
float xoff = mod(z, 8.0);
|
||||
float x = color.x*256.0 + xoff*256.0;
|
||||
float y = color.y*256.0 + yoff*256.0;
|
||||
return vec2(x,y) / size;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
vec2 sub;
|
||||
vec4 dst;
|
||||
vec4 local = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 sam;
|
||||
float l;
|
||||
float smallestDist;
|
||||
if(local.a == 0.0){
|
||||
|
||||
smallestDist = dot(1.0,1.0);
|
||||
}else{
|
||||
sub = getCoordFromColor(local)-textureCoordinate;
|
||||
smallestDist = dot(sub,sub);
|
||||
}
|
||||
dst = local;
|
||||
|
||||
|
||||
sam = texture2D(inputImageTexture, topRightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, topTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, topLeftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomRightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomLeftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, leftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, rightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
gl_FragColor = dst;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageJFAVoronoiFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform vec2 size;
|
||||
//varying vec2 textureCoordinate;
|
||||
//uniform float sampleStep;
|
||||
|
||||
vec2 getCoordFromColor(vec4 color)
|
||||
{
|
||||
float z = color.z * 256.0;
|
||||
float yoff = floor(z / 8.0);
|
||||
float xoff = mod(z, 8.0);
|
||||
float x = color.x*256.0 + xoff*256.0;
|
||||
float y = color.y*256.0 + yoff*256.0;
|
||||
return vec2(x,y) / size;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
||||
vec2 sub;
|
||||
vec4 dst;
|
||||
vec4 local = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 sam;
|
||||
float l;
|
||||
float smallestDist;
|
||||
if(local.a == 0.0){
|
||||
|
||||
smallestDist = dot(1.0,1.0);
|
||||
}else{
|
||||
sub = getCoordFromColor(local)-textureCoordinate;
|
||||
smallestDist = dot(sub,sub);
|
||||
}
|
||||
dst = local;
|
||||
|
||||
|
||||
sam = texture2D(inputImageTexture, topRightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, topTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, topLeftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomRightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, bottomLeftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, leftTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
|
||||
sam = texture2D(inputImageTexture, rightTextureCoordinate);
|
||||
if(sam.a == 1.0){
|
||||
sub = (getCoordFromColor(sam)-textureCoordinate);
|
||||
l = dot(sub,sub);
|
||||
if(l < smallestDist){
|
||||
smallestDist = l;
|
||||
dst = sam;
|
||||
}
|
||||
}
|
||||
gl_FragColor = dst;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@interface GPUImageJFAVoronoiFilter() {
|
||||
int currentPass;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageJFAVoronoiFilter
|
||||
|
||||
@synthesize sizeInPixels = _sizeInPixels;
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageJFAVoronoiVertexShaderString fragmentShaderFromString:kGPUImageJFAVoronoiFragmentShaderString]))
|
||||
{
|
||||
|
||||
NSLog(@"nil returned");
|
||||
return nil;
|
||||
|
||||
}
|
||||
|
||||
sampleStepUniform = [filterProgram uniformIndex:@"sampleStep"];
|
||||
sizeUniform = [filterProgram uniformIndex:@"size"];
|
||||
//[self disableSecondFrameCheck];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setSizeInPixels:(CGSize)sizeInPixels {
|
||||
_sizeInPixels = sizeInPixels;
|
||||
|
||||
//validate that it's a power of 2
|
||||
|
||||
float width = log2(sizeInPixels.width);
|
||||
float height = log2(sizeInPixels.height);
|
||||
|
||||
if (width != height) {
|
||||
NSLog(@"Voronoi point texture must be square");
|
||||
return;
|
||||
}
|
||||
if (width != floor(width) || height != floor(height)) {
|
||||
NSLog(@"Voronoi point texture must be a power of 2. Texture size: %f, %f", sizeInPixels.width, sizeInPixels.height);
|
||||
return;
|
||||
}
|
||||
glUniform2f(sizeUniform, _sizeInPixels.width, _sizeInPixels.height);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Managing the display FBOs
|
||||
|
||||
-(NSUInteger)nextPowerOfTwo:(CGPoint)input {
|
||||
NSUInteger val;
|
||||
if (input.x > input.y) {
|
||||
val = (NSUInteger)input.x;
|
||||
} else {
|
||||
val = (NSUInteger)input.y;
|
||||
}
|
||||
|
||||
val--;
|
||||
val = (val >> 1) | val;
|
||||
val = (val >> 2) | val;
|
||||
val = (val >> 4) | val;
|
||||
val = (val >> 8) | val;
|
||||
val = (val >> 16) | val;
|
||||
val++;
|
||||
return val;
|
||||
}
|
||||
|
||||
//- (void)setOutputFBO;
|
||||
//{
|
||||
// if (currentPass % 2 == 1) {
|
||||
// [self setSecondFilterFBO];
|
||||
// } else {
|
||||
// [self setFilterFBO];
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
// Run the first stage of the two-pass filter
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
currentPass = 0;
|
||||
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glUniform1f(sampleStepUniform, 0.5);
|
||||
|
||||
glUniform2f(sizeUniform, _sizeInPixels.width, _sizeInPixels.height);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
|
||||
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
for (int pass = 1; pass <= numPasses + 1; pass++) {
|
||||
currentPass = pass;
|
||||
// [self setOutputFBO];
|
||||
|
||||
//glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
if (pass % 2 == 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, secondFilterOutputTexture);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
|
||||
}
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
float step = pow(2.0, numPasses - pass) / pow(2.0, numPasses);
|
||||
glUniform1f(sampleStepUniform, step);
|
||||
glUniform2f(sizeUniform, _sizeInPixels.width, _sizeInPixels.height);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
-223
@@ -1,223 +0,0 @@
|
||||
#import "GPUImageKuwaharaFilter.h"
|
||||
|
||||
// Sourced from Kyprianidis, J. E., Kang, H., and Doellner, J. "Anisotropic Kuwahara Filtering on the GPU," GPU Pro p.247 (2010).
|
||||
//
|
||||
// Original header:
|
||||
//
|
||||
// Anisotropic Kuwahara Filtering on the GPU
|
||||
// by Jan Eric Kyprianidis <www.kyprianidis.com>
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageKuwaharaFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform int radius;
|
||||
|
||||
precision highp float;
|
||||
|
||||
const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec2 uv = textureCoordinate;
|
||||
float n = float((radius + 1) * (radius + 1));
|
||||
int i; int j;
|
||||
vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
|
||||
vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
|
||||
vec3 c;
|
||||
|
||||
for (j = -radius; j <= 0; ++j) {
|
||||
for (i = -radius; i <= 0; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = -radius; j <= 0; ++j) {
|
||||
for (i = 0; i <= radius; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j <= radius; ++j) {
|
||||
for (i = 0; i <= radius; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j <= radius; ++j) {
|
||||
for (i = -radius; i <= 0; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float min_sigma2 = 1e+2;
|
||||
m0 /= n;
|
||||
s0 = abs(s0 / n - m0 * m0);
|
||||
|
||||
float sigma2 = s0.r + s0.g + s0.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m0, 1.0);
|
||||
}
|
||||
|
||||
m1 /= n;
|
||||
s1 = abs(s1 / n - m1 * m1);
|
||||
|
||||
sigma2 = s1.r + s1.g + s1.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m1, 1.0);
|
||||
}
|
||||
|
||||
m2 /= n;
|
||||
s2 = abs(s2 / n - m2 * m2);
|
||||
|
||||
sigma2 = s2.r + s2.g + s2.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m2, 1.0);
|
||||
}
|
||||
|
||||
m3 /= n;
|
||||
s3 = abs(s3 / n - m3 * m3);
|
||||
|
||||
sigma2 = s3.r + s3.g + s3.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m3, 1.0);
|
||||
}
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageKuwaharaFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform int radius;
|
||||
|
||||
const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec2 uv = textureCoordinate;
|
||||
float n = float((radius + 1) * (radius + 1));
|
||||
int i; int j;
|
||||
vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
|
||||
vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
|
||||
vec3 c;
|
||||
|
||||
for (j = -radius; j <= 0; ++j) {
|
||||
for (i = -radius; i <= 0; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = -radius; j <= 0; ++j) {
|
||||
for (i = 0; i <= radius; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j <= radius; ++j) {
|
||||
for (i = 0; i <= radius; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j <= radius; ++j) {
|
||||
for (i = -radius; i <= 0; ++i) {
|
||||
c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float min_sigma2 = 1e+2;
|
||||
m0 /= n;
|
||||
s0 = abs(s0 / n - m0 * m0);
|
||||
|
||||
float sigma2 = s0.r + s0.g + s0.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m0, 1.0);
|
||||
}
|
||||
|
||||
m1 /= n;
|
||||
s1 = abs(s1 / n - m1 * m1);
|
||||
|
||||
sigma2 = s1.r + s1.g + s1.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m1, 1.0);
|
||||
}
|
||||
|
||||
m2 /= n;
|
||||
s2 = abs(s2 / n - m2 * m2);
|
||||
|
||||
sigma2 = s2.r + s2.g + s2.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m2, 1.0);
|
||||
}
|
||||
|
||||
m3 /= n;
|
||||
s3 = abs(s3 / n - m3 * m3);
|
||||
|
||||
sigma2 = s3.r + s3.g + s3.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m3, 1.0);
|
||||
}
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageKuwaharaFilter
|
||||
|
||||
@synthesize radius = _radius;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageKuwaharaFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
radiusUniform = [filterProgram uniformIndex:@"radius"];
|
||||
|
||||
self.radius = 3;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setRadius:(NSUInteger)newValue;
|
||||
{
|
||||
_radius = newValue;
|
||||
|
||||
[self setInteger:(GLint)_radius forUniform:radiusUniform program:filterProgram];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,547 +0,0 @@
|
||||
#import "GPUImageKuwaharaRadius3Filter.h"
|
||||
|
||||
// Sourced from Kyprianidis, J. E., Kang, H., and Doellner, J. "Anisotropic Kuwahara Filtering on the GPU," GPU Pro p.247 (2010).
|
||||
//
|
||||
// Original header:
|
||||
//
|
||||
// Anisotropic Kuwahara Filtering on the GPU
|
||||
// by Jan Eric Kyprianidis <www.kyprianidis.com>
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageKuwaharaRadius3FragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
precision highp float;
|
||||
|
||||
const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec2 uv = textureCoordinate;
|
||||
float n = float(16); // radius is assumed to be 3
|
||||
vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
|
||||
vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
|
||||
vec3 c;
|
||||
vec3 cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-3) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-2) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-1) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,3) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,2) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,1) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
float min_sigma2 = 1e+2;
|
||||
m0 /= n;
|
||||
s0 = abs(s0 / n - m0 * m0);
|
||||
|
||||
float sigma2 = s0.r + s0.g + s0.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m0, 1.0);
|
||||
}
|
||||
|
||||
m1 /= n;
|
||||
s1 = abs(s1 / n - m1 * m1);
|
||||
|
||||
sigma2 = s1.r + s1.g + s1.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m1, 1.0);
|
||||
}
|
||||
|
||||
m2 /= n;
|
||||
s2 = abs(s2 / n - m2 * m2);
|
||||
|
||||
sigma2 = s2.r + s2.g + s2.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m2, 1.0);
|
||||
}
|
||||
|
||||
m3 /= n;
|
||||
s3 = abs(s3 / n - m3 * m3);
|
||||
|
||||
sigma2 = s3.r + s3.g + s3.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m3, 1.0);
|
||||
}
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageKuwaharaRadius3FragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);
|
||||
|
||||
void main (void)
|
||||
{
|
||||
vec2 uv = textureCoordinate;
|
||||
float n = float(16); // radius is assumed to be 3
|
||||
vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
|
||||
vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
|
||||
vec3 c;
|
||||
vec3 cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-3) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-2) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,-1) * src_size).rgb;
|
||||
m0 += c;
|
||||
s0 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-3) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-2) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,-1) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m0 += c;
|
||||
s0 += cSq;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-3,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-2,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,3) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,2) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(-1,1) * src_size).rgb;
|
||||
m1 += c;
|
||||
s1 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,3) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,2) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
c = texture2D(inputImageTexture, uv + vec2(0,1) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m1 += c;
|
||||
s1 += cSq;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,3) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,2) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,1) * src_size).rgb;
|
||||
m2 += c;
|
||||
s2 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,0) * src_size).rgb;
|
||||
cSq = c * c;
|
||||
m2 += c;
|
||||
s2 += cSq;
|
||||
m3 += c;
|
||||
s3 += cSq;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(3,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(2,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-3) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-2) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
c = texture2D(inputImageTexture, uv + vec2(1,-1) * src_size).rgb;
|
||||
m3 += c;
|
||||
s3 += c * c;
|
||||
|
||||
float min_sigma2 = 1e+2;
|
||||
m0 /= n;
|
||||
s0 = abs(s0 / n - m0 * m0);
|
||||
|
||||
float sigma2 = s0.r + s0.g + s0.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m0, 1.0);
|
||||
}
|
||||
|
||||
m1 /= n;
|
||||
s1 = abs(s1 / n - m1 * m1);
|
||||
|
||||
sigma2 = s1.r + s1.g + s1.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m1, 1.0);
|
||||
}
|
||||
|
||||
m2 /= n;
|
||||
s2 = abs(s2 / n - m2 * m2);
|
||||
|
||||
sigma2 = s2.r + s2.g + s2.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m2, 1.0);
|
||||
}
|
||||
|
||||
m3 /= n;
|
||||
s3 = abs(s3 / n - m3 * m3);
|
||||
|
||||
sigma2 = s3.r + s3.g + s3.b;
|
||||
if (sigma2 < min_sigma2) {
|
||||
min_sigma2 = sigma2;
|
||||
gl_FragColor = vec4(m3, 1.0);
|
||||
}
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageKuwaharaRadius3Filter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageKuwaharaRadius3FragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,239 +0,0 @@
|
||||
#import "GPUImageLanczosResamplingFilter.h"
|
||||
|
||||
NSString *const kGPUImageLanczosVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
attribute vec2 inputTextureCoordinate;
|
||||
|
||||
uniform float texelWidthOffset;
|
||||
uniform float texelHeightOffset;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepLeftTextureCoordinate;
|
||||
varying vec2 twoStepsLeftTextureCoordinate;
|
||||
varying vec2 threeStepsLeftTextureCoordinate;
|
||||
varying vec2 fourStepsLeftTextureCoordinate;
|
||||
varying vec2 oneStepRightTextureCoordinate;
|
||||
varying vec2 twoStepsRightTextureCoordinate;
|
||||
varying vec2 threeStepsRightTextureCoordinate;
|
||||
varying vec2 fourStepsRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
|
||||
vec2 firstOffset = vec2(texelWidthOffset, texelHeightOffset);
|
||||
vec2 secondOffset = vec2(2.0 * texelWidthOffset, 2.0 * texelHeightOffset);
|
||||
vec2 thirdOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset);
|
||||
vec2 fourthOffset = vec2(4.0 * texelWidthOffset, 4.0 * texelHeightOffset);
|
||||
|
||||
centerTextureCoordinate = inputTextureCoordinate;
|
||||
oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset;
|
||||
twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset;
|
||||
threeStepsLeftTextureCoordinate = inputTextureCoordinate - thirdOffset;
|
||||
fourStepsLeftTextureCoordinate = inputTextureCoordinate - fourthOffset;
|
||||
oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset;
|
||||
twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset;
|
||||
threeStepsRightTextureCoordinate = inputTextureCoordinate + thirdOffset;
|
||||
fourStepsRightTextureCoordinate = inputTextureCoordinate + fourthOffset;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLanczosFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepLeftTextureCoordinate;
|
||||
varying vec2 twoStepsLeftTextureCoordinate;
|
||||
varying vec2 threeStepsLeftTextureCoordinate;
|
||||
varying vec2 fourStepsLeftTextureCoordinate;
|
||||
varying vec2 oneStepRightTextureCoordinate;
|
||||
varying vec2 twoStepsRightTextureCoordinate;
|
||||
varying vec2 threeStepsRightTextureCoordinate;
|
||||
varying vec2 fourStepsRightTextureCoordinate;
|
||||
|
||||
// sinc(x) * sinc(x/a) = (a * sin(pi * x) * sin(pi * x / a)) / (pi^2 * x^2)
|
||||
// Assuming a Lanczos constant of 2.0, and scaling values to max out at x = +/- 1.5
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.38026;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.27667;
|
||||
fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.27667;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.08074;
|
||||
fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.08074;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, threeStepsLeftTextureCoordinate) * -0.02612;
|
||||
fragmentColor += texture2D(inputImageTexture, threeStepsRightTextureCoordinate) * -0.02612;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, fourStepsLeftTextureCoordinate) * -0.02143;
|
||||
fragmentColor += texture2D(inputImageTexture, fourStepsRightTextureCoordinate) * -0.02143;
|
||||
|
||||
gl_FragColor = fragmentColor;
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLanczosFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
varying vec2 centerTextureCoordinate;
|
||||
varying vec2 oneStepLeftTextureCoordinate;
|
||||
varying vec2 twoStepsLeftTextureCoordinate;
|
||||
varying vec2 threeStepsLeftTextureCoordinate;
|
||||
varying vec2 fourStepsLeftTextureCoordinate;
|
||||
varying vec2 oneStepRightTextureCoordinate;
|
||||
varying vec2 twoStepsRightTextureCoordinate;
|
||||
varying vec2 threeStepsRightTextureCoordinate;
|
||||
varying vec2 fourStepsRightTextureCoordinate;
|
||||
|
||||
// sinc(x) * sinc(x/a) = (a * sin(pi * x) * sin(pi * x / a)) / (pi^2 * x^2)
|
||||
// Assuming a Lanczos constant of 2.0, and scaling values to max out at x = +/- 1.5
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.38026;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.27667;
|
||||
fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.27667;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.08074;
|
||||
fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.08074;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, threeStepsLeftTextureCoordinate) * -0.02612;
|
||||
fragmentColor += texture2D(inputImageTexture, threeStepsRightTextureCoordinate) * -0.02612;
|
||||
|
||||
fragmentColor += texture2D(inputImageTexture, fourStepsLeftTextureCoordinate) * -0.02143;
|
||||
fragmentColor += texture2D(inputImageTexture, fourStepsRightTextureCoordinate) * -0.02143;
|
||||
|
||||
gl_FragColor = fragmentColor;
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageLanczosResamplingFilter
|
||||
|
||||
@synthesize originalImageSize = _originalImageSize;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFirstStageVertexShaderFromString:kGPUImageLanczosVertexShaderString firstStageFragmentShaderFromString:kGPUImageLanczosFragmentShaderString secondStageVertexShaderFromString:kGPUImageLanczosVertexShaderString secondStageFragmentShaderFromString:kGPUImageLanczosFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Base texture sampling offset on the input image, not the final size
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
|
||||
{
|
||||
self.originalImageSize = newSize;
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
}
|
||||
|
||||
- (void)setupFilterForSize:(CGSize)filterFrameSize;
|
||||
{
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
// The first pass through the framebuffer may rotate the inbound image, so need to account for that by changing up the kernel ordering for that pass
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
verticalPassTexelWidthOffset = 1.0 / _originalImageSize.height;
|
||||
verticalPassTexelHeightOffset = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
verticalPassTexelWidthOffset = 0.0;
|
||||
verticalPassTexelHeightOffset = 1.0 / _originalImageSize.height;
|
||||
}
|
||||
|
||||
horizontalPassTexelWidthOffset = 1.0 / _originalImageSize.width;
|
||||
horizontalPassTexelHeightOffset = 0.0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
[firstInputFramebuffer unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
CGSize currentFBOSize = [self sizeOfFBO];
|
||||
if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
|
||||
{
|
||||
currentFBOSize.height = self.originalImageSize.height;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentFBOSize.width = self.originalImageSize.width;
|
||||
}
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:currentFBOSize textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
|
||||
[self setUniformsForProgramAtIndex:0];
|
||||
|
||||
glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
|
||||
|
||||
glUniform1i(filterInputTextureUniform, 2);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
[firstInputFramebuffer unlock];
|
||||
|
||||
// Run the second stage of the two-pass filter
|
||||
[GPUImageContext setActiveShaderProgram:secondFilterProgram];
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
secondOutputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[secondOutputFramebuffer activateFramebuffer];
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
[secondOutputFramebuffer lock];
|
||||
}
|
||||
|
||||
[self setUniformsForProgramAtIndex:1];
|
||||
|
||||
glActiveTexture(GL_TEXTURE3);
|
||||
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
|
||||
glVertexAttribPointer(secondFilterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:kGPUImageNoRotation]);
|
||||
|
||||
glUniform1i(secondFilterInputTextureUniform, 3);
|
||||
|
||||
glVertexAttribPointer(secondFilterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
[outputFramebuffer unlock];
|
||||
outputFramebuffer = nil;
|
||||
if (usingNextFrameForImageCapture)
|
||||
{
|
||||
dispatch_semaphore_signal(imageCaptureSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
#import "GPUImageLaplacianFilter.h"
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLaplacianFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mediump mat3 convolutionMatrix;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
mediump vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
mediump vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
mediump vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
mediump vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
mediump vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
mediump vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
|
||||
mediump vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
|
||||
resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
|
||||
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
|
||||
|
||||
// Normalize the results to allow for negative gradients in the 0.0-1.0 colorspace
|
||||
resultColor = resultColor + 0.5;
|
||||
|
||||
gl_FragColor = vec4(resultColor, centerColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLaplacianFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mat3 convolutionMatrix;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;
|
||||
vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;
|
||||
vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;
|
||||
vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;
|
||||
vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;
|
||||
vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;
|
||||
vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;
|
||||
vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;
|
||||
|
||||
vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
|
||||
resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
|
||||
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
|
||||
|
||||
// Normalize the results to allow for negative gradients in the 0.0-1.0 colorspace
|
||||
resultColor = resultColor + 0.5;
|
||||
|
||||
gl_FragColor = vec4(resultColor, centerColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageLaplacianFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLaplacianFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
GPUMatrix3x3 newConvolutionMatrix;
|
||||
newConvolutionMatrix.one.one = 0.5;
|
||||
newConvolutionMatrix.one.two = 1.0;
|
||||
newConvolutionMatrix.one.three = 0.5;
|
||||
|
||||
newConvolutionMatrix.two.one = 1.0;
|
||||
newConvolutionMatrix.two.two = -6.0;
|
||||
newConvolutionMatrix.two.three = 1.0;
|
||||
|
||||
newConvolutionMatrix.three.one = 0.5;
|
||||
newConvolutionMatrix.three.two = 1.0;
|
||||
newConvolutionMatrix.three.three = 0.5;
|
||||
|
||||
self.convolutionKernel = newConvolutionMatrix;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
-152
@@ -1,152 +0,0 @@
|
||||
#import "GPUImageLevelsFilter.h"
|
||||
|
||||
/*
|
||||
** Gamma correction
|
||||
** Details: http://blog.mouaif.org/2009/01/22/photoshop-gamma-correction-shader/
|
||||
*/
|
||||
|
||||
#define GammaCorrection(color, gamma) pow(color, 1.0 / gamma)
|
||||
|
||||
/*
|
||||
** Levels control (input (+gamma), output)
|
||||
** Details: http://blog.mouaif.org/2009/01/28/levels-control-shader/
|
||||
*/
|
||||
|
||||
#define LevelsControlInputRange(color, minInput, maxInput) min(max(color - minInput, vec3(0.0)) / (maxInput - minInput), vec3(1.0))
|
||||
#define LevelsControlInput(color, minInput, gamma, maxInput) GammaCorrection(LevelsControlInputRange(color, minInput, maxInput), gamma)
|
||||
#define LevelsControlOutputRange(color, minOutput, maxOutput) mix(minOutput, maxOutput, color)
|
||||
#define LevelsControl(color, minInput, gamma, maxInput, minOutput, maxOutput) LevelsControlOutputRange(LevelsControlInput(color, minInput, gamma, maxInput), minOutput, maxOutput)
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLevelsFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform mediump vec3 levelMinimum;
|
||||
uniform mediump vec3 levelMiddle;
|
||||
uniform mediump vec3 levelMaximum;
|
||||
uniform mediump vec3 minOutput;
|
||||
uniform mediump vec3 maxOutput;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(LevelsControl(textureColor.rgb, levelMinimum, levelMiddle, levelMaximum, minOutput, maxOutput), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLevelsFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform vec3 levelMinimum;
|
||||
uniform vec3 levelMiddle;
|
||||
uniform vec3 levelMaximum;
|
||||
uniform vec3 minOutput;
|
||||
uniform vec3 maxOutput;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4(LevelsControl(textureColor.rgb, levelMinimum, levelMiddle, levelMaximum, minOutput, maxOutput), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageLevelsFilter
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLevelsFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
minUniform = [filterProgram uniformIndex:@"levelMinimum"];
|
||||
midUniform = [filterProgram uniformIndex:@"levelMiddle"];
|
||||
maxUniform = [filterProgram uniformIndex:@"levelMaximum"];
|
||||
minOutputUniform = [filterProgram uniformIndex:@"minOutput"];
|
||||
maxOutputUniform = [filterProgram uniformIndex:@"maxOutput"];
|
||||
|
||||
[self setRedMin:0.0 gamma:1.0 max:1.0 minOut:0.0 maxOut:1.0];
|
||||
[self setGreenMin:0.0 gamma:1.0 max:1.0 minOut:0.0 maxOut:1.0];
|
||||
[self setBlueMin:0.0 gamma:1.0 max:1.0 minOut:0.0 maxOut:1.0];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Helpers
|
||||
|
||||
- (void)updateUniforms {
|
||||
[self setVec3:minVector forUniform:minUniform program:filterProgram];
|
||||
[self setVec3:midVector forUniform:midUniform program:filterProgram];
|
||||
[self setVec3:maxVector forUniform:maxUniform program:filterProgram];
|
||||
[self setVec3:minOutputVector forUniform:minOutputUniform program:filterProgram];
|
||||
[self setVec3:maxOutputVector forUniform:maxOutputUniform program:filterProgram];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut {
|
||||
[self setRedMin:min gamma:mid max:max minOut:minOut maxOut:maxOut];
|
||||
[self setGreenMin:min gamma:mid max:max minOut:minOut maxOut:maxOut];
|
||||
[self setBlueMin:min gamma:mid max:max minOut:minOut maxOut:maxOut];
|
||||
}
|
||||
|
||||
- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max {
|
||||
[self setMin:min gamma:mid max:max minOut:0.0 maxOut:1.0];
|
||||
}
|
||||
|
||||
- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut {
|
||||
minVector.one = min;
|
||||
midVector.one = mid;
|
||||
maxVector.one = max;
|
||||
minOutputVector.one = minOut;
|
||||
maxOutputVector.one = maxOut;
|
||||
|
||||
[self updateUniforms];
|
||||
}
|
||||
|
||||
- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max {
|
||||
[self setRedMin:min gamma:mid max:max minOut:0.0 maxOut:1.0];
|
||||
}
|
||||
|
||||
- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut {
|
||||
minVector.two = min;
|
||||
midVector.two = mid;
|
||||
maxVector.two = max;
|
||||
minOutputVector.two = minOut;
|
||||
maxOutputVector.two = maxOut;
|
||||
|
||||
[self updateUniforms];
|
||||
}
|
||||
|
||||
- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max {
|
||||
[self setGreenMin:min gamma:mid max:max minOut:0.0 maxOut:1.0];
|
||||
}
|
||||
|
||||
- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut {
|
||||
minVector.three = min;
|
||||
midVector.three = mid;
|
||||
maxVector.three = max;
|
||||
minOutputVector.three = minOut;
|
||||
maxOutputVector.three = maxOut;
|
||||
|
||||
[self updateUniforms];
|
||||
}
|
||||
|
||||
- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max {
|
||||
[self setBlueMin:min gamma:mid max:max minOut:0.0 maxOut:1.0];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#import "GPUImageLightenBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLightenBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = max(textureColor, textureColor2);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLightenBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = max(textureColor, textureColor2);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageLightenBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLightenBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
#import "GPUImageLineGenerator.h"
|
||||
|
||||
NSString *const kGPUImageLineGeneratorVertexShaderString = SHADER_STRING
|
||||
(
|
||||
attribute vec4 position;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = position;
|
||||
}
|
||||
);
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLineGeneratorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform lowp vec3 lineColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(lineColor, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLineGeneratorFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
uniform vec3 lineColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(lineColor, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@interface GPUImageLineGenerator()
|
||||
|
||||
- (void)generateLineCoordinates;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GPUImageLineGenerator
|
||||
|
||||
@synthesize lineWidth = _lineWidth;
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithVertexShaderFromString:kGPUImageLineGeneratorVertexShaderString fragmentShaderFromString:kGPUImageLineGeneratorFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
lineWidthUniform = [filterProgram uniformIndex:@"lineWidth"];
|
||||
lineColorUniform = [filterProgram uniformIndex:@"lineColor"];
|
||||
|
||||
self.lineWidth = 1.0;
|
||||
[self setLineColorRed:0.0 green:1.0 blue:0.0];
|
||||
});
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (lineCoordinates)
|
||||
{
|
||||
free(lineCoordinates);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Rendering
|
||||
|
||||
- (void)generateLineCoordinates;
|
||||
{
|
||||
lineCoordinates = calloc(1024 * 4, sizeof(GLfloat));
|
||||
}
|
||||
|
||||
- (void)renderLinesFromArray:(GLfloat *)lineSlopeAndIntercepts count:(NSUInteger)numberOfLines frameTime:(CMTime)frameTime;
|
||||
{
|
||||
if (self.preventRendering)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (lineCoordinates == NULL)
|
||||
{
|
||||
[self generateLineCoordinates];
|
||||
}
|
||||
|
||||
// Iterate through and generate vertices from the slopes and intercepts
|
||||
NSUInteger currentVertexIndex = 0;
|
||||
NSUInteger currentLineIndex = 0;
|
||||
NSUInteger maxLineIndex = numberOfLines *2;
|
||||
while(currentLineIndex < maxLineIndex)
|
||||
{
|
||||
GLfloat slope = lineSlopeAndIntercepts[currentLineIndex++];
|
||||
GLfloat intercept = lineSlopeAndIntercepts[currentLineIndex++];
|
||||
|
||||
if (slope > 9000.0) // Vertical line
|
||||
{
|
||||
lineCoordinates[currentVertexIndex++] = intercept;
|
||||
lineCoordinates[currentVertexIndex++] = -1.0;
|
||||
lineCoordinates[currentVertexIndex++] = intercept;
|
||||
lineCoordinates[currentVertexIndex++] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lineCoordinates[currentVertexIndex++] = -1.0;
|
||||
lineCoordinates[currentVertexIndex++] = slope * -1.0 + intercept;
|
||||
lineCoordinates[currentVertexIndex++] = 1.0;
|
||||
lineCoordinates[currentVertexIndex++] = slope * 1.0 + intercept;
|
||||
}
|
||||
}
|
||||
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
|
||||
[outputFramebuffer activateFramebuffer];
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, lineCoordinates);
|
||||
glDrawArrays(GL_LINES, 0, ((unsigned int)numberOfLines * 2));
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
[self informTargetsAboutNewFrameAtTime:frameTime];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
|
||||
{
|
||||
// Prevent rendering of the frame by normal means
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
- (void)setLineWidth:(CGFloat)newValue;
|
||||
{
|
||||
_lineWidth = newValue;
|
||||
[GPUImageContext setActiveShaderProgram:filterProgram];
|
||||
glLineWidth(newValue);
|
||||
}
|
||||
|
||||
- (void)setLineColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent;
|
||||
{
|
||||
GPUVector3 lineColor = {redComponent, greenComponent, blueComponent};
|
||||
|
||||
[self setVec3:lineColor forUniform:lineColorUniform program:filterProgram];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,51 +0,0 @@
|
||||
#import "GPUImageLinearBurnBlendFilter.h"
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLinearBurnBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
varying highp vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(clamp(textureColor.rgb + textureColor2.rgb - vec3(1.0), vec3(0.0), vec3(1.0)), textureColor.a);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLinearBurnBlendFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 textureCoordinate2;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
uniform sampler2D inputImageTexture2;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
|
||||
|
||||
gl_FragColor = vec4(clamp(textureColor.rgb + textureColor2.rgb - vec3(1.0), vec3(0.0), vec3(1.0)), textureColor.a);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation GPUImageLinearBurnBlendFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLinearBurnBlendFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,123 +0,0 @@
|
||||
#import "GPUImageLocalBinaryPatternFilter.h"
|
||||
|
||||
// This is based on "Accelerating image recognition on mobile devices using GPGPU" by Miguel Bordallo Lopez, Henri Nykanen, Jari Hannuksela, Olli Silven and Markku Vehvilainen
|
||||
// http://www.ee.oulu.fi/~jhannuks/publications/SPIE2011a.pdf
|
||||
|
||||
// Right pixel is the most significant bit, traveling clockwise to get to the upper right, which is the least significant
|
||||
// If the external pixel is greater than or equal to the center, set to 1, otherwise 0
|
||||
//
|
||||
// 2 1 0
|
||||
// 3 7
|
||||
// 4 5 6
|
||||
|
||||
// 01101101
|
||||
// 76543210
|
||||
|
||||
@implementation GPUImageLocalBinaryPatternFilter
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kGPUImageLocalBinaryPatternFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
precision highp float;
|
||||
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
lowp float centerIntensity = texture2D(inputImageTexture, textureCoordinate).r;
|
||||
lowp float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
|
||||
lowp float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;
|
||||
lowp float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
|
||||
lowp float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
|
||||
lowp float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
|
||||
lowp float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
|
||||
lowp float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
|
||||
lowp float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
|
||||
|
||||
lowp float byteTally = 1.0 / 255.0 * step(centerIntensity, topRightIntensity);
|
||||
byteTally += 2.0 / 255.0 * step(centerIntensity, topIntensity);
|
||||
byteTally += 4.0 / 255.0 * step(centerIntensity, topLeftIntensity);
|
||||
byteTally += 8.0 / 255.0 * step(centerIntensity, leftIntensity);
|
||||
byteTally += 16.0 / 255.0 * step(centerIntensity, bottomLeftIntensity);
|
||||
byteTally += 32.0 / 255.0 * step(centerIntensity, bottomIntensity);
|
||||
byteTally += 64.0 / 255.0 * step(centerIntensity, bottomRightIntensity);
|
||||
byteTally += 128.0 / 255.0 * step(centerIntensity, rightIntensity);
|
||||
|
||||
// TODO: Replace the above with a dot product and two vec4s
|
||||
// TODO: Apply step to a matrix, rather than individually
|
||||
|
||||
gl_FragColor = vec4(byteTally, byteTally, byteTally, 1.0);
|
||||
}
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageLocalBinaryPatternFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
varying vec2 leftTextureCoordinate;
|
||||
varying vec2 rightTextureCoordinate;
|
||||
|
||||
varying vec2 topTextureCoordinate;
|
||||
varying vec2 topLeftTextureCoordinate;
|
||||
varying vec2 topRightTextureCoordinate;
|
||||
|
||||
varying vec2 bottomTextureCoordinate;
|
||||
varying vec2 bottomLeftTextureCoordinate;
|
||||
varying vec2 bottomRightTextureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
float centerIntensity = texture2D(inputImageTexture, textureCoordinate).r;
|
||||
float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;
|
||||
float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;
|
||||
float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;
|
||||
float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;
|
||||
float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;
|
||||
float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;
|
||||
float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;
|
||||
float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;
|
||||
|
||||
float byteTally = 1.0 / 255.0 * step(centerIntensity, topRightIntensity);
|
||||
byteTally += 2.0 / 255.0 * step(centerIntensity, topIntensity);
|
||||
byteTally += 4.0 / 255.0 * step(centerIntensity, topLeftIntensity);
|
||||
byteTally += 8.0 / 255.0 * step(centerIntensity, leftIntensity);
|
||||
byteTally += 16.0 / 255.0 * step(centerIntensity, bottomLeftIntensity);
|
||||
byteTally += 32.0 / 255.0 * step(centerIntensity, bottomIntensity);
|
||||
byteTally += 64.0 / 255.0 * step(centerIntensity, bottomRightIntensity);
|
||||
byteTally += 128.0 / 255.0 * step(centerIntensity, rightIntensity);
|
||||
|
||||
// TODO: Replace the above with a dot product and two vec4s
|
||||
// TODO: Apply step to a matrix, rather than individually
|
||||
|
||||
gl_FragColor = vec4(byteTally, byteTally, byteTally, 1.0);
|
||||
}
|
||||
);
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization and teardown
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kGPUImageLocalBinaryPatternFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user