Tutorial 3: Plasma Asthma

In this tutorial, we will go through some of the basics of Turbo Rascal Syntax Error by producing a simple plasma effect:

The main stuff we will be covering includes

  • Procedures
  • Preprocessor defines
  • User-defined character set
  • Raster wait

Character set

The C64 has a built-in character set that is located in ROM, but it sometimes better to use a user-defined character set. In the TRSE IDE, you can create your own regular color/multicolor character sets and export them directly to be included in your Turbo Rascal source files.

In the tutorials project, double click on “charsets/tutorial3.flf” to view or edit this particular charset. Fluff (*.flf) files are TRSE binary files, and are all editable in the TRSE IDE image editor. However, to use this images in your c64 project, you will mostly have to export the files to binary format (“Export Bin” button). The exception is files from the TRSE Level Editor, which can be included and loaded directly on the C64.

Here’s the map we will be using in this tutorial:

Note that this particular character map has a different font than the standard C64 font, and in addition has blocks from character 64-96 that are “gradients”. These gradient chars will be used to draw the actual plasma, since actually drawing individual pixels would be completely out of the question in terms of speed.

A standard character set with 256 chars contains 8*256 = 2048 = 0x800 bytes if information. You can load the character set (or any other binary file) at a specific position in memory by using the IncBin type definition. Here’s the list of variable declarations:


program Tutorial3_plasma;

var
	// some plasma variables
	c,val,time,c2x, c2y,ax, ay : byte;
	x,y : byte;
	// Use custom charset
	charset: IncBin("charsets/tutorial3.bin","$1fff");
	// nice colors
	fade : array [8] of byte = (11,6,12,12,4,14,15,1,1,1,1,15,14,4,12,12,6,11); 
	
	shiftx: byte;

	// mini sine table
        siny : array[25] of byte; 
	sinx : array[40] of byte; 

Note that the charset is now located at $2000 (actually, $1fff, but whatever), which we will point to later in the code.

Preprocessors

Preprocessor directives are things that are processed *before* the compiler starts doings its thing. It is primarily used to exclude code chuncks from compilation, or defining global variables. These preprocessor variables are basically a string replace being performed before compiling, and the same goes for file inclusion. Currently, there are three types of preprocessors in TRSE:

  • Preprocessor defines : @define blah = something. You can now use @blah anywhere in your code, where a string replacement will occur. Therefore, this also works for procedures and other kinds of definitions
  • @ifdef blah / @ifndef blah: if not defined, if defined. Only include the following code block if “blah” is previously defined.
  • @include “file.ras”  : inserts “file.ras” into the source code at this location

In this tutorial, we define a “y_start” as “5”: the y-position where the plasma is going to start.

In addition, we define “include_color” to be “true” (could be anything, just needs to be defined). If you comment out this line, the ifdef-block defined in the “Plasma”-routine will ignore color filling, and the whole effect is sped up.


// Define y_start as a global preprocessor constant
@define y_start "5"
// Remove the following line to ignore colors! much faster.
@define include_color true

The Plasma procedure

Procedures are simple in Turbo Rascal. You define them by the “procedure” directive followed by the name of the procedure. In addition, you can define your own parameters as such

procedure DoSomething(x,y : byte);

However, be aware that procedure parameters are defined as global variables, and must be unique. It is therefore recommended to use names like

procedure DoSomething(dosomething_x,dosomething_y : byte);

in order not to confuse x/y with other parameter names.

// Plasma procedure
procedure Plasma();
begin
	c2x:=ax;
	c2y:=ay;
	
	shiftx:=shiftx+25;

	// Set up y-sine table
	for x:=0 to 25 do begin 
		siny[x]:=  sine[c2x] + sine[c2y];// + shiftx;
		c2x:=c2x+4;
		c2y:=c2y+9;
	end;

	ax:=ax+3;
	ay:=ay-5;


	// Set up x-sine table
	for x:=0 to 40 do begin 
		sinx[x] := sine[c2x] + sine[c2y];
		c2x:=c2x+3;
		c2y:=c2y+7;

	end;
	// Move cursor to (1,y) on $0400 on bank 1
	moveto(1,@y_start, $04);
	
	for y:=@y_start to 23 do begin
		val:=siny[y];
		for x:=1 to 36 do begin
			screenmemory[x]:=(sinx[x] +val)/8 + 64;
		end;
		// Increase x by 40 (next row)
		incscreenx(40);
	end;


// this block is only compiled if include_color is defined, and will color the plasma with
// the "fade" colors
@ifdef include_color	

	// Move to color area
	moveto(1,@y_start, $D8);

	// Loop through y
	for y:=@y_start to 23 do begin
		val:=siny[y];
		for x:=1 to 36 do begin
			// Color that screen
			screenmemory[x] := fade[ (sinx[x] +val)/16 ];;

		end;
		// Inc screen x by 40
		incscreenx(40);
	end;

@endif
end;

The Plasma routine does a couple of things:

  1. Sets up a small 25 byte sine table for x values
  2. Sets up a small 40 byte sine table for y vales
  3. Loops y from @y_start to 23 and x from 1 to 23, filling in a combination of the said x/y sine tables
  4. (sinx[x] +siny[y])/8 + 64;  

    Ensures that the selected screen value is within the limits of the “gradient” character blocks between 64-96 (64 + 32)

  5. If the “@include_color” preprocessor is defined, color memory is also filled

The main routine

We’re almost done! Here’s the main routine:


begin
	// Set color background
	SCREEN_BG_COL:=BLACK;
	SCREEN_FG_COL:=BLACK;
	// Set charmap location at $2000
	VIC_DATA_LOC := $18;
	// Set custom character pos

	// Initialize sine functions
	ax:=1;
	ay:=5;

	// Clear screen and color memory
	ClearScreen($20, SCREEN_CHAR_LOC);
	ClearScreen(GREEN, SCREEN_COL_LOC);

	// Main loop
	while 1<>2 do begin
		time:=time+1;
		waitForRaster(0);
		Plasma();
	end;
end.
  1. As in tutorial 2, we set the background/foreground color to be black
  2. VIC_DATA_LOC contains information about the location of the custom character set. Since we included our set at $2000, we need to point to this location. The lower 4 bits of the location (8 of $18) does exactly this. It assumes the character set is located at a value $400*lower_nibble, which in our case is $400*$8 = $2000.
  3. Proceed by clearing both the color ram (SCREEN_COL_LOC = $D800) and bank 0 screen ram (SCREEN_CHAR_LOC=$0400)
  4. Perform an infinite loop while
    1. Increasing the time counter
    2. Wait for the rasterline to hit zero (ensuring that the effect with update<25 times per second)
    3. Call the Plasma routine