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

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

core: replace usage of sin() or std::sin() with lol::sin() where appropriate.

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