rev |
line source |
nuclear@16
|
1 /*
|
nuclear@16
|
2 curvedraw - a simple program to draw curves
|
nuclear@16
|
3 Copyright (C) 2015 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@16
|
4
|
nuclear@16
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@16
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@16
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@16
|
8 (at your option) any later version.
|
nuclear@16
|
9
|
nuclear@16
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@16
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@16
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@16
|
13 GNU General Public License for more details.
|
nuclear@16
|
14
|
nuclear@16
|
15 You should have received a copy of the GNU General Public License
|
nuclear@16
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@16
|
17 */
|
nuclear@15
|
18 #include <stdlib.h>
|
nuclear@15
|
19 #include <ctype.h>
|
nuclear@15
|
20 #include <string>
|
nuclear@15
|
21 #include "curvefile.h"
|
nuclear@15
|
22
|
nuclear@15
|
23 static bool save_curve(FILE *fp, const Curve *curve);
|
nuclear@15
|
24
|
nuclear@15
|
25 bool save_curves(const char *fname, const Curve * const *curves, int count)
|
nuclear@15
|
26 {
|
nuclear@15
|
27 FILE *fp = fopen(fname, "wb");
|
nuclear@15
|
28 if(!fp) return false;
|
nuclear@15
|
29
|
nuclear@15
|
30 bool res = save_curves(fp, curves, count);
|
nuclear@15
|
31 fclose(fp);
|
nuclear@15
|
32 return res;
|
nuclear@15
|
33 }
|
nuclear@15
|
34
|
nuclear@15
|
35 bool save_curves(FILE *fp, const Curve * const *curves, int count)
|
nuclear@15
|
36 {
|
nuclear@15
|
37 fprintf(fp, "GCURVES\n");
|
nuclear@15
|
38
|
nuclear@15
|
39 for(int i=0; i<count; i++) {
|
nuclear@15
|
40 if(!save_curve(fp, curves[i])) {
|
nuclear@15
|
41 return false;
|
nuclear@15
|
42 }
|
nuclear@15
|
43 }
|
nuclear@15
|
44 return true;
|
nuclear@15
|
45 }
|
nuclear@15
|
46
|
nuclear@15
|
47 static const char *curve_type_str(CurveType type)
|
nuclear@15
|
48 {
|
nuclear@15
|
49 switch(type) {
|
nuclear@15
|
50 case CURVE_LINEAR:
|
nuclear@15
|
51 return "polyline";
|
nuclear@15
|
52 case CURVE_HERMITE:
|
nuclear@15
|
53 return "hermite";
|
nuclear@15
|
54 case CURVE_BSPLINE:
|
nuclear@15
|
55 return "bspline";
|
nuclear@15
|
56 }
|
nuclear@15
|
57 abort();
|
nuclear@15
|
58 }
|
nuclear@15
|
59
|
nuclear@15
|
60 static bool save_curve(FILE *fp, const Curve *curve)
|
nuclear@15
|
61 {
|
nuclear@15
|
62 fprintf(fp, "curve {\n");
|
nuclear@15
|
63 fprintf(fp, " type %s\n", curve_type_str(curve->get_type()));
|
nuclear@15
|
64 fprintf(fp, " cpcount %d\n", curve->size());
|
nuclear@15
|
65 for(int i=0; i<curve->size(); i++) {
|
nuclear@15
|
66 Vector4 cp = curve->get_point(i);
|
nuclear@15
|
67 fprintf(fp, " cp %g %g %g %g\n", cp.x, cp.y, cp.z, cp.w);
|
nuclear@15
|
68 }
|
nuclear@15
|
69 fprintf(fp, "}\n");
|
nuclear@15
|
70 return true;
|
nuclear@15
|
71 }
|
nuclear@15
|
72
|
nuclear@15
|
73 std::list<Curve*> load_curves(const char *fname)
|
nuclear@15
|
74 {
|
nuclear@15
|
75 std::list<Curve*> res;
|
nuclear@15
|
76 FILE *fp = fopen(fname, "r");
|
nuclear@15
|
77 if(!fp) return res;
|
nuclear@15
|
78
|
nuclear@15
|
79 res = load_curves(fp);
|
nuclear@15
|
80 fclose(fp);
|
nuclear@15
|
81 return res;
|
nuclear@15
|
82 }
|
nuclear@15
|
83
|
nuclear@15
|
84 static std::string next_token(FILE *fp)
|
nuclear@15
|
85 {
|
nuclear@15
|
86 std::string s;
|
nuclear@15
|
87 int c;
|
nuclear@15
|
88 while((c = fgetc(fp)) != -1) {
|
nuclear@15
|
89 if(!isspace(c)) {
|
nuclear@15
|
90 ungetc(c, fp);
|
nuclear@15
|
91 break;
|
nuclear@15
|
92 }
|
nuclear@15
|
93 }
|
nuclear@15
|
94
|
nuclear@15
|
95 if(feof(fp)) return s;
|
nuclear@15
|
96 while((c = fgetc(fp)) != -1) {
|
nuclear@15
|
97 if(isspace(c)) {
|
nuclear@15
|
98 ungetc(c, fp);
|
nuclear@15
|
99 break;
|
nuclear@15
|
100 }
|
nuclear@15
|
101 s.push_back(c);
|
nuclear@15
|
102 }
|
nuclear@15
|
103 return s;
|
nuclear@15
|
104 }
|
nuclear@15
|
105
|
nuclear@15
|
106 static bool expect_str(FILE *fp, const char *s)
|
nuclear@15
|
107 {
|
nuclear@15
|
108 std::string tok = next_token(fp);
|
nuclear@15
|
109 if(tok != std::string(s)) {
|
nuclear@15
|
110 if(tok.empty() && feof(fp)) {
|
nuclear@15
|
111 fprintf(stderr, "expected: %s\n", s);
|
nuclear@15
|
112 }
|
nuclear@15
|
113 return false;
|
nuclear@15
|
114 }
|
nuclear@15
|
115 return true;
|
nuclear@15
|
116 }
|
nuclear@15
|
117
|
nuclear@15
|
118 static bool expect_float(FILE *fp, float *ret)
|
nuclear@15
|
119 {
|
nuclear@15
|
120 std::string tok = next_token(fp);
|
nuclear@15
|
121 const char *cs = tok.c_str();
|
nuclear@15
|
122 char *endp;
|
nuclear@15
|
123 *ret = strtod(cs, &endp);
|
nuclear@15
|
124 if(endp != cs + tok.length()) {
|
nuclear@15
|
125 if(!(tok.empty() && feof(fp))) {
|
nuclear@15
|
126 fprintf(stderr, "number expected\n");
|
nuclear@15
|
127 }
|
nuclear@15
|
128 return false;
|
nuclear@15
|
129 }
|
nuclear@15
|
130 return true;
|
nuclear@15
|
131 }
|
nuclear@15
|
132
|
nuclear@15
|
133 static bool expect_int(FILE *fp, int *ret)
|
nuclear@15
|
134 {
|
nuclear@15
|
135 std::string tok = next_token(fp);
|
nuclear@15
|
136 const char *cs = tok.c_str();
|
nuclear@15
|
137 char *endp;
|
nuclear@15
|
138 *ret = strtol(cs, &endp, 0);
|
nuclear@15
|
139 if(endp != cs + tok.length()) {
|
nuclear@15
|
140 if(!(tok.empty() && feof(fp))) {
|
nuclear@15
|
141 fprintf(stderr, "integer expected\n");
|
nuclear@15
|
142 }
|
nuclear@15
|
143 return false;
|
nuclear@15
|
144 }
|
nuclear@15
|
145 return true;
|
nuclear@15
|
146 }
|
nuclear@15
|
147
|
nuclear@15
|
148 static Curve *curve_block(FILE *fp)
|
nuclear@15
|
149 {
|
nuclear@15
|
150 if(!expect_str(fp, "curve") || !expect_str(fp, "{")) {
|
nuclear@15
|
151 return 0;
|
nuclear@15
|
152 }
|
nuclear@15
|
153
|
nuclear@15
|
154 Curve *curve = new Curve;
|
nuclear@15
|
155 int cpcount = -1;
|
nuclear@15
|
156 std::string tok;
|
nuclear@15
|
157 while(!(tok = next_token(fp)).empty() && tok != "}") {
|
nuclear@15
|
158 if(tok == "cpcount") {
|
nuclear@15
|
159 if(cpcount != -1 || !expect_int(fp, &cpcount) || cpcount <= 0) {
|
nuclear@15
|
160 goto err;
|
nuclear@15
|
161 }
|
nuclear@15
|
162 } else if(tok == "type") {
|
nuclear@15
|
163 tok = next_token(fp);
|
nuclear@15
|
164 if(tok == "polyline") {
|
nuclear@15
|
165 curve->set_type(CURVE_LINEAR);
|
nuclear@15
|
166 } else if(tok == "hermite") {
|
nuclear@15
|
167 curve->set_type(CURVE_HERMITE);
|
nuclear@15
|
168 } else if(tok == "bspline") {
|
nuclear@15
|
169 curve->set_type(CURVE_BSPLINE);
|
nuclear@15
|
170 } else {
|
nuclear@15
|
171 goto err;
|
nuclear@15
|
172 }
|
nuclear@15
|
173 } else {
|
nuclear@15
|
174 if(tok != "cp") {
|
nuclear@15
|
175 goto err;
|
nuclear@15
|
176 }
|
nuclear@15
|
177 Vector4 cp;
|
nuclear@15
|
178 for(int i=0; i<4; i++) {
|
nuclear@15
|
179 if(!expect_float(fp, &cp[i])) {
|
nuclear@15
|
180 goto err;
|
nuclear@15
|
181 }
|
nuclear@15
|
182 }
|
nuclear@15
|
183 curve->add_point(Vector3(cp.x, cp.y, cp.z), cp.w);
|
nuclear@15
|
184 }
|
nuclear@15
|
185 }
|
nuclear@15
|
186
|
nuclear@15
|
187 if(curve->size() != cpcount) {
|
nuclear@15
|
188 fprintf(stderr, "warning: curve cpcount was %d, but read %d control points\n", cpcount, curve->size());
|
nuclear@15
|
189 }
|
nuclear@15
|
190
|
nuclear@15
|
191 return curve;
|
nuclear@15
|
192 err:
|
nuclear@15
|
193 fprintf(stderr, "failed to parse curve block\n");
|
nuclear@15
|
194 delete curve;
|
nuclear@15
|
195 return 0;
|
nuclear@15
|
196 }
|
nuclear@15
|
197
|
nuclear@15
|
198 std::list<Curve*> load_curves(FILE *fp)
|
nuclear@15
|
199 {
|
nuclear@15
|
200 std::list<Curve*> curves;
|
nuclear@15
|
201 if(!expect_str(fp, "GCURVES")) {
|
nuclear@15
|
202 fprintf(stderr, "load_curves: failed to load, invalid file format\n");
|
nuclear@15
|
203 return curves;
|
nuclear@15
|
204 }
|
nuclear@15
|
205
|
nuclear@15
|
206 Curve *curve;
|
nuclear@15
|
207 while((curve = curve_block(fp))) {
|
nuclear@15
|
208 curves.push_back(curve);
|
nuclear@15
|
209 }
|
nuclear@15
|
210
|
nuclear@15
|
211 if(!feof(fp)) {
|
nuclear@15
|
212 std::list<Curve*>::iterator it = curves.begin();
|
nuclear@15
|
213 while(it != curves.end()) {
|
nuclear@15
|
214 delete *it++;
|
nuclear@15
|
215 }
|
nuclear@15
|
216 return curves;
|
nuclear@15
|
217 }
|
nuclear@15
|
218
|
nuclear@15
|
219 return curves;
|
nuclear@15
|
220 }
|
nuclear@15
|
221
|