10 int switch_mode(int m);
11 int find_best_mode(int minx, int miny);
12 void drop_equiv_modes(void);
18 void (*display)(void);
19 void xor_cursor8(int x, int y);
20 void xor_cursor16(int x, int y);
21 void xor_cursor24(int x, int y);
22 void xor_cursor32(int x, int y);
23 void (*xor_cursor)(int x, int y);
25 int equiv_bpp(int a, int b);
26 int vmcmp(const void *a, const void *b);
27 int parse_args(int argc, char **argv);
29 static struct video_mode *vmode;
30 static struct video_mode *vmlist;
31 static int vmlist_size, cur_vm = -1;
34 static int opt_width, opt_height;
35 static int opt_bpp = 16;
36 static const char *opt_fname;
38 static int redraw_pending = 1;
39 static int pan_x, pan_y, max_pan_x, max_pan_y;
41 static struct img_pixmap img;
44 int main(int argc, char **argv)
47 struct video_mode *vmodes;
49 if(parse_args(argc, argv) == -1) {
53 fprintf(stderr, "please specify an image file to open\n");
57 if(init_video() == -1) {
58 fprintf(stderr, "failed to initialize video\n");
62 /* populate and sort the usable video mode list */
63 num = num_video_modes();
64 vmodes = video_modes();
66 if(!(vmlist = chk_malloc(num * sizeof *vmlist))) {
67 fprintf(stderr, "failed to allocate video mode list\n");
72 for(i=0; i<num; i++) {
73 if(equiv_bpp(opt_bpp, vmodes[i].bpp)) {
74 vmlist[vmlist_size++] = vmodes[i];
78 fprintf(stderr, "no usable video modes found for %d bpp\n", opt_bpp);
81 qsort(vmlist, vmlist_size, sizeof *vmlist, vmcmp);
85 if(img_load(&img, opt_fname) == -1) {
86 fprintf(stderr, "failed to load image: %s\n", opt_fname);
93 img_convert(&img, IMG_FMT_RGB565);
96 img_convert(&img, IMG_FMT_RGB24);
99 img_convert(&img, IMG_FMT_RGBA32);
106 opt_width = img.width;
107 opt_height = img.height;
109 modeidx = find_best_mode(opt_width, opt_height);
110 if(switch_mode(modeidx) == -1) {
122 if(cur_vm < vmlist_size - 1) {
123 switch_mode(cur_vm + 1);
130 switch_mode(cur_vm - 1);
139 if((mouse.dx | mouse.dy) && mouse.bn & 1) {
142 if(pan_x < 0) pan_x = 0;
143 if(pan_y < 0) pan_y = 0;
144 if(pan_x > max_pan_x) pan_x = max_pan_x;
145 if(pan_y > max_pan_y) pan_y = max_pan_y;
153 blit_frame(backbuf, FLIP_NOW);
169 int switch_mode(int m)
175 if(!(backbuf = chk_malloc(vmode->ysz * vmode->pitch))) {
176 fprintf(stderr, "failed to allocate back buffer\n");
180 set_video_mode(find_video_mode(vmode->mode), 0);
185 xor_cursor = xor_cursor8;
190 xor_cursor = xor_cursor16;
194 xor_cursor = xor_cursor24;
198 xor_cursor = xor_cursor32;
203 set_mouse_bounds(0, 0, vmode->xsz, vmode->ysz);
206 max_pan_x = img.width - vmode->xsz;
207 max_pan_y = img.height - vmode->ysz;
208 if(max_pan_x < 0) max_pan_x = 0;
209 if(max_pan_y < 0) max_pan_y = 0;
211 if(pan_x > max_pan_x) pan_x = max_pan_x;
212 if(pan_y > max_pan_y) pan_y = max_pan_y;
217 int find_best_mode(int minx, int miny)
221 for(i=0; i<vmlist_size; i++) {
222 if(vmlist[i].xsz >= minx && vmlist[i].ysz >= miny) {
226 return vmlist_size - 1;
229 void drop_equiv_modes(void)
231 struct video_mode *vm, *end;
233 /* modes are sorted, so just keeping the last equiv of a pair, keeps the
237 end = vmlist + vmlist_size;
239 if(vm->xsz == vm[-1].xsz && vm->ysz == vm[-1].ysz &&
240 equiv_bpp(vm->bpp, vm[-1].bpp)) {
241 memmove(vm - 1, vm, (end - vm) * sizeof *vm);
247 vmlist_size = end - vmlist;
257 uint16_t *dptr = backbuf;
258 uint16_t *sptr = (uint16_t*)img.pixels + pan_y * img.width + pan_x;
260 minx = img.width - pan_x;
261 if(minx > vmode->xsz) minx = vmode->xsz;
262 miny = img.height - pan_y;
263 if(miny > vmode->ysz) miny = vmode->ysz;
265 for(i=0; i<miny; i++) {
266 memcpy(dptr, sptr, minx << 1);
267 if(minx < vmode->xsz) {
268 memset(dptr + minx, 0, (vmode->xsz - minx) << 1);
270 dptr += vmode->pitch >> 1;
273 if(miny < vmode->ysz) {
274 memset(dptr, 0, (vmode->ysz - miny) * vmode->pitch);
286 void xor_cursor8(int x, int y)
290 void xor_cursor16(int x, int y)
292 unsigned short *sptr = (unsigned short*)backbuf + y * (vmode->pitch >> 1);
293 int i, x0, x1, y0, y1;
298 if(x1 >= vmode->xsz) x1 = vmode->xsz - 1;
302 if(y1 >= vmode->ysz) y1 = vmode->ysz - 1;
304 for(i=x0; i<=x1; i++) {
308 sptr = (unsigned short*)backbuf + y0 * (vmode->pitch >> 1) + x;
309 for(i=y0; i<=y1; i++) {
313 sptr += vmode->pitch >> 1;
317 void xor_cursor24(int x, int y)
321 void xor_cursor32(int x, int y)
325 int equiv_bpp(int a, int b)
327 if(a == 15 || a == 16) {
328 return b == 15 || b == 16 ? 1 : 0;
330 if(a == 24 || a == 32) {
331 return b == 24 || b == 32 ? 1 : 0;
333 return a == b ? 1 : 0;
336 int vmcmp(const void *a, const void *b)
338 const struct video_mode *vma = a;
339 const struct video_mode *vmb = b;
341 return vma->ysz - vmb->ysz;
344 int parse_args(int argc, char **argv)
347 static const char *usage_fmt = "Usage: %s [options] <image file>\n"
349 " -s <WxH>: choose screen resolution if available\n"
350 " -bpp <n>: video mode color depth (8, 15, 16, 24, 32)\n"
351 " -h,-help: print usage information and exit\n";
353 for(i=1; i<argc; i++) {
354 if(argv[i][0] == '-') {
355 if(strcmp(argv[i], "-s") == 0) {
356 if(!argv[++i] || sscanf(argv[i], "%dx%d", &opt_width, &opt_height) != 2 ||
357 opt_width <= 0 || opt_height <= 0) {
358 fprintf(stderr, "invalid resolution\n");
361 } else if(strcmp(argv[i], "-bpp") == 0) {
362 if(!argv[++i] || (opt_bpp = atoi(argv[i])) <= 0) {
363 fprintf(stderr, "invalid -bpp\n");
366 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) {
367 printf(usage_fmt, argv[0]);
370 fprintf(stderr, "invalid option: %s\n", argv[i]);
371 printf(usage_fmt, argv[0]);
376 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
377 printf(usage_fmt, argv[0]);