-
Notifications
You must be signed in to change notification settings - Fork 2
/
QCOpenGLPort_Blending-kineme.m
211 lines (182 loc) · 7.85 KB
/
QCOpenGLPort_Blending-kineme.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//
// QCOpenGLPort_Blending.m
// GLTools
//
// Created by Christopher Wright on 10/8/08.
// Copyright 2008 Kosada Incorporated. All rights reserved.
//
#import <OpenGL/CGLMacro.h>
#import "SkankySDK/SkankySDK.h"
#import "AlphaBlendModePrincipal.h"
#import <objc/runtime.h>
#import <objc/message.h>
static ptrdiff_t _index;
static ptrdiff_t _enabled;
static ptrdiff_t _testingEnabled; // 10.6 only
static ptrdiff_t _sourceFunction;
static ptrdiff_t _destFunction;
static ptrdiff_t _alphaFunc; // 10.6 only
static ptrdiff_t _alphaRef; // 10.6 only
static Class blendingSuperclass;
static id enhancedBlendingInitWithNodeArguments(id self, SEL sel, id fp8, id fp12)
{
struct objc_super super = {self, blendingSuperclass};
self = objc_msgSendSuper(&super, sel, fp8, [self _argumentsFromAttributesKey:@"_blendingPortAttributes" originalArguments:fp12]);
if(self)
[self setMaxIndexValue: 3]; // 2 by default, plus each additional mode added in attributes
return self;
}
static id enhancedBlendingInitWithNodeArgumentsSL(id self, SEL sel, id fp8, id fp12)
{
struct objc_super super = {self, blendingSuperclass};
self = objc_msgSendSuper(&super, sel, fp8, [self _argumentsFromAttributesKey:@"_blendingPortAttributes" originalArguments:fp12]);
if(self)
{
[self setMaxIndexValue: 3]; // 2 by default, plus each additional mode added in attributes
[self _setFlags:0x4]; // no idea what this does, but if we don't set it, blending is broken
}
return self;
}
static NSDictionary *enhancedBlendingAttributes(id self, SEL sel, id node, id args)
{
struct objc_super super = {self, blendingSuperclass};
NSMutableDictionary *attributes = [objc_msgSendSuper(&super, sel) mutableCopy];
NSMutableArray *menu = [[attributes objectForKey:@"menu"] mutableCopy];
if(![menu containsObject: @"Alpha"])
[menu addObject: @"Alpha"];
[attributes setObject:menu forKey:@"menu"];
[menu release];
return [attributes autorelease];
}
static void enhancedBlendingSetOnOpenGLContext(id self, SEL sel, QCOpenGLContext *context)
{
unsigned int mode = ((unsigned int*)((unsigned char*)self+_index))[0];//[self indexValue];
if(mode)
{
CGLContextObj cgl_ctx = [[context openGLContext] CGLContextObj];
GLint sfunc, dfunc;
glGetIntegerv(GL_BLEND_SRC, (GLint*)((unsigned char*)self+_sourceFunction));
glGetIntegerv(GL_BLEND_DST, (GLint*)((unsigned char*)self+_destFunction));
if(! (*((unsigned char*)self+_enabled) = glIsEnabled(GL_BLEND)) )
glEnable(GL_BLEND);
switch(mode)
{
case 1: // over
sfunc = GL_ONE;
dfunc = GL_ONE_MINUS_SRC_ALPHA;
break;
case 2: // add
sfunc = dfunc = GL_ONE;
break;
case 3: // Alpha!
sfunc = GL_SRC_ALPHA;
dfunc = GL_ONE_MINUS_SRC_ALPHA;
}
// save an unnecessary state transition if things haven't changed
if(sfunc != *(GLint*)((unsigned char*)self+_sourceFunction) ||
dfunc != *(GLint*)((unsigned char*)self+_destFunction))
glBlendFunc(sfunc, dfunc);
}
}
static void enhancedBlendingUnsetOnOpenGLContext(id self, SEL sel, QCOpenGLContext *context)
{
CGLContextObj cgl_ctx = [[context openGLContext] CGLContextObj];
if(!*((unsigned char*)self+_enabled))
glDisable(GL_BLEND);
else
glBlendFunc(*(GLint*)((unsigned char*)self+_sourceFunction),
*(GLint*)((unsigned char*)self+_destFunction));
}
static void enhancedBlendingSetOnOpenGLContextSL(id self, SEL sel, QCOpenGLContext *context)
{
unsigned int mode = ((unsigned int*)((unsigned char*)self+_index))[0];//[self indexValue];
if(mode)
{
// we diverge from QC here -- we don't get the context if we don't change anything
// (apple gets it unconditionally, costing 2 useless message sends per port when in Replace blend mode)
CGLContextObj cgl_ctx = [[context openGLContext] CGLContextObj];
GLint *_sFunc = (GLint*)((unsigned char*)self+_sourceFunction);
GLint *_dFunc = (GLint*)((unsigned char*)self+_destFunction);
if(! (*((unsigned char*)self+_enabled) = glIsEnabled(GL_BLEND)) )
glEnable(GL_BLEND);
glGetIntegerv(GL_BLEND_SRC, _sFunc);
glGetIntegerv(GL_BLEND_DST, _dFunc);
GLint sfunc, dfunc;
switch(mode)
{
case 1: // over
sfunc = GL_ONE;
dfunc = GL_ONE_MINUS_SRC_ALPHA;
break;
case 2: // add
sfunc = dfunc = GL_ONE;
break;
case 3: // Alpha!
sfunc = GL_SRC_ALPHA;
dfunc = GL_ONE_MINUS_SRC_ALPHA;
}
if(sfunc != *_sFunc || dfunc != *_dFunc)
glBlendFunc(sfunc, dfunc);
if(! (*((unsigned char*)self+_testingEnabled) = glIsEnabled(GL_ALPHA_TEST)) )
glEnable(GL_ALPHA_TEST);
glGetIntegerv(GL_ALPHA_TEST_FUNC, (GLint*)((unsigned char*)self+_alphaFunc));
// we diverge from QC here, because we use GL_ALPHA_TEST_REF, instead of _FUNC
// (probably a bugfix) (they fixed this in 10.6.2, finally)
glGetFloatv(GL_ALPHA_TEST_REF, (GLfloat*)((unsigned char*)self+_alphaRef));
glAlphaFunc(GL_GREATER, 0.01f);
}
}
static void enhancedBlendingUnsetOnOpenGLContextSL(id self, SEL sel, QCOpenGLContext *context)
{
// 2 diversions: we don't send indexValue to super, and we get the context inside the block
if( ((unsigned int*)((unsigned char*)self+_index))[0] )
{
CGLContextObj cgl_ctx = [[context openGLContext] CGLContextObj];
glBlendFunc(((unsigned int*)((unsigned char*)self+_sourceFunction))[0],
((unsigned int*)((unsigned char*)self+_destFunction))[0]);
if(!*((unsigned char*)self+_enabled))
glDisable(GL_BLEND);
glAlphaFunc(((unsigned int*)((unsigned char*)self+_alphaFunc))[0],
((float*)((unsigned char*)self+_alphaRef))[0]);
if(!*((unsigned char*)self+_testingEnabled))
glDisable(GL_ALPHA_TEST);
}
}
static void __attribute__ ((constructor)) enhancedBlendingInit()
{
{
id self = [AlphaBlendModePrincipal class];
KIEnsureSystemVersion;
}
BOOL onSnowLeopard = NO;
Class QCOpenGLPort_Blending = objc_getClass("QCOpenGLPort_Blending");
if(!KIOnLeopard())
{
//NSLog(@"on SL");
onSnowLeopard = YES;
_testingEnabled = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_testingEnabled"));
_alphaFunc = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_alphaFunc"));
_alphaRef = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_alphaRef"));
}
_index = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_index"));
_enabled = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_enabled"));
_sourceFunction = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_sourceFunction"));
_destFunction = ivar_getOffset(class_getInstanceVariable(QCOpenGLPort_Blending, "_destFunction"));
blendingSuperclass = class_getSuperclass(QCOpenGLPort_Blending);
// adding a new method -- should check to see if this is already implemented at runtime (it's not in leopard, so we're ok for now)
class_addMethod(QCOpenGLPort_Blending, @selector(attributes), (IMP)enhancedBlendingAttributes, "@@:");
if(onSnowLeopard)
{
if([QCOpenGLPort_Blending instancesRespondToSelector:@selector(initWithNode:arguments:)])
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(initWithNode:arguments:)),(IMP)enhancedBlendingInitWithNodeArgumentsSL);
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(setOnOpenGLContext:)),(IMP)enhancedBlendingSetOnOpenGLContextSL);
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(unsetOnOpenGLContext:)),(IMP)enhancedBlendingUnsetOnOpenGLContextSL);
}
else
{
if([QCOpenGLPort_Blending instancesRespondToSelector:@selector(initWithNode:arguments:)])
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(initWithNode:arguments:)),(IMP)enhancedBlendingInitWithNodeArguments);
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(setOnOpenGLContext:)),(IMP)enhancedBlendingSetOnOpenGLContext);
method_setImplementation(class_getInstanceMethod(QCOpenGLPort_Blending, @selector(unsetOnOpenGLContext:)),(IMP)enhancedBlendingUnsetOnOpenGLContext);
}
}