📄 vgadisp.c
字号:
/* zgv 5.6 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux. * Copyright (C) 1993-2002 Russell Marks. See README for license details. * * vgadisp.c - VGA-specific display routines. */#include <stdio.h>#include <string.h>#include <math.h> /* for pow() */#include <unistd.h>#include <stdlib.h>#include <signal.h>#include <sys/file.h>#include <vga.h>#include <vgagl.h>#include <vgamouse.h>#include "zgv.h"#include "magic.h"#include "readgif.h"#include "readjpeg.h"#include "readpnm.h"#include "readbmp.h"#include "readpng.h"#include "readtga.h"#include "readpcx.h"#include "readxvpic.h"#include "readmrf.h"#include "readxbm.h"#include "readxpm.h"#include "readpcd.h"#include "readtiff.h"#include "readprf.h"#include "readnbkey.h"#include "helppage.h"#include "3deffects.h"#include "rc_config.h"#include "rcfile.h"#include "mousecur.h"#include "rbmenu.h"#include "modesel.h"#include "vgadisp.h"/* zgv.c initialises these */int curvgamode;int zoom,virtual;int vkludge;int pixelsize; /* in bytes - 1 for 8-bit, 3 for 24-bit */int pic_incr; /* after view, 0=stay, -1=prev, 1=next *//* for right-buttom menu */static int rb_ignore_first_left_click=0;static unsigned char *rb_save=NULL;static int rb_save_width,rb_save_height;char *viewerhelp[]= { "? (question mark)\\this help page", "/\\show video mode selection help", " ", "v\\toggle smoothing in virtual/zoom modes", "comma/dot\\contrast down/up", "less-than/greater-than\\brightness down/up", "semicolon\\reset contrast and brightness", "z\\toggle zoomed mode", "r\\rotate clockwise 90 degrees", "m\\mirror", "f\\flip", "d\\double size of picture", "D\\halve size of picture", "Esc or x\\exit the viewer", " ", "hjkl or qaop keys scroll around the picture", "HJKL or QAOP (also the cursor keys) scroll in bigger steps", "" /* end */ };char *viewermodeshelp[]= { "Generic VGA modes:", "5 - 320x200x8\\6 - 320x240x8\\", "7 - 320x400x8\\8 - 360x480x8\\0 - 640x480x4", " ", "SVGA modes (try these first):", "F1 - 640x480x8\\F2 - 800x600x8\\F3 - 1024x768x8", "F4 - 1280x1024x8\\F5 - 320x200x15\\F6 - 320x200x16", "F7 - 320x200x24\\F8 - 640x480x15\\F9 - 640x480x16", "F10 - 640x480x24\\SF1 - 800x600x15\\SF2 - 800x600x16", "SF3 - 800x600x24\\SF4 - 1024x768x15\\SF5 - 1024x768x16", "SF6 - 1024x768x24\\SF7 - 1280x1024x15\\SF8 - 1280x1024x16", "Tab-F1 - 1280x1024x24\\Tab-F2 - 1152x864x8\\Tab-F3 - 1152x864x15", "Tab-F4 - 1152x864x16\\Tab-F5 - 1152x864x24\\Tab-F6 - 1600x1200x8", "Tab-F7 - 1600x1200x15\\Tab-F8 - 1600x1200x16\\Tab-F9 - 1600x1200x24", " ", "Or to browse modes:\\[ - lower-res mode\\] - higher-res mode", "" /* end */ };struct rbm_data_tag viewer_menu_data[]= { /* 31 chars max for label text */ {1, "Exit viewer", RK_ESC }, /* stuff in draw_rb_menu which sets the active field of these * mode buttons assumes they are in *exactly* this order/position. * So don't change anything before the "Normal" button without * thinking twice... or more. :-) * * modes less than 480 pixels high are omitted here since * the mouse menu is disabled on those. */ {1, "360x480x8", '8' }, {1, "640x480x4", '0' }, {1, "640x480x8", RK_F1 }, {1, "800x600x8", RK_F2 }, {1, "1024x768x8", RK_F3 }, {1, "640x480x15", RK_F8 }, {1, "640x480x16", RK_F9 }, {1, "640x480x24", RK_F10 }, {1, "800x600x15", RK_SHIFT_F1 }, {1, "800x600x16", RK_SHIFT_F2 }, {1, "800x600x24", RK_SHIFT_F3 }, {1, "1024x768x15", RK_SHIFT_F4 }, {1, "1024x768x16", RK_SHIFT_F5 }, {1, "1024x768x24", RK_SHIFT_F6 }, {1, "Next file", RK_ENTER }, {1, " ...tag first", ' ' }, /* no gap thing here, due to split between columns */ {1, "Normal size", 'n' }, {1, "Zoom on/off", 'z' }, {1, " ...smooth on/off", 'v' }, {1, "Scale up 1", 's' }, {1, "Scale down 1", 'S' }, {1, "Scale up x2", 'd' }, {1, "Scale down x2", 'D' }, {1, " ...smooth on/off", 'i' }, {1, "Normal orient'n", 128+'n' }, {1, "Save orient'n", 128+'s' }, {1, "Use last orient'n", 128+'o' }, {1, "Rotate c/w", 'r' }, {1, "Rotate anti-c/w", 'R' }, {1, "Mirror", 'm' }, {1, "Flip", 'f' }, /* this next one seems bizarre, but it's to the right of "next file" */ {1, "Previous file", 127 }, {1, "4-bit grey/colour", 'c' }, {0,"",0} };unsigned char vkcache[32768],vkcache_valid[32768];#define MOVSTP 10 /* for q,a,o,p panning */#define BIGSTP 100 /* for Q,A,O,P panning (i.e. with shift) */#define FIX_TO_EIGHT_BIT 1#define FIX_TO_HIGHCOLOUR 2byte *theimage; /* quite slow if passed as parameter */int width,height,numcols; /* same here */byte *image_palette;double contrast=1.0; /* note that double contrast is in fact 2 :-) */int brightness=0;double picgamma=1.0;double initial_picgamma=1.0; /* value set by `4' */int scaling=1,interp=0,inextpix=1;int scrnwide,scrnhigh,scrnpixelsize,scrncols;int palr[256],palg[256],palb[256];byte palr64[256],palg64[256],palb64[256], palt[256];int palrgb[768];unsigned char pal32_no_bc[768];unsigned char dither16_greylookup[256];unsigned char dither16_rgb[768];volatile int repeat_sig;int first_repeat;int loading_file_type;int saved_px,saved_py; /* for persistance in cfg.repeat_timer mode *//* grey values for rgb - NTSC uses these (adding up to 1000) */static int grey_red=299,grey_green=587,grey_blue=114;int sgres;static int override_zoom_clear=0;/* Scary orientation stuff * ----------------------- * * There are eight possible orientations (0 is the original image): * _____ _____ * _______ _______ | a| | b| * |a | |b | | | | | * | 0 | | 1 | | 4 | | 5 | * |______b| |______a| |b____| |a____| * _______ _______ _____ _____ * | b| | a| |b | |a | * | 2 | | 3 | | | | | * |a______| |b______| | 6 | | 7 | * |____a| |____b| * * That gives us these changes in orientation state for each of the * orientation-changing operations (rotate, mirror, flip): * * rot-cw rot-acw mirror flip * 0 to... 4 5 3 2 * 1 to... 5 4 2 3 * 2 to... 7 6 1 0 * 3 to... 6 7 0 1 * 4 to... 1 0 7 6 * 5 to... 0 1 6 7 * 6 to... 2 3 5 4 * 7 to... 3 2 4 5 */int orient_state_rot_cw[8] ={4,5,7,6,1,0,2,3};int orient_state_rot_acw[8]={5,4,6,7,0,1,3,2};int orient_state_mirror[8] ={3,2,1,0,7,6,5,4};int orient_state_flip[8] ={2,3,0,1,6,7,4,5};int orient_override=0; /* override orientation (used by Alt-s) */int orient_override_state=0;#define GET32BITCOLOUR(r,g,b) (b|(g<<8)|(r<<16))/* indirection needed to allow high-colour brightness/contrast */typedef void (*eventuallyfunc)(byte *,int,int,int);eventuallyfunc eventuallydrawscansegment=NULL;int doing_hicol_bc=0; /* non-zero if doing hi-col b/c in current redraw *//* prototypes */int readpicture(char *giffn,hffunc howfarfunc,int show_dont_tell, int quick,int *real_width,int *real_height);int has_highcolour_mode(void);void fix_to_similar_mode(int modetype);void aborted_file_cleanup(void);int is_this_file_jpeg(void);void makerealpal(void);void filterpal(byte *palette);int dimmer(int a);int contrastup(int cp);int apply_gamma(int val);int get_mode_width(int vm);int get_mode_height(int vm);int get_mode_pixelbytes(int vm);int get_mode_numcols(int vm);void setmode_or_clear(int newmode);void init_vkludge_cache(void);void graphicson(void);void graphicsoff(void);int mode_is_usable_now(int modenum);int showgif(char *filename,byte *palette);static void draw_rb_menu(void);static void undraw_rb_menu(void);static int rb_menu_event(int *keyp);void repeat_sighandler(int foo);void setpalvec(int start,int num,int *pal);void redrawgif(int px, int py, int npx, int npy);void eventuallydrawscansegment_without_bc(byte *ptr, int x, int y, int len);void eventuallydrawscansegment_with_bc(byte *ptr, int x, int y, int len);void dither16scansegment(unsigned char *ptr,int x,int y,int len);int getvpix(int px, int py, int x, int y);void drawzoomedgif(void);void fx_mirror(void);void fx_flip(void);void fx_rot(void);int closest(int r, int g, int b);void samecentre(int *ppx, int *ppy, int newscale, int oldpx, int oldpy, int oldscale);void show_dimensions(int px, int py, int scaling);void orient_change_state(int from,int to,int clear_if_rot);int animate_gif(int orient_state);/* to read a picture only, set show_dont_tell=0. * If you're only reading the picture, not showing it, then: * 1. picture is returned in global vars. 'theimage' and 'image_palette' * 2. you have to set pixelsize=whatever and restore it afterwards. * 3. you have to free() both theimage and image_palette when finished. * * The `quick' arg sets whether or not to ask the jpeg decoder for a * rough image. This is useful when doing thumbnails, where we don't * need the accuracy, but you shouldn't use it elsewhere. * * `real_width' and `real_height' give the true width/height of the * image (useful if using `quick', and a smaller image was returned). * Set them to NULL if you don't care. */int readpicture(char *giffn,hffunc howfarfunc,int show_dont_tell, int quick,int *real_width,int *real_height){int result=0;PICINFO ginfo;byte *palette=NULL;int realset=0;first_repeat=1;gif_delaycount=0;do { ginfo.numcols=256; /* only changes for GIF files */ theimage=NULL; if(!first_repeat) howfarfunc=NULL; switch(loading_file_type=magic_ident(giffn)) { case _IS_GIF: /* part of the New Strategy (tm); always use 8-bit for GIFs. * fix the mode to a similar 8-bit one if possible. */ if(show_dont_tell) fix_to_similar_mode(FIX_TO_EIGHT_BIT); result=read_gif_file(giffn,howfarfunc,&theimage,&palette, &pixelsize,&ginfo); height=ginfo.height; width=ginfo.width; break; case _IS_JPEG: /* don't *always* use 24-bit for JPEGs... check for 15/16/24-bit * video modes before doing so, as well as the config. */ if(show_dont_tell) { pixelsize=has_highcolour_mode()?3:1; if(pixelsize==3 && cfg.jpeg24bit==0) pixelsize=1; } theimage=NULL; result=read_JPEG_file(giffn,howfarfunc,&palette, quick,real_width,real_height); realset=1; /* if error, then palette has already been nuked, so only * need to deal with the image. */ if(theimage!=NULL && result!=_PIC_OK) { free(theimage); theimage=NULL; } break; case _IS_PNG: if(show_dont_tell) { pixelsize=has_highcolour_mode()?3:1; if(pixelsize==3 && cfg.jpeg24bit==0) pixelsize=1; } theimage=NULL; result=read_png_file(giffn,howfarfunc,&palette); /* if error, then palette has already been nuked, so only * need to deal with the image. */ if(theimage!=NULL && result!=_PIC_OK) { if(cfg.errignore) result=_PIC_OK; else { free(theimage); theimage=NULL; } } break; case _IS_PNM: case _IS_BMP: case _IS_TGA: case _IS_PCX: case _IS_XVPIC: case _IS_MRF: case _IS_PCD: case _IS_XBM: case _IS_XPM: case _IS_TIFF: case _IS_PRF: if(show_dont_tell) pixelsize=has_highcolour_mode()?3:1; switch(loading_file_type) { case _IS_PNM: result=read_pnm_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_TIFF: result=read_tiff_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_BMP: result=read_bmp_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_TGA: result=read_tga_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_PCX: result=read_pcx_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_XVPIC: result=read_xvpic(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_MRF: result=read_mrf_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_PRF: result=read_prf_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; case _IS_XBM: result=read_xbm_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break;#ifdef PCD_SUPPORT case _IS_PCD: result=read_pcd_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break;#endif case _IS_XPM: result=read_xpm_file(giffn,howfarfunc,&theimage,&palette,&pixelsize, &ginfo); break; } width=ginfo.width; height=ginfo.height; if(result!=_PIC_OK) { gif_delaycount=0; /* ignore any animation stuff */ if(theimage!=NULL) { free(theimage); theimage=NULL; } if(palette!=NULL) { free(palette); palette=NULL; } } else if(loading_file_type==_IS_TGA && tga_need_flip) fx_flip(); /* right way up! */ break; /* if they voted for "none of the above"... */ default: return(_PICERR_BADMAGIC); } if(!realset) { if(real_width) *real_width=width; if(real_height) *real_height=height; realset=1; } if(show_dont_tell) { if(pixelsize==3) fix_to_similar_mode(FIX_TO_HIGHCOLOUR); else fix_to_similar_mode(FIX_TO_EIGHT_BIT); if(result==_PIC_OK) { numcols=ginfo.numcols; sgres=showgif(giffn,palette); free(theimage); free(palette); } } else image_palette=palette; }while(show_dont_tell && cfg.repeat_timer && result==_PIC_OK && sgres==0);return(result);}/* modes aren't counted if they're locked out */int has_highcolour_mode(){struct modedesc_tag *md_ptr;if(cfg.hicolmodes) return(1); /* forces positive response */for(md_ptr=modedesc;md_ptr->mode;md_ptr++) if(md_ptr->bitspp>=15 && vga_hasmode(md_ptr->mode) && cfg.mode_allowed[md_ptr->mode]) return(1);return(0);}/* since we've already tested if it's possible, this can't fail */void fix_to_similar_mode(int modetype){int f,newmode,numpixels,pixdiff,newnp,newdiff,mode_ok;vga_modeinfo *vminfo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -