9 int switch_mode(int m);
10 int find_best_mode(int minx, int miny);
11 void drop_equiv_modes(void);
17 void (*display)(void);
18 void xor_cursor8(int x, int y);
19 void xor_cursor16(int x, int y);
20 void xor_cursor24(int x, int y);
21 void xor_cursor32(int x, int y);
22 void (*xor_cursor)(int x, int y);
24 int equiv_bpp(int a, int b);
25 int vmcmp(const void *a, const void *b);
26 int parse_args(int argc, char **argv);
28 static struct video_mode *vmode;
29 static struct video_mode *vmlist;
30 static int vmlist_size, cur_vm = -1;
33 static int opt_bpp = 16;
34 static const char *opt_fname;
36 static int redraw_pending = 1;
37 static int pan_x, pan_y, max_pan_x, max_pan_y;
39 static struct img_pixmap img;
42 int main(int argc, char **argv)
45 struct video_mode *vmodes;
47 if(parse_args(argc, argv) == -1) {
51 fprintf(stderr, "please specify an image file to open\n");
55 if(init_video() == -1) {
56 fprintf(stderr, "failed to initialize video\n");
60 /* populate and sort the usable video mode list */
61 num = num_video_modes();
62 vmodes = video_modes();
64 if(!(vmlist = malloc(num * sizeof *vmlist))) {
65 fprintf(stderr, "failed to allocate video mode list\n");
70 for(i=0; i<num; i++) {
71 if(equiv_bpp(opt_bpp, vmodes[i].bpp)) {
72 vmlist[vmlist_size++] = vmodes[i];
76 fprintf(stderr, "no usable video modes found for %d bpp\n", opt_bpp);
79 qsort(vmlist, vmlist_size, sizeof *vmlist, vmcmp);
83 if(img_load(&img, opt_fname) == -1) {
84 fprintf(stderr, "failed to load image: %s\n", opt_fname);
91 img_convert(&img, IMG_FMT_RGB565);
94 img_convert(&img, IMG_FMT_RGB24);
97 img_convert(&img, IMG_FMT_RGBA32);
103 modeidx = find_best_mode(img.width, img.height);
104 if(switch_mode(modeidx) == -1) {
116 if(cur_vm < vmlist_size - 1) {
117 switch_mode(cur_vm + 1);
124 switch_mode(cur_vm - 1);
133 if((mouse.dx | mouse.dy) && mouse.bn & 1) {
136 if(pan_x < 0) pan_x = 0;
137 if(pan_y < 0) pan_y = 0;
138 if(pan_x > max_pan_x) pan_x = max_pan_x;
139 if(pan_y > max_pan_y) pan_y = max_pan_y;
147 blit_frame(backbuf, FLIP_NOW);
162 int switch_mode(int m)
168 if(!(backbuf = malloc(vmode->ysz * vmode->pitch))) {
169 fprintf(stderr, "failed to allocate back buffer\n");
173 set_video_mode(find_video_mode(vmode->mode), 0);
178 xor_cursor = xor_cursor8;
183 xor_cursor = xor_cursor16;
187 xor_cursor = xor_cursor24;
191 xor_cursor = xor_cursor32;
196 set_mouse_bounds(0, 0, vmode->xsz, vmode->ysz);
199 max_pan_x = img.width - vmode->xsz;
200 max_pan_y = img.height - vmode->ysz;
201 if(max_pan_x < 0) max_pan_x = 0;
202 if(max_pan_y < 0) max_pan_y = 0;
204 if(pan_x > max_pan_x) pan_x = max_pan_x;
205 if(pan_y > max_pan_y) pan_y = max_pan_y;
210 int find_best_mode(int minx, int miny)
214 for(i=0; i<vmlist_size; i++) {
215 if(vmlist[i].xsz >= minx && vmlist[i].ysz >= miny) {
219 return vmlist_size - 1;
222 void drop_equiv_modes(void)
224 struct video_mode *vm, *end;
226 /* modes are sorted, so just keeping the last equiv of a pair, keeps the
230 end = vmlist + vmlist_size;
232 if(vm->xsz == vm[-1].xsz && vm->ysz == vm[-1].ysz &&
233 equiv_bpp(vm->bpp, vm[-1].bpp)) {
234 memmove(vm - 1, vm, (end - vm) * sizeof *vm);
240 vmlist_size = end - vmlist;
250 uint16_t *dptr = backbuf;
251 uint16_t *sptr = (uint16_t*)img.pixels + pan_y * img.width + pan_x;
253 minx = img.width - pan_x;
254 if(minx > vmode->xsz) minx = vmode->xsz;
255 miny = img.height - pan_y;
256 if(miny > vmode->ysz) miny = vmode->ysz;
258 for(i=0; i<miny; i++) {
259 memcpy(dptr, sptr, minx << 1);
260 if(minx < vmode->xsz) {
261 memset(dptr + minx, 0, (vmode->xsz - minx) << 1);
263 dptr += vmode->pitch >> 1;
266 if(miny < vmode->ysz) {
267 memset(dptr, 0, (vmode->ysz - miny) * vmode->pitch);
279 void xor_cursor8(int x, int y)
283 void xor_cursor16(int x, int y)
285 unsigned short *sptr = (unsigned short*)backbuf + y * (vmode->pitch >> 1);
286 int i, x0, x1, y0, y1;
291 if(x1 >= vmode->xsz) x1 = vmode->xsz - 1;
295 if(y1 >= vmode->ysz) y1 = vmode->ysz - 1;
297 for(i=x0; i<=x1; i++) {
301 sptr = (unsigned short*)backbuf + y0 * (vmode->pitch >> 1) + x;
302 for(i=y0; i<=y1; i++) {
306 sptr += vmode->pitch >> 1;
310 void xor_cursor24(int x, int y)
314 void xor_cursor32(int x, int y)
318 int equiv_bpp(int a, int b)
320 if(a == 15 || a == 16) {
321 return b == 15 || b == 16 ? 1 : 0;
323 if(a == 24 || a == 32) {
324 return b == 24 || b == 32 ? 1 : 0;
326 return a == b ? 1 : 0;
329 int vmcmp(const void *a, const void *b)
331 const struct video_mode *vma = a;
332 const struct video_mode *vmb = b;
334 return vma->ysz - vmb->ysz;
337 int parse_args(int argc, char **argv)
340 static const char *usage_fmt = "Usage: %s [options] <image file>\n"
342 " -bpp <n>: video mode color depth (8, 15, 16, 24, 32)\n"
343 " -h,-help: print usage information and exit\n";
345 for(i=1; i<argc; i++) {
346 if(argv[i][0] == '-') {
347 if(strcmp(argv[i], "-bpp") == 0) {
348 if(!argv[++i] || (opt_bpp = atoi(argv[i])) <= 0) {
349 fprintf(stderr, "invalid -bpp\n");
352 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
353 printf(usage_fmt, argv[0]);
356 fprintf(stderr, "invalid option: %s\n", argv[i]);
357 printf(usage_fmt, argv[0]);
362 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
363 printf(usage_fmt, argv[0]);