source: trunk/src/gpu/shader.cpp @ 1289

Last change on this file since 1289 was 1289, checked in by sam, 8 years ago

gpu: implement a few CG calls.

  • Property svn:keywords set to Id
File size: 19.6 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <cmath>
16#include <cstring>
17#include <cstdio>
18
19#ifdef WIN32
20#   define WIN32_LEAN_AND_MEAN
21#   include <windows.h>
22#   if defined USE_D3D9
23#       include <algorithm>
24        using std::min;
25        using std::max;
26#       include <d3d9.h>
27#       include <d3dx9shader.h>
28#   endif
29#endif
30
31#include "core.h"
32#include "lolgl.h"
33
34using namespace std;
35
36#if defined USE_D3D9
37extern IDirect3DDevice9 *g_d3ddevice;
38#elif defined _XBOX
39extern D3DDevice *g_d3ddevice;
40#endif
41
42namespace lol
43{
44
45/*
46 * Shader implementation class
47 */
48
49class ShaderData
50{
51    friend class Shader;
52
53private:
54#if defined USE_D3D9
55    IDirect3DVertexShader9 *vert_shader;
56    IDirect3DPixelShader9 *frag_shader;
57    ID3DXConstantTable *vert_table, *frag_table;
58#elif defined _XBOX
59    D3DVertexShader *vert_shader;
60    D3DPixelShader *frag_shader;
61    ID3DXConstantTable *vert_table, *frag_table;
62#elif !defined __CELLOS_LV2__
63    GLuint prog_id, vert_id, frag_id;
64#else
65    CGprogram vert_id, frag_id;
66#endif
67    uint32_t vert_crc, frag_crc;
68
69    /* Shader patcher */
70    static int GetVersion();
71    static void Patch(char *dst, char const *vert, char const *frag);
72
73    /* Global shader cache */
74    static Shader *shaders[];
75    static int nshaders;
76};
77
78Shader *ShaderData::shaders[256];
79int ShaderData::nshaders = 0;
80
81/*
82 * Public Shader class
83 */
84
85Shader *Shader::Create(char const *vert, char const *frag)
86{
87    uint32_t new_vert_crc = Hash::Crc32(vert);
88    uint32_t new_frag_crc = Hash::Crc32(frag);
89
90    for (int n = 0; n < ShaderData::nshaders; n++)
91    {
92        if (ShaderData::shaders[n]->data->vert_crc == new_vert_crc
93             && ShaderData::shaders[n]->data->frag_crc == new_frag_crc)
94            return ShaderData::shaders[n];
95    }
96
97    Shader *ret = new Shader(vert, frag);
98    ShaderData::shaders[ShaderData::nshaders] = ret;
99    ShaderData::nshaders++;
100    return ret;
101}
102
103void Shader::Destroy(Shader *shader)
104{
105    /* XXX: do nothing! the shader should remain in cache */
106    (void)shader;
107}
108
109Shader::Shader(char const *vert, char const *frag)
110  : data(new ShaderData())
111{
112#if defined USE_D3D9 || defined _XBOX
113    ID3DXBuffer *shader_code, *error_msg;
114    HRESULT hr;
115#elif !defined __CELLOS_LV2__
116    char buf[4096], errbuf[4096];
117    char const *shader = buf;
118    GLint status;
119    GLsizei len;
120#else
121    /* Initialise the runtime shader compiler. FIXME: this needs only
122     * to be done once. */
123    cgRTCgcInit();
124#endif
125
126    /* Compile vertex shader */
127    data->vert_crc = Hash::Crc32(vert);
128#if defined USE_D3D9 || defined _XBOX
129    hr = D3DXCompileShader(vert, (UINT)strlen(vert), NULL, NULL, "main",
130                           "vs_2_0", 0, &shader_code, &error_msg,
131                           &data->vert_table);
132    if (FAILED(hr))
133    {
134        Log::Error("failed to compile vertex shader: %s",
135                   error_msg ? error_msg->GetBufferPointer() : "error");
136        Log::Error("shader source:\n%s\n", vert);
137    }
138    g_d3ddevice->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
139                                    &data->vert_shader);
140    shader_code->Release();
141#elif !defined __CELLOS_LV2__
142    ShaderData::Patch(buf, vert, NULL);
143    data->vert_id = glCreateShader(GL_VERTEX_SHADER);
144    glShaderSource(data->vert_id, 1, &shader, NULL);
145    glCompileShader(data->vert_id);
146
147    glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
148    if (status != GL_TRUE)
149    {
150        glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
151        Log::Error("failed to compile vertex shader: %s", errbuf);
152        Log::Error("shader source:\n%s\n", buf);
153    }
154#else
155    data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
156                                    cgGLGetLatestProfile(CG_GL_VERTEX),
157                                    NULL, NULL);
158    if (data->vert_id == NULL)
159    {
160        Log::Error("failed to compile vertex shader");
161        Log::Error("shader source:\n%s\n", vert);
162    }
163#endif
164
165    /* Compile fragment shader */
166    data->frag_crc = Hash::Crc32(frag);
167#if defined USE_D3D9 || defined _XBOX
168    hr = D3DXCompileShader(frag, (UINT)strlen(frag), NULL, NULL, "main",
169                           "ps_2_0", 0, &shader_code, &error_msg,
170                           &data->frag_table);
171    if (FAILED(hr))
172    {
173        Log::Error("failed to compile fragment shader: %s",
174                   error_msg ? error_msg->GetBufferPointer() : "error");
175        Log::Error("shader source:\n%s\n", frag);
176    }
177    g_d3ddevice->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
178                                   &data->frag_shader);
179    shader_code->Release();
180#elif !defined __CELLOS_LV2__
181    ShaderData::Patch(buf, NULL, frag);
182    data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
183    glShaderSource(data->frag_id, 1, &shader, NULL);
184    glCompileShader(data->frag_id);
185
186    glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
187    if (status != GL_TRUE)
188    {
189        glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
190        Log::Error("failed to compile fragment shader: %s", errbuf);
191        Log::Error("shader source:\n%s\n", buf);
192    }
193#else
194    data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
195                                    cgGLGetLatestProfile(CG_GL_FRAGMENT),
196                                    NULL, NULL);
197    if (data->frag_id == NULL)
198    {
199        Log::Error("failed to compile fragment shader");
200        Log::Error("shader source:\n%s\n", frag);
201    }
202#endif
203
204#if defined USE_D3D9 || defined _XBOX
205    /* FIXME: this is only debug code, we don't need it. */
206    D3DXCONSTANTTABLE_DESC desc;
207    data->frag_table->GetDesc(&desc);
208    for (int i = 0; i < desc.Constants; i++)
209    {
210        D3DXCONSTANT_DESC cdesc;
211        UINT count = 1;
212        D3DXHANDLE h = data->frag_table->GetConstant(NULL, i);
213        data->frag_table->GetConstantDesc(h, &cdesc, &count);
214    }
215    data->vert_table->GetDesc(&desc);
216    for (int i = 0; i < desc.Constants; i++)
217    {
218        D3DXCONSTANT_DESC cdesc;
219        UINT count = 1;
220        D3DXHANDLE h = data->vert_table->GetConstant(NULL, i);
221        data->frag_table->GetConstantDesc(h, &cdesc, &count);
222    }
223#elif !defined __CELLOS_LV2__
224    /* Create program */
225    data->prog_id = glCreateProgram();
226    glAttachShader(data->prog_id, data->vert_id);
227    glAttachShader(data->prog_id, data->frag_id);
228
229    glLinkProgram(data->prog_id);
230    glValidateProgram(data->prog_id);
231#endif
232}
233
234ShaderAttrib Shader::GetAttribLocation(char const *attr,
235                                       VertexUsage usage, int index) const
236{
237    ShaderAttrib ret;
238    ret.m_flags = (uint64_t)(uint16_t)usage << 16;
239    ret.m_flags |= (uint64_t)(uint16_t)index;
240#if defined USE_D3D9 || defined _XBOX
241#elif !defined __CELLOS_LV2__
242    ret.m_flags |= (uint64_t)
243                  (uint32_t)glGetAttribLocation(data->prog_id, attr) << 32;
244#else
245    /* FIXME: can we do this at all on the PS3? */
246#endif
247    return ret;
248}
249
250ShaderUniform Shader::GetUniformLocation(char const *uni) const
251{
252    ShaderUniform ret;
253#if defined USE_D3D9 || defined _XBOX
254    /* Global variables are prefixed with "$" */
255    char tmpname[128];
256    sprintf(tmpname, "$%s", uni);
257    D3DXCONSTANT_DESC cdesc;
258    D3DXHANDLE hr;
259    UINT count;
260
261    count = 0;
262    hr = data->frag_table->GetConstantByName(NULL, tmpname);
263    if (hr)
264        data->frag_table->GetConstantDesc(hr, &cdesc, &count);
265    if (count)
266    {
267        ret.frag = cdesc.RegisterIndex;
268        ret.flags |= 1;
269    }
270
271    count = 0;
272    hr = data->vert_table->GetConstantByName(NULL, tmpname);
273    if (hr)
274        data->vert_table->GetConstantDesc(hr, &cdesc, &count);
275    if (count)
276    {
277        ret.vert = cdesc.RegisterIndex;
278        ret.flags |= 2;
279    }
280#elif !defined __CELLOS_LV2__
281    ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
282    ret.vert = 0;
283#else
284    ret.frag = (uintptr_t)cgGetNamedParameter(data->frag_id, uni);
285    ret.vert = (uintptr_t)cgGetNamedParameter(data->vert_id, uni);
286#endif
287    return ret;
288}
289
290void Shader::SetUniform(ShaderUniform const &uni, int i)
291{
292#if defined USE_D3D9 || defined _XBOX
293    SetUniform(uni, ivec4(i, 0, 0, 0));
294#elif !defined __CELLOS_LV2__
295    glUniform1i(uni.frag, i);
296#else
297    /* FIXME: does this exist at all? cgGLSetParameter1i doesn't. */
298#endif
299}
300
301void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
302{
303#if defined USE_D3D9 || defined _XBOX
304    SetUniform(uni, ivec4(v, 0, 0));
305#elif !defined __CELLOS_LV2__
306    glUniform2i(uni.frag, v.x, v.y);
307#else
308    /* FIXME: does this exist at all? */
309#endif
310}
311
312void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
313{
314#if defined USE_D3D9 || defined _XBOX
315    SetUniform(uni, ivec4(v, 0));
316#elif !defined __CELLOS_LV2__
317    glUniform3i(uni.frag, v.x, v.y, v.z);
318#else
319    /* FIXME: does this exist at all? */
320#endif
321}
322
323void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
324{
325#if defined USE_D3D9 || defined _XBOX
326    if (uni.flags & 1)
327        g_d3ddevice->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
328    if (uni.flags & 2)
329        g_d3ddevice->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
330#elif !defined __CELLOS_LV2__
331    glUniform4i(uni.frag, v.x, v.y, v.z, v.w);
332#else
333    /* FIXME: does this exist at all? */
334#endif
335}
336
337void Shader::SetUniform(ShaderUniform const &uni, float f)
338{
339#if defined USE_D3D9 || defined _XBOX
340    SetUniform(uni, vec4(f, 0, 0, 0));
341#elif !defined __CELLOS_LV2__
342    glUniform1f(uni.frag, f);
343#else
344    if (uni.frag)
345        cgGLSetParameter1f((CGparameter)uni.frag, f);
346    if (uni.vert)
347        cgGLSetParameter1f((CGparameter)uni.vert, f);
348#endif
349}
350
351void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
352{
353#if defined USE_D3D9 || defined _XBOX
354    SetUniform(uni, vec4(v, 0, 0));
355#elif !defined __CELLOS_LV2__
356    glUniform2fv(uni.frag, 1, &v[0]);
357#else
358    if (uni.frag)
359        cgGLSetParameter2fv((CGparameter)uni.frag, &v[0]);
360    if (uni.vert)
361        cgGLSetParameter2fv((CGparameter)uni.vert, &v[0]);
362#endif
363}
364
365void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
366{
367#if defined USE_D3D9 || defined _XBOX
368    SetUniform(uni, vec4(v, 0));
369#elif !defined __CELLOS_LV2__
370    glUniform3fv(uni.frag, 1, &v[0]);
371#else
372    if (uni.frag)
373        cgGLSetParameter3fv((CGparameter)uni.frag, &v[0]);
374    if (uni.vert)
375        cgGLSetParameter3fv((CGparameter)uni.vert, &v[0]);
376#endif
377}
378
379void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
380{
381#if defined USE_D3D9 || defined _XBOX
382    if (uni.flags & 1)
383        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
384    if (uni.flags & 2)
385        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
386#elif !defined __CELLOS_LV2__
387    glUniform4fv(uni.frag, 1, &v[0]);
388#else
389    if (uni.frag)
390        cgGLSetParameter4fv((CGparameter)uni.frag, &v[0]);
391    if (uni.vert)
392        cgGLSetParameter4fv((CGparameter)uni.vert, &v[0]);
393#endif
394}
395
396void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
397{
398#if defined USE_D3D9 || defined _XBOX
399    /* FIXME: do we need padding here like for the mat3 version? */
400    if (uni.flags & 1)
401        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
402    if (uni.flags & 2)
403        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
404#elif !defined __CELLOS_LV2__
405    glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]);
406#else
407    mat4 tmp(m, 1.0f, 1.0f);
408    if (uni.frag)
409        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
410    if (uni.vert)
411        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
412#endif
413}
414
415void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
416{
417#if defined USE_D3D9 || defined _XBOX
418    /* Padding matrix columns is necessary on DirectX. We need to create
419     * a new data structure; a 4×4 matrix will do. */
420    mat4 tmp(m, 1.0f);
421    if (uni.flags & 1)
422        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
423    if (uni.flags & 2)
424        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
425#elif !defined __CELLOS_LV2__
426    glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]);
427#else
428    /* FIXME: check it's the proper way to do this */
429    mat4 tmp(m, 1.0f);
430    if (uni.frag)
431        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
432    if (uni.vert)
433        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
434#endif
435}
436
437void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
438{
439#if defined USE_D3D9 || defined _XBOX
440    if (uni.flags & 1)
441        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
442    if (uni.flags & 2)
443        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
444#elif !defined __CELLOS_LV2__
445    glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]);
446#else
447    if (uni.frag)
448        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
449    if (uni.vert)
450        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
451#endif
452}
453
454void Shader::Bind() const
455{
456#if defined USE_D3D9 || defined _XBOX
457    HRESULT hr;
458    hr = g_d3ddevice->SetVertexShader(data->vert_shader);
459    hr = g_d3ddevice->SetPixelShader(data->frag_shader);
460#elif !defined __CELLOS_LV2__
461    glUseProgram(data->prog_id);
462#else
463    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
464    cgGLBindProgram(data->vert_id);
465    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
466    cgGLBindProgram(data->frag_id);
467#endif
468}
469
470void Shader::Unbind() const
471{
472#if defined USE_D3D9 || defined _XBOX
473    HRESULT hr;
474    hr = g_d3ddevice->SetVertexShader(NULL);
475    hr = g_d3ddevice->SetPixelShader(NULL);
476#elif !defined __CELLOS_LV2__
477    /* FIXME: untested */
478    glUseProgram(0);
479#else
480    /* FIXME: untested */
481    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
482    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
483#endif
484}
485
486Shader::~Shader()
487{
488#if defined USE_D3D9 || defined _XBOX
489    data->vert_shader->Release();
490    data->vert_table->Release();
491    data->frag_shader->Release();
492    data->frag_table->Release();
493#elif !defined __CELLOS_LV2__
494    glDetachShader(data->prog_id, data->vert_id);
495    glDetachShader(data->prog_id, data->frag_id);
496    glDeleteShader(data->vert_id);
497    glDeleteShader(data->frag_id);
498    glDeleteProgram(data->prog_id);
499#else
500    cgDestroyProgram(data->vert_id);
501    cgDestroyProgram(data->frag_id);
502#endif
503    delete data;
504}
505
506/* Try to detect shader compiler features */
507int ShaderData::GetVersion()
508{
509    static int version = 0;
510
511#if !defined USE_D3D9 && !defined _XBOX && !defined __CELLOS_LV2__
512    if (!version)
513    {
514        char buf[4096];
515        GLsizei len;
516
517        int id = glCreateShader(GL_VERTEX_SHADER);
518
519        /* Can we compile 1.30 shaders? */
520        char const *test130 =
521            "#version 130\n"
522            "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
523        glShaderSource(id, 1, &test130, NULL);
524        glCompileShader(id);
525        glGetShaderInfoLog(id, sizeof(buf), &len, buf);
526        if (len <= 0)
527            version = 130;
528
529        /* If not, can we compile 1.20 shaders? */
530        if (!version)
531        {
532            char const *test120 =
533                "#version 120\n"
534                "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
535            glShaderSource(id, 1, &test120, NULL);
536            glCompileShader(id);
537            glGetShaderInfoLog(id, sizeof(buf), &len, buf);
538            if (len <= 0)
539                version = 120;
540        }
541
542        /* Otherwise, assume we can compile 1.10 shaders. */
543        if (!version)
544            version = 110;
545
546        glDeleteShader(id);
547    }
548#endif
549
550    return version;
551}
552
553/* Simple shader source patching for old GLSL versions.
554 * If supported version is 1.30, do nothing.
555 * If supported version is 1.20:
556 *  - replace "#version 130" with "#version 120"
557 */
558void ShaderData::Patch(char *dst, char const *vert, char const *frag)
559{
560    int ver_driver = GetVersion();
561
562    strcpy(dst, vert ? vert : frag);
563    if (ver_driver >= 130)
564        return;
565
566    int ver_shader = 110;
567    char *parser = strstr(dst, "#version");
568    if (parser)
569        ver_shader = atoi(parser + strlen("#version"));
570
571    if (ver_shader > 120 && ver_driver <= 120)
572    {
573        char const *end = dst + strlen(dst) + 1;
574
575        /* Find main() */
576        parser = strstr(dst, "main");
577        if (!parser) return;
578        parser = strstr(parser, "(");
579        if (!parser) return;
580        parser = strstr(parser, ")");
581        if (!parser) return;
582        parser = strstr(parser, "{");
583        if (!parser) return;
584        char *main = parser + 1;
585
586        /* Perform main() replaces */
587        char const * const main_replaces[] =
588        {
589#if 0
590            "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
591            "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
592            "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
593
594            "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
595            "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
596            "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
597
598            "in vec2 in_MultiTexCoord0;",
599               "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
600            "in vec2 in_MultiTexCoord1;",
601               "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
602            "in vec2 in_MultiTexCoord2;",
603               "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
604            "in vec2 in_MultiTexCoord3;",
605               "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
606            "in vec2 in_MultiTexCoord4;",
607               "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
608            "in vec2 in_MultiTexCoord5;",
609               "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
610            "in vec2 in_MultiTexCoord6;",
611               "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
612            "in vec2 in_MultiTexCoord7;",
613               "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
614#endif
615
616            NULL
617        };
618
619        for (char const * const *rep = main_replaces; rep[0]; rep += 2)
620        {
621            char *match = strstr(dst, rep[0]);
622            if (match && match < main)
623            {
624                size_t l0 = strlen(rep[0]);
625                size_t l1 = strlen(rep[1]);
626                memmove(main + l1, main, end - main);
627                memcpy(main, rep[1], l1);
628                memset(match, ' ', l0);
629                main += l1;
630                end += l1;
631            }
632        }
633
634        /* Perform small replaces */
635        char const * const fast_replaces[] =
636        {
637            "#version 130", "#version 120",
638            "in vec2", vert ? "attribute vec2" : "varying vec2",
639            "in vec3", vert ? "attribute vec3" : "varying vec3",
640            "in vec4", vert ? "attribute vec4" : "varying vec4",
641            "in mat4", vert ? "attribute mat4" : "varying mat4",
642            "out vec2", "varying vec2",
643            "out vec3", "varying vec3",
644            "out vec4", "varying vec4",
645            "out mat4", "varying mat4",
646            NULL
647        };
648
649        for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
650        {
651            char *match;
652            while ((match = strstr(dst, rep[0])))
653            {
654                size_t l0 = strlen(rep[0]);
655                size_t l1 = strlen(rep[1]);
656
657                if (l1 > l0)
658                    memmove(match + l1, match + l0, (end - match) - l0);
659                memcpy(match, rep[1], l1);
660                if (l1 < l0)
661                    memset(match + l0, ' ', l1 - l0);
662                end += l1 - l0;
663            }
664        }
665    }
666}
667
668} /* namespace lol */
669
Note: See TracBrowser for help on using the repository browser.