1 module ecs_utils.gfx.shader;
2 
3 import bindbc.sdl;
4 
5 import bubel.ecs.std;
6 
7 version(WebAssembly)import glad.gl.gles2;
8 else version(Android)import glad.gl.gles2;
9 else import glad.gl.gl;
10 
11 //version = ver1;
12 
13 struct Shader
14 {
15 
16     void create() nothrow
17     {
18         data = Mallocator.make!Data;
19     }
20 
21     bool load(const char[] path) nothrow
22     {
23         if(data is null)data = Mallocator.make!Data;
24 
25         char[] cpath = (cast(char*)alloca(path.length+1))[0..path.length+1];
26         cpath[0..$-1] = path[0..$];
27         cpath[$-1] = 0;
28 
29         int ind = cast(int)path.length - 1;
30         for(;ind>0;ind--)
31         {
32             if(path[ind] == '.')break;
33         }
34         if(ind < 0)return false;
35         ind++;
36         if(ind + 2 > path.length)return false;
37 
38         char[2] ext = path[ind .. ind + 2];
39         if(ext[0] == 'v' && ext[1] == 'p')data.type = Type.vertex;
40         else if(ext[0] == 'f' && ext[1] == 'p')data.type = Type.fragment;
41         else return false;
42         
43         SDL_RWops* file = SDL_RWFromFile(cpath.ptr,"r");//SDL_LoadFile(cpath.ptr,);
44         if(file)
45         {
46             size_t size = cast(size_t)SDL_RWsize(file);
47             data.code = Mallocator.makeArray!char(size+1);
48             data.code[$-1] = 0;
49             SDL_RWread(file,data.code.ptr,size,1);
50 
51             SDL_RWclose(file);
52             return true;
53         }
54         else return false;
55 
56     }
57 
58     bool compile() nothrow
59     {
60         switch(data.type)
61         {
62             case Type.vertex:
63                 data.gl_handle = glCreateShader(GL_VERTEX_SHADER);
64                 break;
65             case Type.fragment:
66                 data.gl_handle = glCreateShader(GL_FRAGMENT_SHADER);
67                 break;
68             default: return false;
69         }
70         
71         version(WebAssembly)const char* glsl = "#version 100\n";
72         else version(Android)const char* glsl = "#version 100\n";
73         else const char* glsl = "#version 120\n";
74         const char* buffer = data.code.ptr;
75         char* ver;
76         version(WebAssembly)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr;
77         else version(Android)ver = cast(char*)"#define ver1 1\n#define GLES\n".ptr;
78         else ver = cast(char*)"#define ver1 1\n".ptr;
79         /*switch(__ecs_used_technique)
80         {
81             case RenderTechnique.simple:
82                 ver = cast(char*)"#define ver1 1\n".ptr;
83                 break;
84             case RenderTechnique.simple_array:
85                 ver = cast(char*)"#define ver2 1\n".ptr;
86                 break;
87             case RenderTechnique.vbo_batch:
88                 ver = cast(char*)"#define ver10 1\n".ptr;
89                 break;
90             case RenderTechnique.instanced_attrib_divisor:
91                 ver = cast(char*)"#define ver8 1\n".ptr;
92                 break;
93             case RenderTechnique.uniform_buffer:
94                 ver = cast(char*)"#define ver3 1\n".ptr;
95                 break;
96             case RenderTechnique.uniform_buffer_indexed:
97                 ver = cast(char*)"#define ver4 1\n".ptr;
98                 break;
99             case RenderTechnique.uniform_buffer_multi_draw:
100                 goto case(RenderTechnique.uniform_buffer_multi_draw_indirect);
101             case RenderTechnique.uniform_buffer_instanced:
102                 ver = cast(char*)"#define ver5 1\n".ptr;
103                 break;
104             case RenderTechnique.uniform_buffer_instanced_mapped_gl2:
105                 goto case(RenderTechnique.uniform_buffer_instanced);
106             case RenderTechnique.uniform_buffer_instanced_mapped:
107                 goto case(RenderTechnique.uniform_buffer_instanced);
108             case RenderTechnique.uniform_buffer_instanced_persistent_mapped:
109                 goto case(RenderTechnique.uniform_buffer_instanced);
110             case RenderTechnique.uniform_buffer_instanced_persistent_mapped_coherent:
111                 goto case(RenderTechnique.uniform_buffer_instanced);
112             case RenderTechnique.ssbo_instanced:
113                 ver = cast(char*)"#define ver6 1\n".ptr;
114                 break;
115             case RenderTechnique.uniform_buffer_draw_indirect:
116                 goto case(RenderTechnique.uniform_buffer);
117             case RenderTechnique.uniform_buffer_multi_draw_indirect:
118                 ver = cast(char*)"#define ver9 1\n".ptr;
119                 break;
120             case RenderTechnique.uniform_buffer_multi_draw_indirect_arb_draw_parameters:
121                 ver = cast(char*)"#define ver7 1\n".ptr;
122                 break;
123             default:break;
124         }*/
125         /*version(ver1)const char* ver = "#define ver1 1\n";
126         version(ver2)const char* ver = "#define ver2 1\n";
127         version(ver3)const char* ver = "#define ver3 1\n";
128         version(ver4)const char* ver = "#define ver4 1\n";
129         version(ver5)const char* ver = "#define ver5 1\n";
130         version(ver6)const char* ver = "#define ver5 1\n";*/
131 
132         const char*[3] input = [glsl,ver,buffer];
133         
134         glShaderSource(data.gl_handle,3,input.ptr,null);
135 
136         glCompileShader(data.gl_handle);
137 
138         int compile;
139         glGetShaderiv(data.gl_handle,GL_COMPILE_STATUS,&compile);
140         if(compile == GL_FALSE)
141         {
142             SDL_Log("Shader compile error! %u %s",data.type,glsl);
143             char[256] log;
144             int log_len;
145             glGetShaderInfoLog(data.gl_handle, 256, &log_len, log.ptr);
146             import ecs_utils.utils;
147             if(log_len)printf("%s",log.ptr);
148             return false;
149         }
150 
151         return true;
152     }
153 
154     void destroy() nothrow
155     {
156         if(data)
157         {
158             if(data.gl_handle)glDeleteShader(data.gl_handle);
159             Mallocator.dispose(data);
160             data = null;
161         }
162     }
163 
164     enum Type
165     {
166         vertex,
167         fragment,
168         geometry
169     }
170 
171     struct Data
172     {
173         char[] code;
174         Type type;
175 
176         uint gl_handle;
177     }
178 
179     Data* data;
180 }