Shop OBEX P1 Docs P2 Docs Learn Events
Graphics using C and Kye's video driver — Parallax Forums

Graphics using C and Kye's video driver

Dr_AculaDr_Acula Posts: 5,484
edited 2011-04-08 20:54 in Propeller 1
This is a quick video demo of Catalina running Kye's video driver http://www.youtube.com/watch?v=Vw3E38Zna8U

A couple of pictures of our recent family expedition to the our local open park zoo http://www.zoossa.com.au/monarto-zoo

This is demonstrating:
1) Running a C on the propeller using external memory (programs up to 512k)
2) Stopping the Catalina video driver cogs
3) Loading in Kye's video driver into a cog from an sd card into one of these cogs and starting it
4) Drawing some pixels and boxes on the screen
5) Loading some pictures off the sd card and displaying them

I believe there is a lot of potential for C to create a GUI on the propeller. I am not sure Spin can do this because by the time you write an sd driver (1/3 of the hub ram) and a video buffer (19200 bytes) there is hardly any ram left for actual code.

So I think an answer is to move the program out into external memory, which Catalina C can do. This frees up virtually all the hub for a video buffer.

Coupled with this is the ability to load 'cogjects' - standalone 2k code that can be loaded into cogs and run. We have cogjects now for keyboard, serial, multiple text video, mouse and now graphics video and these can all be loaded and unloaded under software control.

Next step is to try to speed up the sd reads as this is a lot slower than Kye's sd code (which is able to read in frames at about 20 per second). Maybe Ross H might have some suggestions there?
/* PASM cogject demonstration, see also cogject example in spin*/

#include <stdio.h>
      
	unsigned long cogarray[511];					// external memory common cog array

// start of C functions

void clearscreen()                                                   // white text on dark blue background
{
       int i;
       for (i=0;i<40;i++)
       {
               t_setpos(0,0,i);                                      // move cursor to next line
               t_color(0,0x08FC);                                    // RRGGBBxx eg dark blue background 00001000 white text 11111100
       }
}

void sleep(int milliseconds)                                         // sleep function
{
       _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}

char peek(int address)                                               // function implementation of peek
{
       return *((char *)address);
}

void poke(int address, char value)                                   // function implementation of poke
{
       *((char *)address) = value;
}

void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[])    	//  load a cog from external memory
{
	unsigned long hubcog[511];						// create a local array, this is in hub ram, not external ram	
	int i;	
	for(i=0;i<512;i++)								
	{
		hubcog[i]=cogdata[i];					// move from external memory to a local array in hub
	}
 	_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber);		// load the cog
}  

int EoF (FILE* stream)
{
  	register int c, status = ((c = fgetc(stream)) == EOF);
  	ungetc(c,stream);
  	return status;
}

void readcog(char *filename,unsigned long external_cog[])		// read in a .cog file into external memory array 
{
	int i;
	FILE *FP1;
	i = 0;
	if((FP1=fopen(filename,"rb"))==0)					// open the file
   	{
  		fprintf(stderr,"Can't open file %s\n",filename);
		exit(1);
   	}
  	fseek(FP1,0,0);
	for(i=0;i<24;i++)
	{
		getc(FP1);							// read in the first 24 bytes and discard
	}
	i = 0;
  	while(!EoF(FP1) & (i<505))						// run until end of file or 511-6
	{
		external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
		i+=1;
	}
	if(FP1)
       {
     		fclose(FP1);							// close the file
     		FP1=NULL;
   	}
	printf("external array cog first long = 0x%x \n",external_cog[0]);	// hex value
}

void pix_clearscreen(unsigned long screen[])
{
	int i;
	for (i=0;i<4800;i++)
	{
		screen[i] = 0x00000000;		// fill with black, use longs rather than bytes so 4 pixels per loop
	}
}


void pix_pixel(unsigned long screen[], int x, int y, char color)
{
	poke((y*160+x+(unsigned long)&screen[0]),color);		
}

