git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@219 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2181 lines
61 KiB
C
2181 lines
61 KiB
C
/* -----------------------------------------------------------------------------
|
|
* plot3d.c
|
|
*
|
|
* Three-dimensional plotting.
|
|
*
|
|
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
|
|
* Copyright (C) 1995-1996
|
|
*
|
|
* See the file LICENSE for information on usage and redistribution.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#define PLOT3D
|
|
#include "gifplot.h"
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
#define ORTHO 1
|
|
#define PERSPECTIVE 2
|
|
/* ------------------------------------------------------------------------
|
|
Plot3D *new_Plot3D(FrameBuffer *f, double xmin, double ymin, double zmin,
|
|
double xmax, double ymax, double zmax)
|
|
|
|
Creates a new 3D plot. Min and max coordinates are primarily used to
|
|
pick some default parameters. Returns NULL on failure
|
|
------------------------------------------------------------------------- */
|
|
|
|
Plot3D *new_Plot3D(FrameBuffer *f, double xmin, double ymin, double zmin,
|
|
double xmax, double ymax, double zmax) {
|
|
|
|
Plot3D *p3;
|
|
void Plot3D_maketransform(Plot3D *p3);
|
|
|
|
/* Check to make sure the framebuffer and min/max parameters are valid */
|
|
|
|
if (!f) return (Plot3D *) 0;
|
|
if ((xmin > xmax) || (ymin > ymax) || (zmin > zmax)) return (Plot3D *) 0;
|
|
|
|
p3 = (Plot3D *) malloc(sizeof(Plot3D));
|
|
p3->frame = f;
|
|
p3->xmin = xmin;
|
|
p3->ymin = ymin;
|
|
p3->zmin = zmin;
|
|
p3->xmax = xmax;
|
|
p3->ymax = ymax;
|
|
p3->zmax = zmax;
|
|
|
|
/* Set view region to the entire size of the framebuffer */
|
|
|
|
p3->view_xmin = 0;
|
|
p3->view_ymin = 0;
|
|
p3->view_xmax = f->width;
|
|
p3->view_ymax = f->height;
|
|
p3->width = f->width;
|
|
p3->height = f->height;
|
|
|
|
/* Calculate a center point based off the min and max coordinates given */
|
|
|
|
p3->xcenter = (xmax - xmin)/2.0 + xmin;
|
|
p3->ycenter = (ymax - ymin)/2.0 + ymin;
|
|
p3->zcenter = (zmax - zmin)/2.0 + zmin;
|
|
|
|
/* Calculate the aspect ratio of the viewing region */
|
|
|
|
p3->aspect = (double) f->width/(double) f->height;
|
|
|
|
/* Set default view parameters */
|
|
p3->xshift = 1.0;
|
|
p3->yshift = 1.0;
|
|
p3->zoom = 0.5;
|
|
p3->fovy = 40.0; /* 40 degree field of view */
|
|
|
|
/* Create matrices */
|
|
|
|
p3->model_mat = new_Matrix();
|
|
p3->view_mat = new_Matrix();
|
|
p3->center_mat = new_Matrix();
|
|
p3->fullmodel_mat = new_Matrix();
|
|
p3->trans_mat = new_Matrix();
|
|
p3->pers_mode = ORTHO;
|
|
|
|
FrameBuffer_zresize(p3->frame,p3->width, p3->height);
|
|
Matrix_identity(p3->view_mat);
|
|
Matrix_identity(p3->model_mat);
|
|
Matrix_translate(p3->center_mat, -p3->xcenter,-p3->ycenter,-p3->zcenter);
|
|
Plot3D_maketransform(p3);
|
|
return p3;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
delete_Plot3D(Plot3D *p3)
|
|
|
|
Deletes a 3D plot
|
|
--------------------------------------------------------------------- */
|
|
|
|
void delete_Plot3D(Plot3D *p3) {
|
|
if (p3) {
|
|
delete_Matrix(p3->view_mat);
|
|
delete_Matrix(p3->model_mat);
|
|
delete_Matrix(p3->trans_mat);
|
|
free((char *) p3);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D *Plot3D_copy(Plot3D *p3)
|
|
|
|
This makes a copy of the 3D plot structure and returns a pointer to it.
|
|
--------------------------------------------------------------------- */
|
|
|
|
Plot3D *Plot3D_copy(Plot3D *p3) {
|
|
Plot3D *c3;
|
|
if (p3) {
|
|
c3 = (Plot3D *) malloc(sizeof(Plot3D));
|
|
if (c3) {
|
|
c3->frame = p3->frame;
|
|
c3->view_xmin = p3->view_xmin;
|
|
c3->view_ymin = p3->view_ymin;
|
|
c3->view_xmax = p3->view_xmax;
|
|
c3->view_ymax = p3->view_ymax;
|
|
c3->xmin = p3->xmin;
|
|
c3->ymin = p3->ymin;
|
|
c3->zmin = p3->zmin;
|
|
c3->xmax = p3->xmax;
|
|
c3->ymax = p3->ymax;
|
|
c3->zmax = p3->zmax;
|
|
c3->xcenter = p3->xcenter;
|
|
c3->ycenter = p3->ycenter;
|
|
c3->zcenter = p3->zcenter;
|
|
c3->fovy = p3->fovy;
|
|
c3->aspect = p3->aspect;
|
|
c3->znear = p3->znear;
|
|
c3->zfar = p3->zfar;
|
|
c3->center_mat = Matrix_copy(p3->center_mat);
|
|
c3->model_mat = Matrix_copy(p3->model_mat);
|
|
c3->view_mat = Matrix_copy(p3->view_mat);
|
|
c3->fullmodel_mat = Matrix_copy(p3->fullmodel_mat);
|
|
c3->trans_mat = Matrix_copy(p3->trans_mat);
|
|
c3->lookatz = p3->lookatz;
|
|
c3->xshift = p3->xshift;
|
|
c3->yshift = p3->yshift;
|
|
c3->zoom = p3->zoom;
|
|
c3->width = p3->width;
|
|
c3->height = p3->height;
|
|
c3->pers_mode = p3->pers_mode;
|
|
}
|
|
return c3;
|
|
} else {
|
|
return (Plot3D *) 0;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_clear(Plot3D *p3, Pixel bgcolor)
|
|
|
|
Clear the pixel and zbuffer only for the view region of this image.
|
|
---------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_clear(Plot3D *p3, Pixel bgcolor) {
|
|
int i,j;
|
|
|
|
for (i = p3->view_xmin; i < p3->view_xmax; i++)
|
|
for (j = p3->view_ymin; j < p3->view_ymax; j++) {
|
|
p3->frame->pixels[j][i] = bgcolor;
|
|
p3->frame->zbuffer[j][i] = ZMIN;
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D_maketransform(Plot3D *p3)
|
|
|
|
This function builds the total 3D transformation matrix from a
|
|
collection of components.
|
|
|
|
Trans = View * Rotation * Center
|
|
|
|
Where View is the viewing transformation matrix, Rotation is the
|
|
model rotation matrix, Center is the translation matrix used to
|
|
center the Model at the origin.
|
|
--------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_maketransform(Plot3D *p3) {
|
|
|
|
Matrix_multiply(p3->model_mat,p3->center_mat, p3->fullmodel_mat);
|
|
Matrix_multiply(p3->view_mat,p3->fullmodel_mat, p3->trans_mat);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D_perspective(Plot3D *p3, double fovy, double znear, double zfar)
|
|
|
|
Sets up the perspective viewing transformation. Assumes "lookat"
|
|
has already been called.
|
|
--------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_perspective(Plot3D *p3, double fovy, double znear, double zfar) {
|
|
double theta;
|
|
double mat[16];
|
|
|
|
p3->fovy = fovy;
|
|
p3->znear = znear;
|
|
p3->zfar = zfar;
|
|
|
|
theta = 3.1415926*fovy/180.0;
|
|
|
|
Matrix_identity(mat);
|
|
mat[0] = cos(theta/2.0)/(sin(theta/2.0)*p3->aspect);
|
|
mat[5] = cos(theta/2.0)/(sin(theta/2.0));
|
|
mat[10] = -(zfar + znear)/(zfar-znear);
|
|
mat[14] = -1.0;
|
|
mat[11] = -(2*zfar*znear)/(zfar - znear);
|
|
mat[15] = 0.0;
|
|
|
|
/* Update the view transformation matrix */
|
|
|
|
Matrix_multiply(mat,p3->view_mat,p3->view_mat);
|
|
|
|
/* Update the global transformation matrix */
|
|
|
|
Plot3D_maketransform(p3);
|
|
p3->pers_mode = PERSPECTIVE;
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D_lookat(Plot3D *p3, double z)
|
|
|
|
A greatly simplified version of (lookat). Specifies the position
|
|
of the viewpoint. (can be used for moving image in or out).
|
|
|
|
Destroys the current viewing transformation matrix, so it will have
|
|
to be recalculated.
|
|
--------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_lookat(Plot3D *p3, double z) {
|
|
if (p3) {
|
|
Matrix_translate(p3->view_mat, 0,0,-z);
|
|
p3->lookatz = z;
|
|
Plot3D_maketransform(p3);
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_autoperspective(Plot3D *p3, double fovy)
|
|
|
|
Automatically figures out a semi-decent viewpoint given the
|
|
min,max parameters currently set for this image
|
|
------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_autoperspective(Plot3D *p3, double fovy) {
|
|
|
|
/* Make a perspective transformation matrix for this system */
|
|
|
|
double zfar;
|
|
double znear;
|
|
double d, dmax;
|
|
double cx,cy,cz;
|
|
double xmin,xmax,ymin,ymax,zmin,zmax;
|
|
|
|
xmin = p3->xmin;
|
|
ymin = p3->ymin;
|
|
zmin = p3->zmin;
|
|
xmax = p3->xmax;
|
|
ymax = p3->ymax;
|
|
zmax = p3->zmax;
|
|
cx = p3->xcenter;
|
|
cy = p3->ycenter;
|
|
cz = p3->zcenter;
|
|
|
|
/* Calculate longest point from center point */
|
|
|
|
dmax = (xmin-cx)*(xmin-cx) + (ymin-cy)*(ymin-cy) + (zmin-cz)*(zmin-cz);
|
|
d = (xmax-cx)*(xmax-cx) + (ymin-cy)*(ymin-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymax-cy)*(ymax-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymax-cy)*(ymax-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymin-cy)*(ymin-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymin-cy)*(ymin-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymax-cy)*(ymax-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymax-cy)*(ymax-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
|
|
dmax = sqrt(dmax);
|
|
d = p3->lookatz;
|
|
|
|
znear = d - dmax;
|
|
zfar = znear+1.5*dmax;
|
|
Plot3D_perspective(p3, fovy,znear,zfar);
|
|
|
|
}
|
|
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D_ortho(Plot3D *p3, double left, double right, double bottom, double top)
|
|
|
|
Sets up an orthographic viewing transformation.
|
|
--------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_ortho(Plot3D *p3, double left, double right, double bottom, double top) {
|
|
|
|
|
|
Matrix_identity(p3->view_mat);
|
|
p3->view_mat[0] = (2.0/(right - left))/p3->aspect;
|
|
p3->view_mat[5] = 2.0/(top - bottom);
|
|
p3->view_mat[10] = -1;
|
|
p3->view_mat[15] = 1.0;
|
|
p3->view_mat[3] = -(right+left)/(right-left);
|
|
p3->view_mat[7] = -(top+bottom)/(top-bottom);
|
|
|
|
/* Update the global transformation matrix */
|
|
|
|
Plot3D_maketransform(p3);
|
|
p3->pers_mode = ORTHO;
|
|
p3->ortho_left = left;
|
|
p3->ortho_right = right;
|
|
p3->ortho_bottom = bottom;
|
|
p3->ortho_top = top;
|
|
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
Plot3D_autoortho(Plot3D *p3)
|
|
|
|
Automatically pick an orthographic projection that's probably
|
|
pretty good.
|
|
--------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_autoortho(Plot3D *p3) {
|
|
|
|
/* Make a perspective transformation matrix for this system */
|
|
|
|
double d, dmax;
|
|
double cx,cy,cz;
|
|
double xmin,xmax,ymin,ymax,zmin,zmax;
|
|
|
|
xmin = p3->xmin;
|
|
ymin = p3->ymin;
|
|
zmin = p3->zmin;
|
|
xmax = p3->xmax;
|
|
ymax = p3->ymax;
|
|
zmax = p3->zmax;
|
|
cx = p3->xcenter;
|
|
cy = p3->ycenter;
|
|
cz = p3->zcenter;
|
|
|
|
/* Calculate longest point from center point */
|
|
|
|
dmax = (xmin-cx)*(xmin-cx) + (ymin-cy)*(ymin-cy) + (zmin-cz)*(zmin-cz);
|
|
d = (xmax-cx)*(xmax-cx) + (ymin-cy)*(ymin-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymax-cy)*(ymax-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymax-cy)*(ymax-cy) + (zmin-cz)*(zmin-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymin-cy)*(ymin-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymin-cy)*(ymin-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmin-cx)*(xmin-cx) + (ymax-cy)*(ymax-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
d = (xmax-cx)*(xmax-cx) + (ymax-cy)*(ymax-cy) + (zmax-cz)*(zmax-cz);
|
|
if (d > dmax) dmax = d;
|
|
|
|
dmax = sqrt(dmax);
|
|
|
|
Plot3D_ortho(p3,-dmax,dmax,-dmax,dmax);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_setview(Plot3D *p3, int vxmin, int vymin, int vxmax, int vymax)
|
|
|
|
Sets the viewport for this 3D graph. Will recalculate all of the
|
|
local viewing transformation matrices accordingly.
|
|
------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_setview(Plot3D *p3, int vxmin, int vymin, int vxmax, int vymax) {
|
|
if (p3) {
|
|
if ((vxmin > vxmax) || (vymin >vymax)) return;
|
|
p3->view_xmin = vxmin;
|
|
p3->view_ymin = vymin;
|
|
p3->view_xmax = vxmax;
|
|
p3->view_ymax = vymax;
|
|
p3->width = (vxmax - vxmin);
|
|
p3->height = (vymax - vymin);
|
|
p3->aspect = (double) p3->width/(double) p3->height;
|
|
|
|
/* Fix up the viewing transformation matrix */
|
|
|
|
if (p3->pers_mode == PERSPECTIVE) {
|
|
Plot3D_lookat(p3,p3->lookatz);
|
|
Plot3D_perspective(p3,p3->fovy,p3->znear,p3->zfar);
|
|
} else {
|
|
Plot3D_ortho(p3,p3->ortho_left,p3->ortho_right,p3->ortho_bottom, p3->ortho_top);
|
|
}
|
|
FrameBuffer_setclip(p3->frame,vxmin,vymin,vxmax,vymax);
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Plot2D_start(Plot2D *p3)
|
|
|
|
Set up viewing region and other parameters for this image.
|
|
--------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_start(Plot3D *p3) {
|
|
if (p3)
|
|
FrameBuffer_setclip(p3->frame, p3->view_xmin,p3->view_ymin,p3->view_xmax, p3->view_ymax);
|
|
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_plot(Plot3D *p3, double x, double y, double z, Pixel Color)
|
|
|
|
Plot a 3D point
|
|
------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_plot(Plot3D *p3, double x, double y, double z, Pixel color) {
|
|
|
|
GL_Vector t;
|
|
int ix, iy;
|
|
double invw;
|
|
FrameBuffer *f;
|
|
|
|
/* Perform a transformation */
|
|
|
|
Matrix_transform4(p3->trans_mat,x,y,z,1,&t);
|
|
|
|
/* Scale the coordinates into unit cube */
|
|
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
#ifdef GL_DEBUG
|
|
fprintf(stdout,"t.x = %g, t.y = %g, t.z = %g\n", t.x,t.y,t.z);
|
|
#endif
|
|
/* Calculate the x and y coordinates */
|
|
|
|
ix = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5);
|
|
iy = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5);
|
|
|
|
if ((ix >= 0) && (ix < p3->width) &&
|
|
(iy >= 0) && (ix < p3->height)) {
|
|
ix += p3->view_xmin;
|
|
iy += p3->view_ymin;
|
|
f = p3->frame;
|
|
if (t.z <= f->zbuffer[iy][ix]) {
|
|
f->pixels[iy][ix] = color;
|
|
f->zbuffer[iy][ix] = t.z;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotx(Plot3D *p3, double deg)
|
|
|
|
Rotate the model around its x axis.
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotx(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatex(temp,deg); /* Construct a x rotation matrix */
|
|
Matrix_multiply(p3->model_mat,temp,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_roty(Plot3D *p3, double deg)
|
|
|
|
Rotate the model around its y axis.
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_roty(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatey(temp,deg); /* Construct a y rotation matrix */
|
|
Matrix_multiply(p3->model_mat,temp,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotz(Plot3D *p3, double deg)
|
|
|
|
Rotate the model around its z axis.
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotz(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatez(temp,deg); /* Construct a z rotation matrix */
|
|
Matrix_multiply(p3->model_mat,temp,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotd(Plot3D *p3, double deg)
|
|
|
|
Rotate the model down
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotd(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatex(temp,deg); /* Construct a x rotation matrix */
|
|
Matrix_multiply(temp, p3->model_mat,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotu(Plot3D *p3, double deg)
|
|
|
|
Rotate the model up
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotu(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatex(temp,-deg); /* Construct a x rotation matrix */
|
|
Matrix_multiply(temp,p3->model_mat,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotr(Plot3D *p3, double deg)
|
|
|
|
Rotate the model down
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotr(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatey(temp,deg); /* Construct a y rotation matrix */
|
|
Matrix_multiply(temp, p3->model_mat,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotl(Plot3D *p3, double deg)
|
|
|
|
Rotate the model left
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotl(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatey(temp,-deg); /* Construct a y rotation matrix */
|
|
Matrix_multiply(temp,p3->model_mat,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Plot3D_rotc(Plot3D *p3, double deg)
|
|
|
|
Rotate the model around center point
|
|
---------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_rotc(Plot3D *p3, double deg) {
|
|
double temp[16];
|
|
|
|
Matrix_rotatez(temp,-deg); /* Construct a z rotation matrix */
|
|
Matrix_multiply(temp,p3->model_mat,p3->model_mat);
|
|
Plot3D_maketransform(p3);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_zoom(Plot3D *p3, double percent)
|
|
|
|
Zooms in or out the current image. percent defines a percentage of
|
|
zoom.
|
|
|
|
Zooming is actually done by adjusting the perspective field of view
|
|
instead of scaling the model or moving in the viewpoint. This
|
|
seems to work the best.
|
|
------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_zoom(Plot3D *p3, double percent) {
|
|
|
|
double scale;
|
|
double dx;
|
|
if (percent <= 0) return;
|
|
scale = percent/100.0;
|
|
|
|
dx = (1.0/scale - 1.0)/(2*p3->zoom); /* Don't even ask where this came from */
|
|
p3->xshift += dx;
|
|
p3->yshift += dx;
|
|
p3->zoom = p3->zoom*scale;
|
|
|
|
#ifdef OLD
|
|
p3->fovy = p3->fovy*scale;
|
|
if (p3->fovy > 170.0) p3->fovy = 170.0;
|
|
if (p3->fovy == 0) p3->fovy = 0.0001;
|
|
Plot3D_lookat(p3,p3->lookatz);
|
|
Plot3D_perspective(p3,p3->fovy,p3->znear,p3->zfar);
|
|
#endif
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Plot3D_left(Plot3D *p3, double s)
|
|
|
|
Shifts the image to the left by s units. This is a little funky.
|
|
|
|
s is scaled so that s = 100 equals one full screen.
|
|
-------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_left(Plot3D *p3, double s) {
|
|
p3->xshift -= (s/100.0)/p3->zoom;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Plot3D_right(Plot3D *p3, double s)
|
|
|
|
Shifts the image to the right by s units.
|
|
|
|
s is scaled so that s = 100 equals one full screen.
|
|
-------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_right(Plot3D *p3, double s) {
|
|
p3->xshift += (s/100.0)/p3->zoom;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Plot3D_up(Plot3D *p3, double s)
|
|
|
|
Shifts the image up left by s units.
|
|
|
|
s is scaled so that s = 100 equals one full screen.
|
|
-------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_up(Plot3D *p3, double s) {
|
|
p3->yshift += (s/100.0)/p3->zoom;
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Plot3D_down(Plot3D *p3, double s)
|
|
|
|
Shifts the image down by s units.
|
|
|
|
s is scaled so that s = 100 equals one full screen.
|
|
-------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_down(Plot3D *p3, double s) {
|
|
p3->yshift -= (s/100.0)/p3->zoom;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_center(Plot3D *p3, double cx, double cy)
|
|
|
|
Centers the image on a point in the range (0,0) - (100,100)
|
|
------------------------------------------------------------------------- */
|
|
void
|
|
Plot3D_center(Plot3D *p3, double cx, double cy) {
|
|
Plot3D_left(p3,cx-50);
|
|
Plot3D_down(p3,cy-50);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
* 3d Primitives *
|
|
***************************************************************************/
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_horizontal(Plot3D *p3, int xmin, int xmax, int y, double z1, double z2, Pixel color)
|
|
|
|
Draws a "Horizontal" line on the framebuffer between two screen coordinates,
|
|
but also supplies z-values and zbuffering. This function probably isn't
|
|
too useful by itself, but will be used by a number of other primitives.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_horizontal(Plot3D *p3, int xmin, int xmax, int y, Zvalue z1, Zvalue z2, Pixel color) {
|
|
Pixel *p;
|
|
FrameBuffer *f;
|
|
int i;
|
|
Zvalue *zbuf,z,mz;
|
|
int startx, endx;
|
|
|
|
f = p3->frame;
|
|
if ((y < f->ymin) || (y >= f->ymax)) return;
|
|
if (xmin > f->xmax) return;
|
|
if (xmin < f->xmin) startx = f->xmin;
|
|
else startx = xmin;
|
|
if (xmax < f->xmin) return;
|
|
if (xmax >= f->xmax) endx = f->xmax - 1;
|
|
else endx = xmax;
|
|
|
|
/* Calculate z slope */
|
|
|
|
if (xmax != xmin) {
|
|
mz = (Zvalue) ((double) (z2 - z1)/(double) (xmax - xmin));
|
|
} else {
|
|
mz = 0;
|
|
}
|
|
|
|
/* Draw it */
|
|
|
|
p = &f->pixels[y][startx];
|
|
zbuf = &f->zbuffer[y][startx];
|
|
z = (Zvalue) (mz*(startx-xmin) + z1);
|
|
for (i = startx; i <= endx; i++, p++, zbuf++,z+=mz) {
|
|
if (z <= *zbuf) {
|
|
*p = color;
|
|
*zbuf = z;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_vertical(Plot3D *p3, int ymin, int ymax, int x, double z1, double z2, Pixel color)
|
|
|
|
Draws a "Vertical" line on the framebuffer between two screen coordinates,
|
|
but also supplies z-values and zbuffering. This function probably isn't
|
|
too useful by itself, but will be used by a number of other primitives.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_vertical(Plot3D *p3, int ymin, int ymax, int x, Zvalue z1, Zvalue z2, Pixel color) {
|
|
Pixel *p;
|
|
FrameBuffer *f;
|
|
int i;
|
|
Zvalue *zbuf,z,mz;
|
|
int starty, endy;
|
|
|
|
f = p3->frame;
|
|
if ((x < f->xmin) || (x >= f->xmax)) return;
|
|
if (ymin >= f->ymax) return;
|
|
if (ymin < f->ymin) starty = f->ymin;
|
|
else starty = ymin;
|
|
if (ymax < f->ymin) return;
|
|
if (ymax >= f->ymax) endy = f->ymax - 1;
|
|
else endy = ymax;
|
|
|
|
/* Calculate z slope */
|
|
|
|
mz = (double) (z2 - z1)/(double) (ymax - ymin);
|
|
|
|
/* Draw it */
|
|
|
|
p = &f->pixels[starty][x];
|
|
zbuf = &f->zbuffer[starty][x];
|
|
for (i = starty; i <= endy; i++, p+=f->width, zbuf+=f->width) {
|
|
z = (Zvalue) (mz*(i-ymin) + z1);
|
|
if (z <= *zbuf) {
|
|
*p = color;
|
|
*zbuf = z;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------------
|
|
Plot3D_linetransform(Plot3D *p3, int x1, int y1, Zvalue z1,
|
|
int x2, int y2, Zvalue z2, Pixel c)
|
|
|
|
Draw a 3D line between points that have already been transformed into
|
|
3D space.
|
|
|
|
Uses a Bresenham line algorithm, but with linear interpolation between
|
|
Zvalues.
|
|
------------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_linetransform(Plot3D *p3, int x1, int y1, Zvalue z1, int x2, int y2, Zvalue z2, Pixel c) {
|
|
|
|
int orig_x1, orig_y1, orig_x2,orig_y2;
|
|
Zvalue zt;
|
|
|
|
/* Bresenham line drawing parameters */
|
|
FrameBuffer *f;
|
|
int dx,dy,dxneg,dyneg, inc1,inc2,di;
|
|
int x, y, xpixels, ypixels, xt, yt;
|
|
Pixel *p;
|
|
double m;
|
|
int end1 = 0, end2 = 0;
|
|
Zvalue *zbuf,mz,z;
|
|
|
|
f = p3->frame;
|
|
|
|
/* Need to figure out where in the heck this line is */
|
|
|
|
dx = x2 - x1;
|
|
dy = y2 - y1;
|
|
|
|
if ((dx == 0) && (dy == 0)) {
|
|
if ((x1 < f->xmin) || (x1 >= f->xmax) ||
|
|
(y1 < f->ymin) || (y1 >= f->ymax)) return;
|
|
if (z1 <= f->zbuffer[y1][x1]) {
|
|
f->pixels[y1][x1] = c;
|
|
}
|
|
return;
|
|
}
|
|
if (dx == 0) {
|
|
/* Draw a Vertical Line */
|
|
if (y1 < y2)
|
|
Plot3D_vertical(p3,y1,y2,x1,z1,z2,c);
|
|
else
|
|
Plot3D_vertical(p3,y2,y1,x1,z2,z1,c);
|
|
return;
|
|
}
|
|
if (dy == 0) {
|
|
/* Draw a Horizontal Line */
|
|
if (x1 < x2)
|
|
Plot3D_horizontal(p3,x1,x2,y1,z1,z2,c);
|
|
else
|
|
Plot3D_horizontal(p3,x2,x1,y1,z2,z1,c);
|
|
return;
|
|
}
|
|
|
|
/* Figure out where in the heck these lines are using the
|
|
Cohen-Sutherland Line Clipping Scheme. */
|
|
|
|
end1 = ((x1 - f->xmin) < 0) |
|
|
(((f->xmax- 1 - x1) < 0) << 1) |
|
|
(((y1 - f->ymin) < 0) << 2) |
|
|
(((f->ymax-1 - y1) < 0) << 3);
|
|
|
|
end2 = ((x2 - f->xmin) < 0) |
|
|
(((f->xmax-1 - x2) < 0) << 1) |
|
|
(((y2 - f->ymin) < 0) << 2) |
|
|
(((f->ymax-1 - y2) < 0) << 3);
|
|
|
|
if (end1 & end2) return; /* Nope : Not visible */
|
|
|
|
/* Make sure points have a favorable orientation */
|
|
|
|
if (x1 > x2) {
|
|
xt = x1;
|
|
x1 = x2;
|
|
x2 = xt;
|
|
yt = y1;
|
|
y1 = y2;
|
|
y2 = yt;
|
|
zt = z1;
|
|
z1 = z2;
|
|
z2 = zt;
|
|
}
|
|
|
|
/* Save original points before we clip them off */
|
|
orig_x1 = x1;
|
|
orig_y1 = y1;
|
|
orig_x2 = x2;
|
|
orig_y2 = y2;
|
|
|
|
/* Clip against the boundaries */
|
|
m = (y2 - y1)/(double) (x2-x1);
|
|
if (x1 < f->xmin) {
|
|
y1 = (f->xmin - x1)*m + y1;
|
|
x1 = f->xmin;
|
|
}
|
|
if (x2 >= f->xmax) {
|
|
y2 = (f->xmax -1 -x1)*m + y1;
|
|
x2 = f->xmax - 1;
|
|
}
|
|
|
|
if (y1 > y2) {
|
|
xt = x1;
|
|
x1 = x2;
|
|
x2 = xt;
|
|
yt = y1;
|
|
y1 = y2;
|
|
y2 = yt;
|
|
zt = z1;
|
|
z1 = z2;
|
|
z2 = zt;
|
|
|
|
/* Swap original points */
|
|
|
|
xt = orig_x1;
|
|
orig_x1 = orig_x2;
|
|
orig_x2 = xt;
|
|
yt = orig_y1;
|
|
orig_y1 = orig_y2;
|
|
orig_y2 = yt;
|
|
}
|
|
|
|
m = 1/m;
|
|
if (y1 < f->ymin) {
|
|
x1 = (f->ymin - y1)*m + x1;
|
|
y1 = f->ymin;
|
|
}
|
|
if (y2 >= f->ymax) {
|
|
x2 = (f->ymax-1-y1)*m + x1;
|
|
y2 = f->ymax-1;
|
|
}
|
|
|
|
if ((x1 < f->xmin) || (x1 >= f->xmax) || (y1 < f->ymin) || (y1 >= f->ymax) ||
|
|
(x2 < f->xmin) || (x2 >= f->xmax) || (y2 < f->ymin) || (y2 >= f->ymax)) return;
|
|
|
|
dx = x2 - x1;
|
|
dy = y2 - y1;
|
|
xpixels = f->width;
|
|
ypixels = f->height;
|
|
|
|
dxneg = (dx < 0) ? 1 : 0;
|
|
dyneg = (dy < 0) ? 1 : 0;
|
|
|
|
dx = abs(dx);
|
|
dy = abs(dy);
|
|
if (dx >= dy) {
|
|
/* Slope between -1 and 1. */
|
|
mz = (z2 - z1)/(orig_x2 - orig_x1); /* Z interpolation slope */
|
|
if (dxneg) {
|
|
x = x1;
|
|
y = y1;
|
|
x1 = x2;
|
|
y1 = y2;
|
|
x2 = x;
|
|
y2 = y;
|
|
dyneg = !dyneg;
|
|
}
|
|
inc1 = 2*dy;
|
|
inc2 = 2*(dy-dx);
|
|
di = 2*dy-dx;
|
|
|
|
/* Draw a line using x as independent variable */
|
|
|
|
p = &f->pixels[y1][x1];
|
|
zbuf = &f->zbuffer[y1][x1];
|
|
x = x1;
|
|
while (x <= x2) {
|
|
/* Do a z-buffer check */
|
|
z = mz*(x-orig_x1)+z1;
|
|
if (z <= *zbuf){
|
|
*p = c;
|
|
*zbuf = z;
|
|
}
|
|
p++;
|
|
zbuf++;
|
|
if (di < 0) {
|
|
di = di + inc1;
|
|
} else {
|
|
if (dyneg) {
|
|
p = p - xpixels;
|
|
zbuf = zbuf - xpixels;
|
|
di = di + inc2;
|
|
} else {
|
|
p = p + xpixels;
|
|
zbuf = zbuf + xpixels;
|
|
di = di + inc2;
|
|
}
|
|
}
|
|
x++;
|
|
}
|
|
} else {
|
|
/* Slope < -1 or > 1 */
|
|
mz = (z2 - z1)/(double) (orig_y2 - orig_y1);
|
|
if (dyneg) {
|
|
x = x1;
|
|
y = y1;
|
|
x1 = x2;
|
|
y1 = y2;
|
|
x2 = x;
|
|
y2 = y;
|
|
dxneg = !dxneg;
|
|
}
|
|
inc1 = 2*dx;
|
|
inc2 = 2*(dx-dy);
|
|
di = 2*dx-dy;
|
|
|
|
/* Draw a line using y as independent variable */
|
|
|
|
p = &f->pixels[y1][x1];
|
|
zbuf = &f->zbuffer[y1][x1];
|
|
y = y1;
|
|
while (y <= y2) {
|
|
/* Do a z-buffer check */
|
|
z = mz*(y-orig_y1)+z1;
|
|
if (z <= *zbuf) {
|
|
*p = c;
|
|
*zbuf = z;
|
|
}
|
|
p = p + xpixels;
|
|
zbuf = zbuf + xpixels;
|
|
if (di < 0) {
|
|
di = di + inc1;
|
|
} else {
|
|
if (dxneg) {
|
|
p = p - 1;
|
|
zbuf = zbuf - 1;
|
|
di = di + inc2;
|
|
} else {
|
|
p = p + 1;
|
|
zbuf = zbuf + 1;
|
|
di = di + inc2;
|
|
}
|
|
}
|
|
y++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Plot3D_line(Plot3D *p3, double x1, double y1, double z1, double x2, double y2, double z2,int color)
|
|
|
|
Draws a line in 3D space. This is done as follows (for lack of a better
|
|
method).
|
|
|
|
1. The points (x1,y1,z1) and (x2,y2,z2) are transformed into screen coordinates
|
|
2. We draw the line using a modified Bresenham line algorithm.
|
|
3. Zbuffer values are linearly interpolated between the two points.
|
|
---------------------------------------------------------------------------- */
|
|
|
|
void
|
|
Plot3D_line(Plot3D *p3, double fx1, double fy1, double fz1, double fx2, double fy2,
|
|
double fz2, Pixel c) {
|
|
|
|
/* 3D Transformation parameters */
|
|
GL_Vector t;
|
|
double invw;
|
|
int x1,y1,x2,y2;
|
|
Zvalue z1,z2;
|
|
|
|
/* Transform the two points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,fx1,fy1,fz1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
x1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
y1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
z1 = t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,fx2,fy2,fz2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
x2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
y2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
z2 = t.z;
|
|
Plot3D_linetransform(p3,x1,y1,z1,x2,y2,z2,c);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_triangle(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
Pixel fillcolor)
|
|
|
|
This function draws a 3D z-buffered outline triangle.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_triangle(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3, Pixel color) {
|
|
|
|
int tx1, tx2, tx3, ty1, ty2, ty3;
|
|
Zvalue tz1, tz2, tz3;
|
|
GL_Vector t;
|
|
double invw;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,x1,y1,z1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x2,y2,z2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x3,y3,z3,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx3 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty3 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
|
|
Plot3D_linetransform(p3,tx1,ty1,tz1,tx2,ty2,tz2,color);
|
|
Plot3D_linetransform(p3,tx1,ty1,tz1,tx3,ty3,tz3,color);
|
|
Plot3D_linetransform(p3,tx2,ty2,tz2,tx3,ty3,tz3,color);
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_solidtriangletransform(Plot3D *p3, int tx1, int ty2, Zvalue tz1,
|
|
int tx2, int ty2, Zvalue tz2,
|
|
int tx3, int ty3, Zvalue tz3, Pixel color)
|
|
|
|
This function draws a 3D z-buffered filled triangle. Assumes three
|
|
points have already been transformed into screen coordinates.
|
|
|
|
General idea :
|
|
1. Transform the three points into screen coordinates
|
|
2. Order three points vertically on screen.
|
|
3. Check for degenerate cases (where 3 points are colinear).
|
|
4. Fill in the resulting triangle using horizontal lines.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_solidtriangletransform(Plot3D *p3, int tx1, int ty1, Zvalue tz1,
|
|
int tx2, int ty2, Zvalue tz2,
|
|
int tx3, int ty3, Zvalue tz3, Pixel color) {
|
|
int tempx, tempy;
|
|
Zvalue tempz;
|
|
double m1,m2,m3, mz1, mz2, mz3;
|
|
int y;
|
|
int ix1, ix2;
|
|
Zvalue zz1, zz2;
|
|
FrameBuffer *f;
|
|
register double fy1,fy2;
|
|
register Zvalue fz1,fz2;
|
|
|
|
f = p3->frame;
|
|
|
|
/* Check for degenerate cases here */
|
|
|
|
if ((ty1 == ty2) && (ty2 == ty3)) {
|
|
if (tx2 < tx1) { /* Swap points 1 and 2 if 2 is higher */
|
|
tempx = tx1;
|
|
tempz = tz1;
|
|
tx1 = tx2;
|
|
tz1 = tz2;
|
|
tx2 = tempx;
|
|
tz2 = tempz;
|
|
}
|
|
if (tx3 < tx1) { /* Swap points 1 and 3 if 3 is higher */
|
|
tempx = tx1;
|
|
tempz = tz1;
|
|
tx1 = tx3;
|
|
tz1 = tz3;
|
|
tx3 = tempx;
|
|
tz3 = tempz;
|
|
}
|
|
if (tx3 < tx2) { /* Swap points 2 and 3 if 3 is higher */
|
|
tempx = tx2;
|
|
tempz = tz2;
|
|
tx2 = tx3;
|
|
tz2 = tz3;
|
|
tx3 = tempx;
|
|
tz3 = tempz;
|
|
}
|
|
|
|
/* Points are aligned horizontally. Handle as a special case */
|
|
/* Just draw three lines using the outline color */
|
|
|
|
Plot3D_horizontal(p3,tx1,tx2,ty1,tz1,tz3,color);
|
|
|
|
/* Plot3D_linetransform(p3,tx1,ty1,tz1,tx2,ty2,tz2,color);
|
|
Plot3D_linetransform(p3,tx1,ty1,tz1,tx3,ty3,tz3,color);
|
|
Plot3D_linetransform(p3,tx2,ty2,tz2,tx3,ty3,tz3,color);
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
/* Figure out which point has the greatest "y" value */
|
|
|
|
if (ty2 > ty1) { /* Swap points 1 and 2 if 2 is higher */
|
|
tempx = tx1;
|
|
tempy = ty1;
|
|
tempz = tz1;
|
|
tx1 = tx2;
|
|
ty1 = ty2;
|
|
tz1 = tz2;
|
|
tx2 = tempx;
|
|
ty2 = tempy;
|
|
tz2 = tempz;
|
|
}
|
|
if (ty3 > ty1) { /* Swap points 1 and 3 if 3 is higher */
|
|
tempx = tx1;
|
|
tempy = ty1;
|
|
tempz = tz1;
|
|
tx1 = tx3;
|
|
ty1 = ty3;
|
|
tz1 = tz3;
|
|
tx3 = tempx;
|
|
ty3 = tempy;
|
|
tz3 = tempz;
|
|
}
|
|
if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */
|
|
tempx = tx2;
|
|
tempy = ty2;
|
|
tempz = tz2;
|
|
tx2 = tx3;
|
|
ty2 = ty3;
|
|
tz2 = tz3;
|
|
tx3 = tempx;
|
|
ty3 = tempy;
|
|
tz3 = tempz;
|
|
}
|
|
|
|
/* Points are now order so that t_1 is the highest point, t_2 is the
|
|
middle point, and t_3 is the lowest point */
|
|
|
|
if (ty2 < ty1) {
|
|
/* First process line segments between (x1,y1)-(x2,y2)
|
|
And between (x1,y1),(x3,y3) */
|
|
|
|
m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
|
|
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
|
|
mz1 = (tz2 - tz1)/(double) (ty2 - ty1);
|
|
mz2 = (tz3 - tz1)/(double) (ty3 - ty1);
|
|
|
|
y = ty1;
|
|
fy1 = m1*(y-ty1)+0.5 + tx1;
|
|
fy2 = m2*(y-ty1)+0.5 + tx1;
|
|
fz1 = mz1*(y-ty1) + tz1;
|
|
fz2 = mz2*(y-ty1) + tz1;
|
|
while (y >= ty2) {
|
|
/* Replace with bresenham scheme */
|
|
/* Calculate x values from slope */
|
|
ix1 = (int) fy1;
|
|
ix2 = (int) fy2;
|
|
zz1 = fz1;
|
|
zz2 = fz2;
|
|
fy1-= m1;
|
|
fy2-= m2;
|
|
fz1-= mz1;
|
|
fz2-= mz2;
|
|
if (ix1 > ix2)
|
|
Plot3D_horizontal(p3,ix2,ix1,y,zz2,zz1,color);
|
|
else
|
|
Plot3D_horizontal(p3,ix1,ix2,y,zz1,zz2,color);
|
|
y--;
|
|
}
|
|
}
|
|
if (ty3 < ty2) {
|
|
/* Draw lower half of the triangle */
|
|
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
|
|
m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
|
|
mz2 = (tz3 - tz1)/(double) (ty3 - ty1);
|
|
mz3 = (tz3 - tz2)/(double) (ty3 - ty2);
|
|
y = ty2;
|
|
while (y >= ty3) {
|
|
ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
|
|
ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
|
|
zz1 = mz3*(y-ty2)+tz2;
|
|
zz2 = mz2*(y-ty1)+tz1;
|
|
if (ix1 > ix2)
|
|
Plot3D_horizontal(p3,ix2,ix1,y,zz2,zz1,color);
|
|
else
|
|
Plot3D_horizontal(p3,ix1,ix2,y,zz1,zz2,color);
|
|
y--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_solidtriangle(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
Pixel color)
|
|
|
|
This function draws a 3D z-buffered filled triangle. Can be used to
|
|
draw other primitives such as quadralaterals, etc...
|
|
|
|
This function simply transforms the given points and calls
|
|
Plot3D_SolidTriangleTransform().
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_solidtriangle(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3, Pixel color) {
|
|
|
|
int tx1, tx2, tx3, ty1, ty2, ty3;
|
|
Zvalue tz1, tz2, tz3;
|
|
GL_Vector t;
|
|
double invw;
|
|
Matrix a;
|
|
register double xshift, yshift, zoom, width, height, view_xmin, view_ymin;
|
|
|
|
a = p3->trans_mat;
|
|
xshift = p3->xshift;
|
|
yshift = p3->yshift;
|
|
zoom = p3->zoom;
|
|
height = p3->height;
|
|
width = p3->width;
|
|
view_xmin = p3->view_xmin;
|
|
view_ymin = p3->view_ymin;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
t.w = a[12]*x1 + a[13]*y1 + a[14]*z1 + a[15];
|
|
invw = 1.0/t.w;
|
|
t.x = (a[0]*x1 + a[1]*y1 + a[2]*z1 + a[3])*invw;
|
|
t.y = (a[4]*x1 + a[5]*y1 + a[6]*z1 + a[7])*invw;
|
|
t.z = (a[8]*x1 + a[9]*y1 + a[10]*z1 + a[11])*invw;
|
|
|
|
tx1 = (int) ((t.x +xshift)*zoom*width + 0.5) + view_xmin;
|
|
ty1 = (int) ((t.y +yshift)*zoom*height + 0.5) + view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
|
|
t.w = a[12]*x2 + a[13]*y2 + a[14]*z2 + a[15];
|
|
invw = 1.0/t.w;
|
|
t.x = (a[0]*x2 + a[1]*y2 + a[2]*z2 + a[3])*invw;
|
|
t.y = (a[4]*x2 + a[5]*y2 + a[6]*z2 + a[7])*invw;
|
|
t.z = (a[8]*x2 + a[9]*y2 + a[10]*z2 + a[11])*invw;
|
|
tx2 = (int) ((t.x +xshift)*zoom*width + 0.5) + view_xmin;
|
|
ty2 = (int) ((t.y +yshift)*zoom*height + 0.5) + view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
t.w = a[12]*x3 + a[13]*y3 + a[14]*z3 + a[15];
|
|
invw = 1.0/t.w;
|
|
t.x = (a[0]*x3 + a[1]*y3 + a[2]*z3 + a[3])*invw;
|
|
t.y = (a[4]*x3 + a[5]*y3 + a[6]*z3 + a[7])*invw;
|
|
t.z = (a[8]*x3 + a[9]*y3 + a[10]*z3 + a[11])*invw;
|
|
tx3 = (int) ((t.x +xshift)*zoom*width + 0.5) + view_xmin;
|
|
ty3 = (int) ((t.y +yshift)*zoom*height + 0.5) + view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
Plot3D_solidtriangletransform(p3,tx1,ty1,tz1,tx2,ty2,tz2,tx3,ty3,tz3,color);
|
|
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_horizontalinterp(Plot3D *p3, int xmin, int xmax, int y,
|
|
double z1, double z2, Pixel c1, Pixel c2)
|
|
|
|
Draws a "Horizontal" line on the framebuffer between two screen coordinates,
|
|
but also supplies z-values and zbuffering. Performs a color interpolation
|
|
between c1 and c2. This is primarily used by the SolidTriangleInterp()
|
|
function to give the illusion of smooth surfaces.
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_horizontalinterp(Plot3D *p3, int xmin, int xmax, int y,
|
|
Zvalue z1, Zvalue z2, Pixel c1, Pixel c2) {
|
|
Pixel *p;
|
|
FrameBuffer *f;
|
|
int i;
|
|
Zvalue *zbuf,z,mz;
|
|
double mc;
|
|
int startx, endx;
|
|
double invdx;
|
|
|
|
f = p3->frame;
|
|
if ((y < f->ymin) || (y >= f->ymax)) return;
|
|
if (xmin >= f->xmax) return;
|
|
if (xmin < f->xmin) startx = f->xmin;
|
|
else startx = xmin;
|
|
if (xmax < f->xmin) return;
|
|
if (xmax >= f->xmax) endx = f->xmax - 1;
|
|
else endx = xmax;
|
|
|
|
/* Calculate z slope */
|
|
if (xmax != xmin) {
|
|
invdx = 1.0/(double) (xmax-xmin);
|
|
} else {
|
|
invdx = 0;
|
|
}
|
|
|
|
mz = (Zvalue) (z2 - z1)*invdx;
|
|
|
|
/* Calculate c slope */
|
|
|
|
mc = (double) (c2 - c1)*invdx;
|
|
|
|
/* Draw it */
|
|
|
|
p = &f->pixels[y][startx];
|
|
zbuf = &f->zbuffer[y][startx];
|
|
for (i = startx; i <= endx; i++, p++, zbuf++) {
|
|
z = (Zvalue) (mz*(i-xmin) + z1);
|
|
if (z <= *zbuf) {
|
|
*p = (Pixel) (mc*(i-xmin)+c1);
|
|
*zbuf = z;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_interptriangletransform(Plot3D *p3,
|
|
int tx1, int ty2, Zvalue tz1, Pixel c1,
|
|
int tx2, int ty2, Zvalue tz2, Pixel c2,
|
|
int tx3, int ty3, Zvalue tz3, Pixel c3)
|
|
|
|
This function draws a 3D z-buffered filled triangle with color
|
|
interpolation. Assumes three points have already been transformed
|
|
into screen coordinates.
|
|
|
|
General idea :
|
|
1. Transform the three points into screen coordinates
|
|
2. Order three points vertically on screen.
|
|
3. Check for degenerate cases (where 3 points are colinear).
|
|
4. Fill in the resulting triangle using horizontal lines.
|
|
5. Colors are interpolated between end points
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_interptriangletransform(Plot3D *p3,
|
|
int tx1, int ty1, Zvalue tz1, Pixel c1,
|
|
int tx2, int ty2, Zvalue tz2, Pixel c2,
|
|
int tx3, int ty3, Zvalue tz3, Pixel c3) {
|
|
int tempx, tempy;
|
|
Zvalue tempz;
|
|
double m1,m2,m3, mz1, mz2, mz3;
|
|
double mc1,mc2,mc3;
|
|
Pixel ic1,ic2,tempc;
|
|
int y;
|
|
int ix1, ix2;
|
|
Zvalue zz1, zz2;
|
|
FrameBuffer *f;
|
|
|
|
f = p3->frame;
|
|
|
|
/* Figure out which point has the greatest "y" value */
|
|
|
|
if (ty2 > ty1) { /* Swap points 1 and 2 if 2 is higher */
|
|
tempx = tx1;
|
|
tempy = ty1;
|
|
tempz = tz1;
|
|
tempc = c1;
|
|
tx1 = tx2;
|
|
ty1 = ty2;
|
|
tz1 = tz2;
|
|
c1 = c2;
|
|
tx2 = tempx;
|
|
ty2 = tempy;
|
|
tz2 = tempz;
|
|
c2 = tempc;
|
|
}
|
|
if (ty3 > ty1) { /* Swap points 1 and 3 if 3 is higher */
|
|
tempx = tx1;
|
|
tempy = ty1;
|
|
tempz = tz1;
|
|
tempc = c1;
|
|
tx1 = tx3;
|
|
ty1 = ty3;
|
|
tz1 = tz3;
|
|
c1 = c3;
|
|
tx3 = tempx;
|
|
ty3 = tempy;
|
|
tz3 = tempz;
|
|
c3 = tempc;
|
|
}
|
|
if (ty3 > ty2) { /* Swap points 2 and 3 if 3 is higher */
|
|
tempx = tx2;
|
|
tempy = ty2;
|
|
tempz = tz2;
|
|
tempc = c2;
|
|
tx2 = tx3;
|
|
ty2 = ty3;
|
|
tz2 = tz3;
|
|
c2 = c3;
|
|
tx3 = tempx;
|
|
ty3 = tempy;
|
|
tz3 = tempz;
|
|
c3 = tempc;
|
|
}
|
|
|
|
/* Points are now order so that t_1 is the highest point, t_2 is the
|
|
middle point, and t_3 is the lowest point */
|
|
|
|
/* Check for degenerate cases here */
|
|
|
|
if ((ty1 == ty2) && (ty2 == ty3)) {
|
|
|
|
/* Points are aligned horizontally. Handle as a special case */
|
|
/* Just draw three lines using the outline color */
|
|
|
|
if (tx2 > tx1)
|
|
Plot3D_horizontalinterp(p3,tx1,tx2,ty1,tz1,tz2,c1,c2);
|
|
else
|
|
Plot3D_horizontalinterp(p3,tx2,tx1,ty1,tz2,tz1,c2,c1);
|
|
if (tx3 > tx1)
|
|
Plot3D_horizontalinterp(p3,tx1,tx3,ty1,tz1,tz3,c1,c3);
|
|
else
|
|
Plot3D_horizontalinterp(p3,tx3,tx1,ty1,tz3,tz1,c3,c1);
|
|
if (tx3 > tx2)
|
|
Plot3D_horizontalinterp(p3,tx2,tx3,ty2,tz2,tz3,c2,c3);
|
|
else
|
|
Plot3D_horizontalinterp(p3,tx3,tx2,ty2,tz3,tz2,c3,c2);
|
|
|
|
} else {
|
|
|
|
/* First process line segments between (x1,y1)-(x2,y2)
|
|
And between (x1,y1),(x3,y3) */
|
|
|
|
if (ty2 < ty1) {
|
|
m1 = (double) (tx2 - tx1)/(double) (ty2 - ty1);
|
|
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
|
|
mz1 = (tz2 - tz1)/(double) (ty2 - ty1);
|
|
mz2 = (tz3 - tz1)/(double) (ty3 - ty1);
|
|
mc1 = (c2 - c1)/(double) (ty2 - ty1);
|
|
mc2 = (c3 - c1)/(double) (ty3 - ty1);
|
|
|
|
y = ty1;
|
|
while (y >= ty2) {
|
|
/* Calculate x values from slope */
|
|
ix1 = (int) (m1*(y-ty1)+0.5) + tx1;
|
|
ix2 = (int) (m2*(y-ty1)+0.5) + tx1;
|
|
zz1 = mz1*(y-ty1) + tz1;
|
|
zz2 = mz2*(y-ty1) + tz1;
|
|
ic1 = mc1*(y-ty1) + c1;
|
|
ic2 = mc2*(y-ty1) + c1;
|
|
if (ix1 > ix2)
|
|
Plot3D_horizontalinterp(p3,ix2,ix1,y,zz2,zz1,ic2,ic1);
|
|
else
|
|
Plot3D_horizontalinterp(p3,ix1,ix2,y,zz1,zz2,ic1,ic2);
|
|
y--;
|
|
}
|
|
}
|
|
if (ty3 < ty2) {
|
|
/* Draw lower half of the triangle */
|
|
m2 = (double) (tx3 - tx1)/(double) (ty3 - ty1);
|
|
mz2 = (tz3 - tz1)/(double) (ty3 - ty1);
|
|
mc2 = (c3 - c1)/(double) (ty3 - ty1);
|
|
m3 = (double) (tx3 - tx2)/(double)(ty3 - ty2);
|
|
mz3 = (tz3 - tz2)/(double) (ty3 - ty2);
|
|
mc3 = (c3 - c2)/(double) (ty3 - ty2);
|
|
y = ty2;
|
|
while (y >= ty3) {
|
|
ix1 = (int) (m3*(y-ty2)+0.5)+tx2;
|
|
ix2 = (int) (m2*(y-ty1)+0.5)+tx1;
|
|
zz1 = mz3*(y-ty2)+tz2;
|
|
zz2 = mz2*(y-ty1)+tz1;
|
|
ic1 = mc3*(y-ty2)+c2;
|
|
ic2 = mc2*(y-ty1)+c1;
|
|
if (ix1 > ix2)
|
|
Plot3D_horizontalinterp(p3,ix2,ix1,y,zz2,zz1,ic2,ic1);
|
|
else
|
|
Plot3D_horizontalinterp(p3,ix1,ix2,y,zz1,zz2,ic1,ic2);
|
|
y--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_interptriangle(Plot3D *p3,
|
|
double x1, double y1, double z1, Pixel c1,
|
|
double x2, double y2, double z2, Pixel c2,
|
|
double x3, double y3, double z3, Pixel c3)
|
|
|
|
This function draws a 3D z-buffered filled triangle with color
|
|
interpolation.
|
|
|
|
This function simply transforms the given points and calls
|
|
Plot3D_InterpTriangleTransform().
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_interptriangle(Plot3D *p3,
|
|
double x1, double y1, double z1, Pixel c1,
|
|
double x2, double y2, double z2, Pixel c2,
|
|
double x3, double y3, double z3, Pixel c3) {
|
|
|
|
int tx1, tx2, tx3, ty1, ty2, ty3;
|
|
Zvalue tz1, tz2, tz3;
|
|
GL_Vector t;
|
|
double invw;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,x1,y1,z1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x2,y2,z2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x3,y3,z3,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx3 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty3 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
Plot3D_interptriangletransform(p3,tx1,ty1,tz1,c1,tx2,ty2,tz2,c2,tx3,ty3,tz3,c3);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_quad(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
double x4, double y4, double z4,
|
|
Pixel fillcolor)
|
|
|
|
This function draws a 3D outlined Quadralateral. Used primarily for
|
|
drawing meshes and other things.
|
|
|
|
Plotting is done in the following order :
|
|
(x1,y1,z1) --> (x2,y2,z2)
|
|
(x2,y2,z2) --> (x3,y3,z3)
|
|
(x3,y3,z3) --> (x4,y4,z4)
|
|
(x4,y4,z4) --> (x1,y1,z1)
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_quad(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
double x4, double y4, double z4,
|
|
Pixel color) {
|
|
|
|
int tx1, tx2, tx3, tx4, ty1, ty2, ty3, ty4;
|
|
Zvalue tz1, tz2, tz3, tz4;
|
|
GL_Vector t;
|
|
double invw;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,x1,y1,z1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x2,y2,z2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x3,y3,z3,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx3 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty3 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x4,y4,z4,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx4 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty4 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz4 = (Zvalue) t.z;
|
|
|
|
Plot3D_linetransform(p3,tx1,ty1,tz1,tx2,ty2,tz2,color);
|
|
Plot3D_linetransform(p3,tx2,ty2,tz2,tx3,ty3,tz3,color);
|
|
Plot3D_linetransform(p3,tx3,ty3,tz3,tx4,ty4,tz4,color);
|
|
Plot3D_linetransform(p3,tx4,ty4,tz4,tx1,ty1,tz1,color);
|
|
|
|
}
|
|
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_solidquad(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
double x4, double y4, double z4,
|
|
Pixel fillcolor)
|
|
|
|
This function draws a 3D solid Quadralateral. Uses the function
|
|
Plot3D_SolidTriangleTransform() to fill in the region.
|
|
|
|
Plotting is done in the following order :
|
|
(x1,y1,z1) --> (x2,y2,z2)
|
|
(x2,y2,z2) --> (x3,y3,z3)
|
|
(x3,y3,z3) --> (x4,y4,z4)
|
|
(x4,y4,z4) --> (x1,y1,z1)
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_solidquad(Plot3D *p3, double x1, double y1, double z1,
|
|
double x2, double y2, double z2,
|
|
double x3, double y3, double z3,
|
|
double x4, double y4, double z4,
|
|
Pixel color) {
|
|
|
|
int tx1, tx2, tx3, tx4, ty1, ty2, ty3, ty4;
|
|
Zvalue tz1, tz2, tz3, tz4;
|
|
GL_Vector t;
|
|
double invw;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,x1,y1,z1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x2,y2,z2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x3,y3,z3,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx3 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty3 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x4,y4,z4,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx4 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty4 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz4 = (Zvalue) t.z;
|
|
|
|
Plot3D_solidtriangletransform(p3,tx1,ty1,tz1,tx2,ty2,tz2,tx3,ty3,tz3,color);
|
|
Plot3D_solidtriangletransform(p3,tx1,ty1,tz1,tx4,ty4,tz4,tx3,ty3,tz3,color);
|
|
}
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Plot3D_interpquad(Plot3D *p3, double x1, double y1, double z1, Pixel c1,
|
|
double x2, double y2, double z2, Pixel c2,
|
|
double x3, double y3, double z3, Pixel c3,
|
|
double x4, double y4, double z4, Pixel c4)
|
|
|
|
This function draws a 3D color-interpolated Quadralateral. Uses the function
|
|
Plot3D_InterpTriangleTransform() to fill in the region.
|
|
|
|
Plotting is done in the following order :
|
|
(x1,y1,z1) --> (x2,y2,z2)
|
|
(x2,y2,z2) --> (x3,y3,z3)
|
|
(x3,y3,z3) --> (x4,y4,z4)
|
|
(x4,y4,z4) --> (x1,y1,z1)
|
|
-------------------------------------------------------------------------- */
|
|
|
|
void Plot3D_interpquad(Plot3D *p3, double x1, double y1, double z1, Pixel c1,
|
|
double x2, double y2, double z2, Pixel c2,
|
|
double x3, double y3, double z3, Pixel c3,
|
|
double x4, double y4, double z4, Pixel c4) {
|
|
|
|
|
|
int tx1, tx2, tx3, tx4, ty1, ty2, ty3, ty4;
|
|
Zvalue tz1, tz2, tz3, tz4;
|
|
GL_Vector t;
|
|
double invw;
|
|
|
|
/* Transform the three points into screen coordinates */
|
|
|
|
Matrix_transform4(p3->trans_mat,x1,y1,z1,1,&t); /* Point 1 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx1 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty1 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz1 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x2,y2,z2,1,&t); /* Point 2 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx2 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty2 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz2 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x3,y3,z3,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx3 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty3 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz3 = (Zvalue) t.z;
|
|
|
|
Matrix_transform4(p3->trans_mat,x4,y4,z4,1,&t); /* Point 3 */
|
|
invw = 1.0/t.w;
|
|
t.x = t.x *invw;
|
|
t.y = t.y *invw;
|
|
t.z = t.z *invw;
|
|
tx4 = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty4 = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz4 = (Zvalue) t.z;
|
|
|
|
Plot3D_interptriangletransform(p3,tx1,ty1,tz1,c1,tx2,ty2,tz2,c2,tx3,ty3,tz3,c3);
|
|
Plot3D_interptriangletransform(p3,tx1,ty1,tz1,c1,tx4,ty4,tz4,c4,tx3,ty3,tz3,c3);
|
|
|
|
}
|
|
|
|
/* --------------------------------------------------------------------------
|
|
Plot3D_solidsphere(Plot3 *p3, double x, double y, double z, double radius,
|
|
Pixel c)
|
|
|
|
Makes a 3D sphere at x,y,z with given radius and color.
|
|
|
|
Basic strategy :
|
|
1. Transform point to screen coordinates
|
|
2. Figure out what the radius is in screen coordinates
|
|
3. Use bresenham algorithm for large spheres
|
|
4. Use bitmaps for small spheres
|
|
-------------------------------------------------------------------------- */
|
|
|
|
/* This is used to fill in spheres */
|
|
static int s_xmin;
|
|
static int s_ymin;
|
|
static int s_xmax;
|
|
static int s_ymax;
|
|
static Pixel **s_pixels;
|
|
static Zvalue **s_zbuffer;
|
|
|
|
void Plot3D_spherehorizontal(int xmin, int xmax, int y, Zvalue z, Pixel color) {
|
|
int i;
|
|
int startx, endx;
|
|
Pixel *p;
|
|
Zvalue *zbuf;
|
|
|
|
if ((y < s_ymin) || (y >= s_ymax)) return;
|
|
if (xmin < s_xmin) startx = s_xmin;
|
|
else startx = xmin;
|
|
if (xmax >= s_xmax) endx = s_xmax - 1;
|
|
else endx = xmax;
|
|
|
|
/* Draw it */
|
|
|
|
p = &s_pixels[y][xmin];
|
|
zbuf = &s_zbuffer[y][xmin];
|
|
for (i = startx; i <= endx; i++, p++, zbuf++) {
|
|
if (z <= *zbuf) {
|
|
*p = color;
|
|
*zbuf = z;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Plot3D_solidsphere(Plot3D *p3, double x, double y, double z, double radius,
|
|
Pixel c) {
|
|
|
|
GL_Vector t,r;
|
|
double rad;
|
|
int tx,ty, irad;
|
|
Zvalue tz;
|
|
double invw;
|
|
int ix, iy, ix1,ix2,p;
|
|
FrameBuffer *f;
|
|
|
|
/* First transform the point into model coordinates */
|
|
|
|
Matrix_transform4(p3->fullmodel_mat,x,y,z,1,&t);
|
|
|
|
/* Now transform two points in order to find proper sphere radius */
|
|
|
|
Matrix_transform4(p3->view_mat,t.x+radius,t.y,t.z,t.w,&r); /* transform radius */
|
|
Matrix_transform4(p3->view_mat,t.x,t.y,t.z,t.w,&t);
|
|
|
|
invw = 1.0/t.w;
|
|
t.x = t.x*invw;
|
|
t.y = t.y*invw;
|
|
t.z = t.z*invw;
|
|
invw = 1.0/r.w;
|
|
r.x = r.x*invw;
|
|
r.y = r.y*invw;
|
|
r.z = r.z*invw;
|
|
invw = 1.0/r.w;
|
|
|
|
rad = fabs(t.x - r.x);
|
|
|
|
/* Transform everything into screen coordinates */
|
|
|
|
tx = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz = (Zvalue) t.z;
|
|
irad = (int) (p3->zoom*(rad*p3->width + 0.5));
|
|
|
|
/* This is only a temporary solution (maybe). */
|
|
|
|
#define fill_zcircle(x,y,c) \
|
|
ix1 = tx - x; \
|
|
ix2 = tx + x; \
|
|
if (ix1 < s_xmin) ix1 = s_xmin; \
|
|
if (ix2 >= s_xmax) ix2 = s_xmax; \
|
|
Plot3D_spherehorizontal(ix1,ix2,y,tz,c);
|
|
|
|
f = p3->frame;
|
|
s_xmin = f->xmin;
|
|
s_ymin = f->ymin;
|
|
s_xmax = f->xmax;
|
|
s_ymax = f->ymax;
|
|
s_pixels = f->pixels;
|
|
s_zbuffer = f->zbuffer;
|
|
if (irad <= 1) {
|
|
/* Plot a single pixel */
|
|
if ((tx >= f->xmin) && (tx < f->xmax)) {
|
|
if ((ty >= f->ymin) && (ty <f->ymax)) {
|
|
if (tz <= f->zbuffer[ty][tx]) {
|
|
f->pixels[ty][tx] = c;
|
|
f->zbuffer[ty][tx] = tz;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
ix = 0;
|
|
iy = irad;
|
|
p = 3-2*irad;
|
|
while (ix <= iy) {
|
|
fill_zcircle(ix,ty+iy,c);
|
|
fill_zcircle(ix,ty-iy,c);
|
|
fill_zcircle(iy,ty+ix,c);
|
|
fill_zcircle(iy,ty-ix,c);
|
|
if (p < 0) p = p + 4*ix + 6;
|
|
else {
|
|
p = p + 4*(ix-iy) + 10;
|
|
iy = iy -1;
|
|
}
|
|
ix++;
|
|
}
|
|
}
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
Plot3D_outlinesphere(Plot3D *p3, double x, double y, double z,
|
|
double radius, Pixel color, Pixel bc)
|
|
|
|
Draws an outlined sphere.
|
|
-------------------------------------------------------------------- */
|
|
|
|
void Plot3D_outlinesphere(Plot3D *p3, double x, double y, double z,
|
|
double radius, Pixel c, Pixel bc)
|
|
{
|
|
GL_Vector t,r;
|
|
double rad;
|
|
int tx,ty, irad;
|
|
Zvalue tz;
|
|
double invw;
|
|
int ix, iy, ix1,ix2,p;
|
|
|
|
FrameBuffer *f;
|
|
|
|
/* First transform the point into model coordinates */
|
|
|
|
Matrix_transform4(p3->fullmodel_mat,x,y,z,1,&t);
|
|
|
|
/* Now transform two points in order to find proper sphere radius */
|
|
|
|
Matrix_transform4(p3->view_mat,t.x+radius,t.y,t.z,t.w,&r); /* transform radius */
|
|
Matrix_transform4(p3->view_mat,t.x,t.y,t.z,t.w,&t);
|
|
|
|
invw = 1.0/t.w;
|
|
t.x = t.x*invw;
|
|
t.y = t.y*invw;
|
|
t.z = t.z*invw;
|
|
invw = 1.0/r.w;
|
|
r.x = r.x*invw;
|
|
r.y = r.y*invw;
|
|
r.z = r.z*invw;
|
|
invw = 1.0/r.w;
|
|
|
|
rad = fabs(t.x - r.x);
|
|
|
|
/* Transform everything into screen coordinates */
|
|
|
|
tx = (int) ((t.x +p3->xshift)*p3->zoom*p3->width + 0.5) + p3->view_xmin;
|
|
ty = (int) ((t.y +p3->yshift)*p3->zoom*p3->height + 0.5) + p3->view_ymin;
|
|
tz = (Zvalue) t.z;
|
|
irad = (int) (p3->zoom*(rad*p3->width + 0.5));
|
|
|
|
/* This is only a temporary solution (maybe). */
|
|
#define plot_zcircle(x,y,c) \
|
|
if ((x >= s_xmin) && (x < s_xmax) && \
|
|
(y >= s_ymin) && (y < s_ymax)) {\
|
|
if (tz <= s_zbuffer[y][x]) { \
|
|
s_pixels[y][x] = c; \
|
|
s_zbuffer[y][x] = tz; } \
|
|
}
|
|
|
|
f = p3->frame;
|
|
s_xmin = f->xmin;
|
|
s_ymin = f->ymin;
|
|
s_xmax = f->xmax;
|
|
s_ymax = f->ymax;
|
|
s_pixels = f->pixels;
|
|
s_zbuffer = f->zbuffer;
|
|
|
|
if (irad <= 1) {
|
|
/* Plot a single pixel */
|
|
if ((tx >= f->xmin) && (tx < f->xmax)) {
|
|
if ((ty >= f->ymin) && (ty <f->ymax)) {
|
|
if (tz <= f->zbuffer[ty][tx]) {
|
|
f->pixels[ty][tx] = c;
|
|
f->zbuffer[ty][tx] = tz;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
ix = 0;
|
|
iy = irad;
|
|
p = 3-2*irad;
|
|
while (ix <= iy) {
|
|
fill_zcircle(ix,ty+iy,c);
|
|
fill_zcircle(ix,ty-iy,c);
|
|
fill_zcircle(iy,ty+ix,c);
|
|
fill_zcircle(iy,ty-ix,c);
|
|
|
|
plot_zcircle(tx+ix,ty+iy,bc);
|
|
plot_zcircle(tx-ix,ty+iy,bc);
|
|
plot_zcircle(tx+ix,ty-iy,bc);
|
|
plot_zcircle(tx-ix,ty-iy,bc);
|
|
plot_zcircle(tx+iy,ty+ix,bc);
|
|
plot_zcircle(tx-iy,ty+ix,bc);
|
|
plot_zcircle(tx+iy,ty-ix,bc);
|
|
plot_zcircle(tx-iy,ty-ix,bc);
|
|
if (p < 0) p = p + 4*ix + 6;
|
|
else {
|
|
p = p + 4*(ix-iy) + 10;
|
|
iy = iy -1;
|
|
}
|
|
ix++;
|
|
}
|
|
}
|
|
|
|
/* QUAD Test
|
|
Test out quad functions for graphing */
|
|
|
|
double zf(double x, double y) {
|
|
return cos(sqrt(x*x + y*y)*10.0)/(sqrt(x*x+y*y)+1);
|
|
}
|
|
|
|
void Quad_Test(Plot3D *p3, int npoints) {
|
|
int i,j;
|
|
double dx;
|
|
double x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4,za;
|
|
int c;
|
|
dx = 2.0/npoints;
|
|
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
for (j = 0; j < npoints; j++) {
|
|
x1 = i*dx + -1.0;
|
|
y1 = j*dx + -1.0;
|
|
x2 = x1 + dx;
|
|
x3 = x1 + dx;
|
|
x4 = x1;
|
|
y2 = y1;
|
|
y3 = y1 + dx;
|
|
y4 = y1 + dx;
|
|
z1 = zf(x1,y1);
|
|
z2 = zf(x2,y2);
|
|
z3 = zf(x3,y3);
|
|
z4 = zf(x4,y4);
|
|
za = 0.25*(z1+z2+z3+z4);
|
|
c = 16+((za + 1)*120);
|
|
if (c > 254) c = 254;
|
|
Plot3D_quad(p3,x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4,(Pixel) c);
|
|
}
|
|
}
|
|
|
|
|
|
void Quad_SolidTest(Plot3D *p3, int npoints) {
|
|
int i,j;
|
|
double dx;
|
|
double x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4,za;
|
|
int c;
|
|
dx = 2.0/npoints;
|
|
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
for (j = 0; j < npoints; j++) {
|
|
x1 = i*dx + -1.0;
|
|
y1 = j*dx + -1.0;
|
|
x2 = x1 + dx;
|
|
x3 = x1 + dx;
|
|
x4 = x1;
|
|
y2 = y1;
|
|
y3 = y1 + dx;
|
|
y4 = y1 + dx;
|
|
z1 = zf(x1,y1);
|
|
z2 = zf(x2,y2);
|
|
z3 = zf(x3,y3);
|
|
z4 = zf(x4,y4);
|
|
za = 0.25*(z1+z2+z3+z4);
|
|
c = 16+((za + 1)*120);
|
|
if (c > 254) c = 254;
|
|
Plot3D_solidquad(p3,x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4,(Pixel) c);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Quad_InterpTest(Plot3D *p3, int npoints) {
|
|
int i,j;
|
|
double dx;
|
|
double x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4;
|
|
int c1,c2,c3,c4;
|
|
dx = 2.0/npoints;
|
|
|
|
|
|
for (i = 0; i < npoints; i++)
|
|
for (j = 0; j < npoints; j++) {
|
|
x1 = i*dx + -1.0;
|
|
y1 = j*dx + -1.0;
|
|
x2 = x1 + dx;
|
|
x3 = x1 + dx;
|
|
x4 = x1;
|
|
y2 = y1;
|
|
y3 = y1 + dx;
|
|
y4 = y1 + dx;
|
|
z1 = zf(x1,y1);
|
|
z2 = zf(x2,y2);
|
|
z3 = zf(x3,y3);
|
|
z4 = zf(x4,y4);
|
|
c1 = 16+((z1 + 1)*120);
|
|
c2 = 16+((z2 + 1)*120);
|
|
c3 = 16+((z3 + 1)*120);
|
|
c4 = 16+((z4 + 1)*120);
|
|
if (c1 > 254) c1 = 254;
|
|
if (c2 > 254) c2 = 254;
|
|
if (c3 > 254) c3 = 254;
|
|
if (c4 > 254) c4 = 254;
|
|
Plot3D_interpquad(p3,x1,y1,z1,(Pixel) c1,x2,y2,z2,(Pixel) c2,x3,y3,z3,(Pixel) c3,x4,y4,z4,(Pixel) c4);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|