/****************************************************************************** * * project name: TICT-Explorer * file name: tictexpv.c * initial date: 23/01/2001 * author: thomas.nussbaumer@gmx.net * * description: PV-Picture Viewer * * supports oversized 4-grayscales pictures and animations * generated with Picture Maker v1.3 by CandyMan * * [DIAMOND][LEFT] and [DIAMOND][RIGHT] can be used to adjust the grayscales * frequency calibration (for HW2) * * [+] and [-] can be used to increase and decrease frame rate of animations * * * $Id: tictexpv.c,v 1.8 2002/09/10 11:28:43 tnussb Exp $ * ******************************************************************************/ //----------------------------------------------------------------------------- // check for -DUSE_TI89 commandline flag (for TI-89 version) // *** or *** // check for -DUSE_TI92PLUS commandline flag (for TI-92p version) // // ONLY ONE IS ALLOWED PER COMPILE RUN //----------------------------------------------------------------------------- #if defined(USE_TI89) && defined(USE_TI92PLUS) #error cannot produce both versions at once #elif defined(USE_TI89) #define C89_92(x,y) (x) #elif defined(USE_TI92PLUS) #undef USE_V200 // No warnings please. #define USE_V200 // V200 support !!! #define C89_92(x,y) (y) #else #error Please define either USE_TI89 or USE_TI92PLUS (V200 will be treated as TI92+) #endif #define NO_EXIT_SUPPORT #define OPTIMIZE_ROM_CALLS #include #ifndef GRAY3P_SUPPORT #define VERSION_NUMBER "1.03" #else #include "gray3P.h" #define VERSION_NUMBER "1.03-3P" #endif //----------------------------------------------------------------------------- // useful macro for calculator type definitions //----------------------------------------------------------------------------- #if defined(USE_TI89) #define C89_92(x,y) (x) #else #define C89_92(x,y) (y) #endif //----------------------------------------------------------------------------- // calculator depended definitions //----------------------------------------------------------------------------- #define SCREEN_WIDTH C89_92(20,30) #define SCREEN_HEIGHT C89_92(100,128) #define KEY_GRAYADJUST_PLUS C89_92(16728,8532) #define KEY_GRAYADJUST_MINUS C89_92(16722,8529) #define MINIMUM_GRAYADJUST C89_92(-28,0) #define SECOND_OFF_COMBO C89_92(16651,8459) //----------------------------------------------------------------------------- // pvpicture.h contains definitions of the fileformat of PictureMaker files //----------------------------------------------------------------------------- #include "pvpicture.h" #define DELAY_DEFAULT 100 #define DELAY_MAX 500 #define DELAY_STEP 20 short gray_adjust_value = 0; unsigned short delay_for_animations = DELAY_DEFAULT; /*===========================================================================*/ /* fast replacement for kbhit() */ /*===========================================================================*/ static inline short IsKeyWaiting() { unsigned short key; return OSqinquire(&key,kbd_queue()); } /*===========================================================================*/ /* get input key pressed by user */ /* */ /* replacement for ngetchx() and/or GKeyIn(), because: */ /* */ /* (1) ngetchx() won't check the APD timer value */ /* (2) GKeyIn() destroys the display due to setting the status display */ /* */ /* additionally this function handles the CALCULATOR OFF combinations */ /* */ /*===========================================================================*/ static unsigned short GetUserInput(short is_gray_on) { void *kbq = kbd_queue(); unsigned short key; //------------------------------------------- // restart the APD timer now //------------------------------------------- OSTimerRestart(APD_TIMER); while (1) { //--------------------------------------- // wait until we get a key // if the APD timer expires -> turn // calculator off //--------------------------------------- while (OSdequeue(&key, kbq)) { if (OSTimerExpired(APD_TIMER)) { off(); if (is_gray_on) { GrayAdjust(gray_adjust_value); // necessary ?? } OSTimerRestart(APD_TIMER); } if (!is_gray_on) { idle(); } pokeIO(0x600005,0b10111); } //--------------------------------------- // handle calculator-off key combinations // if the APD timer expires // [2nd] + [ON] & [diamond]+[ON] // calculator off //--------------------------------------- if (key == KEY_OFF || key == SECOND_OFF_COMBO) { off(); if (is_gray_on) { GrayAdjust(gray_adjust_value); // necessary ?? } OSTimerRestart(APD_TIMER); } else { if (is_gray_on) { // grayscale adjustment if (key == KEY_GRAYADJUST_PLUS) { if (gray_adjust_value < 127) { gray_adjust_value++; GrayAdjust(gray_adjust_value); } } else if (key == KEY_GRAYADJUST_MINUS) { if (gray_adjust_value > MINIMUM_GRAYADJUST) { gray_adjust_value--; GrayAdjust(gray_adjust_value); } } } return key & ~(unsigned short)0x800; // map out key repeat flag } } } /*===========================================================================*/ /* "waits" a given number of milliseconds (dummy looping) */ /* NOTE: this wait loop is parametrized to fit on HW2 calculators */ /*===========================================================================*/ asm("xdef WaitForMillis\n" "WaitForMillis:\n" " move.l %d3,-(%sp)\n" " moveq #31,%d1\n" " moveq #31,%d3\n" "_wl2_: move.w #132,%d0 /* modify this value for exact timing !!! */\n" "_wl1_: rol.l %d3,%d1\n" " dbf %d0,_wl1_\n" " dbf %d2,_wl2_\n" " move.l (%sp)+,%d3\n" " rts"); void WaitForMillis(unsigned short delay asm("%d2")); /*===========================================================================*/ /* handles drawing of a single plane */ /*===========================================================================*/ static void HandleDrawPlane(unsigned char* src, unsigned char* dest, unsigned short virtual_width, unsigned short virtual_height, short offsetx, short offsety) { unsigned short y; unsigned short width; unsigned short height; unsigned short bytes_to_draw; unsigned short skip_bytes_before = 0; if (virtual_width > SCREEN_WIDTH) width = SCREEN_WIDTH; else width = virtual_width; if (virtual_height > SCREEN_HEIGHT) height = SCREEN_HEIGHT; else height = virtual_height; src += offsetx + offsety*virtual_width; if (virtual_height-offsetx < width) { bytes_to_draw = virtual_height-offsetx; } else { bytes_to_draw = width; } if (SCREEN_HEIGHT > virtual_height) { dest += 30*(SCREEN_HEIGHT-virtual_height)/2; } if (SCREEN_WIDTH > virtual_width) { skip_bytes_before = (SCREEN_WIDTH-virtual_width)/2; } for (y=0;ynr_pics; unsigned short act_frame = 0; short maxwidth,maxheight; unsigned char* data; short offsetx = 0; short offsety = 0; short input; short redraw; unsigned char* first_plane; unsigned short plane_offset; unsigned char* dest1 = NULL; unsigned char* dest2 = NULL; #ifdef GRAY3P_SUPPORT unsigned char* dest3 = NULL; #endif if (fh->nr_planes == 1) { dest1 = LCD_MEM; dest2 = NULL; } #ifdef GRAY3P_SUPPORT else if (fh->nr_planes == 2) { if (!GrayOn()) { strcpy(msg,"ERR: cannot turn on graymode"); return; } dest1 = GetPlane(1); dest2 = GetPlane(0); dest3 = NULL; } else if (fh->nr_planes == 3) { if (!Gray3POn(TRUE)) { strcpy(msg,"ERR: cannot turn on 3 plane graymode"); return; } dest1 = Gray3PGetPlane(2); dest2 = Gray3PGetPlane(1); dest3 = Gray3PGetPlane(0); } #else else if (fh->nr_planes == 2 || fh->nr_planes == 3) { if (!GrayOn()) { strcpy(msg,"ERR: cannot turn on graymode"); return; } dest1 = GetPlane(1); dest2 = GetPlane(0); } #endif else { strcpy(msg,"ERR: invalid number of planes"); return; } memset(dest1,0,LCD_SIZE); if (dest2) { memset(dest2,0,LCD_SIZE); #ifdef GRAY3P_SUPPORT if (dest3) { memset(dest3,0,LCD_SIZE); } #endif GrayAdjust(gray_adjust_value); } src += sizeof(PV_FILE_HEADER); // maxheight = ((unsigned short)(ph->y_dim_msb) << 8) | ph->y_dim_lsb; // maxwidth = ((unsigned short)(ph->x_dim_msb) << 8) | ph->x_dim_lsb; maxheight = ((unsigned short)(*src++) << 8); maxheight |= *src++; maxwidth = ((unsigned short)(*src++) << 8); maxwidth |= *src++; first_plane = src; plane_offset = maxwidth*maxheight + sizeof(PV_PLANE_HEADER); do { do { data = first_plane+act_frame*fh->nr_planes*plane_offset; redraw = 0; HandleDrawPlane(data, dest1, maxwidth, maxheight, offsetx, offsety); if (dest2) HandleDrawPlane(data+plane_offset, dest2, maxwidth, maxheight, offsetx, offsety); #ifdef GRAY3P_SUPPORT if (dest3) HandleDrawPlane(data+plane_offset+plane_offset, dest3,maxwidth,maxheight,offsetx,offsety); #endif act_frame++; if (act_frame >= nr_frames) act_frame = 0; if (nr_frames) WaitForMillis(delay_for_animations); } while (!IsKeyWaiting() && nr_frames); do { input = GetUserInput(!!dest2); if (maxheight > SCREEN_HEIGHT) { if (input == KEY_DOWN) { if (offsety+8 < (maxheight-SCREEN_HEIGHT)) { offsety += 8; redraw = 1; } } else if (input == KEY_UP) { if (offsety-8 >= 0) { offsety -= 8; redraw = 1; } } } if (maxwidth > SCREEN_WIDTH) { if (input == KEY_RIGHT) { if (offsetx+1 < maxwidth-SCREEN_WIDTH) { offsetx += 1; redraw = 1; } } else if (input == KEY_LEFT) { if (offsetx-1 >= 0) { offsetx -= 1; redraw = 1; } } } if (input == '-') { if (delay_for_animations < DELAY_MAX) delay_for_animations+=DELAY_STEP; } else if (input == '+') { if (delay_for_animations > 0) delay_for_animations-=DELAY_STEP; } if (input == KEY_ESC || input == KEY_F5 || input == KEY_ENTER) { #ifdef GRAY3P_SUPPORT if (dest3) Gray3POff(); else if (dest2) GrayOff(); #else if (dest2) GrayOff(); #endif return; } } while (!redraw && !nr_frames); } while (1); } /*===========================================================================*/ /* check if given file contains a PV picture, which can be handled by us */ /*===========================================================================*/ static short IsValidPic(unsigned char* src,unsigned char* end,unsigned char* msg) { unsigned short total; unsigned short planes; unsigned short width = 0xffff; unsigned short height = 0xffff; PV_FILE_HEADER* fh; if (*end || *(end-1)) { strcpy(msg,"ERR: invalid extension"); return 0; } fh = (PV_FILE_HEADER*)src; if (fh->magic != PV_MAGIC && fh->magic != PV_MAGIC) { strcpy(msg,"ERR: invalid MAGIC marker"); return 0; } if (fh->nr_planes < 1 && fh->nr_planes > 3) { strcpy(msg,"ERR: invalid number of grays"); return 0; } src += sizeof(PV_FILE_HEADER); planes = 0; total = (unsigned short)fh->nr_planes; total += ((unsigned short)fh->nr_planes) * (unsigned short)fh->nr_pics; while (planes < total && src < end) { //unsigned short embheight = ((unsigned short)(ph->y_dim_msb) << 8) | ph->y_dim_lsb; //unsigned short embwidth = ((unsigned short)(ph->x_dim_msb) << 8) | ph->x_dim_lsb; unsigned short embheight; unsigned short embwidth; embheight = ((unsigned short)(*src++) << 8); embheight |= *src++; embwidth = ((unsigned short)(*src++) << 8); embwidth |= *src++; if (width==0xffff) { width = embwidth; height = embheight; } else { if (width != embwidth || height != embheight) { strcpy(msg,"ERR: plane sizes differs"); return 0; } } src += embheight * embwidth; planes++; } if (src != end-1) { strcpy(msg,"ERR: invalid length"); return 0; } return 1; } short menuopt=0; /*===========================================================================*/ /* simple select menu */ /*===========================================================================*/ static inline SYM_ENTRY* SelectMenu(void) { short i,select,index=1,ng=0; HANDLE shandle,mhandle = 0; SYM_ENTRY* symptr=SymFindFirst(NULL,2); unsigned char* fptr; unsigned char* end; unsigned short length; char tmpstr[100]; mhandle=PopupNew((char*)"Select a Picture",C89_92(53,69)); DrawClipRect(ScrToWin(ScrRect),ScrRect,A_NORMAL); while (symptr) { shandle = symptr->handle; if (shandle) { if (HeapGetLock(shandle)) { fptr = HeapDeref(shandle); shandle = 0; } else { fptr = HLock(shandle); } if (fptr) { length = *(unsigned short*)fptr; fptr+=2; end=fptr+length-1; if (IsValidPic(fptr,end,tmpstr)) { PopupAddText(mhandle,-1,symptr->name,index); if (!menuopt) menuopt=index; ng++; } } index++; if (shandle) HeapUnlock(shandle); } symptr=SymFindNext(); } FontSetSys(F_6x8); DrawStr(C89_92(5,120-75),3,"Viewer for PicMaker Files",A_REPLACE); FontSetSys(C89_92(F_4x6,F_6x8)); DrawStr(C89_92(25,20),C89_92(85,110),"Version " VERSION_NUMBER " \xA9 TICT 2014/02",A_REPLACE); if(ng) { #if defined(USE_TI89) select=PopupDo(mhandle,CENTER,(ng>4)?20:(40-4*ng),menuopt); #else select=PopupDo(mhandle,CENTER,(ng>4)?30:(50-4*ng),menuopt); #endif } else { FontSetSys(F_6x8); DrawStr(C89_92(20,60),30,"No pictures found!!!",A_REPLACE); select=0; GetUserInput(0); } ClrScr(); HeapFree(mhandle); if(!select) return NULL; menuopt=select; symptr=SymFindFirst(NULL,2); for(i=1;ihandle)) { unlock_later = 0; src = HeapDeref(symptr->handle); } else { unlock_later = symptr->handle; src = HLock(unlock_later); } length = *(unsigned short*)src; src+=2; end=src+length-1; tmpstr[0] = 0; if (IsValidPic(src,end,tmpstr)) { LCD_save(lcdbuffer); tmpstr[0] = 0; HandleView(src,tmpstr); LCD_restore(lcdbuffer); if (!do_exit && tmpstr[0]) do_exit = 1; } if (unlock_later) HeapUnlock(unlock_later); } while (!do_exit); if (tmpstr[0]) ST_helpMsg(tmpstr); else { ST_helpMsg("PV-Viewer v" VERSION_NUMBER " \xA9 TICT 2014"); } } //============================================================================= // Revision History //============================================================================= // // $Log: tictexpv.c,v $ // Revision 1.8 2002/09/10 11:28:43 tnussb // changes up to v1.30 Beta 4 / examine history.txt for details // // Revision 1.7 2002/03/15 15:12:38 tnussb // necessary changes for V200 // // Revision 1.6 2002/02/21 09:31:24 tnussb // VERSION_TI89 and VERSION_TI92P replaced by new standard USE_TI89 and USE_TI92P // // Revision 1.5 2002/02/07 18:01:18 tnussb // generic commit // // Revision 1.4 2001/02/12 21:42:23 Thomas Nussbaumer // planes switched (using now really dark plane for dark data) // // Revision 1.3 2001/02/04 14:24:58 Thomas Nussbaumer // version number changed back to 1.00 (it was released with 1.00) // // Revision 1.2 2001/02/04 13:11:28 Thomas Nussbaumer // changes up to version 1.00 RC2 (see history.txt) // // Revision 1.1 2001/01/26 21:04:21 Thomas Nussbaumer // initial version // //