void pix_readscreen(char *filename, unsigned long screen[])		// read a full screen 19200 byte file into the screen
{
	int i;
	FILE *FP1;
	i = 0;
	FP1=fopen(filename,"rb");					// open the file
  	fseek(FP1,0,0);
	for(i=0;i<=4800;i++)
	{
		screen[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
	}
	fclose(FP1);							// close the file
     	FP1=NULL;
}

char pix_color(char red,char green,char blue)				// pass red,green,blue 0-3, returns a combined value
{
	return ((red & 0x3) << 6 ) | ((green & 0x3) << 4) | ((blue & 0x3) << 2);
}

void pixenginestart(int cognumber, unsigned long cogarray[], unsigned long screen[], unsigned long pingroup, char kye_graphics_parameters[])
{
/*
    pinGroup := ((pinGroup <# 3) #> 0)                  ' pingroup only used in this pub
    long[screen][2] := ($FF << (8 * pinGroup))          
    long[screen][3] := ($30_00_00_FF | (pinGroup << 9))      

    pinGroup := constant((25_175_000 + 1_600) / 4)      ' pingroup recycled as a new var
    long[screen][4] := 1                                 

    repeat 32
      pinGroup <<= 1
      long[screen][4] <-= 1
      if(pinGroup => clkfreq)
        pinGroup -= clkfreq
        long[screen][4] +=1                          

    long[screen][0] := @displayindicator
    long[screen][1] := @syncindicator
    
    'cogNumber := cognew(@initialization, screen) ' and displayindicatoraddress/syncindicatoraddress are cog variables
    cognumber := cognew(cogarray,screen) ' start cog
    waitcnt((((clkfreq / 1000 * 1) - 4296) #> 381) + cnt)  ' Wait for designated time in ms eg 1000*1 is 1ms
    ' need a short delay otherwise the variables don't get passed to the cog
*/
	// no need for first pingroup test, always will be 0,1,2,3
	int i;
	char *ptr;
	screen[2] = (0xff << (8*pingroup));
	//printf("value is %x \n",screen[2]);
	screen[3] = (0x300000ff | (pingroup << 9));      
	//printf("value is %x \n",screen[3]);
	pingroup = ((25175000 + 1600) / 4);
	//printf("value is %x \n",pingroup);
	screen[4] = 1;
	for(i=0;i<32;i++)
	{
		pingroup = pingroup << 1;
		screen[4] = (screen[4] << 1) | (screen[4] >> 31);
		//printf("value is %x \n",screen[4]);
		if (pingroup >= _clockfreq())
		{
			pingroup -= _clockfreq();
			screen[4] += 1;
		}
	}
	kye_graphics_parameters[0] = 1;			// displayindicator
	kye_graphics_parameters[1] = 0;			// syncindicator
	//printf("pointers \n");
	ptr = &kye_graphics_parameters[0];
	screen[0] = (unsigned long) ptr;
	//printf("value is %u \n",screen[0]);
	ptr = &kye_graphics_parameters[1];
	screen[1] = (unsigned long) ptr;
	//printf("value is %u \n",screen[1]);
	//_cogstop(0); // not video
	_cogstop(1); // video shut down this driver
	// cog 2 is catalina
	_cogstop(3); //  video shut down this driver
	//_cogstop(4); // not sure what this does, hangs prop when add this
	//_cogstop(5); // not video
	//_cogstop(6); // not video
	external_memory_cog_load(7,cogarray,screen);		// load from external ram, pass some values in screen[]
	pix_clearscreen(screen);					// clear the screen to black
}

void pix_colorbar(unsigned long screen[])
{
	int x;
	int c;
	x = 0;
	for (c=0;c<64;c++)
	{
		pix_pixel(screen,x+10,6,(c<<2));			// print all the colors in a bar
		x++;
	}
}

void pix_box_unfilled(unsigned long screen[], int startx, int starty, int endx, int endy, char color) 
{
	int row;
	int col;
	for(col=startx;col <= endx ;col++)
	{
		pix_pixel(screen,col,starty,color);			// horizontal lines
		pix_pixel(screen,col,endy,color);
	}
	for(row=starty;row <= endy;row++)
	{
		pix_pixel(screen,startx,row,color);
		pix_pixel(screen,endx,row,color);
	}
}

void pix_box_fill(unsigned long screen[], int startx, int starty, int endx, int endy, char color) 
{
	int row;
	int col;
	for(row =starty;row <= endy; row++)
	{
		for(col=startx;col <=endx; col++)
		{
			pix_pixel(screen,col,row,color);			// horizontal line
		}
	}
}

void kyegraphicsdemo(unsigned long screen[],char kye_graphics_parameters[])					// kye graphics demo
{
	clearscreen();							// white on blue vga
       printf("Clock speed %u \n",_clockfreq());                     // see page 28 of the propeller manual for other useful commands
       printf("Catalina running in cog number %i \n",_cogid());      // integer
	printf("Kye graphics demonstration \n");
	sleep(2000);								// 2 sec delay
	readcog("vgagraph.cog",cogarray);					// read in kye's graphics driver
       pixenginestart(7,cogarray,screen,2,kye_graphics_parameters);				// start the driver
       pix_pixel(screen,3,3,0x44);
	pix_pixel(screen,4,4,0xFF);
	pix_pixel(screen,5,5,pix_color(1,2,3));				// rgb each 0,1,2 or 3
	pix_box_unfilled(screen,0,0,159,119,pix_color(3,0,0));		// red border for screen
	pix_colorbar(screen);						// a color bar
	pix_box_unfilled(screen,10,10,30,30,pix_color(3,3,0));		// a yellow box
	pix_box_fill(screen,10,50,40,60,pix_color(3,0,3));		// magenta filled rectangle
	sleep(2000);
	pix_readscreen("wallaby.vga",screen);				// display whole screen image 
	pix_readscreen("Giraffe.vga",screen);				// display whole screen image 
	pix_readscreen("prop160.vga",screen);				// display whole screen image
}

void main ()
{
	char kye_graphics_parameters[1];					// displayindicator and syncindicater are permanent hub variables
	unsigned long screen[160*120/4];					// graphics and text video buffer in hub - eg 19200 bytes
	kyegraphicsdemo(screen,kye_graphics_parameters);
	while (1); 								// endless loop as prop reboots on exit from main() 
}

Comments

  • RossHRossH Posts: 5,522
    edited 2011-04-06 17:26
    Very impressive, Dr_A!

    Yes, I know the SD card driver I use is quite slow. It was my own adaption. When I get time I'll have a look at speeding it up.

    Ross.

    P.S. With release 3.0, it is much easier to identiy what cogs are doing what - see the new demo program test_plugin_names.c
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-06 22:14
    Thanks Ross. I've found Kye's sd driver very fast, but it is quite a lot of code too.

    I've got it down to about half a second by storing the picture in external memory. Got a tiny bit more speed using memcpy
    	memcpy(destination,source,19200);					// a strings.h function
    

    I've added a button, text box and radio box - see attached photo. Next step is to capture a font. Catalina with external memory is great because things like fonts can be stored in external ram.
    /* PASM cogject demonstration, see also cogject example in spin*/
    
    #include <stdio.h>
    #include <string.h>
          
    	unsigned long cogarray[512];					// external memory common cog array
    	unsigned long screen_external[4800]	;				// external memory for a screen buffer
    
    // start of C functions
    
    void clearscreen()                                                   // white text on dark blue background
    {
           int i;
           for (i=0;i<40;i++)
           {
                   t_setpos(0,0,i);                                      // move cursor to next line
                   t_color(0,0x08FC);                                    // RRGGBBxx eg dark blue background 00001000 white text 11111100
           }
    }
    
    void sleep(int milliseconds)                                         // sleep function
    {
           _waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
    }
    
    char peek(int address)                                               // function implementation of peek
    {
           return *((char *)address);
    }
    
    void poke(int address, char value)                                   // function implementation of poke
    {
           *((char *)address) = value;
    }
    
    void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[])    	//  load a cog from external memory
    {
    	unsigned long hubcog[511];						// create a local array, this is in hub ram, not external ram	
    	int i;	
    	for(i=0;i<512;i++)								
    	{
    		hubcog[i]=cogdata[i];					// move from external memory to a local array in hub
    	}
     	_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber);		// load the cog
    }  
    
    int EoF (FILE* stream)
    {
      	register int c, status = ((c = fgetc(stream)) == EOF);
      	ungetc(c,stream);
      	return status;
    }
    
    void readcog(char *filename,unsigned long external_cog[])		// read in a .cog file into external memory array 
    {
    	int i;
    	FILE *FP1;
    	i = 0;
    	if((FP1=fopen(filename,"rb"))==0)					// open the file
       	{
      		fprintf(stderr,"Can't open file %s\n",filename);
    		exit(1);
       	}
      	fseek(FP1,0,0);
    	for(i=0;i<24;i++)
    	{
    		getc(FP1);							// read in the first 24 bytes and discard
    	}
    	i = 0;
      	while(!EoF(FP1) & (i<505))						// run until end of file or 511-6
    	{
    		external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
    		i+=1;
    	}
    	if(FP1)
           {
         		fclose(FP1);							// close the file
         		FP1=NULL;
       	}
    	printf("external array cog first long = 0x%x \n",external_cog[0]);	// hex value
    }
    
    void pix_clearscreen(unsigned long screen[])
    {
    	int i;
    	for (i=0;i<4800;i++)
    	{
    		screen[i] = 0x00000000;		// fill with black, use longs rather than bytes so 4 pixels per loop
    	}
    }
    
    
    void pix_pixel(unsigned long screen[], int x, int y, char color)
    {
    	poke((y*160+x+(unsigned long)&screen[0]),color);		
    }
    
    void pix_readscreen(char *filename, unsigned long screen[])		// read a full screen 19200 byte file into the screen
    {
    	int i;
    	FILE *FP1;
    	i = 0;
    	FP1=fopen(filename,"rb");					// open the file
      	fseek(FP1,0,0);
    	for(i=0;i<=4800;i++)
    	{
    		screen[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24);	// get the long
    	}
    	fclose(FP1);							// close the file
         	FP1=NULL;
    }
    
    char pix_color(char red,char green,char blue)				// pass red,green,blue 0-3, returns a combined value
    {
    	return ((red & 0x3) << 6 ) | ((green & 0x3) << 4) | ((blue & 0x3) << 2);
    }
    
    void pixenginestart(int cognumber, unsigned long cogarray[], unsigned long screen[], unsigned long pingroup, char kye_graphics_parameters[])
    {
    /*
        pinGroup := ((pinGroup <# 3) #> 0)                  ' pingroup only used in this pub
        long[screen][2] := ($FF << (8 * pinGroup))          
        long[screen][3] := ($30_00_00_FF | (pinGroup << 9))      
    
        pinGroup := constant((25_175_000 + 1_600) / 4)      ' pingroup recycled as a new var
        long[screen][4] := 1                                 
    
        repeat 32
          pinGroup <<= 1
          long[screen][4] <-= 1
          if(pinGroup => clkfreq)
            pinGroup -= clkfreq
            long[screen][4] +=1                          
    
        long[screen][0] := @displayindicator
        long[screen][1] := @syncindicator
        
        'cogNumber := cognew(@initialization, screen) ' and displayindicatoraddress/syncindicatoraddress are cog variables
        cognumber := cognew(cogarray,screen) ' start cog
        waitcnt((((clkfreq / 1000 * 1) - 4296) #> 381) + cnt)  ' Wait for designated time in ms eg 1000*1 is 1ms
        ' need a short delay otherwise the variables don't get passed to the cog
    */
    	// no need for first pingroup test, always will be 0,1,2,3
    	int i;
    	char *ptr;
    	screen[2] = (0xff << (8*pingroup));
    	//printf("value is %x \n",screen[2]);
    	screen[3] = (0x300000ff | (pingroup << 9));      
    	//printf("value is %x \n",screen[3]);
    	pingroup = ((25175000 + 1600) / 4);
    	//printf("value is %x \n",pingroup);
    	screen[4] = 1;
    	for(i=0;i<32;i++)
    	{
    		pingroup = pingroup << 1;
    		screen[4] = (screen[4] << 1) | (screen[4] >> 31);
    		//printf("value is %x \n",screen[4]);
    		if (pingroup >= _clockfreq())
    		{
    			pingroup -= _clockfreq();
    			screen[4] += 1;
    		}
    	}
    	kye_graphics_parameters[0] = 1;			// displayindicator
    	kye_graphics_parameters[1] = 0;			// syncindicator
    	//printf("pointers \n");
    	ptr = &kye_graphics_parameters[0];
    	screen[0] = (unsigned long) ptr;
    	//printf("value is %u \n",screen[0]);
    	ptr = &kye_graphics_parameters[1];
    	screen[1] = (unsigned long) ptr;
    	//printf("value is %u \n",screen[1]);
    	//_cogstop(0); // not video
    	_cogstop(1); // video shut down this driver
    	// cog 2 is catalina
    	_cogstop(3); //  video shut down this driver
    	//_cogstop(4); // not sure what this does, hangs prop when add this
    	//_cogstop(5); // not video
    	//_cogstop(6); // not video
    	external_memory_cog_load(7,cogarray,screen);		// load from external ram, pass some values in screen[]
    	pix_clearscreen(screen);					// clear the screen to black
    }
    
    void pix_colorbar(unsigned long screen[])
    {
    	int x;
    	int c;
    	x = 0;
    	for (c=0;c<64;c++)
    	{
    		pix_pixel(screen,x+10,6,(c<<2));			// print all the colors in a bar
    		x++;
    	}
    }
    
    void pix_line(unsigned long screen[], int startx, int starty, int endx, int endy, char color) 
    {
    	int row;								// also does an unfilled box
    	int col;
    	for(col=startx;col <= endx ;col++)
    	{
    		pix_pixel(screen,col,starty,color);			// horizontal lines
    		pix_pixel(screen,col,endy,color);
    	}
    	for(row=starty;row <= endy;row++)
    	{
    		pix_pixel(screen,startx,row,color);
    		pix_pixel(screen,endx,row,color);
    	}
    }
    
    void pix_box_fill(unsigned long screen[], int startx, int starty, int endx, int endy, char color) 
    {
    	int row;
    	int col;
    	for(row =starty;row <= endy; row++)
    	{
    		for(col=startx;col <=endx; col++)
    		{
    			pix_pixel(screen,col,row,color);			// horizontal line
    		}
    	}
    }
    
    void pix_button(unsigned long screen[],int startx, int starty, int sizex, int sizey, char *lineoftext)
    {
    	pix_line(screen, startx, starty, startx, starty+sizey, pix_color(3,3,3));		// white vertical line
    	pix_line(screen, startx, starty, startx+sizex, starty, pix_color(3,3,3));		// white horizontal line
    	pix_line(screen, startx+sizex, starty+1, startx+sizex, starty+sizey-1, pix_color(1,1,1)); // vertical dark gray line
    	pix_line(screen, startx+1, starty+sizey, startx+sizex, starty+sizey, pix_color(1,1,1)); // horizontal dark gray line
    	pix_line(screen, startx+sizex+1, starty, startx+sizex+1, starty+sizey+1, pix_color(0,0,0)); // vertical black line
    	pix_line(screen, startx, starty+sizey+1, startx+sizex+1, starty+sizey+1, pix_color(0,0,0)); // horizontal black line
    	// add in the text
    }
    
    void pix_text(unsigned long screen[], int startx, int starty, int sizex, int sizey, char *lineoftext)
    {
    	pix_box_fill(screen, startx+1, starty+1, startx+sizex-1, starty+sizey-1,pix_color(3,3,3));	// white centre
    	pix_line(screen, startx, starty, startx, starty+sizey-1, pix_color(0,0,0));		// black vertical line
    	pix_line(screen, startx, starty, startx+sizex-1, starty, pix_color(0,0,0));		// black horizontal line
    	pix_line(screen, startx+sizex, starty, startx+sizex, starty+sizey, pix_color(2,2,2)); // vertical light gray line
    	pix_line(screen, startx, starty+sizey, startx+sizex, starty+sizey, pix_color(2,2,2)); // horizontal light gray line
    	pix_line(screen, startx-1, starty-1, startx-1, starty+sizey+1, pix_color(1,1,1));		// dark gray vertical line
    	pix_line(screen, startx-1, starty-1, startx+sizex, starty-1, pix_color(1,1,1));		// dark gray horizontal line
    	pix_line(screen, startx+sizex+1, starty-1, startx+sizex+1, starty+sizey+1, pix_color(3,3,3)); // vertical whiteline
    	pix_line(screen, startx-1, starty+sizey+1, startx+sizex, starty+sizey+1, pix_color(3,3,3)); // horizontal whiteline
    }
    
    void pix_radio(unsigned long screen[], int startx, int starty, char check)
    {
    	char radio[144] = {				// black = 0x00, dark gray = 0x54, light gray = A8, white = FC
    	0xa8,0xa8,0xa8,0xa8,0x54,0x54,0x54,0x54,0xa8,0xa8,0xa8,0xa8,	// a radio button
    	0xa8,0xa8,0x54,0x54,0x00,0x00,0x00,0x00,0x54,0x54,0xa8,0xa8,
    	0xa8,0x54,0x00,0x00,0xfc,0xfc,0xfc,0xfc,0x00,0x00,0xfc,0xa8,
    	0xa8,0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,0xa8,
    	0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,
    	0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,
    	0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,
    	0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,
    	0xa8,0x54,0x00,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xa8,0xfc,0xa8,
    	0xa8,0x54,0xa8,0xa8,0xfc,0xfc,0xfc,0xfc,0xa8,0xa8,0xfc,0xa8,
    	0xa8,0xa8,0xfc,0xfc,0xa8,0xa8,0xa8,0xa8,0xfc,0xfc,0xa8,0xa8,
    	0xa8,0xa8,0xa8,0xa8,0xfc,0xfc,0xfc,0xfc,0xa8,0xa8,0xa8,0xa8
    	};
    	int x;
    	int y;
    	int i = 0;
    	if(check !=0)
    	{
    		radio[53]=radio[54]=0x00;
    		radio[64]=radio[65]=radio[66]=radio[67]=0x00;		// draw the circle in the middle
    		radio[76]=radio[77]=radio[78]=radio[79]=0x00;
    		radio[89]=radio[90]=0x00;
    	}
    	for(y=0;y<12;y++)
    	{
    		for(x=0;x<12;x++)
    		{
    			pix_pixel(screen,startx+x, starty+y, radio[i]);	// draw a radio button, white centre
    			i++;
    		}
    	}
    }
    
    
    void copyscreen(unsigned long source[],unsigned long destination[])
    {
    	memcpy(destination,source,19200);					// a strings.h function
    }
    
    void pix_screengray(unsigned long screen[])				// whole screen gray
    {
    	int i;
    	for(i=0;i<4800;i++)
    	{
    		screen[i] = 0xa8a8a8a8;					// same as pix_color(2,2,2)
    	}
    }
    
    void kyegraphicsdemo(unsigned long screen[],char kye_graphics_parameters[])					// kye graphics demo
    {
    	clearscreen();							// white on blue vga
           printf("Clock speed %u \n",_clockfreq());                     // see page 28 of the propeller manual for other useful commands
           printf("Catalina running in cog number %i \n",_cogid());      // integer
    	printf("Kye graphics demonstration \n");
    	//sleep(2000);								// 2 sec delay
    	readcog("vgagraph.cog",cogarray);					// read in kye's graphics driver
           pixenginestart(7,cogarray,screen,2,kye_graphics_parameters);				// start the driver
           pix_pixel(screen,3,3,0x44);
    	pix_pixel(screen,4,4,0xFF);
    	pix_pixel(screen,5,5,pix_color(1,2,3));				// rgb each 0,1,2 or 3
    	pix_line(screen,0,0,159,119,pix_color(3,0,0));			// red border for screen
    	pix_colorbar(screen);						// a color bar
    	pix_line(screen,10,10,30,30,pix_color(3,3,0));		// a yellow box
    	pix_box_fill(screen,10,50,40,60,pix_color(3,0,3));		// magenta filled rectangle
    	//pix_readscreen("wallaby.vga",screen);				// display whole screen image 
    	//copyscreen(screen,screen_external);				// copy to external ram
    	//pix_readscreen("Giraffe.vga",screen);				// display whole screen image 
    	//copyscreen(screen_external,screen);				// copy back to hub
    	//pix_readscreen("prop160.vga",screen);				// display whole screen image
    	//pix_box_fill(screen, 0, 0, 159,119,pix_color(2,2,2));		// whole screen gray	
    	pix_screengray(screen);						// faster whole screen gray
    	pix_button(screen, 50,50,40,20,"Button1");			// a button
    	pix_text(screen, 50,80, 40, 20, "Text1");				// a text box
    	pix_radio(screen, 10,10,1);						// a checked radio button
    	pix_radio(screen, 10,30,0);						// an unchecked radio button
    }
    
    void main ()
    {
    	char kye_graphics_parameters[1];					// displayindicator and syncindicater are permanent hub variables
    	unsigned long screen[160*120/4];					// graphics and text video buffer in hub - eg 19200 bytes
    	kyegraphicsdemo(screen,kye_graphics_parameters);
    	while (1); 								// endless loop as prop reboots on exit from main() 
    }
    
    
    396 x 362 - 21K
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-08 16:00
    For pictures and games, 64 color and 160x120 fits in a 19200 byte screen buffer.

    I've just realised though that if you only want buttons, text boxes, radio buttons etc, and no picture boxes, then a gray scale works fine. That means the color depth can go from 64 down to 4 (black, dark gray, light gray and white) and in theory, that means we could increase the number of pixels.

    So - off to the obex to rummage around, and lo and behold, I managed to find one written by Kye. The demo he has was written at 160x120 and has a blue 3D thing bouncing around the screen. But this does not quite show off the full features of this driver.

    I have tweaked this a little so it is 320x240 and with a light gray background and with some grayscale lines. Attached is a little demo - this will run on all the standard propeller boards with vga on pin group 2. Next step is to turn this into a cogject and port it into C.

    I think Kye's driver can also do 640x480 in two colors - that may come in handy too.

    The nice thing about cogjects and C is you can flip between all these video modes, and text video drivers all within the one program.
  • Bill HenningBill Henning Posts: 6,445
    edited 2011-04-08 16:59
    Sorry,

    640x480 @ 1bpp = 38,400 bytes ... so it does not fit in the prop

    640x240 @ 1bpp = 19,200 bytes
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-04-08 17:27
    Nice work Drac.
    I would think there is likely to be some open source gui c code. That Prop Computer is getting closer :)
    As for the graphics, perhaps a mix of tiles and text is possibly what we require, with these being combined by cogs. Not quite sure how to go about this (maybe a discussion point at the next UPEOZSA conference)

    Ross: I presume the slow SD code is caused by the SD low level access. Perhaps Kye's pasm code could be adapted here??
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-08 18:34
    Yes Bill, you are right - 640x480 is not possible. Oh, for some more memory!

    @Cluso, I'm writing the buttons and radio boxes from scratch - doing a screen capture on standard windows buttons, blowing them up and then turning them into arrays. A little tedious, but most of them are pretty easy to do. I've got an automated font capture almost done - I'm going to try fixed width and variable width fonts.

    I've got a bit stuck though with Kye's video driver. In general terms, when turning an obex into a cogject, there are no common variables between spin and pasm. The only link is via "par" so the first step is to comment out any DAT sections and see where all the errors are. Then pass variables in a list.

    In Kye's 160 video driver I simply passed all the variables via the screen buffer, then in the cog code did a whole lot of rdlongs into the cog variables.

    Kye's 320 video driver is very similar looking but it is not working. I've got the code written but I've had to come back a few steps to test things out one thing at a time. I've narrowed down the problem to a few lines of code:
    PUB BMPEngineStart(pinGroup, colorMode, horizontalResolution, verticalResolution, newDisplayPointer) '' 11 Stack Longs                
    ...
        screenPointer := newDisplayPointer   
    ...
        cogNumber := cognew(@initialization, @screenpointer)   
    

    This is different to the 160 driver as we have this new screenpointer variable.

    To me this is quite confusing, as you start by passing from the 'main' program a pointer to the screen buffer. So that might pass a value like 2000. Then in this routine, you make a pointer equal to that value. Then you pass a pointer to a pointer??

    I need to understand why he is doing this, because if you make one simple change, it garbles the screen:
        cogNumber := cognew(@initialization, @NewDisplaypointer)  
    

    I would have thought this would pass the same value as above?

    As far as I can see, "newdisplaypointer" does not get changed in the startup routine. Is there something else clever going on, some other variable that is next to "newdisplaypointer" that changes it as well?

    Any help here would be most appreciated.
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-08 19:04
        cogNumber := cognew(@initialization, @NewDisplaypointer)  
    
    NewDisplaypointer lives on the stack, once the method returns it gets reused. As cogs need some time to start up the intended value is long gone at the time it's read. So either find a static location or introduce some kind of handshake (e.g. clear long[par]) before you leave.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-08 19:22
    Thanks kuroneko.

    I fixed this with the previous video driver by adding a delay just after the cognew
        waitcnt((((clkfreq / 1000 * 1) - 4296) #> 381) + cnt)  ' 1ms delay    
    

    but this is not working for this video driver.

    This is most confusing. Say I start my main with a declaration of a screen buffer
      long  screen[160*120/4]
    

    and then start the method with this
      gray320.bmpenginestart(2, 2, 320,240,@screen)   ' pin group 2, color mode 2   
    
    and in the method is
    PUB BMPEngineStart(pinGroup, colorMode, horizontalResolution, verticalResolution, newDisplayPointer)
    
    and then there is a line
        screenPointer := newDisplayPointer 
    
    and then I want to fill up the screen buffer. Will this line below work?
        long[screenpointer][0] := displayindicator ' test passing variable this way 
    
    or is this pointing to something different?

    Actually, what I am really confused about is where the screen buffer is. In the previous video driver we pass the value as above, and we have
    PUB PIXEngineStart(cogarray, screen, pinGroup) '' 7 Stack Longs    
    
    and we start the cog with
        cognumber := cognew(cogarray,screen) ' start cog
        waitcnt((((clkfreq / 1000 * 1) - 4296) #> 381) + cnt) ' 1ms delay to start the cog
    
    in other words, we start with "screen", not with "@screen"

    What I don't understand is why this new driver starts with an @ symbol. The value being passed to the method is a number which already has an @ in the main routine, so I can't grasp why there is a pointer to a pointer?

    And I suspect because of this I'm not filling up the screen buffer, but some other random location in ram (and probably overwriting things).
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-08 19:31
    The driver updates the internal screen location once every loop run (rdlong buffer, par). So you really need a location valid for the lifetime of this object which is not part of the screen itself. Think of it as a mailbox (3 longs in fact, 2 longs + 4 bytes).
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-08 20:27
    That might explain it. But maybe not. The first thing my modified object does when starting is to move all the variables from the screen buffer back into the cogs local variables. So it does not matter if they then get overwritten?

    I'm still confused about pointers. There are three of these in a row and I'm not sure why Kye does it that way.

    I'll try a mailbox and see if I can get it working.
  • kuronekokuroneko Posts: 3,623
    edited 2011-04-08 20:39
    Dr_Acula wrote: »
    That might explain it. But maybe not. The first thing my modified object does when starting is to move all the variables from the screen buffer back into the cogs local variables. So it does not matter if they then get overwritten?
    It does matter no matter where you copy them to. The program accesses par directly so it expects the data there (in hub RAM) and nowhere else.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-04-08 20:54
    Yes, I see what you mean. The par rdlong is part of the loop, not part of the initialisation.

    I'll start by putting everything into a mailbox (there are 14 longs in total that are passed), but some of these are stored in cog variables so maybe the mailbox can be made smaller once it is working.

    Addit: Some working code. The only way to do this is to recompile after changing each line. There are too many variables otherwise. Also every time a variable is changed, you have to do a F3 and search for all other places it appears. Cogject programming is a very different style!

    Thanks again to Kuroneko for finding that par rdlong in the main loop. I've changed the loop now so it stores the screen location in a new variable.
    {{
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // VGA64 Bitmap Engine
    //
    // Author: Kwabena W. Agyeman
    // Updated: 7/15/2010
    // Designed For: P8X32A
    // Version: 1.1
    //
    // Copyright (c) 2010 Kwabena W. Agyeman
    // See end of file for terms of use.
    //
    // Update History:
    //
    // v1.0 - Original release - 9/28/2009.
    // v1.1 - Merged and rewrote code and added more features - 7/15/2010.
    //
    // For each included copy of this object only one spin interpreter should access it at a time.
    //
    // Nyamekye,
    // modifications J Moxham April 2011 so can run from a cogject. 
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    }}
    
    
    DAT
    
    ' //////////////////////Variable Arrary////////////////////////////////////////////////////////////////////////////////////////
    
    'screenPointer           long    0                                                   ' Screen pointer.
    pixelColors             long    0                                                   ' Screen colors.
    displayIndicator        byte    1                                                   ' Video output control.
    syncIndicator           byte    0                                                   ' Video update control.
    cogNumber               byte    0                                                   ' Cog ID.
    bitsPerPixel            byte    0                                                   ' Bits ID.
    
    PUB plotPixel(pixelValue, xPixel, yPixel, displayBase) '' 7 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Plots a 1x1 pixel on screen.
    '' //
    '' // PixelValue - The pixel to plot on screen. Between %%0 and %%1 or between %%0, %%1, %%2, and %%3 depending on color mode.
    '' // XPixel - The X cartesian pixel coordinate, will be forced to be multiple of 1. Y will be forced to be a multiple of 1.
    '' // YPixel - The Y cartesian pixel coordinate. Note that this axis is inverted like on all other graphics drivers.
    '' // DisplayBase - The address of the display buffer to draw to.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      xPixel := ((xPixel <# (320 - 1)) #> 0)  ' 320 = horizontal pixels
      displayBase += (((20 * ((yPixel <# (240 - 1)) #> 0)) + (xPixel >> (5 - bitsPerPixel))) << 2) ' 20 is horizontal longs, 240 = vertical pixels
    
      xPixel := ((xPixel & ($1F >> bitsPerPixel)) << bitsPerPixel)
      yPixel := (!((1 + (bitsPerPixel << 1)) << xPixel))
    
      long[displayBase] := ((long[displayBase] & yPixel) | (((pixelValue <# (1 + (bitsPerPixel << 1))) #> 0) << xPixel))
    
    PUB displayState(state) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Enables or disables the BMP Driver's video output - turning the monitor off or putting it into standby mode.
    '' //
    '' // State - True for active and false for inactive.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      displayIndicator := state
    
    PUB displayRate(rate) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns true or false depending on the time elasped according to a specified rate.
    '' //
    '' // Rate - A display rate to return at. 0=0.234375Hz, 1=0.46875Hz, 2=0.9375Hz, 3=1.875Hz, 4=3.75Hz, 5=7.5Hz, 6=15Hz, 7=30Hz.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      result or= (($80 >> ((rate <# 7) #> 0)) & syncIndicator)
    
    PUB displayWait(frames) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Waits for the display vertical refresh.
    '' //
    '' // The best time to draw on screen for flicker free operation is right after this function returns.
    '' //
    '' // Frames - Number of vertical refresh frames to wait for.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat (frames #> 0)
        result := syncIndicator
        repeat until(result <> syncIndicator)
    
    PUB displayColor(pixelNumber, newColor) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Changes a pixel color for the whole screen.
    '' //
    '' // PixelNumber - The pixel number to change for the whole screen. Between 0 and 1 or 0 to 3.
    '' // NewColor - A color byte (%RR_GG_BB_xx) describing the pixel's new color for the whole screen.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      pixelColors.byte[(pixelNumber <# (1 + (bitsPerPixel << 1))) #> 0] := newColor
    
    PUB displayClear(patternValue, displayBase) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Clears the whole screen.
    '' //
    '' // PatternValue - The pattern to plot on screen.
    '' // DisplayBase - The address of the display buffer to draw to.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      longfill(displayBase, patternValue, (20 * 240))    ' 20 is horizontal longs, 240 is vertical pixels
    
    PUB BMPEngineStart(pinGroup, colorMode, horizontalResolution, verticalResolution, screen) '' 11 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Starts up the BMP driver running on a cog.
    '' //
    '' // Returns true on success and false on failure.
    '' //
    '' // PinGroup - Pin group to use to drive the video circuit. Between 0 and 3.
    '' // ColorMode - Color mode to use for the whole screen. Between 1 bit per pixel or 2 bits per pixel.
    '' // HorizontalResolution - The driver will force this value to be a factor of 640 and divisible by 16 or 32. 16/32 to 640.
    '' // VerticalResolution - The driver will force this value to be a factor of 480. 1 to 480.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
        long[screen][0] := screen                           ' pointer to screen buffer
        long[screen][1] := displayindicator                 'pass variables to cog via screen buffer
        long[screen][2] := syncindicator
        pinGroup := ((pinGroup <# 3) #> 0)
        bitsPerPixel := ((colorMode <# 2) #> 1)
        long[screen][3] := ($FF << (8 * pinGroup))          ' directionstate
        long[screen][4] := ($20_00_00_FF | (pinGroup << 9) | ((--bitsPerPixel) << 28)) ' videostate   
        pinGroup := constant((25_175_000 + 1_600) / 4)
        long[screen][5] := 1                                ' frequencystate                                    
        repeat 32
          pinGroup <<= 1
          long[screen][5] <-= 1
          if(pinGroup => clkfreq)
            pinGroup -= clkfreq
            long[screen][5] +=1      
    
        horizontalResolution := ((horizontalResolution <# 640) #> (32 >> bitsPerPixel))
        repeat while((640 // horizontalResolution) or ((horizontalResolution--) // (32 >> bitsPerPixel)))
        long[screen][6] := (640 / (++horizontalResolution))  ' 6 = horizontalscaling
    
        verticalResolution := ((verticalResolution <# 480) #> 1)
        repeat while(480 // verticalResolution--)
        long[screen][7] := (480 / (++verticalResolution))     ' 7 = verticalscaling
        long[screen][8]  := (640 / long[screen][6])           ' 8 = horizontalpixels
        long[screen][9] :=  (480 / long[screen][7])           ' 9 = verticalpixels
        long[screen][10] := ((long[screen][6] << 12) + ((constant(640 * 32) >> bitsPerPixel) / long[screen][8]))  ' 10 is visible scale
        long[screen][11] := (((8 << bitsPerPixel) << 12) + 160) ' 11 is invisible scale
        long[screen][12] := (long[screen][8] / (32 >> bitsPerPixel))  ' 12 is horizontal longs (equals 20 for 320x240)
        long[screen][13] := (long[screen][12] * 4)                   ' 13 is horizontalloops
        long[screen][14] := @pixelColors                             ' 14 is pixel colors
    
        cogNumber := cognew(@initialization, screen)
        waitcnt((((clkfreq / 1000 * 1) - 4296) #> 381) + cnt)  ' 1msec delay to read in values to cog
        result or= ++cogNumber
    
    PUB BMPEngineStop '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Shuts down the BMP driver running on a cog.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      if(cogNumber)
        cogstop(-1 + cogNumber~)
    
    DAT
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       BMP Driver
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            org     0
    
    ' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
    
    initialization          mov     i,                     par                       ' video buffer                
                            rdlong  screenorg,             i
                            add     i,#4 
                            rdlong  displayIndicatorAddress,i                       ' read in ongs from video buffer
                            add     i,#4
                            rdlong  syncIndicatorAddress,i
                            add     i,#4
                            rdlong  directionstate,i
                            add     i,#4
                            rdlong  videostate,i
                            add     i,#4
                            rdlong  frequencystate,i
                            add     i,#4 
                            rdlong  horizontalScaling,i
                            add     i,#4
                            rdlong  verticalScaling,i
                            add     i,#4  
                            rdlong  horizontalPixels,i
                            add     i,#4 
                            rdlong  verticalPixels,i
                            add     i,#4
                            rdlong  visibleScale,i
                            add     i,#4 
                            rdlong  invisibleScale,i
                            add     i,#4 
                            rdlong  horizontalLongs,i
                            add     i,#4
                            rdlong  horizontalLoops,i
                            add     i,#4
                            rdlong  pixelcolorsaddress,i
    
                            mov     vcfg,                 videoState                    ' Setup video hardware.
                            mov     frqa,                 frequencyState                '
                            movi    ctra,                 #%0_00001_101                 '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Active Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    loop                    mov     buffer,               screenorg                     ' get the screen origin 
                            mov     tilesCounter,         verticalPixels                '
    
    tilesDisplay            mov     tileCounter,          verticalScaling               ' Set/Reset tile fill counter.
    
    tileDisplay             mov     vscl,                 visibleScale                  ' Set/Reset the video scale.
                            mov     counter,              horizontalLongs               '
    
    ' //////////////////////Visible Video//////////////////////////////////////////////////////////////////////////////////////////
    
    videoLoop               rdlong  screenPixels,         buffer                        ' Download new pixels.
                            add     buffer,               #4                            '
    
                            waitvid screenColors,         screenPixels                  ' Update display scanline.
    
                            djnz    counter,              #videoLoop                    ' Repeat.
    
    ' //////////////////////Invisible Video////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     vscl,                 invisibleScale                ' Set/Reset the video scale.
    
                            waitvid HSyncColors,          syncPixels                    ' Horizontal Sync.
    
    ' //////////////////////Repeat/////////////////////////////////////////////////////////////////////////////////////////////////
    
                            sub     buffer,               horizontalLoops               ' Repeat.
                            djnz    tileCounter,          #tileDisplay                  '
    
                            add     buffer,               horizontalLoops               ' Repeat.
                            djnz    tilesCounter,         #tilesDisplay                 '
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Inactive Video
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            rdlong  screenColors,         pixelColorsAddress            ' Get new screen colors.
                            or      screenColors,         HVSyncColors                  '
    
    ' //////////////////////Update Indicator///////////////////////////////////////////////////////////////////////////////////////
    
                            add     refreshCounter,       #1                            ' Update sync indicator.
                            wrbyte  refreshCounter,       syncIndicatorAddress          '
    
    ' //////////////////////Front Porch////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,              #11                           ' Set loop counter.
    
    frontPorch              mov     vscl,                 blankPixels                   ' Invisible lines.
                            waitvid HSyncColors,          #0                            '
    
                            mov     vscl,                 invisibleScale                ' Horizontal Sync.
                            waitvid HSyncColors,          syncPixels                    '
    
                            djnz    counter,              #frontPorch                   ' Repeat # times.
    
    ' //////////////////////Vertical Sync//////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,              #(2 + 2)                      ' Set loop counter.
    
    verticalSync            mov     vscl,                 blankPixels                   ' Invisible lines.
                            waitvid VSyncColors,          #0                            '
    
                            mov     vscl,                 invisibleScale                ' Vertical Sync.
                            waitvid VSyncColors,          syncPixels                    '
    
                            djnz    counter,              #verticalSync                 ' Repeat # times.
    
    ' //////////////////////Back Porch/////////////////////////////////////////////////////////////////////////////////////////////
    
                            mov     counter,              #31                           ' Set loop counter.
    
    backPorch               mov     vscl,                 blankPixels                   ' Invisible lines.
                            waitvid HSyncColors,          #0                            '
    
                            mov     vscl,                 invisibleScale                ' Horizontal Sync.
                            waitvid HSyncColors,          syncPixels                    '
    
                            djnz    counter,              #backPorch                    ' Repeat # times.
    
    ' //////////////////////Update Display Settings////////////////////////////////////////////////////////////////////////////////
    
                            rdbyte  buffer,               displayIndicatorAddress wz    ' Update display settings.
                            muxnz   dira,                 directionState                '
    
    ' //////////////////////Loop///////////////////////////////////////////////////////////////////////////////////////////////////
    
                            jmp     #loop                                               ' Loop.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Data
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    blankPixels             long    640                                                 ' Blank scanline pixel length.
    syncPixels              long    $00_00_3F_FC                                        ' F-porch, h-sync, and b-porch.
    HSyncColors             long    $01_03_01_03                                        ' Horizontal sync color mask.
    VSyncColors             long    $00_02_00_02                                        ' Vertical sync color mask.
    HVSyncColors            long    $03_03_03_03                                        ' Horizontal and vertical sync colors.
    
    ' //////////////////////Configuration Settings/////////////////////////////////////////////////////////////////////////////////
    
    directionState          long    0
    videoState              long    0
    frequencyState          long    0
    horizontalScaling       long    0
    verticalScaling         long    0
    horizontalPixels        long    0
    verticalPixels          long    0
    visibleScale            long    0
    invisibleScale          long    0
    horizontalLongs         long    0
    horizontalLoops         long    0
    screenorg               long    0               ' added instead of reading it from par each loop
    
    ' //////////////////////Addresses//////////////////////////////////////////////////////////////////////////////////////////////
    
    pixelColorsAddress      long    0
    displayIndicatorAddress long    0
    syncIndicatorAddress    long    0
    
    ' //////////////////////Run Time Variables/////////////////////////////////////////////////////////////////////////////////////
    
    counter                 res     1
    buffer                  res     1
    
    tileCounter             res     1
    tilesCounter            res     1
    
    screenPixels            res     1
    screenColors            res     1
    
    refreshCounter          res     1
    displayCounter          res     1
    i                       res     1               ' general purpose variable
    
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            fit     496
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    {{
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                  TERMS OF USE: MIT License
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    // Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
Sign In or Register to comment.