
--
-- Copyright (C) 2024  <fastrgv@gmail.com>
--
-- 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 may read the full text of the GNU General Public License
-- at <http://www.gnu.org/licenses/>.
--

with system;
with gl, gl.binding, gl.pointers;
with glu, glu.binding, glu.pointers;
with glext, glext.binding, glext.pointers;

with interfaces.c;
use type interfaces.c.unsigned_short;

with ada.numerics.float_random;

with ada.finalization;
with unchecked_deallocation;

with text_io;

with Ada.Numerics.generic_elementary_functions;



package body splashobj is 
-- for splashs with vertically-sliding textures

-- maps texture coordinates UV to cover the full extent of a side;
-- thus the whole *.png file is visible



	package fmath is new
			Ada.Numerics.generic_elementary_functions( float );
	use fmath;


	onepi : constant float     := 3.14159_26535_89793;
	twopi : constant float     := onepi*2.0;




use text_io;
procedure myassert( condition : boolean;  flag: integer:=0 ) is
begin
  if condition=false then
  		put("ASSERTION Failed!  ");
		if flag /= 0 then
			put_line( "cyl2texobj @ " & integer'image(flag) );
		end if;
		new_line;
  		raise program_error;
  end if;
end myassert;




procedure initialize( rect: in out splash ) is
begin
	rect.vert := new varray;
	rect.txuv := new tarray;
	rect.elem := new earray;
end initialize;

procedure vfree is new unchecked_deallocation(varray,vap);
procedure tfree is new unchecked_deallocation(tarray,tap);
procedure efree is new unchecked_deallocation(earray,eap);

procedure finalize( rect: in out splash ) is
begin
	vfree( rect.vert );
	tfree( rect.txuv );
	efree( rect.elem );
end finalize;


oldet: float := 0.0;




procedure update( rect: in out splash; 
	radvel, etsec: float ) is -- 0.1 time

--Before each draw, this is called to move 
--splash-texture outward...
--by moving the U-texture coords inward

	fn: constant float := float(npts);
	dn: constant float := 1.0/fn; --max radius = 1.0

	k,t: integer := 0;
	dt: float := etsec-oldet;
	du: constant float := radvel*dt;
	up, um: float;

begin


for j in 1..npts loop

	--NW texCoord DEcreases
	up:=rect.txuv(t+1) - du; --xp
	um:=rect.txuv(t+3) - du; --xm
	if um<=0.0 or up<=0.0 then
		um:=um+1.0; up:=up+1.0;
	end if;

	rect.txuv(t+1):=up;
	rect.txuv(t+3):=um;
	rect.txuv(t+5):=um;
	rect.txuv(t+7):=up;
	t:=t+8;




--------------------------------------------

	--SW texCoord DEcreases
	up:=rect.txuv(t+1) - du; --xp
	um:=rect.txuv(t+3) - du; --xm
	if um<=0.0 or up<=0.0 then
		um:=um+1.0; up:=up+1.0;
	end if;

	rect.txuv(t+1):=up;
	rect.txuv(t+3):=um;
	rect.txuv(t+5):=um;
	rect.txuv(t+7):=up;
	t:=t+8;





-----------------------------------------------------------
-----------------------------------------------------------


	--SE texCoord DEcreases
	up:=rect.txuv(t+1) + du;
	um:=rect.txuv(t+3) + du;
	if um>=1.0 and up>=1.0 then
		um:=um-1.0; up:=up-1.0;
	end if;

	rect.txuv(t+1):=up;
	rect.txuv(t+3):=um;
	rect.txuv(t+5):=um;
	rect.txuv(t+7):=up;
	t:=t+8;




--------------------------------------------

	--NE texCoord DEcreases
	up:=rect.txuv(t+1) + du;
	um:=rect.txuv(t+3) + du;
	if um>=1.0 and up>=1.0 then
		um:=um-1.0; up:=up-1.0;
	end if;

	rect.txuv(t+1):=up;
	rect.txuv(t+3):=um;
	rect.txuv(t+5):=um;
	rect.txuv(t+7):=up;
	t:=t+8;






end loop; -- j


myassert( t=nuv, 5 );

	oldet:=etsec;

end update;



-- Here we assume a horizontal, fixed y=0, layout
-- of circular coordinates (ang,rad), rad in [0.0, 1.0]

procedure setrect( rect: splash ) is -- main axis @ x=0

	jj: glushort := 0;
	k, t, e : integer := 0;

	fn: constant float := float(npts);
	dn: constant float := 1.0/fn; --uniform step size

	xm,xp, zm,zp, dnd: float;

	xmd: float :=-dn; --decreasing increment X value
	xpd: float := 0.0; --decreasing increment X value

begin



zm:=0.0;
zp:=1.0;

xpd:=0.0;

for j in 1..npts loop -- slice in x-direction too

	-- uniform spacing:
	xm:= float(j-1)*dn;
	xp:= float(j-0)*dn; -- in 0 .. +1

	dnd:=dn*(1.0-xm); 
	--decreasing step size...creates a subtle effect of foam velocity
	--appearing to decrease with distance from waterfall centerline.

	xmd:=xpd;
	xpd:=xpd+dnd;



	--upperleft(NW) half moving toward +X(westward)
	rect.vert(k+1):=xpd;  rect.vert(k+2):=zm; --LL sw
	rect.vert(k+3):=xmd;  rect.vert(k+4):=zm; --LR se
	rect.vert(k+5):=xmd;  rect.vert(k+6):=zp; --UR ne
	rect.vert(k+7):=xpd;  rect.vert(k+8):=zp; --UL nw

	k:=k+8;

	-- texture UV coords:
	rect.txuv(t+1):=xp;  rect.txuv(t+2):=zm;
	rect.txuv(t+3):=xm;  rect.txuv(t+4):=zm;
	rect.txuv(t+5):=xm;  rect.txuv(t+6):=zp;
	rect.txuv(t+7):=xp;  rect.txuv(t+8):=zp;
	t:=t+8;

	-- element indices:
	rect.elem(e+1):=jj+0;
	rect.elem(e+2):=jj+1;
	rect.elem(e+3):=jj+2;
	rect.elem(e+4):=jj+2;
	rect.elem(e+5):=jj+3;
	rect.elem(e+6):=jj+0;
	e:=e+6;
	jj:=jj+4;

-----------------------------------------------------------

	--lowerleft(SW) half moving toward +X(westward)
	rect.vert(k+1):=xpd;  rect.vert(k+2):=-zp; --LL sw
	rect.vert(k+3):=xmd;  rect.vert(k+4):=-zp; --LR se
	rect.vert(k+5):=xmd;  rect.vert(k+6):=-zm; --UR ne
	rect.vert(k+7):=xpd;  rect.vert(k+8):=-zm; --UL nw
	k:=k+8;

	-- texture UV coords:
	rect.txuv(t+1):=xp;  rect.txuv(t+2):=zm;
	rect.txuv(t+3):=xm;  rect.txuv(t+4):=zm;
	rect.txuv(t+5):=xm;  rect.txuv(t+6):=zp;
	rect.txuv(t+7):=xp;  rect.txuv(t+8):=zp;
	t:=t+8;

	-- element indices:
	rect.elem(e+1):=jj+0;
	rect.elem(e+2):=jj+1;
	rect.elem(e+3):=jj+2;
	rect.elem(e+4):=jj+2;
	rect.elem(e+5):=jj+3;
	rect.elem(e+6):=jj+0;
	e:=e+6;
	jj:=jj+4;




-----------------------------------------------------------
-----------------------------------------------------------
	--lowerright(SE) half moving toward -X(eastward)
	rect.vert(k+1):=-xmd;  rect.vert(k+2):=-zp; --sw
	rect.vert(k+3):=-xpd;  rect.vert(k+4):=-zp; --se
	rect.vert(k+5):=-xpd;  rect.vert(k+6):=-zm; --ne
	rect.vert(k+7):=-xmd;  rect.vert(k+8):=-zm; --nw
	k:=k+8;

	-- texture UV coords:
	--this twist avoids a mirror reflection on the 2 sides
	rect.txuv(t+1):=1.0-xm;  rect.txuv(t+2):=zm;
	rect.txuv(t+3):=1.0-xp;  rect.txuv(t+4):=zm;
	rect.txuv(t+5):=1.0-xp;  rect.txuv(t+6):=zp;
	rect.txuv(t+7):=1.0-xm;  rect.txuv(t+8):=zp;

	t:=t+8;

	-- element indices:
	rect.elem(e+1):=jj+0;
	rect.elem(e+2):=jj+1;
	rect.elem(e+3):=jj+2;
	rect.elem(e+4):=jj+2;
	rect.elem(e+5):=jj+3;
	rect.elem(e+6):=jj+0;
	e:=e+6;
	jj:=jj+4;

---------------------------------------------------------
	--upperright(NE) half moving toward -X(eastward)
	rect.vert(k+1):=-xmd;  rect.vert(k+2):=zm; --sw
	rect.vert(k+3):=-xpd;  rect.vert(k+4):=zm; --se
	rect.vert(k+5):=-xpd;  rect.vert(k+6):=zp; --ne
	rect.vert(k+7):=-xmd;  rect.vert(k+8):=zp; --nw
	k:=k+8;

	-- texture UV coords:
	--this twist avoids a mirror reflection on the 2 sides
	rect.txuv(t+1):=1.0-xm;  rect.txuv(t+2):=zm;
	rect.txuv(t+3):=1.0-xp;  rect.txuv(t+4):=zm;
	rect.txuv(t+5):=1.0-xp;  rect.txuv(t+6):=zp;
	rect.txuv(t+7):=1.0-xm;  rect.txuv(t+8):=zp;


	t:=t+8;

	-- element indices:
	rect.elem(e+1):=jj+0;
	rect.elem(e+2):=jj+1;
	rect.elem(e+3):=jj+2;
	rect.elem(e+4):=jj+2;
	rect.elem(e+5):=jj+3;
	rect.elem(e+6):=jj+0;
	e:=e+6;
	jj:=jj+4;




end loop; -- j


myassert( k=nvert, 1 );
myassert( t=nuv, 2 );
myassert( e=nelm, 3 );



end setrect;









--
-- note:  the shaders for these objects must have two 
-- input "layouts", as well as whatever uniforms are needed:
--
-- layout(location=0) in vec2 vertPosName
-- layout(location=1) in vec2 texUVname
--
-- ...their actual names can be whatever is convenient
--

use gl;
use glext;
use glext.binding;
use gl.binding;

procedure draw( rect: splash; vertbuff, uvbuff, elembuff : gluint ) is
begin

	-- 0th attribute:  vertex locations
	glBindBuffer(gl_array_buffer, vertbuff);
	glBufferData(gl_array_buffer, glsizeiptr(4*nvert), rect.vert(1)'address, gl_static_draw);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0,2,gl_float,gl_false,0, system.null_address);

	-- 1st attribute:  texture UV coords
	glBindBuffer(gl_array_buffer, uvbuff);
	glBufferData(gl_array_buffer, glsizeiptr(4*nuv), rect.txuv(1)'address, gl_static_draw);
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1,2,gl_float,gl_false,0, system.null_address);

	-- element indices:
	glBindBuffer(gl_element_array_buffer, elembuff);
	glBufferData(gl_element_array_buffer, glsizeiptr(2*nelm), rect.elem(1)'address, gl_static_draw);

	glEnable(gl_blend);
	glBlendFunc(gl_src_alpha, gl_one_minus_src_alpha);


	glDrawElements( gl_triangles, glint(nvert), gl_unsigned_short, system.null_address );


	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);

end draw;






end splashobj;

