~unity-team/compiz/plugins-main-trunk.fix_wrong_window_move_expo

« back to all changes in this revision

Viewing changes to colorfilter/src/parser.cpp

  • Committer: David Barth
  • Date: 2011-03-29 16:36:40 UTC
  • Revision ID: david.barth@canonical.com-20110329163640-fpen5qsoo0lbjode
initial import from compiz-plugins-main_0.9.4git20110322.orig.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Compiz fragment program parser
 
3
 *
 
4
 * parser.cpp
 
5
 *
 
6
 * This should be usable on almost any plugin that wishes to parse fragment
 
7
 * program files separately, maybe it should become a separate plugin?
 
8
 *
 
9
 * Author : Guillaume Seguin
 
10
 * Email : guillaume@segu.in
 
11
 *
 
12
 * Copyright (c) 2007 Guillaume Seguin <guillaume@segu.in>
 
13
 *
 
14
 * Port to std::string:
 
15
 * Copyright (c) 2010 Canonical Ltd. <sam.spilsbury@canonical.com>
 
16
 *
 
17
 * This program is free software; you can redistribute it and/or
 
18
 * modify it under the terms of the GNU General Public License
 
19
 * as published by the Free Software Foundation; either version 2
 
20
 * of the License, or (at your option) any later version.
 
21
 *
 
22
 * This program is distributed in the hope that it will be useful,
 
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
25
 * GNU General Public License for more details.
 
26
 *
 
27
 * You should have received a copy of the GNU General Public License
 
28
 * along with this program; if not, write to the Free Software
 
29
 * Foundation, Inc., 51 Franklin Street,
 
30
 * Fifth Floor, Boston, MA  02110-1301, USA.
 
31
 */
 
32
 
 
33
 
 
34
#ifndef _GNU_SOURCE
 
35
#define _GNU_SOURCE
 
36
#endif
 
37
 
 
38
#include <cstring>
 
39
#include <ctype.h>
 
40
#include <sstream>
 
41
#include <fstream>
 
42
#include "parser.h"
 
43
 
 
44
/*
 
45
 * Left trimming function
 
46
 */
 
47
CompString
 
48
FragmentParser::ltrim (const CompString &string)
 
49
{
 
50
    size_t pos = 0;
 
51
    while (!(pos >= string.size ()))
 
52
    {
 
53
        if (isspace (string.at (pos)))
 
54
            pos++;
 
55
        else
 
56
            break;
 
57
    }
 
58
 
 
59
    return string.substr (pos);
 
60
}
 
61
 
 
62
/* General fragment program related functions ----------------------- */
 
63
 
 
64
/*
 
65
 * Clean program name string
 
66
 */
 
67
void
 
68
FragmentParser::programCleanName (CompString &name)
 
69
{
 
70
    unsigned int pos = 0;
 
71
 
 
72
    /* Replace every non alphanumeric char by '_' */
 
73
    while (!(pos >= name.size ()))
 
74
    {
 
75
        if (!isalnum (name.at (pos)))
 
76
            name[pos] = '_';
 
77
 
 
78
        pos++;
 
79
    }
 
80
}
 
81
 
 
82
/*
 
83
 * File reader function
 
84
 */
 
85
CompString
 
86
FragmentParser::programReadSource (const CompString &fname)
 
