/*
	Copyright (C) 2021-2025 Mark Tyler

	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 3 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 in the file COPYING.
*/

#include "lanter_be_terrascene.h"



int LandTriangles::init ( TerraMap const & map )
{
	int const rows = (size_t)map.get_rows ();
	if ( rows < 2 )
	{
		std::cerr <<"Map not initialized, cannot build LandTriangles\n";
		return 1;
	}
	int const rows1 = rows - 1;

	clear ();

	// 4 triangles per square; 3 vertices per triangle.
	m_vertex_count = size_t(rows1 * rows1 * 3 * 4);
	m_data = (mtGin::GL::VertexRGBnormal *)calloc ( m_vertex_count,
		sizeof(m_data[0]));

	if ( ! m_data )
	{
		std::cerr <<"Unable to allocate LandTriangles buffer\n";
		return 1;
	}

	std::cout << "LandTriangles::init rows=" << rows
		<< " vertices=" << m_vertex_count
		<< " bytes=" << m_vertex_count * sizeof(m_data[0])
		<< "\n";

	mtGin::GL::VertexRGBnormal * dest = m_data;

	float const r = m_landscape_color_red;
	float const g = m_landscape_color_green;
	float const b = m_landscape_color_blue;

	for ( int y = 0; y < rows1; y++ )
	{
		for ( int x = 0; x < rows1; x++ )
		{
			float const x0 = map.get_xy_real ( x );
			float const x2 = map.get_xy_real ( x+1 );
			float const y0 = map.get_xy_real ( y );
			float const y2 = map.get_xy_real ( y+1 );
			float const x1 = (x0+x2)/2;
			float const y1 = (y0+y2)/2;

			float const z00 = map.get_value_real ( x, y );
			float const z20 = map.get_value_real ( x+1, y );
			float const z22 = map.get_value_real ( x+1, y+1 );
			float const z02 = map.get_value_real ( x, y+1 );
			float const z11 = (z00 + z20 + z22 + z02) / 4;

			dest->set_xyz ( x0, y0, z00 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x2, y0, z20 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x1, y1, z11 );
			dest->set_rgb ( r, g, b );
			dest->calc_normal ( dest[-2], dest[-1] );
			dest++;

			dest->set_xyz ( x2, y0, z20 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x2, y2, z22 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x1, y1, z11 );
			dest->set_rgb ( r, g, b );
			dest->calc_normal ( dest[-2], dest[-1] );
			dest++;

			dest->set_xyz ( x2, y2, z22 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x0, y2, z02 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x1, y1, z11 );
			dest->set_rgb ( r, g, b );
			dest->calc_normal ( dest[-2], dest[-1] );
			dest++;

			dest->set_xyz ( x0, y2, z02 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x0, y0, z00 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x1, y1, z11 );
			dest->set_rgb ( r, g, b );
			dest->calc_normal ( dest[-2], dest[-1] );
			dest++;
		}
	}

	return 0;
}

int LandLines::init ( TerraMap const & map )
{
	int const rows = (size_t)map.get_rows ();
	if ( rows < 2 )
	{
		std::cerr <<"Map not initialized, cannot build LandLines\n";
		return 1;
	}
	int const rows1 = rows - 1;

	clear ();

	// rows1 lines per row (2 coords), in both dimensions.
	m_vertex_count = size_t(rows * rows1 * 2 * 2);
	m_data = (mtGin::GL::VertexRGB *)calloc ( m_vertex_count,
		sizeof(m_data[0]));

	if ( ! m_data )
	{
		std::cerr <<"Unable to allocate LandLines buffer\n";
		return 1;
	}

	std::cout << "LandLines::init rows=" << rows
		<< " vertices=" << m_vertex_count
		<< " bytes=" << m_vertex_count * sizeof(m_data[0])
		<< "\n";

	mtGin::GL::VertexRGB * dest = m_data;

	float const r = 0;
	float const g = 0;
	float const b = 0;

	for ( int y = 0; y < rows1; y++ )
	{
		for ( int x = 0; x < rows; x++ )
		{
			float const x0 = map.get_xy_real ( x );

			float const y0 = map.get_xy_real ( y );
			float const y2 = map.get_xy_real ( y+1 );

			float const z00 = map.get_value_real ( x, y );
			float const z02 = map.get_value_real ( x, y+1 );

			dest->set_xyz ( x0, y0, z00 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x0, y2, z02 );
			dest->set_rgb ( r, g, b );
			dest++;
		}
	}

	for ( int y = 0; y < rows; y++ )
	{
		for ( int x = 0; x < rows1; x++ )
		{
			float const x0 = map.get_xy_real ( x );
			float const x2 = map.get_xy_real ( x+1 );

			float const y0 = map.get_xy_real ( y );

			float const z00 = map.get_value_real ( x, y );
			float const z02 = map.get_value_real ( x+1, y );

			dest->set_xyz ( x0, y0, z00 );
			dest->set_rgb ( r, g, b );
			dest++;
			dest->set_xyz ( x2, y0, z02 );
			dest->set_rgb ( r, g, b );
			dest++;
		}
	}

	return 0;
}

