/****************************************************************************** * * project name: TICT Tutorial S1P6 * file name: scroller.c * initial date: 19/12/2001 * author: thomas.nussbaumer@gmx.net * * description: Simple GrayScale Text Scroller with a Background Image * * $Id$ * ******************************************************************************/ #define SAVE_SCREEN #define OPTIMIZE_ROM_CALLS #include short _ti92plus; short _ti89; //----------------------------------------------------------------------------- // in this tutorial I use a blackwhite bitmap of 160x100 pixels (uncompressed) // as background (converted using ImageStudio and TTBin2Hex) //----------------------------------------------------------------------------- unsigned long data[] = { 0xffffffff,0xffffffff,0xffffffff,0xfffffff6,0xfdffffff,0xffffffff,0xffffffff,0xffffffff, 0xffffffff,0xad7fffff,0xffffffff,0xffffffff,0xffffffff,0xfffff873,0xffffffff,0xffffffff, 0xffffffff,0xffffffff,0xfffff00b,0xfedfffff,0xffffffff,0xffffffff,0xffffffff,0xffffe024, 0xffdfffff,0xffffffff,0xffffffff,0xffffffff,0xffff9cd0,0xac87ffff,0xffffffff,0xffffffff, 0xffffffff,0xfffff27e,0x60e1ffff,0xffffffff,0xffffffff,0xffffffff,0xffffe66b,0x1388ffff, 0xffffffff,0xffffffff,0xfffffeff,0xffffa269,0xe1fd4fff,0xffffffff,0xffffffff,0xfffffeff, 0xffff71d8,0x60c99fff,0xffffffff,0xffffffff,0xffffffff,0xfffe1e55,0x98768fff,0xffffffff, 0xffffffff,0xffffffff,0xfffe8919,0x187713ff,0xffffffff,0xffffffff,0xffffffff,0xffff7fcd, 0x687fc3ff,0xffffffff,0xffffffff,0xfffffffe,0xffffbf9b,0x80ee41ff,0xffffffff,0xffffffff, 0xffffffff,0xffffa1da,0xc01088ff,0xffffffff,0xffffffff,0xffffffff,0xfffffa76,0xc0700dff, 0xffffffff,0xffffffff,0xffffffff,0xfffffbf3,0x007013ff,0xffffffff,0xffffffff,0xffffffff, 0xffffff90,0x001035ff,0xffffffff,0xffffffff,0xffffffff,0xffffdf41,0x400046ff,0xffffffff, 0xffffffff,0xffffffff,0xffffff97,0xc00043ff,0xffffffff,0xffffffff,0xffffffff,0xffffe97b, 0x00022dff,0xffffffff,0xffffffff,0xffffffff,0xffffe262,0x580187b7,0xffffffff,0xffffffff, 0xffffffff,0xfffffede,0x700121b7,0xffffffff,0xffffffff,0xffffffff,0xfffff99d,0xf8a2cd7f, 0xffffffff,0xffffffff,0xffffffff,0xfffff2b8,0xcb7a3cdf,0xffffffff,0xffaeffff,0xffffffff, 0xfffffef8,0x1f72165b,0xffffffff,0xff063fff,0xffffffff,0xffffffe6,0x6372737f,0xffffffff, 0xfce667ff,0xffffffff,0xfffffebb,0xb020c1bf,0xffffffff,0xf20007ff,0xffffffff,0xf7fffc8a, 0xb723795f,0xffffffff,0xf80001ff,0xffffffff,0xffffffc3,0xf783ff07,0xffffffff,0xd800007f, 0xffffffff,0xfffffef3,0xff62e74b,0xffffffff,0x900000f0,0x01ffffff,0xffffffde,0x381acecf, 0xfffffffd,0x80000080,0x0027ffff,0xffffffff,0x9015246f,0xfffffffe,0x2000010f,0x8001ffff, 0xffffffff,0xe2e5d9e3,0xfffffffa,0xc000020f,0xffac2fff,0xffffffff,0x9f140fa3,0xffffffff, 0x0000003f,0xffffc5ff,0xffffffff,0xffb03ff7,0xfffffffd,0x800000ff,0xfffff07f,0xffffffff, 0xfe03fff7,0xffffffff,0x000003ff,0xfffffa3f,0xffffffff,0xfccffff7,0xfffffffd,0x80001fff, 0xffffff07,0xffffffff,0xfe79fff7,0xfffffffd,0x8000ffff,0xffffffa7,0xffffffff,0xfffffff7, 0xffffffff,0x8001ffff,0xfffffff9,0xffffffff,0xffffffdf,0xfffffffe,0x8007ffff,0xfffffffc, 0x7fffffff,0xffffffff,0xfffffffe,0x017fffff,0xffffffff,0x3fffffff,0xfffffffe,0xfffffffe, 0x07ffffff,0xffffffff,0x9fffffff,0xfffffffe,0xfffffffc,0x3fffffff,0xffffffff,0xc7ffffff, 0xffffffff,0xffffffb4,0x7fffffff,0xffffffff,0xc3fffeff,0xfffffffe,0xfffffff8,0xffffffff, 0xffffffff,0xf1ffffff,0xffffffff,0xffffffe0,0xffffffff,0xffffffff,0xf9ffffff,0xffffffff, 0xfffffee1,0xffffffff,0xffffffff,0xfcffffff,0xffffffff,0xffffffc3,0xffffffff,0xffffffff, 0xfcfffffe,0xffff7f7f,0xfffffd87,0xffffffff,0xffffffff,0xff3fffff,0xffffffff,0x3fffff9f, 0xffffffff,0xffffffff,0xff1fffff,0xffffffff,0xbffffb9f,0xffffffff,0xffffffff,0xff9fffff, 0xffffffff,0x9fffff3f,0xffffffff,0xffffffff,0xffcfffff,0xffffffff,0x97fffe7f,0xffffffff, 0xffffffff,0xffcfffff,0xffffffff,0xc7fffe3f,0xffffffff,0xffffffff,0xffcfffff,0xefffffff, 0xc7fffc7f,0xffffffff,0xffffffff,0xffe7ffff,0xefffffff,0x90fffcff,0xffffffff,0xffffffff, 0xffe3ffff,0xffffffff,0x887ffc7f,0xffffffff,0xffffffff,0xfff3ffff,0xffffffff,0xc83ffdff, 0xffffffff,0xffffffff,0xfff3ffff,0xffffffff,0x46cff9ff,0xffffffff,0xffffffff,0xfff9ffff, 0xffffffff,0x467ff9ff,0xffffffff,0xffffffff,0xfffdffff,0xffffffff,0x637ff1ff,0xffffffff, 0xffffffff,0xfff8ffff,0xffffffff,0xf3c7f3ff,0xffffffff,0xffffffff,0xfffcffff,0xffffffff, 0xb3e7f1ff,0xffffffff,0xffffffff,0xfffa7fff,0x67f9d1cf,0x11fbf3ff,0xffffffff,0xffffffff, 0xffed3ffe,0xdff091ef,0x19f9f5ff,0xffffffff,0xffffffff,0xffc9bffe,0xd7f273ff,0x98c1f5ff, 0xfff7ffff,0xfffff9df,0xffd9dffc,0xcff7c1ff,0x98fcbd83,0xc5240b20,0x3cd26215,0x1db9f470, 0x97e1bcff,0xa97cf981,0xb62c90c8,0x1b87a3e0,0x0631f0e1,0x27e1fefe,0x7cce2126,0x890e3692, 0x6ca11c63,0xee33f606,0x2fe5efc1,0xfca50b36,0x5c0bee37,0x6fa67cab,0x9ca4c176,0x2ff1ffd9, 0xecc1d5c9,0xfce7cff0,0x201bc3aa,0x324c0ffc,0x6ff5ffaa,0xf8ab75c6,0x907f97af,0xefc9c3e1, 0x7e70137d,0xa635ff98,0x78c13967,0x0d97b785,0xbffed829,0xc2cfde38,0xfa21ff39,0xf87d517e, 0x7b7777ca,0x3fff88cc,0x783fde30,0xf2c1ffb9,0xfe6d16e3,0x3dbffaff,0x9fff29c3,0x9201de71, 0xf671ff1d,0xea6f17d6,0xb9bf7ca4,0x8ffff7da,0x80045bff,0xe561fe36,0xfa4d85ac,0xfbfffe60, 0x1ffffff9,0xac17e91f,0xcbe7ff3d,0xfdbdcfc4,0xf5e7ff3c,0x2ffffffb,0xb81fd8ce,0x486fff77, 0xf8874ee8,0x73ffffd9,0xefffffff,0xeb5f88dc,0x9aefff1f,0xfb67cb19,0x22f7ffdb,0x1fffffff, 0xf7ff9cf0,0xb4efff5f,0xfe47ed71,0x41f3ffea,0x1fe0ffff,0xfffffc19,0xa78cff1f,0xfe778d17, 0xd9fb8fed,0xdf187fff,0xfffffa71,0xcffdff1f,0xff678d10,0x33fe77fe,0xdd4e6e3f,0xfffffc05, 0x4cf1ff5f,0xfef7cb84,0xe7fe7bfb,0x3c4fe01f,0xfffffac4,0x5e01cf1f,0xffffa994,0x81fe7ffb, 0xf31fc9b2,0x1ffffe85,0xc80bcf3f,0xffbfae47,0x0ffe79f0,0x274f53f0,0x21fffe94,0x1201c71f, 0xff87afcf,0x5bfcfc18,0x678f0f71,0xec3ffff9,0x40c1037f,0xff9b85cf,0x37fcfef3,0xa72b71f0, 0x501fffb3,0xf47718f0,0xff11d74e,0xeff97ffb,0xecf5e0fe,0x33dfffbb,0xf0ef7400,0xff198f82, 0x7ff47d6f,0xfc3d067f,0x9b5ffff3,0xf3fe7c7f,0xff98e7cf,0xefe57f6f,0xc1bbffef,0xb0c2fffb, 0xf2fefd6f,0xff99ef98,0x5eefbf7f,0x9bdfffc0,0x24f23ff9,0xf0fe0f0f,0xffa8efa5,0x8dffffbe, 0x50ffffe0,0x41f4e1fb,0xf7ff731f,0xfffcffa9,0xd8fffe60,0x56ffffff,0x4ff0f83b,0xf7ff7b7f, 0xffbc6f87,0xfb7e22a0,0x06ffffff,0x5c26921f,0xffffffff,0xffeeffc7,0x9ff060fd,0x4fffffff, 0x7060725f,0xffffffff,0xff78ff9f,0xc7f044f4,0xc1ffffff,0xf1479b5f,0xffffffff,0xfff8ffaf, 0xc7ff8ef4,0xa1fffffc,0x7f8eb8ef,0xffffffff,}; unsigned long* textplane = NULL; // the pointer to the allocated textplane // goes here ... #define ADDITIONALLY_LINES 8 // the textplane is oversized, so no // clipping is necessary #define LINES_TO_SCROLL 1 // how much lines gets scrolled each time INT_HANDLER save_int_1 = NULL; // used to save the old interrupt 1 handler volatile unsigned short counter = 0; // counter used for delay //============================================================================= // our own interrupt 1 handler which only increments the counter and calls // the old interrupt 1 handler afterwards //============================================================================= DEFINE_INT_HANDLER (my_int_1_handler) { counter++; ExecuteHandler(save_int_1); } //============================================================================= // allocates space for textplane and installs own interrupt handler //============================================================================= short InitScroller() { if (!(textplane = (unsigned long*)malloc(20*(100+ADDITIONALLY_LINES)))) { return 0; } // install our own interrupt 1 handler for synchronization and delay save_int_1 = GetIntVec(AUTO_INT_1); counter = 0; SetIntVec(AUTO_INT_1, my_int_1_handler); return 1; } //============================================================================= // frees allocated space again and re-installs own interrupt handler //============================================================================= void CleanupScroller() { if (textplane) { free(textplane); textplane = NULL; SetIntVec(AUTO_INT_1,save_int_1); } PortRestore(); } //============================================================================= // Blits background planes to grayplanes (combining them with the textplane) //============================================================================= void BlitPage(short offset) { unsigned long* backplane_0 = data; unsigned long* tmptext = textplane; unsigned long* p0 = (unsigned long*)((unsigned char*)GetPlane(0)+offset); unsigned long* p1 = (unsigned long*)((unsigned char*)GetPlane(1)+offset); short i; // NOTE: the lightplane is not taken from the image, but filled // with black (0xffffffff). otherwise the white text wouldn't // be readable anymore. // // (The textplane contains white text on black background) // loop once for each line to copy ... for (i=0;i<100;i++) { *p0++ = *(backplane_0++) & ((*tmptext)); *p1++ = 0xffffffff & ((*tmptext++)); *p0++ = *(backplane_0++) & ((*tmptext)); *p1++ = 0xffffffff & ((*tmptext++)); *p0++ = *(backplane_0++) & ((*tmptext)); *p1++ = 0xffffffff & ((*tmptext++)); *p0++ = *(backplane_0++) & ((*tmptext)); *p1++ = 0xffffffff & ((*tmptext++)); *p0++ = *(backplane_0++) & ((*tmptext)); *p1++ = 0xffffffff & ((*tmptext++)); ((unsigned char*)p0)+=10; ((unsigned char*)p1)+=10; } } //============================================================================= // the text which will be scrolled (the number of strings within this array // will be evaluated by searching the terminating NULL) //============================================================================= char* demotext[] = { "TICT-Tutorial S1P6","", "How to write a simple", "Grayscale Text Scroller", "with a Background Image","using","the TIGCC Environment","", "TiCT (c) 19/02/2001","","http://tict.ticalc.org","","","Greetings to Everyone", "Especially my Beta-Testers","","","You can modify the","Scrolling Speed with", "the [+] and [-] Keys.", "","To pause the Scrolling","press [F1].","", "I know that the Text","flickers.","The Program synchronizes", "to the Interrupt 1, so it","is in Principle in Sync","with the Grayscale", "Routine, but it cannot","synchronize to the","Grayscale Pageflip", "Frequency, because it","have no Access to the","necessary Counter.","", "Additionally the Phasing","Effect which is a","Principle Problem of the", "Grayscale Support","comes into Play.","For a short period of", "Time the two Grayplanes","are displayed with an", "Line Offset of 1, although","the data is already stored","in the Planes.","", "","Have a nice Day, Tom","","Credits for the", "Background GFX go to:","","The Developers of","the GENESIS Game","","* * * * *", "Phantasy Star III (tm)","* * * * *","","","","","", NULL }; //============================================================================= // the scrolling routine itself //============================================================================= void ProcessTextScrolling() { short nr_lines = 0; short actline = 0; short i = 9; unsigned short waitnr = 28; short offset = (TI89) ? 0 : 4+30*12; // for the TI92p we center the image short leave = 0; unsigned long* src; unsigned long* dest; short loop; while (demotext[nr_lines++]); // evalute number of lines in demo text // initialize all graphic functions to use our invisible textplane PortSet(textplane,159,99+ADDITIONALLY_LINES); // fill textplane with black memset(textplane,0xff,20*(100+ADDITIONALLY_LINES)); // fill grayplane 0 and 1 with white memset(GetPlane(0),0,LCD_SIZE); memset(GetPlane(1),0,LCD_SIZE); // loop until the user gets bored ... do { dest = textplane; src = &textplane[LINES_TO_SCROLL*5]; // scrolling up the invisible textplane is performed by // a kind of memmove ... for (loop=0;loop<(100+ADDITIONALLY_LINES-LINES_TO_SCROLL)*5;loop++) *dest++ = *src++; // fill part below the last "visible" line with blacks if (i>=7) { memset(&textplane[100*5],0xff,ADDITIONALLY_LINES*20); } // it's time to print the next line to the part below the last // "visible" line ... if (i==9) { i = 0; memset(&textplane[100*5],0xff,ADDITIONALLY_LINES*20); // draw the string centered DrawStr((160-DrawStrWidth(demotext[actline],F_6x8))>>1,100,demotext[actline],A_REVERSE); actline++; if (actline==nr_lines) actline = 0; } else { i+=LINES_TO_SCROLL; } // perform a page blit (combines background planes // with textplane and copy the result to the grayplanes) //BlitPage(offset); // wait a little bit ... while (counter < waitnr); BlitPage(offset); counter=0; // process a key press ... if (kbhit()) { leave = ngetchx(); if (leave == '+') { if (waitnr) waitnr--; leave = 0; } else if (leave == '-') { if (waitnr < 199) waitnr++; leave = 0; } else if (leave == KEY_F1) { ngetchx(); leave = 0; } } } while (!leave); } //============================================================================= // where all the fun starts ... //============================================================================= void _main(void) { if (!InitScroller()) { ST_showHelp("error: out of mem"); return; } if (!GrayMode(GRAY_ON)) { CleanupScroller(); return; } FontSetSys(F_6x8); ProcessTextScrolling(); GrayMode(GRAY_OFF); CleanupScroller(); }