8a52348742a3b68713a1f6181861ab350f1192b2
[summerhack] / src / 3dengfx / src / 3dengfx / sdrman.cpp
1 /*
2 This file is part of the 3dengfx, 3d visualization system.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 3dengfx is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 3dengfx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with 3dengfx; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 /* Shader manager (shader manager)
22  * 
23  * author: John Tsiombikas 2005
24  */
25
26 #include <string>
27 #include <cstdio>
28 #include <cstring>
29 #include <cerrno>
30 #include "3denginefx.hpp"
31 #include "sdrman.hpp"
32 #include "common/hashtable.hpp"
33 #include "common/string_hash.hpp"
34 #include "common/err_msg.h"
35 #include "opengl.h"
36
37 using std::string;
38 using namespace glext;
39 static HashTable<string, Shader> *shaders;
40
41 static void delete_object(GLhandleARB obj) {
42         glDeleteObject(obj);
43 }
44
45 static void init_sdr_man() {
46         if(shaders) return;
47         shaders = new HashTable<string, Shader>;
48         shaders->set_hash_function(string_hash);
49         shaders->set_data_destructor(delete_object);
50 }
51
52 static inline bool check_shader_caps(int sdr_type, const char *name) {
53         if(!engfx_state::sys_caps.prog.shader_obj) {
54                 error("Failed loading GLSL shader %s: system lacks GLSL capability", name);
55                 return false;
56         }
57
58         if(sdr_type == PROG_VERTEX && !engfx_state::sys_caps.prog.glsl_vertex) {
59                 error("Failed loading GLSL vertex shader %s: system lacks GLSL vertex shader capability", name);
60                 return false;
61         }
62         
63         if(sdr_type == PROG_PIXEL && !engfx_state::sys_caps.prog.glsl_pixel) {
64                 error("Failed loading GLSL pixel shader %s: system lacks GLSL pixel shader capability", name);
65                 return false;
66         }
67
68         return true;
69 }
70
71 Shader add_shader_file(const char *fname, int sdr_type) {
72         FILE *fp = fopen(fname, "r");
73         if(!fp) {
74                 error("Failed loading GLSL shader %s: %s\n", fname, strerror(errno));
75                 return 0;
76         }
77
78         fseek(fp, 0, SEEK_END);
79         size_t src_size = ftell(fp);
80         fseek(fp, 0, SEEK_SET);
81
82         char *source = new char[src_size + 1];
83         src_size = fread(source, 1, src_size, fp);
84         source[src_size] = 0;
85         fclose(fp);
86
87         Shader sdr = add_shader_string(source, sdr_type, fname);
88         delete [] source;
89
90         return sdr;
91 }
92
93 Shader add_shader_string(const char *code, int sdr_type, const char *name) {
94         if(!shaders) init_sdr_man();
95         
96         if(!check_shader_caps(sdr_type, name)) return 0;
97
98         Shader sdr = glCreateShaderObject(sdr_type);
99         glShaderSource(sdr, 1, &code, 0);
100         glCompileShader(sdr);
101         
102         int success, info_len;
103         glGetObjectParameteriv(sdr, GL_OBJECT_COMPILE_STATUS_ARB, &success);
104         glGetObjectParameteriv(sdr, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_len);
105
106         char *info_str = 0;
107         
108         if(info_len) {
109                 info_str = new char[info_len + 1];
110                 glGetInfoLog(sdr, info_len, 0, info_str);
111         }
112         
113         if(success) {
114                 if(info_len) {
115                         info("%s compiled: %s", name, info_str);
116                         delete [] info_str;
117                 } else {
118                         info("%s compiled successfully", name);
119                 }
120
121                 shaders->insert(name ? name : tmpnam(0), sdr);
122         } else {
123                 if(info_len) {
124                         error("%s compile failed: %s", name, info_str);
125                         delete [] info_str;
126                 } else {
127                         error("%s compile failed", name);
128                 }
129
130                 glDeleteObject(sdr);
131                 sdr = 0;
132         }
133
134         return sdr;
135 }
136
137
138 Shader get_shader(const char *name, int sdr_type) {
139         if(!shaders) init_sdr_man();
140         
141         Pair<string, Shader> *res = shaders->find(name);
142         if(res) return res->val;
143
144         return add_shader_file(name, sdr_type);
145 }
146
147 void destroy_shaders() {
148         info("Shutting down shader manager, destroying all shaders...");
149         delete shaders;
150         shaders = 0;
151 }