int LandPoints::init ( TerraMap const & map )
{
	int const rows = (size_t)map.get_rows ();
	if ( rows < 2 )
	{
		std::cerr <<"Map not initialized, cannot build LandPoints\n";
		return 1;
	}
//	int const rows1 = rows - 1;

	clear ();

	// rows x rows.
	m_vertex_count = size_t(rows * rows);
	m_data = (mtGin::GL::VertexRGB *)calloc ( m_vertex_count,
		sizeof(m_data[0]));

	if ( ! m_data )
	{
		std::cerr <<"Unable to allocate LandPoints buffer\n";
		return 1;
	}

	std::cout << "LandPoints::init rows=" << rows
		<< " vertices=" << m_vertex_count
		<< " bytes=" << m_vertex_count * sizeof(m_data[0])
		<< "\n";

	mtGin::GL::VertexRGB * dest = m_data;

	float const r = m_landscape_color_red;
	float const g = m_landscape_color_green;
	float const b = m_landscape_color_blue;

	for ( int y = 0; y < rows; y++ )
	{
		for ( int x = 0; x < rows; x++ )
		{
			float const x0 = map.get_xy_real ( x );
			float const y0 = map.get_xy_real ( y );
			float const z00 = map.get_value_real ( x, y );

			dest->set_xyz ( x0, y0, z00 );
			dest->set_rgb ( r, g, b );
			dest++;
		}
	}

	return 0;
}




/// ----------------------------------------------------------------------------



CubeCorners::CubeCorners (
	GLfloat	const	size,
	GLfloat	const	r,
	GLfloat	const	g,
	GLfloat	const	b
	)
{
	for ( int i=0; i<8; i++ )
	{
		point[i].x = size * ((((i/1)%2)==0) ? -1 : 1);
		point[i].y = size * ((((i/2)%2)==0) ? -1 : 1);
		point[i].z = size * ((((i/4)%2)==0) ? -1 : 1);

		point[i].r = r;
		point[i].g = g;
		point[i].b = b;
	}
}

CubeLines::CubeLines ( float const size )
{
	CubeCorners corner ( size, 0.6f, 0.6f, 0.6f );

	mtGin::GL::VertexRGB * dest = point;

	// BOTTOM square
	*dest++ = corner.point[0];
	*dest++ = corner.point[1];
	*dest++ = corner.point[1];
	*dest++ = corner.point[3];
	*dest++ = corner.point[3];
	*dest++ = corner.point[2];
	*dest++ = corner.point[2];
	*dest++ = corner.point[0];

	// Middle supports
	for ( int i=0; i<4; i++ )
	{
		*dest++ = corner.point[i];
		*dest++ = corner.point[i+4];
	}

	// TOP square
	*dest++ = corner.point[4];
	*dest++ = corner.point[5];
	*dest++ = corner.point[5];
	*dest++ = corner.point[7];
	*dest++ = corner.point[7];
	*dest++ = corner.point[6];
	*dest++ = corner.point[6];
	*dest++ = corner.point[4];
}