87
{
 
88
    std::ifstream fp;
 
89
    int length;
 
90
    char *buffer;
 
91
    CompString data, path, home = CompString (getenv ("HOME"));
 
92
 
 
93
    /* Try to open file fname as is */
 
94
    fp.open (fname.c_str ());
 
95
 
 
96
    /* If failed, try as user filter file (in ~/.compiz/data/filters) */
 
97
    if (!fp.is_open () && !home.empty ())
 
98
    {
 
99
        path = home + "/.compiz/data/filters/" + fname;
 
100
        fp.open (path.c_str ());
 
101
    }
 
102
 
 
103
    /* If failed again, try as system wide data file
 
104
     * (in PREFIX/share/compiz/filters) */
 
105
    if (!fp.is_open ())
 
106
    {
 
107
        path = CompString (DATADIR) + "/data/filters/" + fname;
 
108
        fp.open (path.c_str ());
 
109
    }
 
110
 
 
111
    /* If failed again & again, abort */
 
112
    if (!fp.is_open ())
 
113
    {
 
114
        return CompString ("");
 
115
    }
 
116
 
 
117
    /* get length of file: */
 
118
    fp.seekg (0, std::ios::end);
 
119
    length = fp.tellg ();
 
120
    length++;
 
121
    fp.seekg (0, std::ios::beg);
 
122
 
 
123
    /* allocate memory */
 
124
    buffer = new char [length];
 
125
 
 
126
    /* read data as a block: */
 
127
    fp.read (buffer, length - 1);
 
128
    buffer[length - 1] = '\0';
 
129
    fp.close ();
 
130
 
 
131
    data = buffer;
 
132
 
 
133
    delete[] buffer;
 
134
 
 
135
    return data;
 
136
}
 
137
 
 
138
/*
 
139
 * Get the first "argument" in the given string, trimmed
 
140
 * and move source string pointer after the end of the argument.
 
141
 * For instance in string " foo, bar" this function will return "foo".
 
142
 *
 
143
 * This function returns NULL if no argument found
 
144
 * or a malloc'ed string that will have to be freed later.
 
145
 */
 
146
CompString
 
147
FragmentParser::getFirstArgument (const CompString &line,
 
148
                                  size_t &pos)
 
149
{
 
150
    CompString arg;
 
151
    CompString string;
 
152
    size_t next, temp, orig;
 
153
    int length;
 
154
    CompString retArg;
 
155
 
 
156
    if (pos >= line.size ())
 
157
        return CompString ("");
 
158
 
 
159
    /* Left trim */
 
160
    string = FragmentParser::ltrim (line.substr (pos));
 
161
 
 
162
    orig = pos;
 
163
    pos = 0;
 
164
 
 
165
    /* Find next comma or semicolon (which isn't that useful since we
 
166
     * are working on tokens delimited by semicolons) */
 
167
    if ((next = string.find (",", pos)) != std::string::npos ||
 
168
        (next = string.find (";", pos)) != std::string::npos)
 
169
    {
 
170
        length = next - pos;
 
171
        if (!length)
 
172
        {
 
173
            pos = orig + 1;
 
174
            return getFirstArgument (line, pos);
 
175
        }
 
176
        if ((temp = string.find ("{", pos) != std::string::npos) && temp < next &&
 
177
            (temp = string.find ("}", pos) != std::string::npos) && temp > next)
 
178
        {
 
179
            if ((next = string.find (",", temp)) != std::string::npos ||
 
180
                (next = string.find (";", temp)) != std::string::npos)
 
181
                length = next - pos;
 
182
            else
 
183
                length = string.substr (pos).size ();
 
184
        }
 
185
    }
 
186
    else
 
187
        length = string.substr (pos).size ();
 
188
 
 
189
    /* Allocate, copy and end string */
 
190
    arg = string.substr (pos, length);
 
191
 
 
192
    /* Increment source pointer */
 
193
    if ((orig + arg.size () + 1) <= line.size ())
 
194
        pos += orig + arg.size () + 1;
 
195
    else
 
196
        pos = std::string::npos;
 
197
 
 
198
    return arg;
 
199
}
 
200
 
 
201
/* Texture offset related functions ----------------------------------*/
 
202
 
 
203
/*
 
204
 * Add a new fragment offset to the offsets stack from an ADD op string
 
205
 */
 
206
FragmentParser::FragmentOffset *
 
207
FragmentParser::programAddOffsetFromAddOp (const CompString &source)
 
