/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991-1997  Riley Rainey
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 dated June, 1991.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program;  if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
 */

#include "pm.h"

#define place_IMPORT
#include "place.h"

static VPoint origin = {0.0, 0.0, 0.0};

void
place_craft(Viewport * v, craft * c, viewer *u, craft * obj, VPolySet *ps)
{
	int       i, k, n;
	VPoint   *q, tmp, tmp1, center, nc;
	VMatrix   mtx, mtx1, m, m1;
	VPolygon *poly, **p, *p1;
	double    dist;
	int       aspect, offset;
	VObject  *op;

/*
 *  Build a transformation matrix to convert from object to world coordinates.
 */

	if ((obj->flags & FL_FIXED_OBJECT) == 0) {

		VIdentMatrix(&m);

		VRotate(&m, YRotation, -units_DEGtoRAD(90.0));
		VRotate(&m, YRotation, -obj->w.latitude);
		VRotate(&m, ZRotation, obj->w.longitude);

		VEulerToMatrix(obj->curRoll,
						 obj->curPitch,
						 obj->curHeading,
						 &m1);

		VMatrixMultByRank(&m1, &m, &mtx, 3);

		VTranslatePoint(&mtx, obj->Sg);
	}
	else {
		VIdentMatrix(&mtx);
	}

/*
 *  If the object uses a special method to render itself, call that procedure.
 */
	if( obj->cinfo == NULL ){
		printf("%s:%d: obj->cinfo == NULL, obj->type == %d\n",
			__FILE__, __LINE__, obj->type);
		return;
	}

	if (obj->cinfo->placeProc != NULL) {
		(*obj->cinfo->placeProc) (v, obj, &mtx, ps);
		return;
	}

/*
 *  Build a matrix to transform from world to eye coordinate systems.
 */

	VMatrixMult(&mtx, &v->eyeSpace, &mtx1);

/*
 *  Reject the object if is completely outside any of the clipping planes
 */

	if (obj->flags & FL_FIXED_OBJECT)
		tmp = obj->cinfo->object->center;
	else
		VTransform(&obj->cinfo->object->center, &mtx, &tmp);

	VTransform(&tmp, &u->v->eyeSpace, &center);
	for (i = 0; i < 4; ++i) {
		dist = VPointToClipPlaneDistance(&center,
										 &(u->v->clipNormals[i]));
		if (dist > obj->cinfo->object->extent)
			return;
	}

	op = obj->cinfo->object;
	n = op->numPolys;
	p = op->polygon;
	offset = 0;
	if (op->order) {
		VTransform(&origin, &mtx1, &nc);
		VTransform_(&VUnitVectorI, &mtx1, &op->xaxis);
		VTransform_(&VUnitVectorJ, &mtx1, &op->yaxis);
		VTransform_(&VUnitVectorK, &mtx1, &op->zaxis);
		aspect = VComputeObjectAspect(op, &nc);
#ifdef notdef
		printf("%s: %s\n", op->name, VGetAspectName(aspect));
#endif
		offset = aspect * n;
	}

	for (i = 0; i < n; ++i) {

/*
 *  Here is an opportunity to cull back-facing polygons without
 *  copying or transforming them. tmp1 becomes the transformed coordinates
 *  of the first vertex in the polygon.
 */

		p1 = (op->order) ? p[op->order[offset + i]] : p[i];

		VTransform(&p1->vertex[0], &mtx1, &tmp1);
		if (p1->flags & PolyNormalValid) {
			VTransform_(&p1->normal, &mtx1, &tmp);
		}
		if (p1->flags & PolyClipBackface) {
			if (VDotProd(&tmp1, &tmp) >= 0.0) {
				continue;
			}
		}

/*
 *  Beyond the culling distance?  Don't plot this polygon
 */

		if (p1->flags & PolyUseCullDistance) {
			if (sqrt(tmp1.x * tmp1.x + tmp1.y * tmp1.y + tmp1.z * tmp1.z) >
				p1->cullDistance) {
				continue;
			}
		}

		poly = VCopyPolygon(p1);

/*
 *  First copy the normal vector and the transformed first point, then loop
 *  over all remaining points.
 */

		if (poly->flags & PolyNormalValid) {
			poly->normal = tmp;
		}

		q = poly->vertex;

/*
 *  First, copy the previously transformed first vertex.
 */

		*q = tmp1;
		q++;

/*
 *  Now transform and copy the remaining vertices.
 */

		for (k = 1; k < poly->numVtces; (++k, ++q)) {
			VTransform(q, &mtx1, &tmp);
			*q = tmp;
		}

		VPolySet_Add(ps, poly);
	}

}
