rev |
line source |
nuclear@20
|
1 #include <assert.h>
|
nuclear@20
|
2 #include <string>
|
nuclear@20
|
3 #include <map>
|
nuclear@20
|
4 #include "shader.h"
|
nuclear@20
|
5 #include "sdr.h"
|
nuclear@20
|
6 #include "opengl.h"
|
nuclear@20
|
7
|
nuclear@20
|
8 std::map<std::string, unsigned int> sdrdb;
|
nuclear@20
|
9
|
nuclear@21
|
10 const SdrProg *SdrProg::active;
|
nuclear@21
|
11
|
nuclear@20
|
12 SdrProg::SdrProg()
|
nuclear@20
|
13 {
|
nuclear@20
|
14 prog = 0;
|
nuclear@20
|
15 valid = false;
|
nuclear@20
|
16 }
|
nuclear@20
|
17
|
nuclear@20
|
18 SdrProg::~SdrProg()
|
nuclear@20
|
19 {
|
nuclear@20
|
20 destroy();
|
nuclear@20
|
21 }
|
nuclear@20
|
22
|
nuclear@20
|
23 void SdrProg::create()
|
nuclear@20
|
24 {
|
nuclear@20
|
25 destroy();
|
nuclear@20
|
26 prog = glCreateProgram();
|
nuclear@20
|
27 }
|
nuclear@20
|
28
|
nuclear@20
|
29 void SdrProg::destroy()
|
nuclear@20
|
30 {
|
nuclear@20
|
31 if(prog) {
|
nuclear@20
|
32 glDeleteProgram(prog);
|
nuclear@20
|
33 }
|
nuclear@20
|
34 valid = false;
|
nuclear@20
|
35
|
nuclear@20
|
36 for(size_t i=0; i<priv_sdr.size(); i++) {
|
nuclear@20
|
37 glDeleteShader(priv_sdr[i]);
|
nuclear@20
|
38 }
|
nuclear@20
|
39 priv_sdr.clear();
|
nuclear@20
|
40 }
|
nuclear@20
|
41
|
nuclear@20
|
42 bool SdrProg::attach_shader(unsigned int sdr)
|
nuclear@20
|
43 {
|
nuclear@20
|
44 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
45
|
nuclear@20
|
46 glAttachShader(prog, sdr);
|
nuclear@20
|
47 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
48 fprintf(stderr, "failed to attach shader %u to program %u\n", sdr, prog);
|
nuclear@20
|
49 return false;
|
nuclear@20
|
50 }
|
nuclear@20
|
51
|
nuclear@20
|
52 valid = false;
|
nuclear@20
|
53 return true;
|
nuclear@20
|
54 }
|
nuclear@20
|
55
|
nuclear@20
|
56 bool SdrProg::create(unsigned int vsdr, unsigned int psdr)
|
nuclear@20
|
57 {
|
nuclear@20
|
58 create();
|
nuclear@20
|
59
|
nuclear@20
|
60 if(!attach_shader(vsdr) || !attach_shader(psdr)) {
|
nuclear@20
|
61 return false;
|
nuclear@20
|
62 }
|
nuclear@20
|
63
|
nuclear@21
|
64 bind_default_attribs();
|
nuclear@21
|
65 return link();
|
nuclear@20
|
66 }
|
nuclear@20
|
67
|
nuclear@20
|
68 bool SdrProg::create(const char *vsrc, const char *psrc)
|
nuclear@20
|
69 {
|
nuclear@20
|
70 unsigned int vs = create_shader(vsrc, GL_VERTEX_SHADER);
|
nuclear@20
|
71 if(!vs) {
|
nuclear@20
|
72 return false;
|
nuclear@20
|
73 }
|
nuclear@20
|
74
|
nuclear@20
|
75 unsigned int ps = create_shader(psrc, GL_FRAGMENT_SHADER);
|
nuclear@20
|
76 if(!ps) {
|
nuclear@20
|
77 glDeleteShader(vs);
|
nuclear@20
|
78 return false;
|
nuclear@20
|
79 }
|
nuclear@20
|
80
|
nuclear@20
|
81 if(!create(vs, ps)) {
|
nuclear@20
|
82 glDeleteShader(vs);
|
nuclear@20
|
83 glDeleteShader(ps);
|
nuclear@20
|
84 return false;
|
nuclear@20
|
85 }
|
nuclear@20
|
86
|
nuclear@20
|
87 priv_sdr.push_back(vs);
|
nuclear@20
|
88 priv_sdr.push_back(ps);
|
nuclear@20
|
89 return true;
|
nuclear@20
|
90 }
|
nuclear@20
|
91
|
nuclear@20
|
92 bool SdrProg::load(const char *vfname, const char *pfname)
|
nuclear@20
|
93 {
|
nuclear@21
|
94 unsigned int vs = get_shader(vfname, GL_VERTEX_SHADER);
|
nuclear@20
|
95 if(!vs) {
|
nuclear@20
|
96 return false;
|
nuclear@20
|
97 }
|
nuclear@20
|
98
|
nuclear@21
|
99 unsigned int ps = get_shader(pfname, GL_FRAGMENT_SHADER);
|
nuclear@20
|
100 if(!ps) {
|
nuclear@20
|
101 return false;
|
nuclear@20
|
102 }
|
nuclear@20
|
103
|
nuclear@20
|
104 printf("creating shader program (%s, %s)\n", vfname, pfname);
|
nuclear@20
|
105 if(!(prog = create_program_link(vs, ps, 0))) {
|
nuclear@20
|
106 return false;
|
nuclear@20
|
107 }
|
nuclear@21
|
108
|
nuclear@21
|
109 bind_default_attribs();
|
nuclear@21
|
110 return link();
|
nuclear@20
|
111 }
|
nuclear@20
|
112
|
nuclear@20
|
113 bool SdrProg::link() const
|
nuclear@20
|
114 {
|
nuclear@21
|
115 if(link_program(prog) == -1) {
|
nuclear@21
|
116 return false;
|
nuclear@21
|
117 }
|
nuclear@21
|
118 valid = true;
|
nuclear@21
|
119 return true;
|
nuclear@20
|
120 }
|
nuclear@20
|
121
|
nuclear@20
|
122 int SdrProg::get_uniform(const char *name) const
|
nuclear@20
|
123 {
|
nuclear@20
|
124 if(!bind()) {
|
nuclear@20
|
125 return -1;
|
nuclear@20
|
126 }
|
nuclear@20
|
127 return glGetUniformLocation(prog, name);
|
nuclear@20
|
128 }
|
nuclear@20
|
129
|
nuclear@20
|
130 int SdrProg::get_attrib(const char *name) const
|
nuclear@20
|
131 {
|
nuclear@20
|
132 if(!bind()) {
|
nuclear@20
|
133 return -1;
|
nuclear@20
|
134 }
|
nuclear@20
|
135 return glGetAttribLocation(prog, name);
|
nuclear@20
|
136 }
|
nuclear@20
|
137
|
nuclear@20
|
138 bool SdrProg::bind_attrib(const char *name, int loc) const
|
nuclear@20
|
139 {
|
nuclear@20
|
140 if(!prog) {
|
nuclear@20
|
141 return false;
|
nuclear@20
|
142 }
|
nuclear@20
|
143
|
nuclear@20
|
144 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
145 glBindAttribLocation(prog, loc, name);
|
nuclear@20
|
146 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
147 fprintf(stderr, "failed to bind attribute %s of program %u to location %d\n",
|
nuclear@20
|
148 name, prog, loc);
|
nuclear@20
|
149 return false;
|
nuclear@20
|
150 }
|
nuclear@20
|
151 valid = false; /* must relink after the glBindAttribLocation call */
|
nuclear@20
|
152 return true;
|
nuclear@20
|
153 }
|
nuclear@20
|
154
|
nuclear@21
|
155 void SdrProg::bind_default_attribs() const
|
nuclear@21
|
156 {
|
nuclear@21
|
157 // XXX must be in sync with SdrDefaultAttrib enums in shader.h
|
nuclear@21
|
158 static const char *def_names[] = {
|
nuclear@21
|
159 "attr_vertex",
|
nuclear@21
|
160 "attr_normal",
|
nuclear@21
|
161 "attr_texcoord",
|
nuclear@21
|
162 "attr_color",
|
nuclear@21
|
163 "attr_tangent",
|
nuclear@21
|
164 0
|
nuclear@21
|
165 };
|
nuclear@21
|
166
|
nuclear@21
|
167 for(int i=0; def_names[i]; i++) {
|
nuclear@21
|
168 bind_attrib(def_names[i], i);
|
nuclear@21
|
169 }
|
nuclear@21
|
170 }
|
nuclear@21
|
171
|
nuclear@21
|
172
|
nuclear@20
|
173 bool SdrProg::bind() const
|
nuclear@20
|
174 {
|
nuclear@20
|
175 if(!prog || (!valid && !link())) {
|
nuclear@20
|
176 return false;
|
nuclear@20
|
177 }
|
nuclear@20
|
178
|
nuclear@20
|
179 assert(glGetError() == GL_NO_ERROR);
|
nuclear@20
|
180 glUseProgram(prog);
|
nuclear@20
|
181 if(glGetError() != GL_NO_ERROR) {
|
nuclear@20
|
182 fprintf(stderr, "failed to bind program %d\n", prog);
|
nuclear@20
|
183 return false;
|
nuclear@20
|
184 }
|
nuclear@21
|
185
|
nuclear@21
|
186 active = this;
|
nuclear@20
|
187 return true;
|
nuclear@20
|
188 }
|
nuclear@20
|
189
|
nuclear@20
|
190 unsigned int get_shader(const char *name, unsigned int type)
|
nuclear@20
|
191 {
|
nuclear@20
|
192 std::map<std::string, unsigned int>::const_iterator it = sdrdb.find(name);
|
nuclear@20
|
193 if(it != sdrdb.end()) {
|
nuclear@20
|
194 return it->second;
|
nuclear@20
|
195 }
|
nuclear@20
|
196
|
nuclear@20
|
197 unsigned int sdr = load_shader(name, type);
|
nuclear@20
|
198 if(!sdr) {
|
nuclear@20
|
199 return 0;
|
nuclear@20
|
200 }
|
nuclear@20
|
201
|
nuclear@20
|
202 sdrdb[name] = sdr;
|
nuclear@20
|
203 return sdr;
|
nuclear@20
|
204 }
|
nuclear@21
|
205
|
nuclear@21
|
206 SdrProg *get_sdrprog(const char *vfile, const char *pfile)
|
nuclear@21
|
207 {
|
nuclear@21
|
208 SdrProg *sp = new SdrProg;
|
nuclear@21
|
209 if(!sp->load(vfile, pfile)) {
|
nuclear@21
|
210 delete sp;
|
nuclear@21
|
211 return 0;
|
nuclear@21
|
212 }
|
nuclear@21
|
213 return sp;
|
nuclear@21
|
214 }
|