| /* ----------------------------------------------------------------------------- |
| * 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); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |