/*
 * Copyright (c) 2024 Ross Cunniff
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/* Significant portions of this code were adapted from Hoverware, whose
 * GPL copyright is: */
/* (c) Copyright Hewlett-Packard Company 2001
 *
 * 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; either version 2 of the License, or (at
 * your option) any later version.
 *
 * 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.
 */
using namespace oadl;

#include "libo3d.oah"
#include "libstd.oah"

o3d::Display disp(nil,nil) { o3dDefaultOptFlags = o3d::OPT_USE_DL }
var done = false;

var doPause = false;
var pauseLight = false;
var pauseCamera = false;
var pauseObject = false;
var doPerPixel = false;

proc callback(draw, event)
{
    switch (event) {
    case o3d::INPUT_KEYBOARD :
        switch (arg(2)) {
        case 27       : done = true;
        case ' '      : doPause = !doPause;
        case 'b', 'B' : doPerPixel = !doPerPixel;
        case 'l', 'L' : pauseLight = !pauseLight;
        case 'c', 'C' : pauseCamera = !pauseCamera;
        case 'r', 'R' : pauseObject = !pauseObject;
        }
    case o3d::INPUT_DESTROY :
        done = true;
    case o3d::INPUT_CONFIG :
        disp.viewport(0, 0, arg(4), arg(5));
    }
}

proc main(args)
{
    var graphN = 133, graphM = 165;
    var wireframe = false;
    var sampvert = false;
    var reliefScale = 4.0;

    var n = args.length();
    for (var i = 1; i < n; i++) {
        switch (args[i]) {
        case "-wire" :
            wireframe = true;
        case "-rows" :
            if( i < (n-1) ) {
                i++;
                graphN = str2var(args[i]);
            }
        case "-cols" :
            if( i < (n-1) ) {
                i++;
                graphM = str2var(args[i]);
            }
        case "-rgb" :
            sampvert = true;
        case "-relief" :
            if( i < (n-1) ) {
                i++;
                reliefScale = str2var(args[i]);
            }
        }
    }

    disp.chooseVisual(o3d::VIS_DBUFF|o3d::VIS_DEPTH, 0);

    var draw = disp.createWindow( "Test", 100, 100, 512, 512, o3d::WIN_INPUT );
    disp.makeCurrent(draw);
    disp.inputHandler(callback);

    var env = new o3d::Environ() {
        AmbientFactor = 0.5
        BackgroundColor = {0.0, 0.0, 1.0}
        FogColor = {0.0, 0.0, 1.0}
        Fog = true
        FogPlanes = {1.0, 3.5}
        FogType = o3d::FOG_LINEAR
    };

    var cam = new o3d::Camera() {
        Planes = {0.5, 3.5}
        Field = 90
        Perspective = true
    };

    var tm = {
        new o3d::Texture() {
            FileName = "Texture/earthbump1k.jpg"
            InternalFormat = o3d::TM_HEIGHT
            Apply = o3d::TM_RELIEF
            ReliefScale = reliefScale
        },
        new o3d::Texture() {
            FileName = "Texture/earthmap1k.jpg"
            InternalFormat = o3d::TM_COLOR
            Apply = o3d::TM_MODULATE
            CoordMode = o3d::TM_STAGE_0
        },
        new o3d::Texture() {
            FileName = "Texture/earthspec1k.jpg"
            InternalFormat = o3d::TM_COLOR
            Apply = o3d::TM_GLOSS
            CoordMode = o3d::TM_STAGE_0
        }
    };

    var sphere = new o3d::Sphere() {
        Texture = tm
        Color = [1.0, 1.0, 1.0]
        OptFlags = o3d::OPT_DL_ATTRS
        HasNormals = true
        HasTangent = true
        GraphN = graphN
        GraphM = graphM
        Wireframe = wireframe
        SampVert = sampvert
        Shininess = 0.5
    };

    var light = new o3d::Light() {
        Dir = {1.0, 1.0, -1.0}
    };


    var Mat = new PackFloat(16);
    var CamAng = 0.0;
    var Ang = 0.0;
    var LightAng = 0.0;
    while( !done ) {
        env.draw(disp);

        var cx;
        var cy = (CamAng * math::PI / 180.0).cos();
        var cz = (CamAng * math::PI / 180.0).sin();
        with (cam) {
            Pos = [0.0, 2.0*cy, 2.0*cz]
            Dir = [0.0, -cy, -cz]
            Up = [0.0, -cz, cy]
        }

        cx = (LightAng * math::PI / 180.0).cos();
        cy = (LightAng * math::PI / 180.0).sin();
        with (light) {
            Dir = [cx, cy, 0.0]
        }

        cam.draw();
        light.draw();
        o3d::RotateY(Mat, Ang);
        disp.pushMatrix(Mat);
        sphere.draw();
        disp.popMatrix();
        disp.update( o3d::UPDATE_ALL );

        if (!doPause) {
            if (!pauseObject) {
                Ang += 0.4;
                if (Ang > 360.0) Ang -= 360.0;
            }
            if (!pauseCamera) {
                CamAng += 0.08;
                if (CamAng > 360.0) CamAng -= 360.0;
            }
            if (!pauseLight) {
                LightAng += 1.6;
                if (LightAng > 360.0) LightAng -= 360.0;
            }
        }
    }
}