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

Last change on this file since 1470 was 1470, checked in by sam, 9 years ago

gpu: be more verbose about shader compilation; some warnings are useful.

  • Property svn:keywords set to Id
File size: 22.1 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 *lolfx)
86{
87    char *src = new char[strlen(lolfx) + 2];
88    memcpy(src + 1, lolfx, strlen(lolfx) + 1);
89    src[0] = '\n';
90
91    /* Parse the crap */
92    Array<char const *, char const *> sections;
93    char *key = NULL;
94    for (char *parser = src; *parser; )
95    {
96        if (key == NULL && (parser[0] == '\n' || parser[0] == '\r')
97             && parser[1] == '-' && parser[2] == '-' && parser[3] == ' ')
98        {
99            *parser = '\0';
100            parser += 4;
101            key = parser;
102        }
103        else if (key && parser[0] == ' ')
104        {
105            *parser++ = '\0';
106        }
107        else if (key && (parser[0] == '\n' || parser[0] == '\r'))
108        {
109            sections.Push(key, parser);
110            parser++;
111            key = NULL;
112        }
113        else
114        {
115            parser++;
116        }
117    }
118
119    char const *vert = NULL, *frag = NULL;
120    for (int i = 0; i < sections.Count(); i++)
121    {
122#if !defined __CELLOS_LV2__ && !defined _XBOX && !defined USE_D3D9
123        if (!strcmp(sections[i].m1, "GLSL.Vert"))
124            vert = sections[i].m2;
125        if (!strcmp(sections[i].m1, "GLSL.Frag"))
126            frag = sections[i].m2;
127#else
128        if (!strcmp(sections[i].m1, "HLSL.Vert"))
129            vert = sections[i].m2;
130        if (!strcmp(sections[i].m1, "HLSL.Frag"))
131            frag = sections[i].m2;
132#endif
133    }
134
135    Shader *ret = NULL;
136    if (vert && frag)
137        ret = Create(vert, frag);
138
139    delete[] src;
140
141    return ret;
142}
143
144Shader *Shader::Create(char const *vert, char const *frag)
145{
146    uint32_t new_vert_crc = Hash::Crc32(vert);
147    uint32_t new_frag_crc = Hash::Crc32(frag);
148
149    for (int n = 0; n < ShaderData::nshaders; n++)
150    {
151        if (ShaderData::shaders[n]->data->vert_crc == new_vert_crc
152             && ShaderData::shaders[n]->data->frag_crc == new_frag_crc)
153            return ShaderData::shaders[n];
154    }
155
156    Shader *ret = new Shader(vert, frag);
157    ShaderData::shaders[ShaderData::nshaders] = ret;
158    ShaderData::nshaders++;
159    return ret;
160}
161
162void Shader::Destroy(Shader *shader)
163{
164    /* XXX: do nothing! the shader should remain in cache */
165    (void)shader;
166}
167
168Shader::Shader(char const *vert, char const *frag)
169  : data(new ShaderData())
170{
171#if defined USE_D3D9 || defined _XBOX
172    ID3DXBuffer *shader_code, *error_msg;
173    HRESULT hr;
174    D3DXMACRO macros[] =
175    {
176#if defined _XBOX
177        { "_XBOX", "1" },
178#endif
179        { NULL, NULL }
180    };
181#elif !defined __CELLOS_LV2__
182    char buf[4096], errbuf[4096];
183    char const *shader = buf;
184    GLint status;
185    GLsizei len;
186#else
187    /* Initialise the runtime shader compiler. FIXME: this needs only
188     * to be done once. */
189    cgRTCgcInit();
190#endif
191
192    /* Compile vertex shader */
193    data->vert_crc = Hash::Crc32(vert);
194#if defined USE_D3D9 || defined _XBOX
195    hr = D3DXCompileShader(vert, (UINT)strlen(vert), macros, NULL, "main",
196                           "vs_2_0", 0, &shader_code, &error_msg,
197                           &data->vert_table);
198    if (FAILED(hr))
199    {
200        Log::Error("failed to compile vertex shader: %s",
201                   error_msg ? error_msg->GetBufferPointer() : "error");
202        Log::Error("shader source:\n%s\n", vert);
203    }
204    g_d3ddevice->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
205                                    &data->vert_shader);
206    shader_code->Release();
207#elif !defined __CELLOS_LV2__
208    ShaderData::Patch(buf, vert, NULL);
209    data->vert_id = glCreateShader(GL_VERTEX_SHADER);
210    glShaderSource(data->vert_id, 1, &shader, NULL);
211    glCompileShader(data->vert_id);
212
213    glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
214    glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
215    if (status != GL_TRUE)
216    {
217        Log::Error("failed to compile vertex shader: %s", errbuf);
218        Log::Error("shader source:\n%s\n", buf);
219    }
220    else if (len > 1)
221    {
222        Log::Debug("compile log for vertex shader: %s", errbuf);
223        Log::Debug("shader source:\n%s\n", buf);
224    }
225#else
226    data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
227                                    cgGLGetLatestProfile(CG_GL_VERTEX),
228                                    NULL, NULL);
229    if (data->vert_id == NULL)
230    {
231        Log::Error("failed to compile vertex shader");
232        Log::Error("shader source:\n%s\n", vert);
233    }
234#endif
235
236    /* Compile fragment shader */
237    data->frag_crc = Hash::Crc32(frag);
238#if defined USE_D3D9 || defined _XBOX
239    hr = D3DXCompileShader(frag, (UINT)strlen(frag), macros, NULL, "main",
240                           "ps_2_0", 0, &shader_code, &error_msg,
241                           &data->frag_table);
242    if (FAILED(hr))
243    {
244        Log::Error("failed to compile fragment shader: %s",
245                   error_msg ? error_msg->GetBufferPointer() : "error");
246        Log::Error("shader source:\n%s\n", frag);
247    }
248    g_d3ddevice->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
249                                   &data->frag_shader);
250    shader_code->Release();
251#elif !defined __CELLOS_LV2__
252    ShaderData::Patch(buf, NULL, frag);
253    data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
254    glShaderSource(data->frag_id, 1, &shader, NULL);
255    glCompileShader(data->frag_id);
256
257    glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
258    glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
259    if (status != GL_TRUE)
260    {
261        Log::Error("failed to compile fragment shader: %s", errbuf);
262        Log::Error("shader source:\n%s\n", buf);
263    }
264    else if (len > 1)
265    {
266        Log::Debug("compile log for fragment shader: %s", errbuf);
267        Log::Debug("shader source:\n%s\n", buf);
268    }
269#else
270    data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
271                                    cgGLGetLatestProfile(CG_GL_FRAGMENT),
272                                    NULL, NULL);
273    if (data->frag_id == NULL)
274    {
275        Log::Error("failed to compile fragment shader");
276        Log::Error("shader source:\n%s\n", frag);
277    }
278#endif
279
280#if defined USE_D3D9 || defined _XBOX
281    /* FIXME: this is only debug code, we don't need it. */
282    D3DXCONSTANTTABLE_DESC desc;
283    data->frag_table->GetDesc(&desc);
284    for (int i = 0; i < desc.Constants; i++)
285    {
286        D3DXCONSTANT_DESC cdesc;
287        UINT count = 1;
288        D3DXHANDLE h = data->frag_table->GetConstant(NULL, i);
289        data->frag_table->GetConstantDesc(h, &cdesc, &count);
290    }
291    data->vert_table->GetDesc(&desc);
292    for (int i = 0; i < desc.Constants; i++)
293    {
294        D3DXCONSTANT_DESC cdesc;
295        UINT count = 1;
296        D3DXHANDLE h = data->vert_table->GetConstant(NULL, i);
297        data->frag_table->GetConstantDesc(h, &cdesc, &count);
298    }
299#elif !defined __CELLOS_LV2__
300    /* Create program */
301    data->prog_id = glCreateProgram();
302    glAttachShader(data->prog_id, data->vert_id);
303    glAttachShader(data->prog_id, data->frag_id);
304
305    glLinkProgram(data->prog_id);
306    glGetProgramInfoLog(data->prog_id, sizeof(errbuf), &len, errbuf);
307    glGetProgramiv(data->prog_id, GL_LINK_STATUS, &status);
308    if (status != GL_TRUE)
309    {
310        Log::Error("failed to link program: %s", errbuf);
311    }
312    else if (len > 1)
313    {
314        Log::Debug("link log for program: %s", errbuf);
315    }
316    glValidateProgram(data->prog_id);
317#endif
318}
319
320ShaderAttrib Shader::GetAttribLocation(char const *attr,
321                                       VertexUsage usage, int index) const
322{
323    ShaderAttrib ret;
324    ret.m_flags = (uint64_t)(uint16_t)usage << 16;
325    ret.m_flags |= (uint64_t)(uint16_t)index;
326#if defined USE_D3D9 || defined _XBOX
327#elif !defined __CELLOS_LV2__
328    ret.m_flags |= (uint64_t)
329                  (uint32_t)glGetAttribLocation(data->prog_id, attr) << 32;
330#else
331    /* FIXME: can we do this at all on the PS3? */
332#endif
333    return ret;
334}
335
336ShaderUniform Shader::GetUniformLocation(char const *uni) const
337{
338    ShaderUniform ret;
339#if defined USE_D3D9 || defined _XBOX
340    /* Global variables are prefixed with "$" */
341    char tmpname[128];
342    sprintf(tmpname, "$%s", uni);
343    D3DXCONSTANT_DESC cdesc;
344    D3DXHANDLE hr;
345    UINT count;
346
347    count = 0;
348    hr = data->frag_table->GetConstantByName(NULL, tmpname);
349    if (hr)
350        data->frag_table->GetConstantDesc(hr, &cdesc, &count);
351    if (count)
352    {
353        ret.frag = cdesc.RegisterIndex;
354        ret.flags |= 1;
355    }
356
357    count = 0;
358    hr = data->vert_table->GetConstantByName(NULL, tmpname);
359    if (hr)
360        data->vert_table->GetConstantDesc(hr, &cdesc, &count);
361    if (count)
362    {
363        ret.vert = cdesc.RegisterIndex;
364        ret.flags |= 2;
365    }
366#elif !defined __CELLOS_LV2__
367    ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
368    ret.vert = 0;
369#else
370    ret.frag = (uintptr_t)cgGetNamedParameter(data->frag_id, uni);
371    ret.vert = (uintptr_t)cgGetNamedParameter(data->vert_id, uni);
372#endif
373    return ret;
374}
375
376void Shader::SetUniform(ShaderUniform const &uni, int i)
377{
378#if defined USE_D3D9 || defined _XBOX
379    SetUniform(uni, ivec4(i, 0, 0, 0));
380#elif !defined __CELLOS_LV2__
381    glUniform1i(uni.frag, i);
382#else
383    /* FIXME: does this exist at all? cgGLSetParameter1i doesn't. */
384#endif
385}
386
387void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
388{
389#if defined USE_D3D9 || defined _XBOX
390    SetUniform(uni, ivec4(v, 0, 0));
391#elif !defined __CELLOS_LV2__
392    glUniform2i(uni.frag, v.x, v.y);
393#else
394    /* FIXME: does this exist at all? */
395#endif
396}
397
398void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
399{
400#if defined USE_D3D9 || defined _XBOX
401    SetUniform(uni, ivec4(v, 0));
402#elif !defined __CELLOS_LV2__
403    glUniform3i(uni.frag, v.x, v.y, v.z);
404#else
405    /* FIXME: does this exist at all? */
406#endif
407}
408
409void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
410{
411#if defined USE_D3D9 || defined _XBOX
412    if (uni.flags & 1)
413        g_d3ddevice->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
414    if (uni.flags & 2)
415        g_d3ddevice->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
416#elif !defined __CELLOS_LV2__
417    glUniform4i(uni.frag, v.x, v.y, v.z, v.w);
418#else
419    /* FIXME: does this exist at all? */
420#endif
421}
422
423void Shader::SetUniform(ShaderUniform const &uni, float f)
424{
425#if defined USE_D3D9 || defined _XBOX
426    SetUniform(uni, vec4(f, 0, 0, 0));
427#elif !defined __CELLOS_LV2__
428    glUniform1f(uni.frag, f);
429#else
430    if (uni.frag)
431        cgGLSetParameter1f((CGparameter)uni.frag, f);
432    if (uni.vert)
433        cgGLSetParameter1f((CGparameter)uni.vert, f);
434#endif
435}
436
437void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
438{
439#if defined USE_D3D9 || defined _XBOX
440    SetUniform(uni, vec4(v, 0, 0));
441#elif !defined __CELLOS_LV2__
442    glUniform2fv(uni.frag, 1, &v[0]);
443#else
444    if (uni.frag)
445        cgGLSetParameter2fv((CGparameter)uni.frag, &v[0]);
446    if (uni.vert)
447        cgGLSetParameter2fv((CGparameter)uni.vert, &v[0]);
448#endif
449}
450
451void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
452{
453#if defined USE_D3D9 || defined _XBOX
454    SetUniform(uni, vec4(v, 0));
455#elif !defined __CELLOS_LV2__
456    glUniform3fv(uni.frag, 1, &v[0]);
457#else
458    if (uni.frag)
459        cgGLSetParameter3fv((CGparameter)uni.frag, &v[0]);
460    if (uni.vert)
461        cgGLSetParameter3fv((CGparameter)uni.vert, &v[0]);
462#endif
463}
464
465void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
466{
467#if defined USE_D3D9 || defined _XBOX
468    if (uni.flags & 1)
469        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
470    if (uni.flags & 2)
471        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
472#elif !defined __CELLOS_LV2__
473    glUniform4fv(uni.frag, 1, &v[0]);
474#else
475    if (uni.frag)
476        cgGLSetParameter4fv((CGparameter)uni.frag, &v[0]);
477    if (uni.vert)
478        cgGLSetParameter4fv((CGparameter)uni.vert, &v[0]);
479#endif
480}
481
482void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
483{
484#if defined USE_D3D9 || defined _XBOX
485    /* FIXME: do we need padding here like for the mat3 version? */
486    if (uni.flags & 1)
487        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
488    if (uni.flags & 2)
489        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
490#elif !defined __CELLOS_LV2__
491    glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]);
492#else
493    mat4 tmp(m, 1.0f, 1.0f);
494    if (uni.frag)
495        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
496    if (uni.vert)
497        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
498#endif
499}
500
501void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
502{
503#if defined USE_D3D9 || defined _XBOX
504    /* Padding matrix columns is necessary on DirectX. We need to create
505     * a new data structure; a 4×4 matrix will do. */
506    mat4 tmp(m, 1.0f);
507    if (uni.flags & 1)
508        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
509    if (uni.flags & 2)
510        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
511#elif !defined __CELLOS_LV2__
512    glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]);
513#else
514    /* FIXME: check it's the proper way to do this */
515    mat4 tmp(m, 1.0f);
516    if (uni.frag)
517        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
518    if (uni.vert)
519        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
520#endif
521}
522
523void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
524{
525#if defined USE_D3D9 || defined _XBOX
526    if (uni.flags & 1)
527        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
528    if (uni.flags & 2)
529        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
530#elif !defined __CELLOS_LV2__
531    glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]);
532#else
533    if (uni.frag)
534        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
535    if (uni.vert)
536        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
537#endif
538}
539
540void Shader::SetTexture(ShaderUniform const &uni, int id, int index)
541{
542#if defined USE_D3D9 || defined _XBOX
543    /* FIXME: unimplemented */
544#elif !defined __CELLOS_LV2__
545    glActiveTexture(GL_TEXTURE0 + index);
546    //glEnable(GL_TEXTURE_2D);
547    glBindTexture(GL_TEXTURE_2D, id);
548    SetUniform(uni, index);
549#else
550    /* FIXME: unimplemented */
551#endif
552}
553
554void Shader::Bind() const
555{
556#if defined USE_D3D9 || defined _XBOX
557    HRESULT hr;
558    hr = g_d3ddevice->SetVertexShader(data->vert_shader);
559    hr = g_d3ddevice->SetPixelShader(data->frag_shader);
560#elif !defined __CELLOS_LV2__
561    glUseProgram(data->prog_id);
562#else
563    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
564    cgGLBindProgram(data->vert_id);
565    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
566    cgGLBindProgram(data->frag_id);
567#endif
568}
569
570void Shader::Unbind() const
571{
572#if defined USE_D3D9 || defined _XBOX
573    HRESULT hr;
574    hr = g_d3ddevice->SetVertexShader(NULL);
575    hr = g_d3ddevice->SetPixelShader(NULL);
576#elif !defined __CELLOS_LV2__
577    /* FIXME: untested */
578    glUseProgram(0);
579#else
580    /* FIXME: untested */
581    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
582    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
583#endif
584}
585
586Shader::~Shader()
587{
588#if defined USE_D3D9 || defined _XBOX
589    data->vert_shader->Release();
590    data->vert_table->Release();
591    data->frag_shader->Release();
592    data->frag_table->Release();
593#elif !defined __CELLOS_LV2__
594    glDetachShader(data->prog_id, data->vert_id);
595    glDetachShader(data->prog_id, data->frag_id);
596    glDeleteShader(data->vert_id);
597    glDeleteShader(data->frag_id);
598    glDeleteProgram(data->prog_id);
599#else
600    cgDestroyProgram(data->vert_id);
601    cgDestroyProgram(data->frag_id);
602#endif
603    delete data;
604}
605
606/* Try to detect shader compiler features */
607int ShaderData::GetVersion()
608{
609    static int version = 0;
610
611#if !defined USE_D3D9 && !defined _XBOX && !defined __CELLOS_LV2__
612    if (!version)
613    {
614        char buf[4096];
615        GLsizei len;
616
617        int id = glCreateShader(GL_VERTEX_SHADER);
618
619        /* Can we compile 1.30 shaders? */
620        char const *test130 =
621            "#version 130\n"
622            "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
623        glShaderSource(id, 1, &test130, NULL);
624        glCompileShader(id);
625        glGetShaderInfoLog(id, sizeof(buf), &len, buf);
626        if (len <= 0)
627            version = 130;
628
629        /* If not, can we compile 1.20 shaders? */
630        if (!version)
631        {
632            char const *test120 =
633                "#version 120\n"
634                "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
635            glShaderSource(id, 1, &test120, NULL);
636            glCompileShader(id);
637            glGetShaderInfoLog(id, sizeof(buf), &len, buf);
638            if (len <= 0)
639                version = 120;
640        }
641
642        /* Otherwise, assume we can compile 1.10 shaders. */
643        if (!version)
644            version = 110;
645
646        glDeleteShader(id);
647    }
648#endif
649
650    return version;
651}
652
653/* Simple shader source patching for old GLSL versions.
654 * If supported version is 1.30, do nothing.
655 * If supported version is 1.20:
656 *  - replace "#version 130" with "#version 120"
657 */
658void ShaderData::Patch(char *dst, char const *vert, char const *frag)
659{
660    int ver_driver = GetVersion();
661
662    strcpy(dst, vert ? vert : frag);
663    if (ver_driver >= 130)
664        return;
665
666    int ver_shader = 110;
667    char *parser = strstr(dst, "#version");
668    if (parser)
669        ver_shader = atoi(parser + strlen("#version"));
670
671    if (ver_shader > 120 && ver_driver <= 120)
672    {
673        char const *end = dst + strlen(dst) + 1;
674
675        /* Find main() */
676        parser = strstr(dst, "main");
677        if (!parser) return;
678        parser = strstr(parser, "(");
679        if (!parser) return;
680        parser = strstr(parser, ")");
681        if (!parser) return;
682        parser = strstr(parser, "{");
683        if (!parser) return;
684        char *main = parser + 1;
685
686        /* Perform main() replaces */
687        char const * const main_replaces[] =
688        {
689#if 0
690            "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
691            "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
692            "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
693
694            "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
695            "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
696            "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
697
698            "in vec2 in_MultiTexCoord0;",
699               "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
700            "in vec2 in_MultiTexCoord1;",
701               "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
702            "in vec2 in_MultiTexCoord2;",
703               "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
704            "in vec2 in_MultiTexCoord3;",
705               "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
706            "in vec2 in_MultiTexCoord4;",
707               "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
708            "in vec2 in_MultiTexCoord5;",
709               "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
710            "in vec2 in_MultiTexCoord6;",
711               "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
712            "in vec2 in_MultiTexCoord7;",
713               "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
714#endif
715
716            NULL
717        };
718
719        for (char const * const *rep = main_replaces; rep[0]; rep += 2)
720        {
721            char *match = strstr(dst, rep[0]);
722            if (match && match < main)
723            {
724                size_t l0 = strlen(rep[0]);
725                size_t l1 = strlen(rep[1]);
726                memmove(main + l1, main, end - main);
727                memcpy(main, rep[1], l1);
728                memset(match, ' ', l0);
729                main += l1;
730                end += l1;
731            }
732        }
733
734        /* Perform small replaces */
735        char const * const fast_replaces[] =
736        {
737            "#version 130", "#version 120",
738            "in vec2", vert ? "attribute vec2" : "varying vec2",
739            "in vec3", vert ? "attribute vec3" : "varying vec3",
740            "in vec4", vert ? "attribute vec4" : "varying vec4",
741            "in mat4", vert ? "attribute mat4" : "varying mat4",
742            "out vec2", "varying vec2",
743            "out vec3", "varying vec3",
744            "out vec4", "varying vec4",
745            "out mat4", "varying mat4",
746            NULL
747        };
748
749        for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
750        {
751            char *match;
752            while ((match = strstr(dst, rep[0])))
753            {
754                size_t l0 = strlen(rep[0]);
755                size_t l1 = strlen(rep[1]);
756
757                if (l1 > l0)
758                    memmove(match + l1, match + l0, (end - match) - l0);
759                memcpy(match, rep[1], l1);
760                if (l1 < l0)
761                    memset(match + l0, ' ', l1 - l0);
762                end += l1 - l0;
763            }
764        }
765    }
766}
767
768} /* namespace lol */
769
Note: See TracBrowser for help on using the repository browser.