// https://archive.org/details/HAKMEM/page/n73/mode/1up
// articles 149-152
#include "TVout.h"
#include "TVOlogo.h"
#include "schematic.h"
#include "font6x8.h"
TVout TV;
#define INVERT 2
#define invert(color) fill(2)
int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 64;
float angle = PI / 60;
float cube3d[8][3] = {
{xOff - cSize, yOff + cSize, zOff - cSize},
{xOff + cSize, yOff + cSize, zOff - cSize},
{xOff - cSize, yOff - cSize, zOff - cSize},
{xOff + cSize, yOff - cSize, zOff - cSize},
{xOff - cSize, yOff + cSize, zOff + cSize},
{xOff + cSize, yOff + cSize, zOff + cSize},
{xOff - cSize, yOff - cSize, zOff + cSize},
{xOff + cSize, yOff - cSize, zOff + cSize}
};
unsigned char cube2d[8][2];
//#include "TVoutfonts/font6x8.h"
void setup() {
Serial.begin(9600);
Serial.println("setup");
TV.begin(NTSC, 120, 96);
/*
Serial.println("Intro");
TV.select_font(font6x8);
intro();
TV.println("I am the TVout\nlibrary running on a freeduino\n");
TV.delay(1000);
TV.println("I generate a PAL\nor NTSC composite video using\ninterrupts\n");
TV.delay(1000);
TV.println("My schematic:");
TV.delay(1500);
TV.bitmap(0,0,schematic);
TV.delay(10000);
TV.clear_screen();
TV.println("Lets see what\nwhat I can do");
TV.delay(2000);
Serial.println("fonts");
TV.clear_screen();
TV.println(0,0,"Multiple fonts:");
//TV.select_font(font4x6);
TV.println("4x6 font FONT");
//TV.select_font(font6x8);
TV.println("6x8 font FONT");
//TV.select_font(font8x8);
TV.println("8x8 font FONT");
//TV.select_font(font6x8);
TV.delay(2000);
*/
/*
TV.clear_screen();
TV.print(9,44,"Draw Basic Shapes");
TV.delay(2000);
Serial.println("circles");
TV.clear_screen();
TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/3,WHITE);
TV.delay(500);
TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/2,WHITE,INVERT);
TV.delay(1000);
Serial.println("rectangles and lines");
TV.clear_screen();
TV.draw_rect(20,20,80,56,WHITE);
TV.delay(500);
TV.draw_rect(10,10,100,76,WHITE,INVERT);
TV.delay(500);
TV.draw_line(60,20,60,76,INVERT);
TV.draw_line(20,48,100,48,INVERT);
TV.delay(500);
TV.draw_line(10,10,110,86,INVERT);
TV.draw_line(10,86,110,10,INVERT);
TV.delay(1000);
*/
Serial.println("random cube forever.");
TV.clear_screen();
TV.print(16, 40, "Random Cube");
TV.print(28, 48, "Rotation");
TV.delay(1000);
randomSeed(analogRead(0));
Serial.println("setup done");
}
int prevRsteps;
int prevrandomsteps;
void loop() {
int rsteps = map(analogRead(0), 0, 1024, 10, 60); //random(10,60);
if (prevRsteps != rsteps) {
Serial.print("rsteps="); Serial.println(rsteps);
prevRsteps = rsteps;
}
int randomsteps = map(analogRead(1), 0, 1024, 0, 2); //random(10,60);
if (prevrandomsteps != randomsteps) {
Serial.print("randomsteps="); Serial.println(randomsteps);
prevrandomsteps = randomsteps;
}
switch (random(6)) {
case 0:
for (int i = 0; i < rsteps; i++) {
xrotate(map(analogRead(A2),0,1024,-360,360));
yrotate(map(analogRead(A3),0,1024,-360,360));
printcube();
}
break;
case 1:
for (int i = 0; i < rsteps; i++) {
xrotate(angle);
printcube();
}
break;
case 2:
for (int i = 0; i < rsteps; i++) {
yrotate(angle);
printcube();
}
break;
case 3:
for (int i = 0; i < rsteps; i++) {
xrotate(2 * PI - angle);
printcube();
}
break;
case 4:
for (int i = 0; i < rsteps; i++) {
yrotate(angle);
printcube();
}
break;
case 5:
for (int i = 0; i < rsteps; i++) {
yrotate(2 * PI - angle);
printcube();
}
break;
}
}
void intro() {
unsigned char w, l, wb;
int index;
w = pgm_read_byte(TVOlogo);
l = pgm_read_byte(TVOlogo + 1);
if (w & 7)
wb = w / 8 + 1;
else
wb = w / 8;
index = wb * (l - 1) + 2;
for ( unsigned char i = 1; i < l; i++ ) {
TV.bitmap((TV.hres() - w) / 2, 0, TVOlogo, index, w, i);
index -= wb;
TV.delay(50);
}
for (unsigned char i = 0; i < (TV.vres() - l) / 2; i++) {
TV.bitmap((TV.hres() - w) / 2, i, TVOlogo);
TV.delay(50);
}
TV.delay(3000);
TV.clear_screen();
}
void printcube() {
//calculate 2d points
for (byte i = 0; i < 8; i++) {
cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (TV.hres() / 2));
cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (TV.vres() / 2));
}
TV.delay_frame(1);
TV.clear_screen();
draw_cube();
}
void zrotate(float q) {
float tx, ty, temp;
for (byte i = 0; i < 8; i++) {
tx = cube3d[i][0] - xOff;
ty = cube3d[i][1] - yOff;
temp = tx * cos(q) - ty * sin(q);
ty = tx * sin(q) + ty * cos(q);
tx = temp;
cube3d[i][0] = tx + xOff;
cube3d[i][1] = ty + yOff;
}
}
void yrotate(float q) {
float tx, tz, temp;
for (byte i = 0; i < 8; i++) {
tx = cube3d[i][0] - xOff;
tz = cube3d[i][2] - zOff;
temp = tz * cos(q) - tx * sin(q);
tx = tz * sin(q) + tx * cos(q);
tz = temp;
cube3d[i][0] = tx + xOff;
cube3d[i][2] = tz + zOff;
}
}
void xrotate(float q) {
float ty, tz, temp;
for (byte i = 0; i < 8; i++) {
ty = cube3d[i][1] - yOff;
tz = cube3d[i][2] - zOff;
temp = ty * cos(q) - tz * sin(q);
tz = ty * sin(q) + tz * cos(q);
ty = temp;
cube3d[i][1] = ty + yOff;
cube3d[i][2] = tz + zOff;
}
}
void draw_cube() {
TV.draw_line(cube2d[0][0], cube2d[0][1], cube2d[1][0], cube2d[1][1], WHITE);
TV.draw_line(cube2d[0][0], cube2d[0][1], cube2d[2][0], cube2d[2][1], WHITE);
TV.draw_line(cube2d[0][0], cube2d[0][1], cube2d[4][0], cube2d[4][1], WHITE);
TV.draw_line(cube2d[1][0], cube2d[1][1], cube2d[5][0], cube2d[5][1], WHITE);
TV.draw_line(cube2d[1][0], cube2d[1][1], cube2d[3][0], cube2d[3][1], WHITE);
TV.draw_line(cube2d[2][0], cube2d[2][1], cube2d[6][0], cube2d[6][1], WHITE);
TV.draw_line(cube2d[2][0], cube2d[2][1], cube2d[3][0], cube2d[3][1], WHITE);
TV.draw_line(cube2d[4][0], cube2d[4][1], cube2d[6][0], cube2d[6][1], WHITE);
TV.draw_line(cube2d[4][0], cube2d[4][1], cube2d[5][0], cube2d[5][1], WHITE);
TV.draw_line(cube2d[7][0], cube2d[7][1], cube2d[6][0], cube2d[6][1], WHITE);
TV.draw_line(cube2d[7][0], cube2d[7][1], cube2d[3][0], cube2d[3][1], WHITE);
TV.draw_line(cube2d[7][0], cube2d[7][1], cube2d[5][0], cube2d[5][1], WHITE);
}