initial commit

This commit is contained in:
hybris 2023-08-18 00:03:31 +02:00
commit 38d90de7b3
4 changed files with 3741 additions and 0 deletions

624
data/matrix2.html Normal file
View File

@ -0,0 +1,624 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type = "text/javascript">
var framecount=0;
var buf = new Uint8ClampedArray(768);
var framebuffer1 = "";
var starttime = new Date().getTime();
var currentfps = 25;
var fpsms = 1000/currentfps;
var videocontrast=0;
var sat_r=256;
var sat_g=256;
var sat_b=256;
var vf_size_x = 480;
var vf_size_y = 360;
var vf_pos_x = 0;
var vf_pos_y = 0;
var v_size_x = 32;
var v_size_y = 24;
var v_pos_x = 0;
var v_pos_y = 0;
var zoom=1;
var loop_video=0;
var mute_video=0;
function contrastImage(imgData, contrast){ //input range [-100..100]
var d = imgData.data;
contrast = (contrast/100) + 1; //convert to decimal & shift range: [0..2]
var intercept = 128 * (1 - contrast);
for(var i=0;i<d.length;i+=4){ //r,g,b,a
d[i] = d[i]*contrast + intercept;
d[i+1] = d[i+1]*contrast + intercept;
d[i+2] = d[i+2]*contrast + intercept;
}
return imgData;
}
var loc = window.location, new_uri;
new_uri = "ws://" + loc.host + "/ws";
var ws = new WebSocket(new_uri);
ws.onopen = function() {
console.log("WS BINARY TYPE: "+ws.binaryType);
};
ws.onmessage = function(evt) {
/* INCOMING MESSAGE */
};
let processor = {
timerCallback: function() {
var timenow = new Date().getTime();
var timediff = timenow-starttime;
if (this.video.paused || this.video.ended) {
return;
}
if (timediff>fpsms) {
starttime=timenow;
//console.log("timediff: "+timediff);
this.computeFrame();
}
let self = this;
setTimeout(function () {
self.timerCallback();
}, 0);
},
doLoad: function() {
console.log("doLoad");
document.querySelector('input').addEventListener('change', processor.extractFrames, false);
this.video = document.getElementById("video");
this.c1 = document.getElementById("c1");
this.ctx1 = this.c1.getContext("2d");
this.matrix = document.getElementById("matrix");
let self = this;
/* CREATE PIXEL NODES */
for (var i=0; i<768; i++) {
var px = document.createElement("div");
px.className = "px";
matrix.appendChild(px);
}
this.video.addEventListener("play", function() {
self.width = self.video.videoWidth / 10;
self.height = self.video.videoHeight / 10;
self.timerCallback();
}, false);
},
readURL: function(input) {
console.log("readURL");
var video = document.getElementById("video");
var matrix = document.getElementById("matrix");
video.pause();
if (input.files && input.files[0]) {
var file = input.files[0];
var url = URL.createObjectURL(file);
console.log(url);
var reader = new FileReader();
reader.onload = function() {
video.src = url;
video.load();
video.addEventListener('loadeddata', function() {
var xratio = video.videoWidth/480;
var yratio = video.videoHeight/360;
console.log(video.videoWidth);
var video_container = document.getElementById("video_container");
var video_frame = document.getElementById("vidframe");
var vidframe_offset_x = video_frame.offsetLeft-video_container.offsetLeft;
var vidframe_offset_y = video_frame.offsetTop-video_container.offsetTop;
v_pos_x=Math.floor(vidframe_offset_x*xratio);
v_pos_y=Math.floor(vidframe_offset_y*yratio);
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
console.log("vpx: "+v_pos_x+" --- vpy: "+v_pos_y);
/*
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
v_pos_x=Math.floor(vf_pos_x*10*xratio);
v_pos_y=Math.floor(vf_pos_y*10*yratio);
*/
console.log("V z "+zoom+" "+xratio+" "+v_pos_x+" "+v_pos_y+" "+v_size_x+" "+v_size_y);
video.controls = false;
video.play();
}, false);
//video.controls = true;
console.log(video);
console.log("loaded height "+video.videoHeight);
}
reader.readAsDataURL(file);
for (let i = 0; i < 768; i+=1) {
matrix.childNodes[i].style.backgroundColor = "rgb(0,0,0)";
buf[i]=0;
}
}
},
computeFrame: function() {
framebuffer1="";
this.ctx1 = this.c1.getContext("2d");
var ratio = this.video.videoHeight/this.video.videoWidth;
this.width = 32;
this.cw = Math.round(32*ratio);
if (this.cw%2!=0) this.cw+=1;
//if (zoom>1) this.cw = 24;
this.height = this.cw;
this.offsety = Math.floor((24-this.cw)*.5)*32;
this.ctx1.drawImage(this.video, v_pos_x, v_pos_y, v_size_x, v_size_y, 0, 0, this.width, this.height);
//let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
let frame = contrastImage(this.ctx1.getImageData(0, 0, this.width, this.height),videocontrast);
let l = frame.data.length / 4;
for (let i = 0; i < 768; i+=1) {
buf[i]=0;
}
for (let i = 0; i < l; i+=1) {
var true_r = Math.floor((frame.data[i * 4 + 0] / 32 * (sat_r/256)));
var true_g = Math.floor((frame.data[i * 4 + 1] / 32 * (sat_g/256)));
var true_b = Math.floor((frame.data[i * 4 + 2] / 64 * (sat_b/256)));
let r = (true_r << 5);
let g = (true_g << 2); //0 << 2;
let b = true_b;
var px_r = true_r * 32;
var px_g = true_g * 32;
var px_b = true_b * 64;
if (i+this.offsety<768) {
matrix.childNodes[i+this.offsety].style.backgroundColor = "rgb("+px_r+","+px_g+","+px_b+")";
var py = Math.floor((i+this.offsety)/32);
var pii = (i+this.offsety)-(py*32);
//var pii = (i+this.offsety);
if (py%2==0) {
//buf[py*32+31-pii]=r+g+b;
buf[py*32+pii]=r+g+b;
} else {
//buf[py*32+pii]=r+g+b;
buf[py*32+31-pii]=r+g+b;
}
}
}
ws.send(buf.buffer);
framecount+=1;
return;
}
};
document.addEventListener("DOMContentLoaded", () => {
processor.doLoad();
var slider_r = document.getElementById("rgb_r");
var slider_g = document.getElementById("rgb_g");
var slider_b = document.getElementById("rgb_b");
var slider_zoom = document.getElementById("zoom");
var contrast_slider = document.getElementById("video_contrast");
var slider_offsetx = document.getElementById("vf_offset_x");
var slider_offsety = document.getElementById("vf_offset_y");
slider_offsetx.value=0;
slider_offsety.value=0;
slider_zoom.value=1;
slider_r.value=8;
slider_g.value=8;
slider_b.value=8;
var playvid = document.getElementById("playvid");
var loopvid = document.getElementById("loopvid");
var mutevid = document.getElementById("mutevid");
var myVideo = document.getElementById("video");
var viframe = document.getElementById("vidframe");
var v_progress = document.getElementById("v_progress");
var v_volume = document.getElementById("v_volume");
var docbody = document.getElementById("body");
var fullvid = document.getElementById("fullvid");
docbody.onresize = function() {
var vidc = document.getElementById("video_container");
var vidfr = document.getElementById("vidframe");
console.log("newx "+vidc.offsetLeft);
vidfr.style.top = (parseInt(vidc.offsetTop)+parseInt(slider_offsety.value))+"px";
vidfr.style.left = (parseInt(vidc.offsetLeft)+parseInt(slider_offsetx.value))+"px";
console.log("vidframe x: "+vidfr.offsetLeft);
console.log("slider x: "+slider_offsetx.value);
//console.log("vidcontainer x: "+vidc.offsetLeft+" "+slider_offsetx.value);
}
v_progress.oninput = function() {
var skipto = Math.floor((v_progress.value/100)*myVideo.duration);
myVideo.currentTime = skipto;
processor.computeFrame();
};
v_volume.oninput = function() {
myVideo.volume = v_volume.value*.01;
if (v_volume.value==0) {
mutevid.className = "muteactive";
} else {
mutevid.className = "";
}
};
function togglePlay() {
if (myVideo.paused) {
myVideo.play();
playvid.innerHTML = "⏸";
} else {
myVideo.pause();
playvid.innerHTML = "▶";
}
};
myVideo.onended = function() {
console.log("The video has ended");
playvid.innerHTML = "▶";
};
myVideo.onplay = function() {
console.log("The video has started");
playvid.innerHTML = "⏸";
};
myVideo.ontimeupdate = function(){
var percentage = Math.floor(( myVideo.currentTime / myVideo.duration ) * 100);
//console.log("percent: "+percentage);
v_progress.value = percentage;
};
slider_r.oninput = function() {
sat_r=this.value*32;
this.style.backgroundColor = "rgb("+sat_r+",0,0)";
processor.computeFrame();
}
slider_g.oninput = function() {
sat_g=this.value*32;
this.style.backgroundColor = "rgb(0,"+sat_g+",0)";
processor.computeFrame();
}
slider_b.oninput = function() {
sat_b=this.value*64;
this.style.backgroundColor = "rgb(0,0,"+sat_b+")";
processor.computeFrame();
}
slider_zoom.oninput = function() {
zoom=this.value*.1;
makeZoom();
}
contrast_slider.oninput = function() {
videocontrast=this.value;
}
slider_offsetx.oninput = function() {
var tempvideo = document.getElementById("video");
var vidframe = document.getElementById("vidframe");
vf_pos_x=this.value;
vidframe.style.marginLeft = ((vf_pos_x*10)-2)+"px";
var xratio = tempvideo.videoWidth/480;
v_pos_x=Math.floor(vf_pos_x*10*xratio);
console.log("xratio: "+xratio);
processor.computeFrame();
}
slider_offsety.oninput = function() {
var tempvideo = document.getElementById("video");
var vidframe = document.getElementById("vidframe");
vf_pos_y=this.value;
vidframe.style.marginTop = ((vf_pos_y*10)-2)+"px";
var yratio = tempvideo.videoHeight/360;
v_pos_y=Math.floor(vf_pos_y*10*yratio);
console.log("yratio: "+yratio);
processor.computeFrame();
}
playvid.onclick = function() {
var tempvideo = document.getElementById("video");
console.log("aka");
//tempvideo.play();
togglePlay();
}
fullvid.onclick = function() {
var tempvideo = document.getElementById("video");
tempvideo.requestFullscreen();
}
loopvid.onclick = function() {
var tempvideo = document.getElementById("video");
var loopvid = document.getElementById("loopvid");
if (loop_video==0) {
tempvideo.loop = true;
loop_video=1;
loopvid.classList.add("loopactive");
} else {
tempvideo.loop = false;
loop_video=0;
loopvid.classList.remove("loopactive");
}
}
mutevid.onclick = function() {
var tempvideo = document.getElementById("video");
if (mute_video==1) {
tempvideo.volume = .5;
mute_video=0;
this.classList.remove("muteactive");
v_volume.value=50;
} else {
tempvideo.volume = 0;
mute_video=1;
this.classList.add("muteactive");
v_volume.value=0;
}
}
function doZoom(event) {
event.preventDefault();
console.log(event.deltaY);
if (zoom-event.deltaY*.1>=1 && zoom-event.deltaY*.1<=10) {
zoom-=event.deltaY*.1;
makeZoom();
}
}
function makeZoom(event) {
var tempvideo = document.getElementById("video");
var xratio = tempvideo.videoWidth/480;
var yratio = tempvideo.videoHeight/360;
vf_size_x = Math.floor(480/zoom);
console.log("vf_Sx: "+vf_size_x);
console.log("vf_Px: "+vf_pos_x);
vf_size_y = Math.floor(360/zoom);
v_size_x = Math.floor((480/zoom)*xratio);
v_size_y = Math.floor((360/zoom)*yratio);
var vidframe = document.getElementById("vidframe");
vidframe.style.width = vf_size_x+"px";
vidframe.style.height = vf_size_y+"px";
processor.computeFrame();
}
video.onwheel = doZoom;
viframe.onwheel = doZoom;
dragElement(document.getElementById("vidframe"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0, vftop = 0, vfleft = 0;
if (document.getElementById(elmnt.id + "header")) {
// if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
var video_container = document.getElementById("video_container");
var video_frame = document.getElementById("vidframe");
var vf_rightbound = elmnt.offsetLeft-pos1-video_container.offsetLeft+video_frame.offsetWidth;
var vf_bottombound = elmnt.offsetTop-pos2-video_container.offsetTop+video_frame.offsetHeight;
//console.log("vf_right: "+vf_rightbound+" --- vf_bottom: "+vf_bottombound);
if (vf_rightbound<480 && (elmnt.offsetLeft - pos1)>=video_container.offsetLeft && vf_bottombound<360 && (elmnt.offsetTop - pos2)>=video_container.offsetTop) {
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
/* UPDATE FRAME INFO */
var tempvideo = document.getElementById("video");
var yratio = tempvideo.videoHeight/360;
var xratio = tempvideo.videoWidth/480;
var tvf_pos_x=elmnt.offsetLeft-video_container.offsetLeft;
var tvf_pos_y=elmnt.offsetTop-video_container.offsetTop;
vf_pos_x=tvf_pos_x;
vf_pos_y=tvf_pos_y;
v_pos_x=Math.floor(tvf_pos_x*xratio);
v_pos_y=Math.floor(tvf_pos_y*yratio);
var slide_offsetx = document.getElementById("vf_offset_x");
var slide_offsety = document.getElementById("vf_offset_y");
slide_offsetx.value = tvf_pos_x;
slide_offsety.value = tvf_pos_y;
} else {
}
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
var video_container = document.getElementById("video_container");
//console.log(video_container);
var video_frame = document.getElementById("vidframe");
//console.log(video_frame);
processor.computeFrame();
}
}
});
</script>
<style>
body { background:#333; font-family:sans-serif; margin:0px; padding:20px; color:#f7f7f7; }
#c2 { background-repeat: no-repeat; }
#matrix { float:none; clear:both; width:320px; height:240px; }
.px { float:left; width:9px; height:9px; margin:0px; padding:0px; display:block; border:0px; border-left:1px solid #222; border-top:1px solid #222; }
#video_container { width:480px; height:360px; margin-bottom:10px; }
#video { width:100%; height:100%; outline:0; }
#c1 { float:left; display:none; }
/* slider */
.slidecontainer { width: 482px; float:right; margin-bottom:20px; }
.slidecontainer span { margin-bottom:10px; display:block; font-weight:bold; }
.slider { -webkit-appearance: none; width: 100%; height: 9px; border-radius: 5px; background: #444; outline: 0px!important; -webkit-transition: .2s; transition: opacity .2s; margin-bottom:10px; }
.slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 50%; background: #00f; cursor: pointer; outline:0px!important; }
.slider::-moz-range-thumb { width: 11px; height: 11px; border-radius: 50%; border:0px; background: #fff; cursor: pointer; outline:0px!important; }
.slider.red { background:#e00; }
.slider.green { background:#0a0; }
.slider.blue { background:#00b; }
.slider.white { background:#555; }
.slider.grey { background:#222; }
.slider.grey:hover::-moz-range-thumb { background:#098; }
.slider.grey::-moz-range-thumb:hover { background:#098; }
#vidframe { position:absolute; width:480px; height:360px; border:1px solid rgba(255,255,255,.5); margin-top:0px; margin-left:0px; cursor:grab; }
#playvid { display:block; background:#222; padding:5px; width:20px; text-align:center; cursor:pointer; height:22px; margin-left:0px; margin-bottom:10px; float:left; }
#playvid:hover { background:#089; }
#outputleft { float:left; width:340px; }
#outputleft span { margin-bottom:10px; display:block; font-weight:bold; }
#inputright { float:right; width:500px; }
#v_progress { float:left; width:250px; margin-top:12px; margin-left:10px; }
#v_volume { float:left; width:100px; margin-top:12px; margin-left:10px; }
#fullvid { float:right; margin-top:7px; text-align:center; background:#222; cursor:pointer; }
#mutevid { float:left; margin-top:7px; text-align:center; margin-left:15px; cursor:pointer; }
#loopvid { float:left; margin-top:7px; margin-left:10px; text-align:center; cursor:pointer; }
.loopactive { color:#089; }
.muteactive { color:rgba(255,255,255,.1); }
</style>
</head>
<body id="body">
<div id="outputleft">
<span>Matrix Output</span>
<div id="matrix"></div>
</div>
<div id="inputright">
<div class="slidecontainer">
<span>Video Input &amp; Controls</span>
<div id="video_container">
<div id="vidframe"></div>
<video id="video" src="input.mp4" />
</div>
<div id="playvid"></div>
<input type="range" min="0" max="100" value="0" class="slider grey" id="v_progress">
<div id="loopvid"></div>
<div id="mutevid">🔊</div>
<input type="range" min="0" max="100" value="50" class="slider grey" id="v_volume">
<div id="fullvid"></div>
<br/>
<input type="file" accept="video/*" style="margin-top:30px; float:none; clear:both; display:block; max-width:100%;" onchange="processor.readURL(this);" />
<div style="clear:both"></div>
<br/>
</div>
<div class="slidecontainer">
<span>Channel Saturation</span>
<input type="range" min="1" max="8" value="8" class="slider red" id="rgb_r">
<input type="range" min="1" max="8" value="8" class="slider green" id="rgb_g">
<input type="range" min="1" max="4" value="4" class="slider blue" id="rgb_b">
</div>
<div class="slidecontainer">
<span>Contrast</span>
<input type="range" min="-100" max="200" value="0" class="slider white" id="video_contrast">
</div>
<div class="slidecontainer">
<span>Zoom</span>
<input type="range" min="10" max="100" value="1" class="slider white" id="zoom">
</div>
<div class="slidecontainer">
<span>Offset</span>
<input type="range" min="0" max="480" value="0" class="slider white" id="vf_offset_x">
<input type="range" min="0" max="360" value="0" class="slider white" id="vf_offset_y">
</div>
<canvas id="c1" width="320" height="240"></canvas>
<div style="clear:both;"></div>
</div>
</body>
</html>

1234
fonts.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

532
tetris.h Normal file
View File

@ -0,0 +1,532 @@
/* TETRIS */
uint8_t last_leds[768*3];
int last_led_count = 768;
// First dimension: which shape
// Second dimension: which rotation, + color
// Third & fourth dimensions: rows and columns of shape
bool shapetypes[7][5][4][4] = {
{
// Line of four
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 1 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 }
},
{
{1}, {1}, {0}
}
},
{
// S-shape (orientation 1)
{
{ 0, 0, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{0}, {0}, {1}
}
},
{
// S-shape (orientation 2)
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 1, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 1, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {0}, {0}
}
},
{
// T-piece
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 1, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 0, 0 },
{ 1, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {1}, {1}
}
},
{
// L-piece (orientation 1)
{
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 1, 1, 1, 0 },
{ 1, 0, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 0, 1, 0 },
{ 1, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{0}, {1}, {0}
}
},
{
// L-piece (orientation 2)
{
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 1, 1 },
{ 0, 0, 0, 0 }
},
{
{ 0, 1, 1, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 1 },
{ 0, 0, 0, 1 },
{ 0, 0, 0, 0 }
},
{
{0}, {1}, {1}
}
},
{
// Cube
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{ 0, 0, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 0, 0 }
},
{
{1}, {0}, {1}
}
}
};
/* SOMEBRICKS: Position, Type and Rotation of current piece (array index = player) */
/* number of players */
int players=2;
/* field position */
int p_field_pos[2][2] = {{2,2},{20,2}};
/* set players current shape xy-position */
int set_x[2]={3,3};
int set_y[2]={0,0};
/* set players current shapetype & rotation */
int current_btype[2]={0,1};
int current_brot[2]={0,0};
/* Somebricks Functions */
void init_lights() {
int arrsize = last_led_count*3;
int i;
int x;
int y;
int idx = 0;
for (int led=0;led<last_led_count;led++) {
x = lookup[led][0];
y = lookup[led][1];
last_leds[idx] = 0;
last_leds[idx+1] = 0;
last_leds[idx+2] = 0;
idx+=3;
}
}
void update_stones() {
/* Position in grid */
int field_x;
int field_y;
int light_i;
/* Walk piece-array, draw pixels */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
/* Check active pixels */
for (int p=0; p<players; p++) {
if (shapetypes[current_btype[p]][current_brot[p]][i][j] == 1) {
/* set xy for current active pixel */
field_x=p_field_pos[p][0]+set_x[p]+j;
field_y=p_field_pos[p][1]+set_y[p]+i;
/* check boundaries */
if (field_x<32 && field_x>=0 && field_y<24 && field_y>=0) {
light_i = lookup_yx[field_y][field_x];
/* set rgb of pieces separately */
if (shapetypes[current_btype[p]][4][0][0]==1) { last_leds[light_i*3] = 100; } else { last_leds[light_i*3] = 0; }
if (shapetypes[current_btype[p]][4][1][0]==1) { last_leds[light_i*3+1] = 100; } else { last_leds[light_i*3+1] = 0; }
if (shapetypes[current_btype[p]][4][2][0]==1) { last_leds[light_i*3+2] = 100; } else { last_leds[light_i*3+2] = 0; }
}
}
}
}
}
}
void clear_lines(int player_id) {
int stones_in_line;
int pixel_value;
int light_int;
int light_int_old;
int field_newx;
int field_newy;
for (int j=p_field_pos[player_id][1]+19; j>p_field_pos[player_id][1]; j--) {
/* Count stones in line */
stones_in_line=0;
for (int i=p_field_pos[player_id][0]; i<p_field_pos[player_id][0]+10; i++) {
light_int = lookup_yx[j][i];
pixel_value=last_leds[light_int*3+0]+last_leds[light_int*3+1]+last_leds[light_int*3+2];
if (pixel_value>99) {
stones_in_line++;
}
}
/* Found complete line */
if (stones_in_line==10) {
/* Move down everything by 1 line */
for (int y=j; y>p_field_pos[player_id][1]; y--) {
for (int x=p_field_pos[player_id][0]; x<10+p_field_pos[player_id][0]; x++) {
light_int = lookup_yx[y][x];
if ((y-1)>=0) {
light_int_old = lookup_yx[y-1][x];
last_leds[light_int*3+0]=last_leds[(light_int_old)*3+0];
last_leds[light_int*3+1]=last_leds[(light_int_old)*3+1];
last_leds[light_int*3+2]=last_leds[(light_int_old)*3+2];
}
}
}
/* Set index to last line */
j++;
/* Change Enemy Field - Move up everything by 1 line */
for (int p=0; p<players; p++) {
if (p != player_id) {
/* Remove current position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[p]][current_brot[p]][i][j] == 1) {
field_newx=p_field_pos[p][0]+set_x[p]+j;
field_newy=p_field_pos[p][1]+set_y[p]+i;
light_int = lookup_yx[field_newy][field_newx];
last_leds[light_int*3+0]=0;
last_leds[light_int*3+1]=0;
last_leds[light_int*3+2]=0;
}
}
}
/* Move all up */
for (int y=p_field_pos[p][1]; y<p_field_pos[p][1]+19; y++) {
for (int x=p_field_pos[p][0]; x<10+p_field_pos[p][0]; x++) {
light_int = lookup_yx[y][x];
if ((y+1)<p_field_pos[p][1]+20) {
light_int_old = lookup_yx[y+1][x];
last_leds[light_int*3+0]=last_leds[(light_int_old)*3+0];
last_leds[light_int*3+1]=last_leds[(light_int_old)*3+1];
last_leds[light_int*3+2]=last_leds[(light_int_old)*3+2];
}
}
}
/* Add a random line */
for (int x=p_field_pos[p][0]; x<10+p_field_pos[p][0]; x++) {
light_int = lookup_yx[p_field_pos[p][1]+19][x];
last_leds[light_int*3+1]=0;
if (rand()%10<3) {
last_leds[light_int*3]=0;
} else {
last_leds[light_int*3]=100;
}
last_leds[light_int*3+2]=0;
}
}
}
}
}
update_stones();
}
/* fix player_id's current stone in position, create new */
void merge_stone(int player_id) {
int field_newx;
int field_newy;
int light_int;
/* Place current position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][current_brot[player_id]][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+set_x[player_id]+j;
field_newy=p_field_pos[player_id][1]+set_y[player_id]+i;
light_int = lookup_yx[field_newy][field_newx];
if (shapetypes[current_btype[player_id]][4][0][0] == 1) { last_leds[light_int*3] = 100; } else { last_leds[light_int*3] = 0; }
if (shapetypes[current_btype[player_id]][4][1][0] == 1) { last_leds[light_int*3+1] = 100; } else { last_leds[light_int*3+1] = 0; }
if (shapetypes[current_btype[player_id]][4][2][0] == 1) { last_leds[light_int*3+2] = 100; } else { last_leds[light_int*3+2] = 0; }
}
}
}
if (set_y[player_id]<1) {
init_lights();
}
/* set new piece position */
set_y[player_id]=0;
current_btype[player_id]=rand()%7;
current_brot[player_id]=rand()%4;
set_x[player_id]=3;
clear_lines(player_id);
}
/* check if player_id's next shapemove is possible */
/* returns false when move is not possible */
bool check_movement(int player_id, int x, int y, int rot) {
/* var for current pixel */
int field_newx;
int field_newy;
int light_int;
/* XY Offset for 4x4 shape field */
int temp_set_x=set_x[player_id]+x;
int temp_set_y=set_y[player_id]+y;
/* current rotation */
int temp_brot=(current_brot[player_id]+rot)%4;
int pixel_value;
/* Remove current shape position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
/* player_id's current shape and current rotation */
if (shapetypes[current_btype[player_id]][current_brot[player_id]][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+set_x[player_id]+j;
field_newy=p_field_pos[player_id][1]+set_y[player_id]+i;
light_int = lookup_yx[field_newy][field_newx];
/* set pixels to 0 */
last_leds[light_int*3+0]=0;
last_leds[light_int*3+1]=0;
last_leds[light_int*3+2]=0;
}
}
}
/* Check future position */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][temp_brot][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+temp_set_x+j;
field_newy=p_field_pos[player_id][1]+temp_set_y+i;
if (field_newx>=0 && field_newx<32 && field_newy>=0 && field_newy<22) {
light_int = lookup_yx[field_newy][field_newx];
pixel_value=last_leds[light_int*3+0]+last_leds[light_int*3+1]+last_leds[light_int*3+2];
int p_min_x = p_field_pos[player_id][0];
int p_min_y = p_field_pos[player_id][1];
int p_max_x = p_field_pos[player_id][0]+9;
int p_max_y = p_field_pos[player_id][1]+19;
/* collision */
if (field_newx>p_max_x || field_newx<p_min_x || field_newy>p_max_y || field_newy<p_min_y || pixel_value > 99) {
if (y==1) {
merge_stone(player_id);
}
update_stones();
return false;
}
} else {
/* piece at the lowest point -> merge */
if (y==1) {
merge_stone(player_id);
}
update_stones();
return false;
}
}
}
}
/* Place future position (eventually will not be reached) */
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (shapetypes[current_btype[player_id]][temp_brot][i][j] == 1) {
field_newx=p_field_pos[player_id][0]+temp_set_x+j;
field_newy=p_field_pos[player_id][1]+temp_set_y+i;
light_int = lookup_yx[field_newy][field_newx];
if (shapetypes[current_btype[player_id]][4][0][0]==1) { last_leds[light_int*3] = 100; } else { last_leds[light_int*3] = 0; }
if (shapetypes[current_btype[player_id]][4][1][0]==1) { last_leds[light_int*3+1] = 100; } else { last_leds[light_int*3+1] = 0; }
if (shapetypes[current_btype[player_id]][4][2][0]==1) { last_leds[light_int*3+2] = 100; } else { last_leds[light_int*3+2] = 0; }
}
}
}
set_x[player_id] = temp_set_x;
set_y[player_id] = temp_set_y;
current_brot[player_id] = temp_brot;
update_stones();
return true;
}