3dphotoshoot

view src/shader.cc @ 21:4ca4e3c5a754

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