// lamp.cpp

#include <iostream.h>
#include <math.h>

/* global for light index assignment for various lightsources */
int lightIndex = 0;

/* parameteres controlling size of lamp */
float lampSize = 2.2;
float largeWidth = 1.0 + 7.0 / 8.0;
float smallWidth = 0.75;
float totalHeight = 7.25;
float topHeight = 4.0;
float upperHeight = 1.0;

/* bmrt 2.6 built-in listing */
/*
//"ambientlight",
//"arealight",
//"background",
"brick",
//"brickbump",
"brushedmetal",
//"castucco",
"ceramic",
"ceramictiles",
//"clamptoalpha",
"clay",
"constant",
"defaultsurface",
//"dented",
//"depthcue",
//"distantlight",
"fakesky",
//"fog",
"funkyglass",
"glass",
"gmarbtile_polish",
"greenmarble",
//"lensflare",
"matte",
"metal",
//"null",
"oak",
"oakplank",
"paintedplastic",
"parquet_plank",
"plank",
"plastic",
//"pointlight",
"roughmetal",
"screen",
"screen_aa",
"shiny",
"shinymetal",
"shinyplastic",
"smoke",
//"spotlight",
//"stucco",
"superplank",
"supertexmap",
//"uberlight",
"veinedmarble",
"wallpaper_2stripe",
//"windowlight",
"wood2"
*/

void
rotate(float degree, float x, float y, float z)
{
  cout << "Rotate " << degree << " " << x << " " << y << " " << z << endl;
}

void
move(float x, float y, float z)
{
  cout << "Translate " << x << " " << y << " " << z << endl;
}

/* for initial setting of world coordinates */
void
setCamera(float x, float y, float z, float degree, float xx, float yy, float zz)
{
  move(-x, -y, -z);
  rotate(degree, xx, yy, zz);
}

void
light(char *type, float intensity)
{
  cout << "LightSource \"" << type << "\" " << ++lightIndex << " \"intensity\" " << intensity << endl;
}

void
color(float r, float g, float b)
{
  cout << "Color [" << r << " " << g << " " << b << "]" << endl;
}

/* specify shader */
void
surface(char *shader, char *paramters)
{
  cout << "Surface \"" << shader << "\" " << paramters << endl;
}

void
polygon(float x00,
        float x01,
        float x02,
        float x10,
        float x11,
        float x12,
        float x20,
        float x21,
        float x22,
        float x30,
        float x31,
        float x32)
{
  cout << "Polygon \"P\" [ "
    << x00 << " "
    << x01 << " "
    << x02 << " "
    << x10 << " "
    << x11 << " "
    << x12 << " "
    << x20 << " "
    << x21 << " "
    << x22 << " "
    << x30 << " "
    << x31 << " "
    << x32 << " "
    << "]" << endl;;
}

void
sphere(float radius)
{
  cout << "Sphere " << radius << " -" << radius << " " << radius << " 360" << endl;
}

/* commons */
void  beginWorld()      { cout << "WorldBegin" << endl; }
void  endWorld()        { cout << "WorldEnd" << endl; }
void  beginTransform()  { cout << "TransformBegin" << endl; }
void  endTransform()    { cout << "TransformEnd" << endl; }
void  beginAttribute()  { cout << "AttributeBegin" << endl; }
void  endAttribute()    { cout << "AttributeEnd" << endl; }

/* wax "lava" droplet */
void
drop(float r, float g, float b, char *shader, float x, float y, float z, float radius)
{
  beginAttribute();
    color(r, g, b);
    surface(shader, "");
    beginTransform();
      move(x, y, z);
      sphere(radius);
    endTransform();
  endAttribute();
}

/* wooden table */
void
table()
{
  float size = 25;

  beginAttribute();
    surface("wood2", "");
    beginTransform();
      move(0, 0, 0);
      polygon(-size,0,-size,
              -size,0,size,
              size,0,size,
              size,0,-size);
    endTransform();
  endAttribute();
}

/* header */
void
head(char *fileName)
{
  cout << "Option \"searchpath\" \"shader\" \".:myshaders/\"" << endl;
  cout << "Projection \"perspective\" \"fov\" 65" << endl;
  cout << "Display \"" << fileName << "\" \"file\" \"rgb\"" << endl;
//  cout << "Format 640 480 1.0" << endl;
  cout << "Format 1280 1024 1.0" << endl;
}

void
lamp_strip(float width, float length, char *shader)
{
  surface(shader,"");
  polygon(0,0,0,
          width,0,0,
          width,length,0,
          0,length,0);
}