208
{
 
209
    FragmentOffset  offset;
 
210
    CompString  op;
 
211
    size_t          pos = 0;
 
212
    CompString      name;
 
213
    CompString      offsetString;
 
214
    CompString      temp;
 
215
    std::list <FragmentOffset>::iterator it = offsets.begin ();
 
216
 
 
217
    if (source.size () < 5)
 
218
        return NULL;
 
219
 
 
220
    op = source;
 
221
    pos += 3;
 
222
    name = getFirstArgument (op, pos);
 
223
    if (name.empty ())
 
224
        return NULL;
 
225
 
 
226
    temp = getFirstArgument (op, pos);
 
227
 
 
228
    /* If an offset with the same name is
 
229
     * already registered, skip this one */
 
230
    if ((!offsets.empty () &&
 
231
         !programFindOffset (it, name).empty ()) ||
 
232
         temp.empty ())
 
233
        return &(*it);
 
234
 
 
235
    /* Just use the end of the op as the offset */
 
236
    pos += 1;
 
237
    offsetString = ltrim (op.substr (pos));
 
238
    if (offsetString.empty ())
 
239
        return NULL;
 
240
 
 
241
    offset.name =  name;
 
242
    offset.offset = offsetString;
 
243
 
 
244
    offsets.push_back (offset);
 
245
 
 
246
    return &(offsets.back ());
 
247
}
 
248
 
 
249
/*
 
250
 * Find an offset according to its name
 
251
 */
 
252
CompString
 
253
FragmentParser::programFindOffset (std::list<FragmentOffset>::iterator it,
 
254
                                   const CompString &name)
 
255
{
 
256
    if (it->name == name)
 
257
        return (*it).offset;
 
258
 
 
259
    return programFindOffset ((it++), name);
 
260
}
 
261
 
 
262
/*
 
263
 * Recursively free offsets stack
 
264
 */
 
265
void
 
266
FragmentParser::programFreeOffset ()
 
267
{
 
268
    offsets.clear ();
 
269
}
 
270
 
 
271
/* Actual parsing/loading functions ----------------------------------*/
 
272
 
 
273
/*
 
274
 * Parse the source buffer op by op and add each op to function data
 
275
 *
 
276
 * FIXME : I am more than 200 lines long, I feel so heavy!
 
277
 */
 
278
void
 
279
FragmentParser::programParseSource (GLFragment::FunctionData *data,
 
280
                                    int target, CompString &source)
 
