/*-
 * Copyright (c) 1999,2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of the source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Any redistribution solely in binary form must conspicuously
 *    reproduce the following disclaimer in documentation provided with the
 *    binary redistribution.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'', WITHOUT ANY WARRANTIES, EXPRESS
 * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  LICENSOR SHALL
 * NOT BE LIABLE FOR ANY LOSS OR DAMAGES RESULTING FROM THE USE OF THIS
 * SOFTWARE, EITHER ALONE OR IN COMBINATION WITH ANY OTHER SOFTWARE.
 * 
 * 	$Id: primbuilder.cpp,v 1.3 2000/04/20 15:48:17 n_hibma Exp $
 */

#include <stddef.h>
#include "primbuilder.h"

PrimBuilder::PrimBuilder()
{
    top.uScale(3);
    top.vScale(3);
    
    bottom.uScale(1);
    bottom.vScale(1);
    
    cylmapper.uScale(2);
    cylmapper.vScale(1);
    
    mapper.uScale(2);
    mapper.vScale(2);
}

void
PrimBuilder::addTriangle(int w1, int w2, int w3)
{
    tris->add(w1, w2, w3);
}

struct Vertex {
    Maths::Vec3f	vertex;
    float		blend;
    Maths::Vec3f	normal;
    Maths::Color4b	vertexColor;
    Maths::Vec2f	texCoord;
};

unsigned int
PrimBuilder::addWedge(const Wedge& w)
{
    Vertex v;
    v.vertex = w.vertex;
    v.normal = w.normal;
    v.vertexColor = w.vertexColor;
    v.texCoord = w.texCoord;
    v.blend = (w.vertex.y + 1) / 2;
    return verts->add((void*)&v);
}

void
PrimBuilder::clear()
{
    delete verts;
    delete tris;
    
    alloc();
}

void
PrimBuilder::alloc()
{
    verts = factory->createVertexArray(Draw::FVF::Coord |
				       Draw::FVF::Normal |
				       Draw::FVF::MaterialColor |
				       Draw::FVF::TexCoord(1) |
				       Draw::FVF::Blend(1),
				       0);
    
    tris = factory->createPrimitiveArray(Draw::PrimitiveArray::Triangles, 0);
}

static void
collectTriangles(unsigned int v1, unsigned int v2, unsigned int v3)
{
    PrimBuilder::primitive.addTriangle(v1, v2, v3);
}

static unsigned int
collectWedge(const Wedge& wedge)
{
    Wedge w = wedge;

    const Vec3f& v = wedge.vertex;
    w.vertexColor = Color4b(Vec4f((v.x + 1) * 0.5f,
                                  (v.y + 1) * 0.5f,
                                  (v.z + 1) * 0.5f, 1));
    w.vertexColor = Color4b(255,255,255);

    return PrimBuilder::primitive.addWedge(w);
}

void
PrimBuilder::buildPrim(unsigned int p)
{
    clear();

    type = p;
    
    switch (p) {
    case 0:
	PrimGenerator::makeSphere(50, 50, mapper,
				  collectTriangles,
				  collectWedge);
	break;
    case 1:
	PrimGenerator::makeCylinder(50, 20, 10,
				    top, bottom, cylmapper,
				    collectTriangles,
				    collectWedge);
	break;
    case 2:
	PrimGenerator::makeFrustum(0.25, 50, 30, 20,
				   top, bottom, cylmapper,
				   collectTriangles,
				   collectWedge);
	break;
    }
}

void
PrimBuilder::render(Buffer* buffer, Shader* shader,
		    LightManager* lightman)
{
    Draw::Material material;
    material.emissive = 0;
    material.ambient = Vec3f(1, 1, 1);
    material.diffuse = Vec3f(1, 1, 1);
    material.specular = Vec3f(1, 1, 1);
    material.shininess = 15;
    material.brilliance = 1;

    unsigned int triCount = tris->size();
    
    buffer->setMaterial(material);
    buffer->setLights(lightman);
    buffer->setVertices(verts);
    buffer->setShader(shader);
    
    buffer->render(tris, 0, triCount);
}

void
PrimBuilder::reBuild()    
{
    buildPrim(type);
}
