#include <stdio.h>
#include <conio.h>
#include <math.h>
#include "3dtools.h"
#include "mode13h.h"

//  otmvoxel.cpp - released 11-08-94
//  simple voxel landscape demo
//  coded by Voltaire/OTM
//  all source Copyright (C) 1994 Zach Mortensen
//
//  see OTMVOXEL.NFO and OTM-94.NFO for more information
//
//  this source is included purely as an example.  If you want to re-compile
//  it as is, you must link in the following files:
//
//  3dtools.obj
//  mode13h.obj
//  sin.obj
//
//  sources to these files have been previously released in V3DT090.ZIP
//  which is availible via ftp at hornet.eng.ufl.edu in the
//  /demos/code/graph/library directory, as well as at OTM distribution
//  sites listed in OTM-94.NFO


// z threshold - maximum depth at which a voxel is displayed

#define ZTHRESH 2048

int *x16;
char *vPage;

void initX16(int threshold);
void voxel(int x, int y, int z, int c);

void main()
{
    int count, x, y, pos;
    point3d *temp;

    // create object and associated points

    obj3d *land = new obj3d(0, -75, 1024);
    point3d **point = new point3d* [100];

    // set up object as 3d sine curve

    for (y = 0; y < 10; y++)
        for (x = 0; x < 10; x++)
            {
                point[y * 10 + x] = new point3d(x * 10,
                                        (int) ((double) 25 * (sin((double) PI * 18 *x / 180) + sin((double) PI * 18 * y / 180))) + 25,
                                        y * 10);
                land->addLocalPoint(point[y * 10 + x]);
            }

    // initialize speedy size routine and sin/cos tables

    initX16(ZTHRESH);
    initSinCos();

    // virtual page for off screen drawing

    vPage = new char [64000];

    // setup video mode etc.

    setMode13h(vPage);

    // initialize palette

    for (count = 1; count < 16; count++)
        set_dac_register(count, 0, 0, 0);

    for (count = 1; count < 32; count++)
    {
        set_dac_register(count + 16, 0, count * 2, 0);
        set_dac_register(count + 31 + 16, count * 2, 63, count * 2);
    }

    // setup for off screen drawing

    setActivePage(pVirtual);

    // main loop

    while (!kbhit())
    {
        clearScreen(0);

        // draw the landscape

        for (count = 99; count > 0; count--)
            voxel(point[count]->x2d, point[count]->y2d, point[count]->z3d, point[count]->localY);

        // now show the virtual page

        flipVPage();

        // rotate the landscape 1 degree about the y axis

        land->localRotate(0, 1, 0);

        // linear sort points according to depth

        for (count = 0; count < land->numPoints - 1; count++)
        {
            pos = count;
            for (x = count + 1; x < land->numPoints; x++)
                if (point[x]->z3d < point[pos]->z3d)
                    pos = x;

            if (pos != count)
            {
                temp = point[pos];
                point[pos] = point[count];
                point[count] = temp;
            }
        }

    }

    // read a keypress

    getch();

    // back to 80x25 text mode

    textMode();

    // clean house

    delete x16;
    delete vPage;
    delete land;
    delete point;

}

void initX16(int threshold)
{
    int count;

    x16 = new int [threshold];

    // setup a table containing perspective sizes of 16 pixels at given
    // depths for speedy reference

    for (count = 1; count < threshold; count++)
        x16[count] = 16 * 1024 / count;

}


void voxel(int x, int y, int z, int c)
{
    int index, count, col;

    // make sure we're positive

    if (c < 0)
        c += 256;

    // calculate starting offset into virtual screen

    index = (int) vPage + (320 * y) + x;

    // display the voxel if it is within the z threshold

    if (z < ZTHRESH)
    {
        // draw a shaded square to the offscreen buffer

        for (count = 0; count < x16[z]; count++)
        {
            // draw one row of the square

            for (col = 0; col < x16[z]; col++)
            {
                *(char *) index = (char) c;
                index++;
            }

            // go to next line

            index += 320;
            index -= x16[z];

            // change colors

            c--;
        }
    }

}
