editor: another undo fix
[iv.d.git] / test_zmbv / test.d
blob7c4edd1a3e95fdeb3602891808f48e8a5b2b9892
1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module zmbv_test /*is aliced*/;
19 import core.stdc.stdlib : malloc, free;
20 import core.stdc.string : memset, memcpy, memcmp;
21 import std.exception;
22 import std.getopt;
23 import std.path;
24 import std.stdio;
25 import std.string;
27 import iv.alice;
28 import iv.zmbv;
31 private:
32 ////////////////////////////////////////////////////////////////////////////////
33 // each KeyframeInterval frame will be key one
34 enum KeyframeInterval = 300;
37 ////////////////////////////////////////////////////////////////////////////////
38 string inname, outname;
39 File flScreen;
40 int screenCount;
41 ubyte[256*3] curPal = void;
42 ubyte[320*240] curScreen = void;
43 int frameNo;
44 bool thisIsKeyframe;
45 uint[] idxarray;
47 Codec.Compression cpr = Codec.Compression.ZLib;
48 int complevel = -1;
51 ////////////////////////////////////////////////////////////////////////////////
52 void openVPF () {
53 uint scc;
54 flScreen = File(inname, "r");
55 flScreen.rawRead((&scc)[0..1]);
56 if (scc == 0) throw new Exception("invalid screen cound!");
57 screenCount = scc;
58 writefln("%s screens found", screenCount);
59 frameNo = 0;
63 void closeVPF () {
64 if (flScreen.isOpen) flScreen.close();
68 ////////////////////////////////////////////////////////////////////////////////
69 // 4 bytes: screen count
70 // 768+320*240: screen
71 bool nextScreen () {
72 if (frameNo < screenCount) {
73 flScreen.rawRead(curPal);
74 flScreen.rawRead(curScreen);
75 ++frameNo;
76 return true;
78 return false;
82 ////////////////////////////////////////////////////////////////////////////////
83 void encodeScreens (void delegate (const(void)[] buf) writer) {
84 auto zc = new Encoder(320, 240, Codec.bpp2format(8), complevel, cpr);
85 auto zd = new Decoder(320, 240);
86 scope(exit) { zc.clear(); zd.clear(); }
87 frameNo = 0;
88 uint oldprc = 999;
89 while (nextScreen()) {
90 thisIsKeyframe = ((frameNo-1)%KeyframeInterval == 0);
91 zc.prepareFrame((thisIsKeyframe ? zc.PrepareFlags.Keyframe : zc.PrepareFlags.None), curPal);
92 foreach (/*auto*/ y; 0..240) zc.encodeLine(curScreen[y*320..(y+1)*320]);
93 auto written = zc.finishFrame();
94 writer(written);
95 zd.decodeFrame(written);
96 ubyte fb = (cast(ubyte[])written)[0];
97 if (fb&0x01) {
98 enforce(zd.paletteChanged);
99 } else {
100 enforce(((fb&0x02) != 0) == zd.paletteChanged);
102 enforce(zd.palette == curPal);
103 foreach (/*auto*/ y; 0..240) {
104 auto line = zd.line(y);
105 if (curScreen[y*320..(y+1)*320] != line[]) {
106 writeln("\nframe ", frameNo, "; line ", y);
107 foreach (/*auto*/ x; 0..320) {
108 if (curScreen[y*320+x] != line[x]) {
109 writefln(" x=%3s; orig=0x%02x; unp=0x%02x", x, curScreen[y*320+x], line[x]);
112 assert(0);
115 uint prc = 100*frameNo/screenCount;
116 if (prc != oldprc) {
117 stdout.writef("\r[%s/%s] %s%%", frameNo, screenCount, prc);
118 stdout.flush();
119 oldprc = prc;
122 stdout.writefln("\r[%s/%s] %s%%", frameNo, screenCount, 100);
126 ////////////////////////////////////////////////////////////////////////////////
127 void encodeScreensToBin () {
128 auto fo = File(outname, "w");
130 void writer (const(void)[] buf) {
131 if (thisIsKeyframe) idxarray ~= cast(uint)fo.tell;
132 uint size = cast(uint)buf.length;
133 fo.rawWrite((&size)[0..1]);
134 fo.rawWrite(buf);
137 uint scc = screenCount;
138 // frame count
139 fo.rawWrite((&scc)[0..1]);
140 // idxarray count
141 scc = 0;
142 fo.rawWrite((&scc)[0..1]);
143 // idxarray offset
144 fo.rawWrite((&scc)[0..1]);
145 encodeScreens(&writer);
146 // write idxarray
147 auto ipos = fo.tell;
148 fo.rawWrite(idxarray);
149 // update header
150 fo.seek(4);
151 scc = cast(uint)idxarray.length;
152 fo.rawWrite((&scc)[0..1]);
153 scc = cast(uint)ipos;
154 fo.rawWrite((&scc)[0..1]);
158 ////////////////////////////////////////////////////////////////////////////////
159 void main (string[] args) {
160 getopt(args,
161 std.getopt.config.caseSensitive,
162 std.getopt.config.bundling,
163 "z", &complevel,
164 "Z", (string opt) { cpr = Codec.Compression.None; },
166 if (complevel > 9) throw new Exception("invalid compression level");
167 if (args.length < 2) throw new Exception("input file name missing");
168 if (args.length > 3) throw new Exception("too many file names");
169 inname = args[1];
170 if (args.length < 3) {
171 outname = inname.setExtension(".zmbv");
172 } else {
173 outname = args[2].defaultExtension(".zmbv");
175 writefln("using compression level %s", complevel);
176 openVPF();
177 encodeScreensToBin();
178 closeVPF();