281
{
 
282
    CompString line, next;
 
283
    CompString current;
 
284
    CompString strtok;
 
285
    size_t     pos = 0, strippos = 0;
 
286
    int   length, oplength, type;
 
287
 
 
288
    CompString arg1, arg2, temp;
 
289
 
 
290
    /* Find the header, skip it, and start parsing from there */
 
291
 
 
292
    pos = source.find ("!!ARBfp1.0", pos);
 
293
    if (pos != std::string::npos)
 
294
    {
 
295
        pos += 9;
 
296
    }
 
297
 
 
298
    /* Strip comments */
 
299
    while ((strippos = source.find ("#", strippos)) != std::string::npos)
 
300
    {
 
301
        size_t carriagepos = source.find ("\n", strippos);
 
302
 
 
303
        if (carriagepos != std::string::npos)
 
304
        {
 
305
            source.erase (strippos, carriagepos - strippos);
 
306
            strippos = 0;
 
307
        }
 
308
        else
 
309
            source = source.substr (0, strippos);
 
310
    }
 
311
 
 
312
    strippos = 0;
 
313
 
 
314
    /* Strip linefeeds */
 
315
    while ((strippos = source.find ("\n", strippos)) != std::string::npos)
 
316
        source[strippos] = ' ';
 
317
 
 
318
    /* Parse each instruction */
 
319
    while (!(pos >= (source.size () - 1)))
 
320
    {
 
321
        size_t nPos = source.find (";", pos + 1);
 
322
        line = source.substr (pos + 1, nPos - pos);
 
323
        CompString origcurrent = current = ltrim (line);
 
324
        /* Find instruction type */
 
325
        type = NoOp;
 
326
 
 
327
        /* Data ops */
 
328
        if (current.substr (0, 3) == "END")
 
329
            type = NoOp;
 
330
        else if (current.substr (0, 3) == "ABS" ||
 
331
                 current.substr (0, 3) == "CMP" ||
 
332
                 current.substr (0, 3) == "COS" ||
 
333
                 current.substr (0, 3) == "DP3" ||
 
334
                 current.substr (0, 3) == "DP4" ||
 
335
                 current.substr (0, 3) == "EX2" ||
 
336
                 current.substr (0, 3) == "FLR" ||
 
337
                 current.substr (0, 3) == "FRC" ||
 
338
                 current.substr (0, 3) == "KIL" ||
 
339
                 current.substr (0, 3) == "LG2" ||
 
340
                 current.substr (0, 3) == "LIT" ||
 
341
                 current.substr (0, 3) == "LRP" ||
 
342
                 current.substr (0, 3) == "MAD" ||
 
343
                 current.substr (0, 3) == "MAX" ||
 
344
                 current.substr (0, 3) == "MIN" ||
 
345
                 current.substr (0, 3) == "POW" ||
 
346
                 current.substr (0, 3) == "RCP" ||
 
347
                 current.substr (0, 3) == "RSQ" ||
 
348
                 current.substr (0, 3) == "SCS" ||
 
349
                 current.substr (0, 3) == "SIN" ||
 
350
                 current.substr (0, 3) == "SGE" ||
 
351
                 current.substr (0, 3) == "SLT" ||
 
352
                 current.substr (0, 3) == "SUB" ||
 
353
                 current.substr (0, 3) == "SWZ" ||
 
354
                 current.substr (0, 3) == "TXP" ||
 
355
                 current.substr (0, 3) == "TXB" ||
 
356
                 current.substr (0, 3) == "XPD")
 
357
                type = DataOp;
 
358
        else if (current.substr (0, 4) == "TEMP")
 
359
            type = TempOp;
 
360
        else if (current.substr (0, 5) == "PARAM")
 
361
            type = ParamOp;
 
362
        else if (current.substr (0, 6) == "ATTRIB")
 
363
            type = AttribOp;
 
364
        else if (current.substr (0, 3) == "TEX")
 
365
            type = FetchOp;
 
366
        else if (current.substr (0, 3) == "ADD")
 
367
        {
 
368
            if (current.find ("fragment.texcoord", 0) != std::string::npos)
 
369
                programAddOffsetFromAddOp (current.c_str ());
 
370
            else
 
371
                type = DataOp;
 
372
        }
 
373
        else if (current.substr (0, 3) == "MUL")
 
374
        {
 
375
            if (current.find ("fragment.color", 0) != std::string::npos)
 
376
                type = ColorOp;
 
377
            else
 
378
                type = DataOp;
 
379
        }
 
380
        else if (current.substr (0, 3) == "MOV")
 
381
        {
 
382
            if (current.find ("result.color", 0) != std::string::npos)
 
383
                type = ColorOp;
 
384
            else
 
385
                type = DataOp;
 
386
        }
 
387
        size_t cpos = 0;
 
388
        switch (type)
 
389
        {
 
390
            /* Data op : just copy paste the
 
391
             * whole instruction plus a ";" */
 
392
            case DataOp:
 
393
                data->addDataOp (current.c_str ());
 
394
                break;
 
395
            /* Parse arguments one by one */
 
396
            case TempOp:
 
397
            case AttribOp:
 
398
            case ParamOp:
 
399
            {
 
400
                if (type == TempOp) oplength = 4;
 
401
                else if (type == ParamOp) oplength = 5;
 
402
                else if (type == AttribOp) oplength = 6;
 
403
                length = current.size ();
 
404
                if (length < oplength + 2) break;
 
405
 
 
406
                cpos = oplength + 1;
 
407
 
 
408
                while (current.size () && !(cpos >= current.size ()) &&
 
409
                       (arg1 = getFirstArgument (current, cpos)).size ())
 
410
                {
 
411
                    /* "output" is a reserved word, skip it */
 
412
                    if (arg1.substr (0, 6) == "output")
 
413
                        continue;
 
414
                    /* Add ops */
 
415
                    if (type == TempOp)
 
416
                        data->addTempHeaderOp (arg1.c_str ());
 
417
                    else if (type == ParamOp)
 
418
                        data->addParamHeaderOp (arg1.c_str ());
 
419
                    else if (type == AttribOp)
 
420
                        data->addAttribHeaderOp (arg1.c_str ());
 
421
                }
 
422
            }
 
423
                break;
 
424
            case FetchOp:
 
425
            {
 
426
                /* Example : TEX tmp, coord, texture[0], RECT;
 
427
                 * "tmp" is dest name, while "coord" is either
 
428
                 * fragment.texcoord[0] or an offset */
 
429
                cpos += 3;
 
430
 
 
431
                if ((arg1 = getFirstArgument (current, cpos)).size ())
 
432
                {
 
433
                    if (!(temp = getFirstArgument (current, cpos)).size ())
 
434
                        break;
 
435
 
 
436
                    if (temp == "fragment.texcoord[0]")
 
437
                        data->addFetchOp (arg1.c_str (), NULL, target);
 
438
                    else if (offsets.size ())
 
439
                    {
 
440
                        arg2 = programFindOffset (
 
441
                                              offsets.begin (),
 
442
                                              temp);
 
443
                        if (arg2.size ())
 
444
                            data->addFetchOp (arg1.c_str (),
 
445
                                              arg2.c_str (), target);
 
446
                    }
 
447
                }
 
448
            }
 
449
                break;
 
450
            case ColorOp:
 
451
            {
 
452
                if (current.substr (0, 3) == "MUL") /* MUL op, 2 ops */
 
453
                {
 
454
                    /* Example : MUL output, fragment.color, output;
 
455
                     * MOV arg1, fragment.color, arg2 */
 
456
                    cpos += 3;
 
457
 
 
458
                    if  (!(arg1 = getFirstArgument (current, cpos)).size ())
 
459
                    {
 
460
                        break;
 
461
                    }
 
462
 
 
463
                    if (!(temp = getFirstArgument (current, cpos)).size ())
 
464
                        break;
 
465
 
 
466
                    if (!(arg2 = getFirstArgument (current, cpos)).size ())
 
467
                        break;
 
468
 
 
469
                    data->addColorOp (arg1.c_str (), arg2.c_str ());
 
470
                }
 
471
                else /* MOV op, 1 op */
 
472
                {
 
473
                    /* Example : MOV result.color, output;
 
474
                     * MOV result.color, arg1; */
 
475
                    cpos = current.find (",") + 1;
 
476
 
 
477
                    if ((arg1 = getFirstArgument (current, cpos)).size ())
 
478
                        data->addColorOp ("output", arg1.c_str ());
 
479
                }
 
480
                break;
 
481
            }
 
482
            default:
 
483
                break;
 
484
        }
 
485
        pos = nPos;
 
486
    }
 
487
    programFreeOffset ();
 
488
}
 
