First draft of XML Shader reference implementation.
[bsnes:xml-shaders.git] / reference / texreader.py
1 #!/usr/bin/python
2 import re
3 import string
4
5 TOKEN_RE = re.compile("[^" + string.whitespace + "]+")
6 WS_RE = re.compile("[" + string.whitespace + "]+")
7
8
9 class TexReaderException(Exception):
10         pass
11
12
13 def consume_token(data, offset):
14         """
15         Reads a single whitespace-delimited token at the given offset.
16
17         Returns the token.
18         """
19         match = TOKEN_RE.match(data, offset)
20         if match is None:
21                 raise TexReaderException("Could not find token at offset %d"
22                                 % (offset,))
23
24         return match.group()
25
26
27 def consume_ws(data, offset):
28         """
29         Returns the number of bytes of whitespace that occur at the given offset.
30         """
31         match = WS_RE.match(data, offset)
32         if match is None:
33                 raise TexReaderException("Could not find whitespace at offset %d"
34                                 % (offset,))
35
36         return len(match.group())
37
38
39 def parse_ppm(data):
40         """
41         Parse the PPM data from the given byte string.
42         """
43         offset = 0
44
45         magic = consume_token(data, offset)
46         offset += len(magic)
47
48         if magic != "P6":
49                 raise TexReaderException("Unrecognised magic %r" % (magic,))
50
51         offset += consume_ws(data, offset)
52
53         widthStr = consume_token(data, offset)
54         try:
55                 width = int(widthStr)
56         except ValueError:
57                 raise TexReaderException("Can't parse width %r at offset %d"
58                                 % (widthStr, offset))
59
60         offset += len(widthStr)
61         offset += consume_ws(data, offset)
62
63         heightStr = consume_token(data, offset)
64         try:
65                 height = int(heightStr)
66         except ValueError:
67                 raise TexReaderException("Can't parse height %r at offset %d"
68                                 % (heightStr, offset))
69
70         offset += len(heightStr)
71         offset += consume_ws(data, offset)
72
73         sampleMaxStr = consume_token(data, offset)
74         try:
75                 sampleMax = int(sampleMaxStr)
76         except ValueError:
77                 raise TexReaderException("Can't parse sampleMax %r at offset %d"
78                                 % (sampleMaxStr, offset))
79
80         # Always exactly one whitespace char after the sample mox.
81         offset += len(sampleMaxStr) + 1
82
83         if sampleMax != 255:
84                 raise TexReaderException("Textures must have 8 bits per channel.")
85
86         # Now to convert this packed RGB pixel data to RGBA data that OpenGL can
87         # understand.
88         pixels = []
89         for pxOffset in range(offset, offset + (width * height * 3), 3):
90                 pixels.append(data[pxOffset:pxOffset+3])
91                 pixels.append("\xff")
92
93         return (width, height, "".join(pixels))
94
95
96 if __name__ == "__main__":
97         import sys
98         with open(sys.argv[1]) as handle:
99                 data = handle.read()
100                 print parse_ppm(data)