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_width, opt_height;
34 static int opt_bpp = 16;
35 static const char *opt_fname;
37 static int redraw_pending = 1;
38 static int pan_x, pan_y, max_pan_x, max_pan_y;
40 static struct img_pixmap img;
43 int main(int argc, char **argv)
46 struct video_mode *vmodes;
48 if(parse_args(argc, argv) == -1) {
52 fprintf(stderr, "please specify an image file to open\n");
56 if(init_video() == -1) {
57 fprintf(stderr, "failed to initialize video\n");
61 /* populate and sort the usable video mode list */
62 num = num_video_modes();
63 vmodes = video_modes();
65 if(!(vmlist = malloc(num * sizeof *vmlist))) {
66 fprintf(stderr, "failed to allocate video mode list\n");
71 for(i=0; i<num; i++) {
72 if(equiv_bpp(opt_bpp, vmodes[i].bpp)) {
73 vmlist[vmlist_size++] = vmodes[i];
77 fprintf(stderr, "no usable video modes found for %d bpp\n", opt_bpp);
80 qsort(vmlist, vmlist_size, sizeof *vmlist, vmcmp);
84 if(img_load(&img, opt_fname) == -1) {
85 fprintf(stderr, "failed to load image: %s\n", opt_fname);
92 img_convert(&img, IMG_FMT_RGB565);
95 img_convert(&img, IMG_FMT_RGB24);
98 img_convert(&img, IMG_FMT_RGBA32);
105 opt_width = img.width;
106 opt_height = img.height;
108 modeidx = find_best_mode(opt_width, opt_height);
109 if(switch_mode(modeidx) == -1) {
121 if(cur_vm < vmlist_size - 1) {
122 switch_mode(cur_vm + 1);
129 switch_mode(cur_vm - 1);
138 if((mouse.dx | mouse.dy) && mouse.bn & 1) {
141 if(pan_x < 0) pan_x = 0;
142 if(pan_y < 0) pan_y = 0;
143 if(pan_x > max_pan_x) pan_x = max_pan_x;
144 if(pan_y > max_pan_y) pan_y = max_pan_y;
152 blit_frame(backbuf, FLIP_NOW);
167 int switch_mode(int m)
173 if(!(backbuf = malloc(vmode->ysz * vmode->pitch))) {
174 fprintf(stderr, "failed to allocate back buffer\n");
178 set_video_mode(find_video_mode(vmode->mode), 0);
183 xor_cursor = xor_cursor8;
188 xor_cursor = xor_cursor16;
192 xor_cursor = xor_cursor24;
196 xor_cursor = xor_cursor32;
201 set_mouse_bounds(0, 0, vmode->xsz, vmode->ysz);
204 max_pan_x = img.width - vmode->xsz;
205 max_pan_y = img.height - vmode->ysz;
206 if(max_pan_x < 0) max_pan_x = 0;
207 if(max_pan_y < 0) max_pan_y = 0;
209 if(pan_x > max_pan_x) pan_x = max_pan_x;
210 if(pan_y > max_pan_y) pan_y = max_pan_y;
215 int find_best_mode(int minx, int miny)
219 for(i=0; i<vmlist_size; i++) {
220 if(vmlist[i].xsz >= minx && vmlist[i].ysz >= miny) {
224 return vmlist_size - 1;
227 void drop_equiv_modes(void)
229 struct video_mode *vm, *end;
231 /* modes are sorted, so just keeping the last equiv of a pair, keeps the
235 end = vmlist + vmlist_size;
237 if(vm->xsz == vm[-1].xsz && vm->ysz == vm[-1].ysz &&
238 equiv_bpp(vm->bpp, vm[-1].bpp)) {
239 memmove(vm - 1, vm, (end - vm) * sizeof *vm);
245 vmlist_size = end - vmlist;
255 uint16_t *dptr = backbuf;
256 uint16_t *sptr = (uint16_t*)img.pixels + pan_y * img.width + pan_x;
258 minx = img.width - pan_x;
259 if(minx > vmode->xsz) minx = vmode->xsz;
260 miny = img.height - pan_y;
261 if(miny > vmode->ysz) miny = vmode->ysz;
263 for(i=0; i<miny; i++) {
264 memcpy(dptr, sptr, minx << 1);
265 if(minx < vmode->xsz) {
266 memset(dptr + minx, 0, (vmode->xsz - minx) << 1);
268 dptr += vmode->pitch >> 1;
271 if(miny < vmode->ysz) {
272 memset(dptr, 0, (vmode->ysz - miny) * vmode->pitch);
284 void xor_cursor8(int x, int y)
288 void xor_cursor16(int x, int y)
290 unsigned short *sptr = (unsigned short*)backbuf + y * (vmode->pitch >> 1);
291 int i, x0, x1, y0, y1;
296 if(x1 >= vmode->xsz) x1 = vmode->xsz - 1;
300 if(y1 >= vmode->ysz) y1 = vmode->ysz - 1;
302 for(i=x0; i<=x1; i++) {
306 sptr = (unsigned short*)backbuf + y0 * (vmode->pitch >> 1) + x;
307 for(i=y0; i<=y1; i++) {
311 sptr += vmode->pitch >> 1;
315 void xor_cursor24(int x, int y)
319 void xor_cursor32(int x, int y)
323 int equiv_bpp(int a, int b)
325 if(a == 15 || a == 16) {
326 return b == 15 || b == 16 ? 1 : 0;
328 if(a == 24 || a == 32) {
329 return b == 24 || b == 32 ? 1 : 0;
331 return a == b ? 1 : 0;
334 int vmcmp(const void *a, const void *b)
336 const struct video_mode *vma = a;
337 const struct video_mode *vmb = b;
339 return vma->ysz - vmb->ysz;
342 int parse_args(int argc, char **argv)
345 static const char *usage_fmt = "Usage: %s [options] <image file>\n"
347 " -s <WxH>: choose screen resolution if available\n"
348 " -bpp <n>: video mode color depth (8, 15, 16, 24, 32)\n"
349 " -h,-help: print usage information and exit\n";
351 for(i=1; i<argc; i++) {
352 if(argv[i][0] == '-') {
353 if(strcmp(argv[i], "-s") == 0) {
354 if(!argv[++i] || sscanf(argv[i], "%dx%d", &opt_width, &opt_height) != 2 ||
355 opt_width <= 0 || opt_height <= 0) {
356 fprintf(stderr, "invalid resolution\n");
359 } else if(strcmp(argv[i], "-bpp") == 0) {
360 if(!argv[++i] || (opt_bpp = atoi(argv[i])) <= 0) {
361 fprintf(stderr, "invalid -bpp\n");
364 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
365 printf(usage_fmt, argv[0]);
368 fprintf(stderr, "invalid option: %s\n", argv[i]);
369 printf(usage_fmt, argv[0]);
374 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
375 printf(usage_fmt, argv[0]);