489
 
 
490
/*
 
491
 * Build a Compiz Fragment Function from a source string
 
492
 */
 
493
GLFragment::FunctionId
 
494
FragmentParser::buildFragmentProgram (CompString &source,
 
495
                                      const CompString &name,
 
496
                                      int target)
 
497
{
 
498
    GLFragment::FunctionData *data;
 
499
    int handle;
 
500
    /* Create the function data */
 
501
    data = new GLFragment::FunctionData ();
 
502
    if (!data)
 
503
        return 0;
 
504
    /* Parse the source and fill the function data */
 
505
    programParseSource (data, target, source);
 
506
    /* Create the function */
 
507
    handle = data->createFragmentFunction (name.c_str ());
 
508
    delete data;
 
509
    return handle;
 
510
}
 
511
 
 
512
/*
 
513
 * Load a source file and build a Compiz Fragment Function from it
 
514
 */
 
515
GLFragment::FunctionId
 
516
FragmentParser::loadFragmentProgram (const CompString &file,
 
517
                                     CompString &name,
 
518
                                     int target)
 
519
{
 
520
    CompString source;
 
521
    GLFragment::FunctionId handle;
 
522
 
 
523
    /* Clean fragment program name */
 
524
    programCleanName (name);
 
525
    /* Read the source file */
 
526
    source = programReadSource (file);
 
527
    if (source.empty ())
 
528
    {
 
529
        return 0;
 
530
    }
 
531
 
 
532
    /* Build the Compiz Fragment Program */
 
533
    handle = buildFragmentProgram (source,
 
534
                                   name, target);
 
535
 
 
536
    return handle;
 
537
}