Bars
///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // bars - tinygraphics.cpp // // Written by greystar/quantum sufficient on 12-11-2004 for the TMDC 7 compo. // // The demo should fit in 4KB if proper build settings are used (see comments below). // The music player has real song and pattern data. I think it could be expanded a // little, but I had really hoped to fit under the 3KB mark and did not continue with // its development. // // This code is being placed into the public domain. // // Contact me on efnet irc - #c++ or #SouthCarolina . // http://webpages.charter.net/wyatt/ // // // Special Greets to the TMDC organizers for putting together a contest to create test // code for the MS console team :) // // // // ///////////////////////////////////////////////////////////////////////////////////////// // b u i l d s e t t i n g s /////////////////////////////////////////////////////////// #pragma comment(linker, "/entry:\"main\"") #pragma comment(linker, "/opt:NOWIN98") #pragma comment(linker, "/nodefaultlib") #pragma comment(linker, "/merge:.data=.text") #pragma comment(linker, "/merge:.rdata=.text") #pragma comment(linker, "/subsystem:console") #pragma comment(linker, "/ALIGN:512") #pragma comment(linker, "/STACK:0x8000,0x8000") #pragma check_stack(off) //does not seem to work... #pragma pack(1) #pragma comment(lib, "kernel32") #pragma comment(lib, "winmm") //use the /QIfist compiler option to fix the missing __ftol symbol. //make sure to remove /GZ from the compiler options to fix unresolved external symbol "__chkesp". //make sure to add /Gs999999 to the compiler options to fix unresolved external symbol "__chkesp". make sure to commit the stack space. //get floating point support from the compiler: extern "C" { int _fltused; } //Can be compiled at the command line via: //cl tinygraphics.cpp winmm.lib kernel32.lib /QIfist /Gs999999 /Os ///////////////////////////////////////////////////////////////////////////////////////// // i n c l u d e s ////////////////////////////////////////////////////////////////////// #include<windows.h> ///////////////////////////////////////////////////////////////////////////////////////// // c o n s t a n t s //////////////////////////////////////////////////////////////////// const size_t xMin=0, xMax=80, yMin=0, yMax=50; COORD size = { xMax, yMax }; typedef unsigned __int8 pixel; pixel *frame, *pic; HANDLE hCon; CHAR_INFO lut[16]={ { 0xB0, 0x00 }, //0 { 0xB0, 0x08 }, //1 { 0xB0, 0x07 }, //2 { 0xB0, 0x80 }, //3 { 0xB0, 0x88 }, //4 { 0xB0, 0x0F }, //5 { 0xB0, 0x70 }, //6 { 0xB0, 0x87 }, //7 { 0xB1, 0x78 }, //8 { 0xB0, 0x78 }, //9 { 0xB0, 0xF0 }, //A { 0xB0, 0x77 }, //B { 0xB0, 0x7F }, //C { 0xB0, 0xF8 }, //D { 0xB0, 0xF7 }, //E { 0xB0, 0xFF } //F }; ///////////////////////////////////////////////////////////////////////////////////////// // p r o t o t y p e s ////////////////////////////////////////////////////////////////// DWORD WINAPI PlayMusic(LPVOID); ///////////////////////////////////////////////////////////////////////////////////////// // i m p l e m e n t a t i o n ////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// //BlitScreen() - Takes the framebuffer, converts it to a format compatible with the // console window, and then displays it in the console window. //Precondition: frame[] must be allocated //Postcondition:frame[] has been displayed on the console. void BlitScreen() { CHAR_INFO cMap[xMax*yMax]; pixel pix; //Map the frame buffer to console mode characters: for(size_t n=0; n<xMax*yMax; n++) { pix=frame[n]; if(pix>15) pix=15; cMap[n].Char.AsciiChar=lut[pix].Char.AsciiChar; cMap[n].Attributes=lut[pix].Attributes; } //Dump the console buffer to the console window: COORD src={0,0}; SMALL_RECT outrect= {0, 0, xMax-1, yMax-1}; WriteConsoleOutput(hCon, cMap, size, src, &outrect); } ///////////////////////////////////////////////////////////////////////////////////////// //RotoZoom() - Rotates and zooms the bitmap in "pic[]" onto the framebuffer "frame[]". //Precondition: Zoomfactor must not be 0. // frame[] and pic[] have been allocated. //Postcondition:frame[] contains the rotated+zoomed version of pic[]. //Note: does not copy pixels with the color 0. void RotoZoom(double theta, double zoomfactor) { //Get the sin, cos values from the FPU: double c,s; __asm { fld theta fsincos fstp c fstp s } //Rotate+Zoom the picture: for(int y=yMin; y<yMax; y++) { for(int x=xMin; x<xMax; x++) { //Rotation about (0,0) is defined as: (x',y')=(x*cos(t)-y*sin(t), x*sin(t)+y*cos(t)). int pcx=int((x*c-y*s) * zoomfactor)%xMax; int pcy=int((x*s+y*c) * zoomfactor)%yMax; if(pcx<0) pcx+=80; if(pcy<0) pcy+=50; pixel pixCurrentPixel=pic[pcy*xMax + pcx]; if(0!=pixCurrentPixel) frame[y*xMax + x] = pixCurrentPixel/(zoomfactor+0.8); } } } ///////////////////////////////////////////////////////////////////////////////////////// //main() - performs app initialization and runs the demo graphics. //Precondition: none //Postcondition:demo has been played. //Note: [Esc] will exit the demo. void main() { //Start the music thread: CreateThread(NULL, 0x10000, PlayMusic, NULL, 0, NULL); Sleep(100); //Let audio initialization catch up before starting video. //Allocate buffers: //pixel *pic=(pixel*)GlobalAlloc(0, xMax*yMax*sizeof(pixel)); //frame=(pixel*)GlobalAlloc(0, xMax*yMax*sizeof(pixel)); pic=(pixel*)GlobalAlloc(GMEM_ZEROINIT, 2*xMax*yMax*sizeof(pixel)); frame=pic+xMax*yMax; //Setup the console: hCon=GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hStdIn=GetStdHandle(STD_INPUT_HANDLE); SetConsoleScreenBufferSize(hCon, size); //attempt to set 80x50 mode SetConsoleMode(hCon, 0); //disable character code processing and line wraps. //Make the cursor invisible: //CONSOLE_CURSOR_INFO cci; //cci.bVisible=FALSE; //cci.dwSize=1; //SetConsoleCursorInfo(hCon, &cci); //Create a bitmap of the "copper" bars: for(size_t y=0; y<8; y++) { for(size_t x=0; x<xMax; x++) { pic[y*xMax+x]=15-y; pic[(49-y)*xMax+x]=15-y; } } //Main video loop: double theta, zoom; for(;;) { //clear the frame buffer: for(int n=0; n<xMax*yMax; n++) frame[n]=0; //Check for [Esc] key and exit if pressed. DWORD dw; if(PeekConsoleInput(hStdIn, (PINPUT_RECORD)frame, 1, &dw)) { if(dw>0) { ReadConsoleInput(hStdIn, (PINPUT_RECORD)frame, 1, &dw); INPUT_RECORD *p=(PINPUT_RECORD)frame; if( p->EventType==KEY_EVENT) { if(p->Event.KeyEvent.wVirtualScanCode==VK_ESCAPE) { break; } } } } //Draw the "copper" bars RotoZoom(theta/6.0, zoom+8.0); RotoZoom(theta/5.0, zoom+5.0); RotoZoom(theta/4.0, zoom+3.0); RotoZoom(theta/3.0, zoom+2.0); RotoZoom(theta/2.0, zoom+1.0); RotoZoom(theta , zoom ); //Blit frame buffer to console window: BlitScreen(); //Update demo counters: theta+=0.05; zoom-=0.0025; if(zoom<=0.0) zoom+=1.0; //Frame rate limiting: Sleep(10); } BlitScreen(); char credits[]="bars by greystar/quantum.sufficient"; WriteFile(hCon, credits, sizeof(credits), NULL, NULL); ExitProcess(0); } ///////////////////////////////////////////////////////////////////////////////////////// //PlayMusic() - plays the demo soundtrack //Precondition: none. //Postcondition:does not exit. //Note: this function must be run in its own thread. DWORD WINAPI PlayMusic(LPVOID) { size_t n=0; // 0 1 2 3 4 5 6 7 8 9 10 11 // A B- B C C# D E- E F F# G G# unsigned __int8 freqtbl[12]={ 32, 34, 36, 38, 40, 42, 44, 48, 50, 54, 56, 60 }; typedef unsigned __int8 PatternData; const size_t VOLUME_LEVEL=0x20; const size_t NUM_CHANNELS=2; const size_t PATTERN_LENGTH=16; size_t nSamplePos[NUM_CHANNELS]; //Songs are composed of a list of orders. Each order points to a pattern and has a note transposition value. struct OrderData { PatternData *pattern; //note data, arranged in two tracks of PATTERN_LENGTH notes. __int8 transposition; //amount to transpose each note in the pattern. }; PatternData pattern0[NUM_CHANNELS*PATTERN_LENGTH]= { 12, 0,12, 0,12, 0,12, 0,12, 0,12, 0,12, 0,12, 0, //track 1 (left channel) 12, 0,24, 0,24, 0,12, 0,24, 0,24, 0,12, 0,24, 0 //track 2 (right channel) }; /* PatternData pattern1[NUM_CHANNELS*PATTERN_LENGTH]= { 24,24,24,24, 0, 0, 0, 0, 0, 0, 0, 0,22,22,22,22, //track 1 (left channel) 12, 0,24, 0,24, 0,12, 0,24, 0,24, 0,12, 0,24, 0 //track 2 (right channel) }; PatternData pattern2[NUM_CHANNELS*PATTERN_LENGTH]= { 24,24,24,24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //track 1 (left channel) 12, 0,24, 0,24, 0,12, 0,24, 0,24, 0,12, 0,24, 0 //track 2 (right channel) }; */ const size_t SONG_LENGTH=9; OrderData song[SONG_LENGTH] = { //song data is { pattern, transposition }, { pattern, transposition }, ... { pattern0, 5 }, { pattern0, 5 }, { pattern0, 7 }, { pattern0, 7 }, { pattern0, 3 }, { pattern0, 6 }, { pattern0, 5 }, { pattern0, 5 }, { pattern0, 5 }, /* { pattern1, 17 }, { pattern1, 17 }, { pattern1, 18 }, { pattern1, 12 }, { pattern1, 17 }, { pattern1, 17 }, { pattern2, 17 }, { pattern0, 5 }, */ }; //Allocate the sound structures: HWAVEOUT hWave; const size_t AUDIO_BUF_SIZE=22050*2; //char *audio=(char*)GlobalAlloc(GMEM_ZEROINIT, AUDIO_BUF_SIZE); //WAVEFORMATEX *pwfx=(WAVEFORMATEX*)GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEFORMATEX)); //WAVEHDR *pwh=(WAVEHDR*)GlobalAlloc(GMEM_ZEROINIT, sizeof(WAVEHDR)); char *audio=(char*)GlobalAlloc(GMEM_ZEROINIT, AUDIO_BUF_SIZE+sizeof(WAVEFORMATEX)+sizeof(WAVEHDR)); WAVEFORMATEX *pwfx=(WAVEFORMATEX*)(audio+AUDIO_BUF_SIZE); WAVEHDR *pwh=(WAVEHDR*)(audio+AUDIO_BUF_SIZE+sizeof(WAVEFORMATEX)); //Set up 8-bit stereo PCM audio at 11025 Hz: pwfx->wFormatTag=WAVE_FORMAT_PCM; pwfx->nChannels=2; pwfx->nSamplesPerSec=11025; pwfx->wBitsPerSample=8; pwfx->nBlockAlign=pwfx->nChannels*pwfx->wBitsPerSample/8; pwfx->nAvgBytesPerSec=pwfx->nSamplesPerSec*pwfx->nBlockAlign; pwfx->cbSize=0; //amount of *extra* data past end of structure. //Set up a looping buffer to send to the wave mapper: pwh->lpData=audio; pwh->dwBufferLength=AUDIO_BUF_SIZE; pwh->dwUser=NULL; pwh->dwFlags=WHDR_BEGINLOOP | WHDR_ENDLOOP; pwh->dwLoops=-1; //Open the sound hardware through the wave mapper: if(!waveOutOpen(&hWave, WAVE_MAPPER, pwfx, NULL, NULL, CALLBACK_NULL)) { if(!waveOutPrepareHeader(hWave, pwh, sizeof(WAVEHDR))) { if(!waveOutWrite(hWave, pwh, sizeof(WAVEHDR))) { size_t songpos=0, patternpos, channel=0; //Loop through the song and play the note data: for(songpos=0; songpos<SONG_LENGTH; songpos++) { for(patternpos=0; patternpos<PATTERN_LENGTH; patternpos++) { for(n=0; n<AUDIO_BUF_SIZE/2; n++) { //Mix the left and right channels (tracks): //left channel: if( ((nSamplePos[0]>>8)%8192)>4096) audio[(n<<1)]=0x80+VOLUME_LEVEL; else audio[(n<<1)]=0x80-VOLUME_LEVEL; //right channel: if( ((nSamplePos[1]>>8)%8192)>4096) audio[(n<<1)+1]=0x80+VOLUME_LEVEL; else audio[(n<<1)+1]=0x80-VOLUME_LEVEL; //Update sample positions: for(channel=0; channel<NUM_CHANNELS; channel++) { size_t nNote=song[songpos].pattern[channel*PATTERN_LENGTH+patternpos]; if(nNote>0) { //Only update the sample position if the note number is not 0 (0==note cutoff) nNote+=song[songpos].transposition; nSamplePos[channel]+=((nNote/12+1)*freqtbl[nNote%12])<<7; //scaling factor for sample } } } Sleep(80); //Wait until time to play next note. } //Make the song loop at the end: if(songpos==SONG_LENGTH-1) songpos=0; } } } //Silence and close the wave mapper: //waveOutReset(hWave); //waveOutClose(hWave); } return(0); }
[ back to the prod ]