TriOS-alt/demo/graphics/potato-commented-graphics-c...

646 lines
54 KiB
Plaintext

''***************************************
''* Graphics Demo *
''* Author: Chip Gracey *
''* Copyright (c) 2005 Parallax, Inc. *
''* See end of file for terms of use. *
''***************************************
''*Color / Screen layout commented version by Potatohead '2010 done at UPEW!!
''* ---> Enjoy!!! and share with your friends --a newbie will thank you!
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
{HYBRID example clock:
_clkmode = xtal1 + pll16x 'Set these for your board
_xinfreq = 6_000_000
}
'This allocates two complete bitmap screen buffers, consuming nearly all the HUB memory
'Each graphics "page" is $3000 in size, and one is the display page, the other being the draw
'page. By default, this program copies the draw page to the display page, after each
'iteration of the animated objects
'Considerable memory can be saved, by only having one page, with it being the draw and display
'page at the same time. This is known as a single buffer display, as opposed to the default
'double buffer one. Care must be taken when drawing objects to avoid flicker...
'It's also possible to draw in a small region of memory, and have it "pop" on to the display
'Region as well.
_stack = ($3000 + $3000 + 100) >> 2 'accomodate display memory and stack
x_tiles = 16 '16 pixels * 16 tiles = 256 pixel resolution in the X direction
y_tiles = 12 '16 pixels * 12 tiles = 192 pixel resolution in the Y direction
paramcount = 14 'This is the number of parameters passed to the TV driver
bitmap_base = $2000 'This is the base address of the drawing page
display_base = $5000 'The address of the display page. Make these two equal for single buffer
lines = 5 'These two are just demo variables for the number of lines drawn
thickness = 2
VAR
'Reserved variable space for comms with the mouse
long mousex, mousey
'Reserved variable space for comms with the TV driver
long tv_status '0/1/2 = off/visible/invisible read-only
long tv_enable '0/? = off/on write-only
long tv_pins '%ppmmm = pins write-only
long tv_mode '%ccinp = chroma,interlace,ntsc/pal,swap write-only
long tv_screen 'pointer to screen (words) write-only
long tv_colors 'pointer to colors (longs) write-only
long tv_hc 'horizontal cells write-only
long tv_vc 'vertical cells write-only
long tv_hx 'horizontal cell expansion write-only
long tv_vx 'vertical cell expansion write-only
long tv_ho 'horizontal offset write-only
long tv_vo 'vertical offset write-only
long tv_broadcast 'broadcast frequency (Hz) write-only
long tv_auralcog 'aural fm cog write-only
'This is "the screen array" where all the pointers to form a bitmap are stored for the TV driver to use
word screen[x_tiles * y_tiles]
'In the original program, the colors array was defined here, then computationally filled with values
'I've put it into the DAT section for clarity on how the colors really work.
'long colors[64]
byte x[lines] 'Demo variable space for the spiraling lines
byte y[lines]
byte xs[lines]
byte ys[lines]
OBJ
tv : "tv" 'Draws the actual TV graphics, based on parameters, colors array, screen array, HUB memory data
gr : "graphics" 'Responsible for offering simple graphics primitive commands, line, arc, etc....
mouse : "mouse" 'Reads the mouse and keeps the position vars updated
PUB start | i, j, k, kk, dx, dy, pp, pq, rr, numx, numchr, addr
'start tv
'Here the values defining how the TV driver is to operate are copied into it's HUB variable space
'allocated above
longmove(@tv_status, @tvparams, paramcount)
'Here, the TV driver is given it's list of tile pixel data addresses
tv_screen := @screen
'And now the TV driver is given the sets of colors to use with those addresses, forming "a tile"
tv_colors := @colors
'Having set it all up, it's time to start the TV driver up, so we can see the graphics!
tv.start(@tv_status)
'init tile screen "The Screen Array"
{
This bit of code, writes the hub screen memory address pointers for each tile on the screen.
Each tile = 64 bytes, or 16 longs. Tiles are 16 pixels, 2 bits per pixel for a total of 1 long wide, and
16 pixels high. Tiles are numbered (0,0) at the upper right, incrementing horizontally, then down to
reach the limits of x_tiles and y tiles as given above.
The lower 10 bits of each screen address entry contain the address where the pixels for that tile are
contained in the HUB.
The upper 6 bits of each screen address entry contain the pointer to the color palette for that tile.
Again, these lists are used by the TV driver to know where in the hub the picture is, and what colors it has.
}
repeat dx from 0 to tv_hc - 1
repeat dy from 0 to tv_vc - 1
screen[dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc '+ ((dy & $3F) << 10)
'I've commented out the original Parallax color scheme, which means all tiles are referencing
'Color Palette entry 0, which is black, dark green, light green background, and white, just to
'show how the tile color palettes work.
'Change the line below to whatever 4 colors you want, and those will be used for all but the two tiles
'I've pointed to the ROM below. Be careful to choose actual colors. 02 = black, and there is a color
'table in the graphics_palette.spin program to help you with this. Some color numbers actually equal
'signal values, and will mess up your display. Make one color change at a time, being careful to
'undo it, should you no longer see the images.
set_color_palette(0, $02_07_7b_7d) 'Define color palette 0
'----------------------------------------------------------------------------------------------
' The Parallax Demo stuff...
'----------------------------------------------------------------------------------------------
'init bouncing lines
i := 1001
j := 123123
k := 8776434
repeat i from 0 to lines - 1
x[i] := ?j // 64
y[i] := k? // 48
repeat until xs[i] := k? ~> 29
repeat until ys[i] := ?j ~> 29
'-----------------------------------------------------------------------------------------------
'start and setup graphics
'We have to tell the graphics COG, where in the HUB to draw, and what the size of the screen is.
'The screen is 16 tiles in the X = 256 pixels, 12 tiles in the Y = 192 pixels.
'128, and 96 are the X and Y "center pixel" values, which define the screen origin
'bitmap_base, is the start of the screen, or as defined above, the "draw page"
'Note: these can be changed on the fly, should you want to play tricks with the screen layout
gr.start
gr.setup(16, 12, 128, 96, bitmap_base)
'start mouse --> easy! 'nuff said.
mouse.start(24, 25)
'--------------------------------------------------------------------------------------------
{
Here, I've called a few methods to make things really easy. These are to demonstrate how the
tile address and color palette can be changed!
I'll comment them in-line below, but for now, know the "set_tile_color" points the tile specified
in terms of it's X and Y screen location (0,0) = upper left, to the colors DAT entry below, thus
assigning the 4 colors contained in the colors entry to that particular tile.
Each tile can have it's own 4 colors!
For demo purposes, I've pointed two of the graphics tiles at the Propeller ROM, to display a
character, instead of the pixels that exist in the HUB. The graphics COG does not know this,
and is happily drawing pixels there anyway :)
I've also set a few of the tiles to distinctive color combinations so that they can be seen
and changed as needed more easily than has been possible in the past.
See the method comments below...
}
set_tile_color(10,0,1) 'Set tile 10, 0 to palette 1
set_tile_color(10,1,1) 'Set tile 10, 1 to palette 1
set_tile_address(10,0,$8000+(128*47)) 'Point tile 10, 0 to ROM
set_tile_address(10,1,$8000+(128*47)+64) 'Point tile 10, 1 to ROM
'-------------------------------------------------------------------------------------
repeat 200 'do the graphics demo 2000 iterations, or frames.
'clear bitmap
gr.clear
'draw spinning triangles
gr.colorwidth(3,0)
repeat i from 1 to 8
gr.vec(0, 0, (k & $7F) << 3 + i << 5, k << 6 + i << 8, @vecdef)
'draw expanding mouse crosshairs
gr.colorwidth(2,k>>2)
mousex := mousex + mouse.delta_x #> -128 <# 127
mousey := mousey + mouse.delta_y #> -96 <# 95
gr.pix(mousex, mousey, k>>4 & $7, @pixdef)
'if left mouse button pressed, throw snowballs
if mouse.button(0)
gr.width(pq & $F)
gr.color(2)
pp := (pq & $F)*(pq & $F) + 5
pq++
gr.arc(mousex, mousey, pp, pp>>1, -k * 200, $200, 8, 0)
else
pq~
'if right mouse button pressed, pause
repeat while mouse.button(1)
'draw expanding pixel halo
gr.colorwidth(1,k)
gr.arc(0,0,80,30,-k<<5,$2000/9,9,0)
'step bouncing lines
repeat i from 0 to lines - 1
if ||~x[i] > 60
-xs[i]
if ||~y[i] > 40
-ys[i]
x[i] += xs[i]
y[i] += ys[i]
'draw bouncing lines
gr.colorwidth(1,thickness)
gr.plot(~x[0], ~y[0])
repeat i from 1 to lines - 1
gr.line(~x[i],~y[i])
gr.line(~x[0], ~y[0])
'draw spinning stars and revolving crosshairs and dogs
gr.colorwidth(2,0)
repeat i from 0 to 7
gr.vecarc(80,50,30,30,-(i<<10+k<<6),$40,-(k<<7),@vecdef2)
gr.pixarc(-80,-40,30,30,i<<10+k<<6,0,@pixdef2)
gr.pixarc(-80,-40,20,20,-(i<<10+k<<6),0,@pixdef)
'draw small box with text
gr.colorwidth(1,14)
gr.box(60,-80,60,16)
gr.textmode(1,1,6,5)
gr.colorwidth(2,0)
gr.text(90,-72,@pchip)
'draw incrementing digit
if not ++numx & 7
numchr++
if numchr < "0" or numchr > "9"
numchr := "0"
gr.textmode(8,8,6,5)
gr.colorwidth(1,8)
gr.text(-90,50,@numchr)
'copy bitmap to display
gr.copy(display_base)
'increment counter that makes everything change
k++
'-------------------------------------------------------------------------
'Once the demo is over, make some screen changes
'
'Then stop!
'-------------------------------------------------------------------------
'set a few tiles to different colors
repeat dx from 2 to 7
repeat dy from 2 to 6
waitcnt (cnt + 10_000_000)
set_tile_color(dx, dy, 2)
'Cycle one of the displayed colors
repeat 5
dx := $1b_3c_9d_02
repeat k from $2b to $cb step 16
dx := dx & $FF_FF_00_FF
dx := dx + K << 8
waitcnt (cnt + 10_000_000)
set_color_palette(2, dx)
'Set that region to a different background color
dx := dx & $FF_FF_FF_00
dx := dx + $2D
set_color_palette(2, dx)
'Clone part of the screen by changing tile addresses
'And assign it it's own palette
repeat dx from 2 to 7
repeat dy from 2 to 6
addr := get_tile_address(dx, dy)
set_tile_address(dx + 8, dy + 3, addr)
set_tile_color(dx + 8, dy +3, 5)
waitcnt (cnt + 10_000_000)
waitcnt (cnt + 100_000_000)
'Show that it's all still in the HUB!
'Using the original code that defined the screen addresses to draw in
repeat dx from 0 to tv_hc - 1
repeat dy from 0 to tv_vc - 1
waitcnt(cnt + 5_000_000)
screen[dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc
set_tile_color(dx, dy, 5) 'set them to monochrome
'Now it's possible to redefine the bitmap base, allowing for graphics "windows"
'and other tricks. What needs to happen is the tiles must be pointed to a
'sequental set of addresses, then that base address and tile dimenions gets
'communicated to the graphics cog via the method "gr.setup"
'Define a new bitmap space and coordinates that draw into the cloned portion of the screen
'New screen is 6 tiles = 96 pixels in the X, and 5 tiles = 80 in the Y
'Screen center is = 0, 0 for a standard upper left coordinate system, instead of the one used
'by the demo code above.
'Once this is done, the graphics draw commands will operate on the new screen dimensions
'To draw on the full screen, gr.setup must be run again, with the original specifications
'For this demo, part of the draw screen will be used, so our screen addresses will start at $2000
'Screen addresses are sequential, 64 byte chunks, running from upper left, horizontally to the right
'then filling down, ending at lower left. Each tile is 64 bytes.
' Tile 0,0 = $2000 Tile 1,0 = $2040 Tile 2,0 = $2080 Tile 3,0 = $20C0 ... Tile 5,0 = $2140
' Tile 0,1 = $2180
'First point the tiles to the right screen addresses, offset into screen in both directions to make
'the new graphics area like a "window"
addr := $2000
repeat dx from 0 to 5 '6 tiles in the X = 96 pixels
repeat dy from 0 to 4 '5 tiles in the Y = 80 pixels
set_tile_address(dx + 3, dy + 3, addr)
set_tile_color(dx + 3, dy + 3, 2)
addr := addr + 64
gr.setup(6, 5, 0, 0, $2000) 'Time time, we make 0,0 the bottom left corner, instead of the center
waitcnt (cnt + 50_000_000) 'Pause to see the left over graphics in the draw page from the demo
gr.clear 'Clear the screen
'draw some lines that radiate out from 0,0 to the extents of the screen
repeat dx from 0 to 95 step 3
gr.colorwidth(3,0)
gr.plot(0,0)
gr.line(dx, 79)
repeat dy from 0 to 79 step 5
gr.colorwidth(2,1)
gr.plot(95,0)
gr.line(0, dy)
waitcnt(cnt + 50_000_000)
'Because we drew the bitmap in the double buffer draw space, the original screen is still in the HUB!
repeat dx from 0 to tv_hc - 1
repeat dy from 0 to tv_vc - 1
waitcnt(cnt + 5_000_000)
screen[dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc
set_tile_color(dx, dy, 2) 'Restore original graphics screen
'And end with the lines we drew, defined as a window somewhere else!!
addr := $2000
repeat dx from 0 to 5 '6 tiles in the X = 96 pixels
repeat dy from 0 to 4 '5 tiles in the Y = 80 pixels
set_tile_address(dx + 6, dy + 4, addr)
set_tile_color(dx + 6, dy + 4, 7)
addr := addr + 64
PUB set_tile_color(tilex, tiley, palette) | temp 'doug@opengeek.org
'The screen[] array contains both the tile HUB image data address, and an index into the color palette
'array, which can be defined as a DAT block, as done in this program, or as a VAR as done in the
'original
'The lower 10 bits are the HUB image address data (where the pixels are defined)
'The upper 6 bits point to sets of colors, contained in the colors[] array
temp := screen[tiley * tv_hc + tilex] 'get current screen tile value
temp := temp & %00000011_11111111 'clear color palette index value, leaving image address bits
temp := temp + (palette << 10) 'replace color palette index value with the new one
screen[tiley * tv_hc + tilex] := temp 'update the screen
PUB set_color_palette(palette_num, palette_colors) 'doug@opengeek.org
'only 64 palettes possible... (& %111111) insures no overwrite occurs on larger values
'the colors run like this in the long: 33_22_11_00, where 33 = color 3, 22 = color 2, etc...
'color 00 is the background color.
colors[palette_num & %111111] := palette_colors 'Write the colors into the colors[] array
PUB set_tile_address(tilex, tiley, HUB_address) | temp 'doug@opengeek.org
temp := screen[tiley * tv_hc + tilex] 'Get current screen tile value from screen[] array
temp := temp & %11111100_00000000 'Zero out the screen memory address pointer bits, leaving color bits
temp := temp + (HUB_address >> 6) 'Set screen memory pointer bits, from the most significant bits in the HUB
'address given. Tiles must be 64 byte aligned, due to how the TV driver
'decodes the screen array bits, 6 for color, 10 for screen pixel address in HUB
screen[tiley * tv_hc + tilex] := temp 'Update screen array for that tile, reflecting address change.
PUB get_tile_address(tilex, tiley) | temp 'doug@opengeek.org
temp := screen[tiley * tv_hc + tilex] 'Get current screen tile value from screen[] array
temp := temp & %00000011_11111111 'Zero out the color bits, leaving just the address
temp := temp << 6 'Shift to reflect effective HUB address. Tiles must
'be 64 byte aligned, due to how the TV driver
'decodes the screen array bits, 6 for color, 10 for
'screen pixel address in HUB
return temp 'return that address!
DAT
'This is where we define the TV parameters to be used for our graphics show
'The documentation for these is actually in the TV driver, so go look there
'for Chip's rather complete explanation of what all these do.
'
'All you really need to do, in order to make this work on your board, is deal
'with the right clock setting at the program top, set your pin group according
'to the documentation in the TV driver, and the display mode bits, again according
'to the TV driver comments, and your hardware setup.
'I've included a sample change for the HYBRID 96Mhz board, as an example.
{
'HYBRID
tvparams long 0 'status
long 1 'enable
long %011_0000 'pins ***
long %0000 'mode ***
long 0 'screen
long 0 'colors
long x_tiles 'hc
long y_tiles 'vc
long 10 'hx
long 1 'vx
long 0 'ho
long 0 'vo
long 0 'broadcast
long 0 'auralcog
}
'Demoboard defaults...
tvparams long 0 'status
long 1 'enable
long %010_0101 'pins
long %0000 'mode
long 0 'screen
long 0 'colors
long x_tiles 'hc
long y_tiles 'vc
long 10 'hx
long 1 'vx
long 0 'ho
long 0 'vo
long 0 'broadcast
long 0 'auralcog
DAT
{ I've put the colors array here in the DAT section to illustrate how the colors
actually work. Feel free to define a smaller array in a VAR section, or cut this
one down to the number of unique color combinations you think you need.
The only ones necessary, are those you define as in use with the SPIN methods:
set_tile_color(tilex, tiley, palette) ==> Used to assign a palette to a screen tile
set_color_palette(palette_num, palette_colors) ==> Used to change the contents of a palette
}
'64 Palette entries follow!
colors long $07_05_04_02 'This is palette 0
long $02_04_06_07 'This is palette 1
long $1b_3c_9d_02 'This is palette 2, containing a few colors
long $07_05_04_02
long $07_05_04_02 'All of them are greyscale, with black background to start
long $07_05_04_02 'And some are changed by the color demo above...
long $07_05_04_02
long $1b_3c_9d_02 'A lot of them go unused, but are here for clarity
long $07_05_04_02
long $07_05_04_02 'When you get it all sorted, feel free to trim the fat!
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
long $07_05_04_02
DAT
'These are things used in the little Parallax demo.
vecdef word $4000+$2000/3*0 'triangle
word 50
word $8000+$2000/3*1+1
word 50
word $8000+$2000/3*2-1
word 50
word $8000+$2000/3*0
word 50
word 0
vecdef2 word $4000+$2000/12*0 'star
word 50
word $8000+$2000/12*1
word 20
word $8000+$2000/12*2
word 50
word $8000+$2000/12*3
word 20
word $8000+$2000/12*4
word 50
word $8000+$2000/12*5
word 20
word $8000+$2000/12*6
word 50
word $8000+$2000/12*7
word 20
word $8000+$2000/12*8
word 50
word $8000+$2000/12*9
word 20
word $8000+$2000/12*10
word 50
word $8000+$2000/12*11
word 20
word $8000+$2000/12*0
word 50
word 0
pixdef word 'crosshair
byte 2,7,3,3
word %%00333000,%%00000000
word %%03020300,%%00000000
word %%30020030,%%00000000
word %%32222230,%%00000000
word %%30020030,%%02000000
word %%03020300,%%22200000
word %%00333000,%%02000000
pixdef2 word 'dog
byte 1,4,0,3
word %%20000022
word %%02222222
word %%02222200
word %%02000200
pchip byte "Propeller",0 'text
{{
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 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. │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
}}