-
Notifications
You must be signed in to change notification settings - Fork 6
/
GLLProgram.m
140 lines (116 loc) · 3.82 KB
/
GLLProgram.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
//
// GLLProgram.m
//
//
// Created by Torsten Kammer on 14.09.12.
//
//
#import "GLLProgram.h"
#import <OpenGL/gl3.h>
#import "GLLResourceManager.h"
#import "GLLShader.h"
@interface GLLProgram () {
NSMutableDictionary *uniformOffsets;
}
@end
@implementation GLLProgram
- (id)initWithName:(NSString *)name fragmentShaderName:(NSString *)fragmentName geometryShaderName:(NSString *)geometryName vertexShaderName:(NSString *)vertexName baseURL:(NSURL *)base additionalDefines:(NSDictionary *)additionalDefines resourceManager:(GLLResourceManager *)manager error:(NSError *__autoreleasing*)error;
{
GLLShader *vertex, *fragment, *geometry;
if (vertexName)
{
vertex = [manager shaderForName:vertexName additionalDefines:additionalDefines type:GL_VERTEX_SHADER baseURL:base error:error];
if (!vertex)
{
[self unload];
return nil;
}
}
if (geometryName)
{
fragment = [manager shaderForName:geometryName additionalDefines:additionalDefines type:GL_GEOMETRY_SHADER baseURL:base error:error];
if (!fragment)
{
[self unload];
return nil;
}
}
if (fragmentName)
{
fragment = [manager shaderForName:fragmentName additionalDefines:additionalDefines type:GL_FRAGMENT_SHADER baseURL:base error:error];
if (!fragment)
{
[self unload];
return nil;
}
}
return [self initWithName:name fragmentShader:fragment geometryShader:geometry vertexShader:vertex error:error];
}
- (id)initWithName:(NSString *)name fragmentShader:(GLLShader *)fragment geometryShader:(GLLShader *)geometry vertexShader:(GLLShader *)vertex error:(NSError *__autoreleasing*)error;
{
if (!(self = [super init])) return nil;
uniformOffsets = [[NSMutableDictionary alloc] init];
_name = name;
_programID = glCreateProgram();
if (vertex)
glAttachShader(_programID, vertex.shaderID);
if (fragment)
glAttachShader(_programID, fragment.shaderID);
if (geometry)
glAttachShader(_programID, geometry.shaderID);
[self bindAttributeLocations];
glLinkProgram(_programID);
GLint linkStatus;
glGetProgramiv(_programID, GL_LINK_STATUS, &linkStatus);
if (linkStatus != GL_TRUE)
{
GLsizei length;
glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &length);
GLchar log[length+1];
glGetProgramInfoLog(_programID, length+1, NULL, log);
log[length] = '\0';
if (error)
*error = [NSError errorWithDomain:@"OpenGL" code:1 userInfo:@{ NSLocalizedDescriptionKey : [NSString stringWithFormat:NSLocalizedString(@"The shader \"%@\" could not be linked", @"GLLShader error message description"), _name],
NSLocalizedFailureReasonErrorKey : [NSString stringWithFormat:NSLocalizedString(@"Message from OpenGL driver: %s", "No shader there wtf?"), log],
NSLocalizedRecoverySuggestionErrorKey : NSLocalizedString(@"Please inform a developer of this problem.", @"No shader there wtf?")
}];
NSLog(@"link error in shader %@: %s", _name, log);
[self unload];
return nil;
}
return self;
}
- (void)bindAttributeLocations;
{
}
- (void)dealloc
{
NSAssert(_programID == 0, @"Did not call unload before deallocing.");
}
- (void)unload;
{
glDeleteProgram(_programID);
_programID = 0;
}
- (NSInteger)offsetForUniform:(NSString *)uniformName inBlock:(NSString *)blockName
{
return [self offsetForUniform:[NSString stringWithFormat:@"%@.%@", blockName, uniformName]];
}
- (NSInteger)offsetForUniform:(NSString *)uniformName
{
NSNumber *result = uniformOffsets[uniformName];
if (!result) {
GLuint uniformIndex;
glGetUniformIndices(self.programID, 1, (const GLchar *[]) { uniformName.UTF8String }, &uniformIndex);
if (uniformIndex == GL_INVALID_INDEX) {
result = @(-1);
} else {
GLint byteOffset;
glGetActiveUniformsiv(self.programID, 1, &uniformIndex, GL_UNIFORM_OFFSET, &byteOffset);
result = @(byteOffset);
}
uniformOffsets[uniformName] = result;
}
return result.integerValue;
}
@end