/* $Id$ */
/*
* Copyright (c) 2009 Dimitri Sokolyuk <sokolyuk@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct point Point;
typedef struct patch Patch;
struct point {
float x, y, z;
} *point, *ppoint, max;
struct patch {
int p[16];
} *patch, *ppatch;
int tekheight = 3072;
int tekwidth = 4096;
int npoints = 100;
void
sc(char c)
{
putchar(c);
}
void
ss(char *s)
{
while (*s)
putchar(*s++);
}
void
tekenable(int flag)
{
if (flag) {
sc(27); ss("[?38h");
} else {
sc(27); sc(003);
}
}
void
tekclear()
{
tekenable(1);
sc(27); sc(014);
tekenable(0);
}
void
tekpen(int flag)
{
if (flag) {
sc(29); sc(007);
} else {
sc(29);
}
}
void
tekcoord(unsigned int x, unsigned int y)
{
unsigned char lox, loy, hix, hiy, eb;
static unsigned char lloy, lhix, lhiy, leb;
lloy = lhix = lhiy = leb = 0xff;
if (y >= tekheight)
y = tekheight - 1;
if (x >= tekwidth)
x = tekwidth - 1;
hiy = (y >> 7) & 0x1f;
loy = (y >> 2) & 0x1f;
hix = (x >> 7) & 0x1f;
lox = (x >> 2) & 0x1f;
eb = (x & 3) | ((y & 3) << 2);
if (hiy != lhiy)
sc(hiy | 0x20);
if (eb != leb)
sc(eb | 0x60);
if (eb != leb || loy != lloy || hix != lhix)
sc(loy | 0x60);
if (hix != lhix)
sc(hix | 0x20);
sc(lox | 0x40);
lhiy = hiy;
lhix = hix;
lloy = loy;
leb = eb;
}
void
loadpatch(char *filename, int *patches, int *verticles)
{
int ii, jj;
float x, y, z;
int a, b, c, d;
FILE *fd;
fd = fopen(filename, "r");
if (!fd)
err(1, "can't open %s", filename);
fscanf(fd, "%i\n", patches);
patch = calloc(*patches, sizeof(Patch));
if (!patch)
err(1, "can't allocate memory");
ppatch = patch;
for (ii = 0; ii < *patches; ii++) {
jj = 0;
a = 0;
b = 0;
c = 0;
d = 0;
fscanf(fd, "%i, %i, %i, %i,", &a, &b, &c, &d);
ppatch->p[jj++] = --a;
ppatch->p[jj++] = --b;
ppatch->p[jj++] = --c;
ppatch->p[jj++] = --d;
fscanf(fd, "%i, %i, %i, %i,", &a, &b, &c, &d);
ppatch->p[jj++] = --a;
ppatch->p[jj++] = --b;
ppatch->p[jj++] = --c;
ppatch->p[jj++] = --d;
fscanf(fd, "%i, %i, %i, %i,", &a, &b, &c, &d);
ppatch->p[jj++] = --a;
ppatch->p[jj++] = --b;
ppatch->p[jj++] = --c;
ppatch->p[jj++] = --d;
fscanf(fd, "%i, %i, %i, %i\n", &a, &b, &c, &d);
ppatch->p[jj++] = --a;
ppatch->p[jj++] = --b;
ppatch->p[jj++] = --c;
ppatch->p[jj++] = --d;
++ppatch;
}
fscanf(fd, "%i\n", verticles);
point = calloc(*verticles, sizeof(Point));
if (!point)
err(1, "can't allocate memory");
ppoint = point;
max.x = 0;
max.y = 0;
max.z = 0;
for (ii = 0; ii < *verticles; ii++) {
fscanf(fd, "%f, %f, %f\n", &x, &y, &z);
ppoint->x = x;
if (abs(x) > max.x)
max.x = abs(x);
ppoint->y = y;
if (abs(y) > max.y)
max.y = abs(y);
ppoint->z = z;
if (abs(z) > max.z)
max.z = abs(z);
++ppoint;
}
fclose(fd);
}
int
rnd(float f)
{
if (f > 0)
f += 0.5;
else
f -= 0.5;
return (int)f;
}
void
rotx(Point *p)
{
p->y = 0.5 * p->y + 0.866 * p->z;
p->z = -0.866 * p->y + 0.5 * p->z;
}
void
project(Point *p)
{
float d = 100 * max.z;
float zoom = 1000;
rotx(p);
p->x *= d/(2*d - p->z);
p->y *= d/(2*d - p->z);
p->x *= zoom;
p->y *= zoom;
p->x += tekwidth/2;
p->y += tekheight/3;
tekcoord(rnd(p->x), rnd(p->y));
}
void
vec(Point *a, Point *b, float lambda)
{
a->x += lambda*(b->x - a->x);
a->y += lambda*(b->y - a->y);
a->z += lambda*(b->z - a->z);
}
void
bezier(Patch *pp, int step, int steps)
{
Point p[16];
int i, j, k;
float s = (float)step/(float)steps;
for (i = 0; i < 16; i++) {
k = pp->p[i];
p[i].x = point[k].x;
p[i].y = point[k].y;
p[i].z = point[k].z;
}
for (i = 15; i > 0; i--)
for (j = 0; j < i; j++)
vec(&p[j], &p[j + 1], s);
project(p);
}
void
usage()
{
extern char *__progname;
fprintf(stderr, "usage: %s datafile\n", __progname);
exit(1);
}
int
main(int argc, char **argv)
{
int patches, verticles;
int i, j;
if (argc != 2)
usage();
loadpatch(*++argv, &patches, &verticles);
tekclear();
tekenable(1);
for (i = 0; i < patches; i++) {
tekpen(0);
for (j = 0; j < npoints; j++)
bezier(&patch[i], j, npoints);
tekpen(1);
}
tekenable(0);
return 0;
}