void
lamp_cone(float degreeIncrement)
{
  float degree;
  float radius, width, length;

  float l1,l2,angle;

  radius = largeWidth / 2.0;
  width = 2 * 3.141592654 * radius * degreeIncrement / 360.0;

  l1 = (largeWidth - smallWidth) / 2.0;
  l2 = (totalHeight - topHeight) / 2.0;
  length = sqrt(l1*l1 + l2*l2);

  angle = atan2(l1, l2) * 360.0 / 2.0 / 3.141592654;

  for (degree = 0; degree < 360; degree += degreeIncrement)
  {
    beginTransform();
      rotate(degree, 0,1,0);
      move(0,0,lampSize * radius);
      rotate(angle,-1,0,0);
      lamp_strip(lampSize * width, lampSize * length ,"plastic");
    endTransform();
  }  
}

void
lamp_stand(float degreeIncrement)
{
  lamp_cone(degreeIncrement);
}

void
lamp_bottom(float degreeIncrement)
{
  beginTransform();
    move(0,(totalHeight - topHeight) * lampSize,0);
    rotate(180,1,0,0);
    lamp_cone(degreeIncrement);
  endTransform();
}

void
lamp_glass(float degreeIncrement)
{
  float degree;
  float radius, width, length;

  float l1,l2,angle;

  radius = largeWidth / 2.0;
  width = 2 * 3.141592654 * radius * degreeIncrement / 360.0;

  l1 = ((topHeight - upperHeight) / topHeight) * (largeWidth - smallWidth) / 2.0;
  l2 = (topHeight - upperHeight);
  length = sqrt(l1*l1 + l2*l2);

  angle = atan2(l1, l2) * 360.0 / 2.0 / 3.141592654;

  beginTransform();
    move(0,(totalHeight - topHeight) * lampSize,0);

    for (degree = 0; degree < 360; degree += degreeIncrement)
    {
      beginTransform();
        rotate(degree, 0,1,0);
        move(0,0,lampSize * radius);
        rotate(angle,-1,0,0);
        lamp_strip(lampSize * width, lampSize * length, "myglass");
      endTransform();
    }  
  endTransform();
}

void
lamp_top(float degreeIncrement)
{
  float degree;
  float radius, width, length;

  float l1,l2,angle;

  radius = ((upperHeight / topHeight) * (largeWidth - smallWidth) + smallWidth) / 2.0;
  width = 2 * 3.141592654 * radius * degreeIncrement / 360.0;

  l1 = (upperHeight / topHeight) * (largeWidth - smallWidth) / 2.0;
  l2 = upperHeight;
  length = sqrt(l1*l1 + l2*l2);

  angle = atan2(l1, l2) * 360.0 / 2.0 / 3.141592654;

  beginTransform();
    move(0,(totalHeight - upperHeight) * lampSize,0);

    for (degree = 0; degree < 360; degree += degreeIncrement)
    {
      beginTransform();
        rotate(degree, 0,1,0);
        move(0,0,lampSize * radius);
        rotate(angle,-1,0,0);
        lamp_strip(lampSize * width, lampSize * length, "plastic");
      endTransform();
    }  
  endTransform();
}

void
lamp(float r, float g, float b)
{
  float step = 0.5;

  /* lightsource within lamp */
  beginTransform();
    move(0,(totalHeight - topHeight) * lampSize / 2.0,0);
    light("pointlight", 140.0);
  endTransform();
  
  color(r,g,b);
  lamp_stand(step);
  lamp_bottom(step);
  lamp_glass(step);
  lamp_top(step);

  /* sample lava */
  drop(
    1.0, 
    1.0, 
    0.0,
    "myplastic", 
    0, 
    (totalHeight - topHeight + upperHeight) * lampSize, 
    0, 
    ((upperHeight / topHeight) * (largeWidth - smallWidth) + smallWidth) / 2.0);
}

void
body()
{
  setCamera(0, 7.6, -15.0, 0, 0, 0, 0);
  beginWorld();

    light("ambientlight", 0.5);

    beginTransform();
      move(3.0, 4.0, -8.0);
      light("pointlight", 80.0);
    endTransform();

    table();
    lamp(0,0.5,0.75);

    beginTransform();
      move(2.5 * largeWidth,0,0);
      lamp(0.2,0.8,0.4);
    endTransform();

    beginTransform();
      move(-2.5 * largeWidth,0,0);
      lamp(1,1,1);
    endTransform();

  endWorld();
}

int
main()
{
  head("lamp.tif");
  body();

  return 0;
}