Generally clean up main.c
dkl9

dkl9 commited on 2025-180 21:37:47
Showing 1 changed files, with 135 additions and 96 deletions.

... ...
@@ -16,11 +16,27 @@
16 16
 #define FRAMETIME (1000 / FPS)
17 17
 #define DZDS 0.25
18 18
 
19
-/* if cond is true, exit the program as a failure, with msg as the message,
20
-along with the SDL error, if showsdl is true */
21
-void cfail(int cond, char* msg, int showsdl) {
19
+struct ViewState {
20
+    /* image index */
21
+    int ci;
22
+    /* image dimensions */
23
+    int iw;
24
+    int ih;
25
+    /* zoom level */
26
+    float zoom;
27
+    /* pan position (centre of image) */
28
+    int px;
29
+    int py;
30
+    /* keep track of mouse coordinates */
31
+    int mx;
32
+    int my;
33
+};
34
+
35
+/* if cond is true, exit the program as a failure,
36
+with msg as the message, along with the SDL error, if showsdl is true */
37
+void cfail(const int cond, const char* msg, const int showsdl) {
22 38
     if (cond) {
23
-        fprintf(stderr, "Could not %s\n", msg);
39
+        fprintf(stderr, "iv: failed to %s\n", msg);
24 40
         if (showsdl) {
25 41
             fprintf(stderr, "SDL: %s\n", SDL_GetError());
26 42
         }
... ...
@@ -28,29 +44,28 @@ void cfail(int cond, char* msg, int showsdl) {
28 44
     }
29 45
 }
30 46
 
31
-int main(int argc, char** argv) {
32
-    /* load alpha checkers, relative to iv binary (not working directory) */
33
-    char* tpath = malloc(strlen(argv[0]) + 32);
47
+/* load and return alpha checkers, relative to iv binary */
48
+SDL_Texture* checker(SDL_Renderer* ren, char* progname, int* w, int* h) {
49
+    char* tpath = malloc(strlen(progname) + 32);
34 50
     cfail(!tpath, "allocate memory", 0);
35
-    sprintf(tpath, "%s/alpha_checker.bmp", dirname(argv[0]));
51
+    sprintf(tpath, "%s/alpha_checker.bmp", dirname(progname));
36 52
     SDL_Surface* acs = SDL_LoadBMP(tpath);
53
+    if (w) {
54
+        *w = acs->w;
55
+    }
56
+    if (h) {
57
+        *h = acs->h;
58
+    }
37 59
     cfail(!acs, "load alpha checker texture", 1);
38
-    int cw = acs->w;
39
-    int ch = acs->h;
40
-
41
-    /* require a file argument */
42
-    if (argc < 2) {
43
-        fprintf(stderr, "usage: iv -h or iv FILE\n");
44
-        exit(EXIT_FAILURE);
60
+    SDL_Texture* act = SDL_CreateTextureFromSurface(ren, acs);
61
+    cfail(!act, "create surface", 1);
62
+    SDL_FreeSurface(acs);
63
+    return act;
45 64
 }
46 65
 
47
-    /* setup */
48
-    SDL_Init(SDL_INIT_VIDEO);
49
-    atexit(SDL_Quit);
50
-
51
-    /* process arguments */
66
+/* process command-line options, setting pointed strings */
67
+void handleargs(int argc, char** argv, char** title) {
52 68
     int oc;
53
-    char* ct = NULL;
54 69
     while ((oc = getopt(argc, argv, "ht:")) != -1) {
55 70
         switch (oc) {
56 71
             case 'h':
... ...
@@ -63,24 +78,24 @@ int main(int argc, char** argv) {
63 78
                     "Right-click or space key to centre image\n"
64 79
                     "Middle-click to get coordinates at cursor\n"
65 80
                     "Arrow keys to move between images in the list\n"
66
-                    "version 1.6\n"
81
+                    "version 1.8-dev\n"
67 82
                 );
68 83
                 exit(EXIT_SUCCESS);
69 84
             case 't':
70
-                ct = optarg;
85
+                *title = optarg;
71 86
                 break;
72 87
             case ':':
73 88
             case '?':
74
-                cfail(1, "handle invalid options", 0);
89
+                cfail(1, "parse options", 0);
90
+        }
75 91
     }
76 92
 }
77 93
 
78
-    /* load images before creating window, to determine window size */
79
-    cfail(optind >= argc, "find filename in options", 0);
80
-    int fc = argc - optind;
94
+/* load images from arguments */
95
+SDL_Surface** loadimages(char** argv, const int fc) {
81 96
     SDL_Surface** isurf = calloc(fc, sizeof (SDL_Surface*));
82 97
     for (int i = 0; i < fc; i++) {
83
-        char* fname = argv[optind + i];
98
+        const char* fname = argv[optind + i];
84 99
         SDL_RWops* ir;
85 100
         if (!strcmp(fname, "-")) {
86 101
             ir = SDL_RWFromFP(stdin, 0);
... ...
@@ -91,12 +106,65 @@ int main(int argc, char** argv) {
91 106
         isurf[i] = IMG_Load_RW(ir, 1);
92 107
         cfail(!isurf[i], "load image", 1);
93 108
     }
94
-    int ci = 0;
95
-    int iw = isurf[ci]->w;
96
-    int ih = isurf[ci]->h;
109
+    return isurf;
110
+}
111
+
112
+void updatetitle(SDL_Window* window, const char* ct, char** title, const char* fname, const struct ViewState vs) {
113
+    if (!ct) {
114
+        free(*title);
115
+        *title = malloc(strlen(fname) + 32);
116
+        cfail(!*title, "allocate memory", 0);
117
+        sprintf(*title, "iv: %s (%dx%d)", fname, vs.iw, vs.ih);
118
+        SDL_SetWindowTitle(window, *title);
119
+    }
120
+}
121
+
122
+void showcoords(const SDL_MouseButtonEvent button, const struct ViewState vs) {
123
+    printf(
124
+        "%.0f, %.0f\n",
125
+        ZSH((float)button.x - (float)vs.px + ZSH(vs.iw, vs.zoom - 1.0), -vs.zoom),
126
+        ZSH((float)button.y - (float)vs.py + ZSH(vs.ih, vs.zoom - 1.0), -vs.zoom)
127
+    );
128
+    fflush(stdout);
129
+}
130
+
131
+void drawbg(SDL_Renderer* ren, const int ww, const int wh, const int cw, const int ch, SDL_Texture* act) {
132
+    /* clear to background colour */
133
+    cfail(SDL_RenderClear(ren), "clear screen", 1);
134
+    /* alpha checker background */
135
+    for (int i = 0; i < ww; i += APS * cw) {
136
+        for (int j = 0; j < wh; j += APS * ch) {
137
+            cfail(SDL_RenderCopy(ren, act, NULL, &(SDL_Rect){
138
+                .x = i, .y = j, .w = APS * cw, .h = APS * ch
139
+            }), "draw checker background", 1);
140
+        }
141
+    }
142
+}
143
+
144
+void drawfg(SDL_Renderer* ren, const struct ViewState vs, SDL_Texture* imgtex) {
145
+    /* render image */
146
+    cfail(SDL_RenderCopy(ren, imgtex, NULL, &(SDL_Rect){
147
+        .x = vs.px - ZSH(vs.iw, vs.zoom - 1.0), .y = vs.py - ZSH(vs.ih, vs.zoom - 1.0),
148
+        .w = ZSH(vs.iw, vs.zoom), .h = ZSH(vs.ih, vs.zoom)
149
+    }), "display image", 1);
150
+}
151
+
152
+int main(int argc, char** argv) {
153
+    /* setup */
154
+    SDL_Init(SDL_INIT_VIDEO);
155
+    atexit(SDL_Quit);
156
+    char* ct = NULL;
157
+    handleargs(argc, argv, &ct);
158
+
159
+    /* load images before creating window, to determine window size */
160
+    cfail(optind >= argc, "find filename(s) in options", 0);
161
+    int fc = argc - optind;
162
+    SDL_Surface** isurf = loadimages(argv, fc);
163
+    int iw = isurf[0]->w;
164
+    int ih = isurf[0]->h;
97 165
 
98 166
     /* create window and renderer */
99
-    char* title;
167
+    char* title = NULL;
100 168
     if (ct) {
101 169
         title = ct;
102 170
     } else {
... ...
@@ -113,15 +181,14 @@ int main(int argc, char** argv) {
113 181
     cfail(!ren, "create renderer", 1);
114 182
 
115 183
     /* make images into textures */
184
+    int cw, ch;
185
+    SDL_Texture* act = checker(ren, argv[0], &cw, &ch);
116 186
     SDL_Texture** itex = calloc(fc, sizeof (SDL_Texture*));
117 187
     for (int i = 0; i < fc; i++) {
118 188
         itex[i] = SDL_CreateTextureFromSurface(ren, isurf[i]);
119 189
         cfail(!itex[i], "create texture", 1);
120 190
         SDL_FreeSurface(isurf[i]);
121 191
     }
122
-    SDL_Texture* act = SDL_CreateTextureFromSurface(ren, acs);
123
-    cfail(!act, "create surface", 1);
124
-    SDL_FreeSurface(acs);
125 192
 
126 193
     /* background (transparent black) */
127 194
     cfail(SDL_SetRenderDrawColor(ren, 0, 0, 0, 0), "set colour", 1);
... ...
@@ -134,18 +201,14 @@ int main(int argc, char** argv) {
134 201
     /* only bother to redraw if an event that requires it is found */
135 202
     int ef;
136 203
     /* window size */
137
-    int ww, wh;
138
-    /* zoom level */
139
-    float zoom = 0;
140
-    /* pan position (centre of image) */
141
-    int px = iw / 2;
142
-    int py = ih / 2;
143
-    /* keep track of mouse coordinates */
144
-    int mx = 0;
145
-    int my = 0;
204
+    int ww = iw;
205
+    int wh = ih;
206
+    struct ViewState vs = {
207
+        .ci = 0, .iw = iw, .ih = ih, .zoom = 0,
208
+        .px = iw / 2, .py = ih / 2, .mx = 0, .my = 0
209
+    };
146 210
 
147 211
     while (r) {
148
-        SDL_GetWindowSize(window, &ww, &wh);
149 212
         ef = 0;
150 213
         while (SDL_PollEvent(&ev)) {
151 214
             switch (ev.type) {
... ...
@@ -155,8 +218,8 @@ int main(int argc, char** argv) {
155 218
                     switch (ev.key.keysym.sym) {
156 219
                         /* bring image back into focus when Space is pressed */
157 220
                         case SDLK_SPACE:
158
-                            px = ww / 2;
159
-                            py = wh / 2;
221
+                            vs.px = ww / 2;
222
+                            vs.py = wh / 2;
160 223
                             ef = 1;
161 224
                             break;
162 225
                         /* exit when Esc is pressed */
... ...
@@ -166,49 +229,38 @@ int main(int argc, char** argv) {
166 229
                         /* navigate image list with arrow keys */
167 230
                         case SDLK_LEFT:
168 231
                         case SDLK_UP:
169
-                            if (ci > 0) {
170
-                                ci--;
232
+                            if (vs.ci > 0) {
233
+                                vs.ci--;
171 234
                                 iic = 1;
172 235
                             }
173 236
                             break;
174 237
                         case SDLK_RIGHT:
175 238
                         case SDLK_DOWN:
176
-                            if (ci < fc - 1) {
177
-                                ci++;
239
+                            if (vs.ci < fc - 1) {
240
+                                vs.ci++;
178 241
                                 iic = 1;
179 242
                             }
180 243
                             break;
181 244
                     }
182 245
                     if (iic) {
183
-                        cfail(SDL_QueryTexture(itex[ci], NULL, NULL, &iw, &ih), "query texture", 1);
184
-                        zoom = 0;
185
-                        px = iw / 2;
186
-                        py = ih / 2;
187
-                        if (!ct) {
188
-                            free(title);
189
-                            title = malloc(strlen(argv[optind + ci]) + 32);
190
-                            cfail(!title, "allocate memory", 0);
191
-                            sprintf(title, "iv: %s (%dx%d)", argv[optind + ci], iw, ih);
192
-                            SDL_SetWindowTitle(window, title);
193
-                        }
246
+                        cfail(SDL_QueryTexture(itex[vs.ci], NULL, NULL, &vs.iw, &vs.ih), "query texture", 1);
247
+                        vs.zoom = 0;
248
+                        vs.px = vs.iw / 2;
249
+                        vs.py = vs.ih / 2;
194 250
                         ef = 1;
251
+                        updatetitle(window, ct, &title, argv[optind + vs.ci], vs);
195 252
                     }
196 253
                     break;
197 254
 
198 255
                 case SDL_MOUSEBUTTONDOWN:
199 256
                     /* output coordinates of cursor in image on middle-click */
200 257
                     if (ev.button.button == 2) {
201
-                        printf(
202
-                            "%.0f, %.0f\n",
203
-                            ZSH((float)ev.button.x - (float)px + ZSH(iw, zoom - 1.0), -zoom),
204
-                            ZSH((float)ev.button.y - (float)py + ZSH(ih, zoom - 1.0), -zoom)
205
-                        );
206
-                        fflush(stdout);
258
+                        showcoords(ev.button, vs);
207 259
                     }
208 260
                     /* bring image back into focus on right-click */
209 261
                     if (ev.button.button == 3) {
210
-                        px = ww / 2;
211
-                        py = wh / 2;
262
+                        vs.px = ww / 2;
263
+                        vs.py = wh / 2;
212 264
                         ef = 1;
213 265
                     }
214 266
                     break;
... ...
@@ -216,31 +268,31 @@ int main(int argc, char** argv) {
216 268
                 case SDL_MOUSEMOTION:
217 269
                     /* pan-dragging if mouse is down */
218 270
                     if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(1)) {
219
-                        int sw = ZSH(iw, zoom - 1.0);
220
-                        int sh = ZSH(ih, zoom - 1.0);
271
+                        int sw = ZSH(vs.iw, vs.zoom - 1.0);
272
+                        int sh = ZSH(vs.ih, vs.zoom - 1.0);
221 273
                         /* clamp panning to edges of window,
222 274
                         unless zoomed image is bigger than window */
223 275
                         if (2 * sw > ww) {
224
-                            px += ev.motion.xrel;
276
+                            vs.px += ev.motion.xrel;
225 277
                         } else {
226
-                            px = CLAMP(sw, px + ev.motion.xrel, ww - sw);
278
+                            vs.px = CLAMP(sw, vs.px + ev.motion.xrel, ww - sw);
227 279
                         }
228 280
                         if (2 * sh > wh) {
229
-                            py += ev.motion.yrel;
281
+                            vs.py += ev.motion.yrel;
230 282
                         } else {
231
-                            py = CLAMP(sh, py + ev.motion.yrel, wh - sh);
283
+                            vs.py = CLAMP(sh, vs.py + ev.motion.yrel, wh - sh);
232 284
                         }
233 285
                         ef = 1;
234 286
                     }
235
-                    mx = ev.motion.x;
236
-                    my = ev.motion.y;
287
+                    vs.mx = ev.motion.x;
288
+                    vs.my = ev.motion.y;
237 289
                     break;
238 290
 
239 291
                 case SDL_MOUSEWHEEL:
240 292
                     /* scrolling changes zoom */
241
-                    zoom += DZDS * ev.wheel.y;
242
-                    px = mx - ZSH((mx - px), DZDS * ev.wheel.y);
243
-                    py = my - ZSH((my - py), DZDS * ev.wheel.y);
293
+                    vs.zoom += DZDS * ev.wheel.y;
294
+                    vs.px = vs.mx - ZSH((vs.mx - vs.px), DZDS * ev.wheel.y);
295
+                    vs.py = vs.my - ZSH((vs.my - vs.py), DZDS * ev.wheel.y);
244 296
                     ef = 1;
245 297
                     break;
246 298
 
... ...
@@ -267,21 +319,8 @@ int main(int argc, char** argv) {
267 319
 
268 320
         if (ef) {
269 321
             SDL_GetWindowSize(window, &ww, &wh);
270
-            /* clear to background colour */
271
-            cfail(SDL_RenderClear(ren), "clear screen", 1);
272
-            /* alpha checker background */
273
-            for (int i = 0; i < ww; i += APS * cw) {
274
-                for (int j = 0; j < wh; j += APS * ch) {
275
-                    cfail(SDL_RenderCopy(ren, act, NULL, &(SDL_Rect){
276
-                        .x = i, .y = j, .w = APS * cw, .h = APS * ch
277
-                    }), "draw checker background", 1);
278
-                }
279
-            }
280
-            /* render image */
281
-            cfail(SDL_RenderCopy(ren, itex[ci], NULL, &(SDL_Rect){
282
-                .x = px - ZSH(iw, zoom - 1.0), .y = py - ZSH(ih, zoom - 1.0),
283
-                .w = ZSH(iw, zoom), .h = ZSH(ih, zoom)
284
-            }), "display image", 1);
322
+            drawbg(ren, ww, wh, cw, ch, act);
323
+            drawfg(ren, vs, itex[vs.ci]);
285 324
             SDL_RenderPresent(ren);
286 325
         }
287 326
 
288 327