// vim: tabstop=4:shiftwidth=4:expandtab
/*
* fbutils helper library for pythons fbpy module. Draws stuff in the
* Linux framebuffer.
* Copyright (C) 2014 Marcell Marosvolgyi aka noisegate
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <math.h>
#include "font.h"
#include <png.h>
#include "test.h"
#include "fbutils.h"
#include <time.h>
//TODO: I really have to clean this
//shit. It's getting way too GLOBAL
#ifndef FB_VBLANK_HAVE_STICKY
#define FB_VBLANK_HAVE_STICKY 0
#endif
#ifndef FB_VBLANK_STICKY
#define FB_VBLANK_STICKY 0
#endif
#ifdef FBIOGET_VBLANK
static int vblank_flags; /* supports retrace detection? */
#endif
#define TO_BLOCK 1
#define FROM_BLOCK 0
#define FBUTILS_ERROR_OUT_OF_MEMORY -2
#define FBUTILS_ERROR_GENERAL -3
#define FBUTILS_ERROR_NOT_YET_IMPLEMENTED -1
#define max255(x) (((x)>255)?255:(x))
#define MAXBLUR 10
#define MAXBLURHALF 5
#define TON start=clock()
#define TOFF end=clock();printf("elapsed %1d.",(double)(end-start))
#define BPP 4 //well, bytes per pixel
#define xaxis 0
#define yaxis 9
#define zaxis 18
int fbfd = 0;
struct fb_var_screeninfo orig_vinfo;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
char *fbp = NULL;
char *tmp_buf = NULL;
char *dummy_buf = NULL;
char skipper; //for linestyle, global 4 continuity
int blur; //makes plot dots blurred
int blurrad; //gauss width or somethin'
int sigma; //sigma of the Gaussian
char linestyle; //0 = solid, 1=dash, 2=dot
int bytes_per_pixel = 0;
int Ox;
int Oy;
int width;
int width4;
int height;
int cur_page = 1;
unsigned char kern[MAXBLUR][MAXBLUR];
clock_t end,start;
struct Color *currentcolor = NULL;
struct Trafo *currenttrafo = NULL;
struct Trafo3 *currenttrafo3 = NULL;
int (*pPlot) (int x, int y);
int (*lintrafo[5])(int *, int *, int *, struct TrafoL )={NULL};
char gauzz[]={
0x10,0x10,0x10,0x10, 0x20,0x20,0x20,0x20, 0x10,0x10,0x10,0x10,
0x20,0x20,0x20,0x20, 0xff,0xff,0xff,0xff, 0x20,0x20,0x20,0x20,
0x10,0x10,0x10,0x10, 0x20,0x20,0x20,0x20, 0x10,0x10,0x10,0x10};
int setup(void)
{
//http://stackoverflow.com/questions/4996777/paint-pixels-to-screen-via-linux-framebuffer
//modified
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd) {
fprintf(stderr, "Error: cannot open framebuffer device.\n");
return FBUTILS_ERROR_GENERAL;
}
//printf("The framebuffer device was opened successfully.\n");
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
fprintf(stderr, "Error reading variable information.\n");
return FBUTILS_ERROR_GENERAL;
}
//printf("Original %dx%d, %dbpp\n", vinfo.xres, vinfo.yres,
// vinfo.bits_per_pixel );
// Store for reset (copy vinfo to vinfo_orig)
// should not be here, but/??
// maybe before update??? trying...
// memcpy(&orig_vinfo, &vinfo, sizeof(struct fb_var_screeninfo));
// Change variable info
vinfo.bits_per_pixel = 32;
//vinfo.xres = 1366;
//vinfo.yres = 768;
vinfo.xres_virtual = vinfo.xres;
vinfo.yres_virtual = vinfo.yres * 1; // double the physical
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) {
fprintf(stderr, "Error setting variable information.\n");
return -1;
}
bytes_per_pixel = vinfo.bits_per_pixel / 4;
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
fprintf(stderr, "Error reading fixed information.\n");
return -1;
}
// map fb to user mem
// TODO:
//finfo line_length gives 5504
//5504/4 = 1376 not 1366 hmmm
//
//added 4 here!!! 'cos bits per pixel is 32 not 8
//screensize = 4*vinfo.xres * vinfo.yres;
//doubling this because of the flipping
//use virtual is already twice the physical
//screensize = 4 * vinfo.xres_virtual * vinfo.yres_virtual;
//screensize = finfo.line_length * vinfo.yres_virtual;
//screensize = BPP * vinfo.xres * vinfo.yres;
screensize = finfo.line_length * vinfo.yres;
fbp = (char*)mmap(0,
screensize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fbfd,
0);
Ox = 0;
Oy = 0;
width = vinfo.xres;
width4 = vinfo.xres * BPP;//yih
height = vinfo.yres;
//printf ("screensize %i \n", screensize);
//printf ("screensize %i \n", finfo.smem_len);
//allocate temp memory stuff....
//
tmp_buf = malloc((size_t)screensize);
if (tmp_buf == NULL){
fprintf(stderr, "Out of memory...\n");
return FBUTILS_ERROR_OUT_OF_MEMORY;
}
dummy_buf = malloc((size_t)screensize);
if (dummy_buf == NULL){
fprintf(stderr, "Out of memory...\n");
return FBUTILS_ERROR_OUT_OF_MEMORY;
}
memcpy(tmp_buf, fbp, screensize);
memcpy(dummy_buf, fbp, screensize);
//memset(tmp_buf, (int)0, screensize+1);
//printf("screensize %i\n", screensize);
//printf("size of tmp buf: %i \n", sizeof(tmp_buf));
//use the fast plotroutine by default.
//
pPlot = plot_;
currentcolor = malloc(sizeof(struct Color));
currenttrafo = malloc(sizeof(struct Trafo));
currenttrafo3= malloc(sizeof(struct Trafo3));
kernel();
printf("yres = %i", vinfo.yres);fflush(stdout);
return 0;
}
int swappage(int i)
{
return -1;
}
int keepcurrent()
{
memcpy(tmp_buf, fbp, screensize);
return 0;
}
int setblurrad(int r)
{
blurrad = r;
}
int settrafo (struct Trafo *mytrafo)
{
currenttrafo->m11 = mytrafo->m11;
currenttrafo->m12 = mytrafo->m12;
currenttrafo->m21 = mytrafo->m21;
currenttrafo->m22 = mytrafo->m22;
currenttrafo->unity = mytrafo->unity;
return 0;
}
int settrafo3 (struct Trafo3 *mytrafo)
{
currenttrafo3->tetax = mytrafo->tetax;
currenttrafo3->tetay = mytrafo->tetay;
currenttrafo3->tetaz = mytrafo->tetaz;
currenttrafo3->ctetax = mytrafo->ctetax;
currenttrafo3->ctetay = mytrafo->ctetay;
currenttrafo3->ctetaz = mytrafo->ctetaz;
currenttrafo3->ex = mytrafo->ex;
currenttrafo3->ey = mytrafo->ey;
currenttrafo3->ez = mytrafo->ez;
currenttrafo3->cx = mytrafo->cx;
currenttrafo3->cy = mytrafo->cy;
currenttrafo3->cz = mytrafo->cz;
return 0;
}
int setwinparams( int x, int y, int width_, int height_,
unsigned char r, unsigned char g, unsigned char b,
unsigned char a,
unsigned char linestyle_,
int blur_, int blurrad_, int sigma_)
{
//this function should really be invoked
//each time a fb method is called
//maybe move color and style here too
//TODO: here we need a struct, soooooo
//many args are UGLY
Ox = x;
Oy = y;
width = width_;
width4 = width*BPP;
height = height_;
currentcolor->r = r;
currentcolor->g = g;
currentcolor->b = b;
currentcolor->a = a;
linestyle = linestyle_;
if (blur_ == 0) pPlot = plot_;
if (blur_ == 1) pPlot = plotalpha_;
if (blur_ == 2) pPlot = plotblurred_;
blurrad = blurrad_>5?5:blurrad_; //decided to put this here anywayzzzz
sigma = sigma_;
kernel();
return 0;
}
int getwinparams(int *x, int *y, int *wi, int *he)
{
*x = Ox;
*y = Oy;
*wi = width;
*he = height;
return 0;
}
int checkbounds()
{
int y=0;
int offset;
do {
offset = Ox*BPP + ((Oy+y) * finfo.line_length);
y++;
}while((offset<=(screensize-(width4)))&&(y<=height));
y--;
//printf("y = %i \n",y);
return (y);
}
int clearbuffer(char *buffy)
{
/*
* utility function
* either clear buffer
* or framebuffer
*/
int c = 0;
int y;
int pix_offset = 0;
int maxheight;
maxheight = checkbounds();
for (y=0; y < maxheight; y++){
pix_offset = (0+Ox*BPP) + ((Oy+y) * finfo.line_length);
memset(buffy+pix_offset, c, finfo.line_length);
}
//update();
return 0;
}
int cleartmpbuffer()
{
clearbuffer(tmp_buf);
return 0;
}
int clearscreen()
{
clearbuffer(fbp);
return 0;
}
int closefb(void)
{
//memcpy(fbp, dummy_buf, screensize);
munmap(fbp, screensize);
//free(fbp);
fbp=NULL;
free(currentcolor);
currentcolor = NULL;
free(currenttrafo);
currenttrafo = NULL;
free(currenttrafo3);
currenttrafo3 = NULL;
free(tmp_buf);
tmp_buf = NULL;
//if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo)) {
// fprintf(stderr, "Error re-setting variable information.\n");
//}
free(dummy_buf);
dummy_buf = NULL;
close(fbfd);
return 0;
}
int kernel()
{
int i, j;
float r2;
for (i=0; i<MAXBLUR; i++){
for (j=0;j<MAXBLUR;j++){
r2 = ((i-MAXBLURHALF)*(i-MAXBLURHALF) + (j-MAXBLURHALF)*(j-MAXBLURHALF)+0.02);
kern[i][j] = (unsigned char)(255.0*expf(-r2/blurrad/sigma));
}
}
return 0;
}
int plotalpha_(int x, int y)
{
unsigned int pix_offset;
float opacity;
float faintb, faintg, faintr, fainta;
float r,g,b, a;
//x = Ox + (x % width);
//y = Oy + (y % height);
if (x>width) return -1;
if (x<0) return -1;
if (y>height) return -1;
if (y<0) return -1;
x+=Ox;
y+=Oy;
pix_offset = BPP*x + y * finfo.line_length;
if (pix_offset<0) return -1;
if (pix_offset>screensize) return -1;
opacity = (float)(1.0 - ((unsigned char)currentcolor->a)/255.0);
b = (float)(*((unsigned char*)(tmp_buf + pix_offset)));
g = (float)(*((unsigned char*)(tmp_buf + pix_offset+1)));
r = (float)(*((unsigned char*)(tmp_buf + pix_offset+2)));
faintb = (float)((opacity * currentcolor->b) + b);
faintr = (float)((opacity * currentcolor->r) + r);
faintg = (float)((opacity * currentcolor->g) + g);
fainta = (float)(255.0 - ((255-*((unsigned char *)(tmp_buf + pix_offset + 3))) + (255-currentcolor->a)));
if (fainta<0) fainta = 0;
// what we want
// 0 = opacity., 255 = opaq
// old + new
// but we have
// 0 = opaq, 255 = opacity
// 255 - ((255-old) + (255-new))
// 255 - (510 -old -new) = -250 + old + new
//
if (faintb>255) faintb = (float)255;
if (faintr>255) faintr = (float)255;
if (faintg>255) faintg = (float)255;
*((char*)(tmp_buf + pix_offset)) = (unsigned char)faintb;
*((char*)(tmp_buf + pix_offset+1)) = (unsigned char)faintg;
*((char*)(tmp_buf + pix_offset+2)) = (unsigned char)faintr;
*((char*)(tmp_buf + pix_offset+3)) = (unsigned char)fainta;
return 0;
}
int plotblurred_(int x, int y)
{
struct Color tmpcol;
int i, j;
float fucktor; //r squared, yih
int r_max = blurrad;
int startx, starty, endx, endy;
tmpcol.r = currentcolor->r;
tmpcol.g = currentcolor->g;
tmpcol.b = currentcolor->b;
tmpcol.a = currentcolor->a;
startx = (x-r_max)<0?0:x-r_max;
endx = (x+r_max)>(Ox+width)?(Ox+width):x+r_max+1;
starty = (y-r_max)<0?0:y-r_max;
endy = (y+r_max)>(Oy+height)?(Oy+height):y+r_max+1;
fucktor = (1.0-(tmpcol.a/255.0));
//kernel();
for (i=startx; i<endx;i++){
for (j=starty; j<endy;j++){
// if the exp =0 a should be 255
// if exp =1 a below 255 but not 0
//
// 1 - (1-a)gauss
currentcolor->a =(unsigned char)(255.0 - fucktor * kern[i-x+MAXBLURHALF][j-y+MAXBLURHALF]);
plotalpha_(i, j);
}
}
currentcolor->a = tmpcol.a;
currentcolor->r = tmpcol.r;
currentcolor->g = tmpcol.g;
currentcolor->b = tmpcol.b;
return 0;
}
int get_pixel(int x, int y, struct Color *color, char *buffer)
{
unsigned int pix_offset;
x = Ox + (x % width);
y = Oy + (y % height);
pix_offset = BPP*x + y * finfo.line_length;
color->b = *((char *)(buffer + pix_offset));
color->g = *((char *)(buffer + pix_offset+1));
color->r = *((char *)(buffer + pix_offset+2));
color->a = *((char *)(buffer + pix_offset+3));
return 0;
}
int plot_(int x, int y)
{
//this is gonna be the fast implementation.
unsigned int pix_offset;
x = Ox + (x % width);
y = Oy + (y % height);
pix_offset = BPP*x + y * finfo.line_length;
*((char*)(tmp_buf + pix_offset)) = currentcolor->b;
*((char*)(tmp_buf + pix_offset+1)) = currentcolor->g;
*((char*)(tmp_buf + pix_offset+2)) = currentcolor->r;
*((char*)(tmp_buf + pix_offset+3)) = currentcolor->a;
return 0;
}
int plot(int x, int y)
{
pPlot(x, y);
return 0;
}
int fillrect(int x0, int y0, int w, int h)
{
int x;
int y;
for (x=0;x<w;x++)
for(y=0;y<h;y++)
pPlot(x0+x, y0+y);
return 0;
}
int snow()
{
//http://stackoverflow.com/questions/2572366/how-to-use-dev-random-or-urandom-in-c
//int surfsize =0;
//int pix_offset;
//int sub_offset;
//int y;
//char *snow_buf;
//FILE *fp;
tvsnow();
return 0;
/*
surfsize = height * width4;
snow_buf = malloc((size_t)surfsize);
fp = fopen("/dev/urandom", "r");
fread(snow_buf, 1, surfsize, fp);
fclose(fp);
for (y=0; y<height;y++){
pix_offset = (0+Ox*4) + ((Oy+y)*finfo.line_length);
sub_offset = y*width4;
memcpy(tmp_buf+pix_offset, snow_buf+sub_offset, width4);
}
free(snow_buf);
snow_buf=NULL;
return 0;
*/
}
int tvsnow()
{
int surfsize=0;
int x, y;
unsigned char *snow_buf=NULL;
struct Color tmpcol;
FILE *fp;
surfsize=height*width4;
snow_buf = malloc((size_t)surfsize);
fp = fopen("/dev/urandom", "r");
fread(snow_buf, 1, surfsize, fp);
fclose(fp);
tmpcol.r = currentcolor->r;
tmpcol.g = currentcolor->g;
tmpcol.b = currentcolor->b;
tmpcol.a = currentcolor->a;
for (x=2; x<(width);x+=5){
for (y=2;y< (height);y+=5){
currentcolor->r = *((unsigned char*)(snow_buf+BPP*x+(y*width4)));
currentcolor->g = *((unsigned char*)(snow_buf+BPP*x+(y*width4)+1));
currentcolor->b = *((unsigned char*)(snow_buf+BPP*x+(y*width4)+2));
currentcolor->a = (unsigned char)0;//*((char*)(snow_buf+BPP*x+(y*width4)));
plotblurred_(x+Ox, y+Oy);
}
}
free(snow_buf);
snow_buf=NULL;
currentcolor->a = tmpcol.a;
currentcolor->r = tmpcol.r;
currentcolor->g = tmpcol.g;
currentcolor->b = tmpcol.b;
return 0;
}
int waitforvsync(void)
{
/* fb_vsync:
* Waits for a retrace.
* straight from fbcon.c //cellom
*/
unsigned int prev;
#ifdef FBIOGET_VBLANK
struct fb_vblank vblank;
if (vblank_flags & FB_VBLANK_HAVE_STICKY) {
/* it's really good if sticky bits are available */
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
return -3;
do {
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
break;
} while (!(vblank.flags & FB_VBLANK_STICKY));
}
else if (vblank_flags & FB_VBLANK_HAVE_VCOUNT) {
/* we can read the exact scanline position, which avoids skipping */
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
return -3;
do {
prev = vblank.vcount;
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
break;
} while (vblank.vcount >= prev);
}
else if (vblank_flags & FB_VBLANK_HAVE_VBLANK) {
/* boring, normal style poll operation */
do {
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
break;
} while (vblank.flags & FB_VBLANK_VBLANKING);
do {
if (ioctl(fbfd, FBIOGET_VBLANK, &vblank) != 0)
break;
} while (!(vblank.flags & FB_VBLANK_VBLANKING));
}
else {}//no need for swearing printf("No SUPPORT for vsync shit, you FUCK\nAARHGGGHH!!!!");
#endif
/* bodged implementation for when the framebuffer doesn't support it */
/* We must not to run this loop while returning from a VT switch as timer
* "interrupts" will not be running at that time so retrace_count will
* remain constant.
if (_timer_installed && !in_fb_restore) {
prev = retrace_count;
do {
} while (retrace_count == (int)prev);
}*/
return 0;
}
int styledredraw()
{
/*
* this function redraws the canvas using
* the plot function, thus applying
* pixelstyle
*/
int x;
int y;
int xr;
int yr;
struct Color tempcolor;
//store buffer in temp mem
memcpy(dummy_buf, tmp_buf, screensize);
tempcolor.r = currentcolor->r;
tempcolor.g = currentcolor->g;
tempcolor.b = currentcolor->b;
tempcolor.a = currentcolor->a;
//redraw buffer form temp mem
//first clear it
clearbuffer(tmp_buf);
for (x=0; x<width;x++){
for (y=0;y<height;y++){
get_pixel(x, y, currentcolor, dummy_buf);
currentcolor->a = tempcolor.a;
xr = x;
yr = y;
if ((currentcolor->r!=0) || (currentcolor->g!=0) || (currentcolor->b!=0)){
//aint gonna tranform nonvisible pixels pixels. cmon.
transform(&xr, &yr);
if ((xr>0) && (xr<width)){
if ((yr>0)&&(yr<height)){
pPlot(xr,yr);
}
}
}
}
}
currentcolor->a = tempcolor.a;
currentcolor->r = tempcolor.r;
currentcolor->g = tempcolor.g;
currentcolor->b = tempcolor.b;
return 0;
}
int update(void)
{
int y;
int pix_offset = 0;
int maxheight;
maxheight = checkbounds();
for (y=0; y < maxheight; y++){
pix_offset = (0+Ox*BPP) + ((Oy+y) * finfo.line_length);
waitforvsync();
memcpy(fbp+pix_offset, tmp_buf+pix_offset, width4);
}
return 0;
}
int poly(int *x, int *y, int l)
{
int i;
l-=1;
for (i=0; i<l; i++){
line(x[i],y[i],x[i+1],y[i+1]);
}
return 0;
}
int matrixvec3(double m[9], int *x, int *y, int *z)
{
double xl,yl,zl;
xl = (double)(m[0]* *x + m[1]* *y + m[2]* *z);
yl = (double)(m[3]* *x + m[4]* *y + m[5]* *z);
zl = (double)(m[6]* *x + m[7]* *y + m[8]* *z);
*x = (int)xl;
*y = (int)yl;
*z = (int)zl;
return 0;
}
int rotate(double angle, int *x, int *y, int *z, char axis)
{
/*
* positioning values in rotation matrix
* value Z Y X
* ------------------
* cos 0 0 4
* cos 4 8 8
* sin 3 2 7
* -sin 1 6 5
* 1 8 4 0
* 0 2 1 1
* 0 5 3 2
* 0 6 5 3
* 0 7 7 6
*/
double m[9];
double C,S,nS;
static R[27]={4,8,7,5,0,1,2,3,6,
0,8,2,6,4,1,3,5,7,
0,4,3,1,8,2,5,6,7};
C = cos(-angle);
S = sin(-angle);
nS= -S;
*(m+*(R+0+axis)) = C;
*(m+*(R+1+axis)) = C;
*(m+*(R+2+axis)) = S;
*(m+*(R+3+axis)) = nS;
*(m+*(R+4+axis)) = 1.0;
*(m+*(R+5+axis)) = 0.0;
*(m+*(R+6+axis)) = 0.0;
*(m+*(R+7+axis)) = 0.0;
*(m+*(R+8+axis)) = 0.0;
matrixvec3(m, x, y, z);
return 0;
}
int project(int *x, int *y, int *z)
{
double bx,by;
if (
(currenttrafo3->tetaz==0.0) &&
(currenttrafo3->tetay==0.0) &&
(currenttrafo3->tetax==0.0) ){
goto Translate;
}
else{
rotate(currenttrafo3->tetaz,x, y, z,zaxis);
rotate(currenttrafo3->tetay,x, y, z,yaxis);
rotate(currenttrafo3->tetax,x, y, z,xaxis);
}
Translate:
*x -= (int)currenttrafo3->cx;
*y -= (int)currenttrafo3->cy;
*z -= (int)currenttrafo3->cz;
if (
(currenttrafo3->ctetaz==0.0) &&
(currenttrafo3->ctetay==0.0) &&
(currenttrafo3->ctetax==0.0) ){
goto projection;
}
else{
rotate(currenttrafo3->ctetaz,x, y, z,zaxis);
rotate(currenttrafo3->ctetay,x, y, z,yaxis);
rotate(currenttrafo3->ctetax,x, y, z,xaxis);
}
projection:
if ((*z>-1)) return -1;
// *z=-1.0;
bx = (double)(currenttrafo3->ez/ *z * *x - currenttrafo3->ex);
by = (double)(currenttrafo3->ez/ *z * *y - currenttrafo3->ey);
//bx = bx<0?0.0:bx;
//bx = bx>vinfo.xres?vinfo.xres:bx;
//by = by<0?0.0:by;
//by = by>vinfo.yres?vinfo.yres:by;
if (bx<0) return -1;
if (bx>width) return -1;
if (by<0) return -1;
if (by>height) return -1;
*x = (int)bx;
*y = (int)by;
return 0;
}
int poly3d(int *x, int *y, int *z, int l)
{
/*
* TODO:
* I am going to pass by ref
* and the project decides whether
* to mess up or not...
* you might wanna have a 'state'
* gott think this over...
*/
int i;
int xi,yi,zi; //local copies for messup
int xf,yf,zf;
l-=1;
for (i=0; i<l; i++){
xi=x[i];
yi=y[i];
zi=z[i];
xf=x[i+1];
yf=y[i+1];
zf=z[i+1];
if (!project(&xi,&yi,&zi))
if (!project(&xf,&yf,&zf))
line(xi,yi,xf,yf);
}
return 0;
}
int drawpolys(Polys *p)
{
int i;
int l;
for (i=0; i<p->polyc;i++){
l = *(p->polyl+i);
poly(*(p->x+i), *(p->y+i), l);
}
return 0;
}
int draw3dpolys(Polys *p)
{
int i;
int l;
for (i=0;i<p->polyc;i++){
l=*(p->polyl+i);
poly3d(*(p->x+i),*(p->y+i),*(p->z+i),l);
}
return 0;
}
int rotateX(int *x, int *y, int *z, struct TrafoL *trpms)
{
rotate(trpms->tetax, x, y, z,xaxis);
return 0;
}
int rotateY(int *x, int *y, int *z, struct TrafoL *trpms)
{
rotate(trpms->tetay, x, y, z,yaxis);
return 0;
}
int rotateZ(int *x, int *y, int *z, struct TrafoL *trpms)
{
rotate(trpms->tetaz, x, y, z,zaxis);
return 0;
}
int identity(int *x, int *y, int *z, struct TrafoL *trpms)
{
return 0;
}
int translate(int *x, int *y, int *z, struct TrafoL *trpms)
{
*x += trpms->dx;
*y += trpms->dy;
*z += trpms->dz;
return 0;
}
int seltrafo( Polys *p, struct TrafoL *trpms,
int (*lintrafo[]) (int *, int*, int *, struct TrafoL *),
int *order, int numtrafo)
{
int i, j, k, l;
int *x;
int *y;
int *z;
for (i=0;i<p->polyc;i++){
l=*(p->polyl+i);
for (j=0;j<l;j++){
x = (*(p->x+i)+j);
y = (*(p->y+i)+j);
z = (*(p->z+i)+j);
for (k=0;k<numtrafo;k++)
lintrafo[*(order+k)](x, y, z, trpms);
}
}
return 0;
}
int transform3d(Polys *p, struct TrafoL *trpms, int *order,int numtrafo)
{
lintrafo[0] = identity;
lintrafo[1] = rotateX;
lintrafo[2] = rotateY;
lintrafo[3] = rotateZ;
lintrafo[4] = translate;
seltrafo(p, trpms, lintrafo, order, numtrafo);
return 0;
}
int memblockcpy(char *to_buffer, int l, char DIRECTION)
{
//this is a helper function
//will probably put in separate
//lib function, with optimized
//compiler settings?
//NOT YET FINNISHED!!!!!!!!!!
int y;
int pix_offset;
int sub_offset;
//sub_offset = y * width * BPP
//and cannot exceed l
//l = y * width * BPP => y_max = l / (width * BPP)
//because of tmp_buff on the other hand, y_max cannot
//exceed height
y = l / width4;
if (y>height) y=height;
//guess this covers it for the moment.
if (DIRECTION == TO_BLOCK){
while(y--){
pix_offset = (Ox*BPP) + ((Oy+y)*finfo.line_length);
sub_offset = y*width4;
memcpy(to_buffer+sub_offset, tmp_buf+pix_offset, width4);
}
}
if (DIRECTION == FROM_BLOCK){
while(y--){
pix_offset = (Ox*BPP) + ((Oy+y)*finfo.line_length);
sub_offset = y*width4;
memcpy(tmp_buf+pix_offset, to_buffer+sub_offset, width4);
}
}
return 0;
}
int get_raw(char *sprite_buf, int l)
{
memblockcpy(sprite_buf, l, TO_BLOCK);
return 0;
}
int set_raw(char *sprite_buf, int l)
{
memblockcpy(sprite_buf, l, FROM_BLOCK);
return 0;
}
int transform(int *x, int *y)
{
//here we do some linalg. it is soooo
//simple: no gsl or thelike used
//TODO:
//apply petit 1998 stuff
float tmpx, tmpy,X, Y;
float centerX, centerY;
//come on, wont go through the trouble
//if it is a unity transform really
//mayB some otha trick in the future
//TODO:
if (currenttrafo->unity) return 0;
//for the moment we assume rotation around
//the center of the surface.
centerX = width/2.0;
centerY = height/2.0;
X = *x - centerX;
Y = *y - centerY;
tmpx = (currenttrafo->m11 * X) + (currenttrafo->m12 * Y);
tmpy = (currenttrafo->m21 * X) + (currenttrafo->m22 * Y);
*x = (int)(tmpx + centerX);
*y = (int)(tmpy + centerY);
return 0;
}
int line(int x0, int y0, int x1, int y1)
{
//http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm
int dx, dy, err;
int sx, sy, e2;
/*
if(transform(&x0, &y0)||transform(&x1, &y1)){
fprintf(stderr, "Transformation ERROR\n");
return -1;
}
*/
transform(&x0, &y0);
transform(&x1, &y1);
dx = abs(x1-x0);
sx = x0<x1 ? 1 : -1;
dy = abs(y1-y0);
sy = y0<y1 ? 1 : -1;
err = (dx>dy ? dx : -dy)/2;
//e2;
//char skipper = 0;
//not sure about this yet, but
//for the moment trafo is implemented
//here
for(;;){
//the style shit should become global,
//if you do poly s you want continuity etc..
//Right??
if (linestyle == 1) {
skipper++;
if (skipper<5) pPlot(x0, y0);
else if (skipper==10) skipper = 0;
}
if (linestyle == 2) {
if (skipper==1) {
pPlot(x0,y0);
skipper=0;
}else skipper++;
}
if (linestyle == 0) pPlot(x0, y0);
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
return 0;
}
int arc(int x0, int y0, int r1, int r2, int startseg, int endseg, int segs)
{
int i;
double alpha;
int x_old, y_old;
int x, y;
alpha = 2 * M_PI * startseg/segs;
x_old = (int)(r1*cos(alpha)+x0);
y_old = (int)(r2*sin(alpha)+y0);
for (i=(startseg+1); i<=endseg; i++){
alpha = 2 * M_PI * i/segs;
x = (int)(r1*cos(alpha)+x0);
y = (int)(r2*sin(alpha)+y0);
line(x_old, y_old, x, y);
x_old = x;
y_old = y;
}
return 0;
}
int circle(int x0, int y0, int r1, int segs)
{
return arc(x0, y0, r1, r1, 0, segs, segs);
}
int printxy(int x0, int y0, char *text, int size_)
{
int w=0;
int i,j;
int tx;
int ty;
static unsigned char mask[] = {128, 64, 32, 16, 8, 4, 2, 1};
struct Color backgrnd;
while (*(text+w)!=0){
for (i=0;i<CHARH;i++)
for (j=0;j<CHARW;j++)
if (CHARMAP[CHARH* *(text+w) + i] & mask[j]){
if (size_ == 1){
tx = x0+j+(CHARW*w);
ty = y0+i;
transform(&tx, &ty);
pPlot(tx, ty);
}
else{
pPlot(x0+j*3+(CHARW*w*3), y0+(i*3));
pPlot(x0+j*3+(CHARW*w*3)+1, y0+(i*3));
pPlot(x0+j*3+(CHARW*w*3), y0+(i*3)+1);
pPlot(x0+j*3+(CHARW*w*3)+1, y0+(i*3)+1);
}
}
w++;
if (w>255) return -1;//dont make long sentences...
}
return 0;
}
int graticule(int x0, int y0, int w, int h)
{
int i;
int j;
unsigned char tmpls; //line style store
int dx,dy;
double xstep;
double ystep;
int grid = 10;
struct Color dummycolor;
tmpls = linestyle;
xstep = 1.0*w/grid;
ystep = 1.0*h/grid;
for (i=0; i<=grid;i++){
dx = (int)(i*xstep);
dy = (int)(i*ystep);
if (i==5) {
linestyle = 0;
//dummycolor = *mycolor2;
}
else {
linestyle = 2;
//dummycolor = *mycolor;
}
//main cross
line(x0+dx,y0,x0+dx,y0+h);
line(x0,y0+dy,x0+w,y0+dy);
//ticks
line(x0+dx,y0+(int)(4.8*ystep), x0+dx, y0+(int)(5.2*ystep));
line(x0+(int)(4.8*xstep),y0+dy,x0+(int)(5.2*xstep),y0+dy);
}
linestyle = tmpls;
//currentcolor =
return 0;
}
int getHeight()
{
return vinfo.yres;
}
int getWidth()
{
return vinfo.xres;
}
int overlay(char *res_buf, char *sprite_buf, int xo, int yo, char sprmode)
{
int offset;
int offn4,offo4; //offn * 4
int voffo, voffn;
int pix_offset;
int l;
int Oxsb, Oysb, wsb4, hsb;
int LOx, LOy; //local winparams
int tailn, tailo; //tail + offset = width
int vtailn, vtailo;
int tmpL; //mod tails
int xi,yi;
/*
* Determine the major square containing sprite @
* old position and new position,
* I'll call this me scratchbook sb
* Ill copy current fb to sb
* restore with res_buf, grab the new res_buf
* patch N draw the sprite @ new R in tmp_buf.
* finaly copy tmp_buf to fb
*
* returns -1 if new crds are outabounds
* returns -2 if old ---,,---
*/
/*
* and prevent segfaultHELLLLL
*
* and leave stage gracefully...
*/
if (-Ox>=width) return -1;
//negative Ox would be > line_length wo
//(int)
if (Ox>=(int)vinfo.xres) return -1;
if (-Oy>=height) return -1;
if (Oy>=(int)vinfo.yres) return -1;
if (-xo>=width) return -2;
if (xo>=(int)vinfo.xres) return -2;
if (-yo>=height) return -2;
if (yo>=(int)vinfo.yres) return -2;
if (Ox<0){
LOx = 0;
offn4 = BPP*-Ox;
}
else{
LOx = Ox;
offn4 = 0;
}
if (Oy<0){
LOy=0;
voffn = -Oy;
}
else{
LOy = Oy;
voffn = 0;
}
if (xo<0){
offo4 = -BPP*xo;
xo = 0;
}
else{
offo4 =0;
}
if (yo<0){
voffo = -yo;
yo=0;
}
else{
voffo=0;
}
tmpL=finfo.line_length-BPP*xo;
if (tmpL<width4)
tailo = tmpL;
else
tailo = width4-offo4;
tmpL=finfo.line_length-BPP*Ox;
if (tmpL < width4){
tailn = tmpL;
}
else{
tailn = width4-offn4;
}
tmpL = vinfo.yres - yo;
if (tmpL<height)
vtailo = tmpL;
else
vtailo = height-voffo;
tmpL = vinfo.yres -Oy;
if (tmpL<height)
vtailn = tmpL;
else
vtailn = height-voffn;
if (Ox>xo){
Oxsb = xo;
wsb4 = BPP*(LOx-xo)+tailn;
}
else{
Oxsb = LOx;
wsb4 = BPP*(xo-LOx)+tailo;
}
if (Oy>yo){
Oysb = yo;
hsb = LOy-yo+vtailn;
}
else{
Oysb = LOy;
hsb = yo-LOy+vtailo;
}
/*
* Dump current framebuffer to a dummy buffer
* then I'll restore the old sprite patch
* here. This will give a pre sprite era
* /situation
*/
pix_offset = Oxsb*BPP + Oysb*finfo.line_length;
l=hsb;
while(l--){
memcpy(dummy_buf+pix_offset, fbp+pix_offset, wsb4);
pix_offset+=finfo.line_length;
}
/* restore dummy (current) frambefuffer
* Like no sprite had ever messed up my
*background
*/
pix_offset = xo*BPP + yo*finfo.line_length;
offset = offo4+(voffo*width4);
l=vtailo;
while(l--){
memcpy(tmp_buf+pix_offset, res_buf+offset, tailo);
memcpy(dummy_buf+pix_offset, res_buf+offset, tailo);
pix_offset += finfo.line_length;
offset+=width4;
}
/* prepare new patch
* by grabn new sprite
* pos from restored fb
* AND
* draw new sprite into tmp_buffer
*/
if (sprmode==1){
//TON;
for (yi=0;yi<vtailn;yi++){
offset = (yi+voffn)*width4+offn4;
pix_offset = LOx*BPP+(LOy+yi)*finfo.line_length;
for(xi=0;xi<tailn;xi++){
*(res_buf+offset) = *(dummy_buf+pix_offset);
if (*(sprite_buf+offset)!=0){
*(tmp_buf+pix_offset) = *(sprite_buf+offset);
}
offset++;
pix_offset++;
}
}
//TOFF;
}
//dumps tmp_buff into frambebuffer
//only scratchbook size ofcourse
pix_offset = Oxsb*BPP + Oysb*finfo.line_length;
l=hsb;
waitforvsync();
while(l--){
memcpy(fbp+pix_offset, tmp_buf+pix_offset, wsb4);
pix_offset+=finfo.line_length;
}
return 0;
}
int helloworld(int x, int y)
{
printf("Hello world %i + %i = %i!!\n", x, y, x+y);
return 0;
}
int mandelbrot()
{
//just a gimick,
//but fun
return 0;
}
int read_PNG(char *file_name)
{
/*
* Took this code from doc/fblib
* and adjusted it to the likings
* of this program.
* ?i
* It is really awesome that a NOOB
* like me, Noisegate can actually
* make useable software on an open
* system like this Linux...
*
* openSOFtWARE rocKS
*/
png_structp png_ptr;
png_infop info_ptr;
unsigned int sig_read = 0;
png_uint_32 _width, _height, row;
int bit_depth, color_type, interlace_type;
FILE *fp;
float screen_gamma;
if ((fp = fopen(file_name, "rb")) == NULL)
return -1;
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also supply the
* the compiler header file version, so that we know if the application
* was compiled with a compatible version of the library. REQUIRED
*/
//png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp user_error_ptr, user_error_fn, user_warning_fn);
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
(png_voidp)NULL,
(png_error_ptr)NULL,
(png_error_ptr)NULL);
if (png_ptr == NULL){
fclose(fp);
return -1;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
return -1;
}
/* Set error handling if you are using the setjmp/longjmp method (this is
* the normal method of doing things with libpng). REQUIRED unless you
* set up your own error handlers in the png_create_read_struct() earlier.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
fclose(fp);
/* If we get here, we had a problem reading the file */
fprintf(stderr, "Error: Couldn't read the file.");
return -1;
}
/* One of the following I/O initialization methods is REQUIRED */
/* Set up the input control if you are using standard C streams */
png_init_io(png_ptr, fp);
/* If we have already read some of the signature */
png_set_sig_bytes(png_ptr, sig_read);
/* OK, you're doing it the hard way, with the lower-level functions */
/* The call to png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk). REQUIRED
*/
png_read_info(png_ptr, info_ptr);
png_get_IHDR(png_ptr, info_ptr, &_width, &_height, &bit_depth, &color_type,
&interlace_type, int_p_NULL, int_p_NULL);
/* Set up the data transformations you want. Note that these are all
* optional. Only call them if you want/need them. Many of the
* transformations only work on specific types of images, and many
* are mutually exclusive.
*/
/* Tell libpng to strip 16 bit/color files down to 8 bits/color */
png_set_strip_16(png_ptr);
/* Strip alpha bytes from the input data without combining with the
* background (not recommended).
*/
//png_set_strip_alpha(png_ptr);
/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
* byte into separate bytes (useful for paletted and grayscale images).
*/
png_set_packing(png_ptr);
/* Change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing). */
png_set_packswap(png_ptr);
/* Expand paletted colors into true RGB triplets */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
/* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand_gray_1_2_4_to_8(png_ptr);
/* Expand paletted or RGB images with transparency to full alpha channels
* so the data will be available as RGBA quartets.
*/
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
/* Set the background color to draw transparent and alpha images over.
* It is possible to set the red, green, and blue components directly
* for paletted images instead of supplying a palette index. Note that
* even if the PNG file supplies a background, you are not required to
* use it - you should use the (solid) application background if it has one.
*/
png_color_16 my_background, *image_background;
if (png_get_bKGD(png_ptr, info_ptr, &image_background))
png_set_background(png_ptr, image_background,
PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
else
png_set_background(png_ptr, &my_background,
PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
screen_gamma = 1.0;
int intent;
if (png_get_sRGB(png_ptr, info_ptr, &intent))
png_set_gamma(png_ptr, screen_gamma, 0.45455);
else
{
double image_gamma;
if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
png_set_gamma(png_ptr, screen_gamma, image_gamma);
else
png_set_gamma(png_ptr, screen_gamma, 0.45455);
}
/* Invert monochrome files to have 0 as white and 1 as black */
png_set_invert_mono(png_ptr);
/* If you want to shift the pixel values from the range [0,255] or
* [0,65535] to the original [0,7] or [0,31], or whatever range the
* colors were originally in:
*/
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
{
png_color_8p sig_bit_p;
png_get_sBIT(png_ptr, info_ptr, &sig_bit_p);
png_set_shift(png_ptr, sig_bit_p);
}
/* Flip the RGB pixels to BGR (or RGBA to BGRA) */
if (color_type & PNG_COLOR_MASK_COLOR)
png_set_bgr(png_ptr);
/* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
png_set_swap_alpha(png_ptr);
/* Swap bytes of 16 bit files to least significant byte first */
png_set_swap(png_ptr);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
png_set_filler(png_ptr, 0x00, PNG_FILLER_AFTER);
/* Turn on interlace handling. REQUIRED if you are not using
* png_read_image(). To see how to handle interlacing passes,
* see the png_read_row() method below:
*/
//number_passes = png_set_interlace_handling(png_ptr);
/* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (ie you selected such a transform above).
*/
png_read_update_info(png_ptr, info_ptr);
/* Allocate the memory to hold the image using the fields of info_ptr. */
/* The easiest way to read the image: */
png_bytep row_pointers[_height];
/* Clear the pointer array */
for (row = 0; row < _height; row++)
row_pointers[row] = NULL;
for (row = 0; row < _height; row++)
row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
info_ptr));
/* Now it's time to read the image. One of these methods is REQUIRED */
png_read_image(png_ptr, row_pointers);
/* Now mess this rowpointer thing into the tmp_buf
* U dont know if width>_width and height>_height
* so we trunc the guy
*/
int maxY = _height>height?height:_height;
int maxX = _width>width?finfo.line_length:_width;
int pix_offset=0;
for (row=0; row<maxY;row++){
pix_offset = Ox*BPP + ((Oy+row)*finfo.line_length);
memcpy(tmp_buf+pix_offset, row_pointers[row], maxX*BPP);
}
/* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(png_ptr, info_ptr);
/* At this point you have read the entire image */
/* Clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
/* Close the file */
fclose(fp);
//printf("png W x H = %i x %i\n", _width, _height);
/* That's it */
return 0;
}
int write_PNG(char *filename, int interlace, char borfb)
{
//hardcore theft from fbgrab.c
/*
* fbgrab - takes screenshots using the framebuffer.
*
* (C) Gunnar Monell <gmo@linux.nu> 2002
*
* This program is free Software, see the COPYING file
* and is based on Stephan Beyer's <fbshot@s-beyer.de> FBShot
* (C) 2000.
*
* For features and differences, read the manual page.
*
* This program has been checked with "splint +posixlib" without
* warnings. Splint is available from http://www.splint.org/ .
* Patches and enhancements of fbgrab have to fulfill this too.
*/
png_uint_32 i;
int bit_depth=0, color_type;
png_uint_32 uheight, uwidth;
uheight = (png_uint_32)height;
uwidth = (png_uint_32)width;
png_bytep row_pointers[uheight];
png_structp png_ptr;
png_infop info_ptr;
FILE *outfile = fopen(filename, "wb");
interlace = PNG_INTERLACE_NONE;
//printf ("%d, %d\n", uheight, uwidth);
//well, either from the buffer or the framebuffer...
//yih, gotta clean this one up, reallyyyyy
//
if (borfb == 0)
for (i=0; i<uheight; i++)
row_pointers[i] = (unsigned char *)(fbp + (BPP*Ox) + (Oy + i) * 1 * (finfo.line_length/*uwidth+10*/));
if (borfb == 1)
for (i=0; i<uheight; i++)
row_pointers[i] = (unsigned char *)(tmp_buf + (BPP*Ox) + (Oy + i) * 1 * (finfo.line_length/*uwidth+10*/));
if (!outfile){
fprintf (stderr, "Error: Couldn't fopen %s.\n", filename);
return -1;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
(png_voidp) NULL, (png_error_ptr) NULL, (png_error_ptr) NULL);
if (!png_ptr){
fprintf(stderr,"Error: Couldn't create PNG write struct.");
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr){
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
fprintf(stderr, "Error: Couldn't create PNG info struct.");
return -1;
}
if (setjmp(png_jmpbuf(png_ptr))){
fclose(outfile);
png_destroy_write_struct(&png_ptr, &info_ptr);
return -2;
}
png_init_io(png_ptr, outfile);
//png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
bit_depth = 8;
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
png_set_IHDR(png_ptr, info_ptr, uwidth, uheight,
bit_depth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
//png_set_packing(png_ptr);
png_set_invert_alpha(png_ptr);
//
//png_set function must be after set_IHDR
//according to libpng-manual
png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
png_set_filler(png_ptr, 0 , PNG_FILLER_BEFORE);
png_set_bgr(png_ptr);
png_write_info(png_ptr, info_ptr);
//printf ("Now writing PNG file\n");
png_write_image(png_ptr, row_pointers);
//png_write_rows(png_ptr, row_pointers, uheight);
png_write_end(png_ptr, info_ptr);
//puh, done, now freeing memory...
png_destroy_write_struct(&png_ptr, &info_ptr);
if (outfile != NULL)
(void) fclose(outfile);
//printf("Done writing...\n");
return 0;
}
/*
* TODO:
double Sx[3][3];
double Sy[3][3];
Sx[0][0] = 1.0;
Sx[0][1] = 0.0;
Sx[0][2] = 0.0;
Sx[1][0] = 0.0;
Sx[1][1] = 1.0;
Sx[1][2] = 0.0;
Sx[2][0] = -tan(-angle/2.0);
Sx[2][1] = 0.0;
Sx[2][2] = 1.0;
Sy[0][0] = 1.0;
Sy[0][1] = 0.0;
Sy[0][2] = sin(-angle);
Sy[1][0] = 0.0;
Sy[1][1] = 1.0;
Sy[1][2] = 0.0;
Sy[2][0] = 0.0;
Sy[2][1] = 0.0;
Sy[2][2] = 1.0;
matrixvec3(Sx, x, y, z);
matrixvec3(Sy, x, y, z);
matrixvec3(Sx, x, y, z);
*/