require 'luagl'
require 'luaglut'
require 'memarray'
local fi = require 'luafreeimage'

local splif_version = 'SPACETIME SPECIAL'
local splif_titletext = 'Trilobit ScriPtable Lua Interactive MultiplatForm (SPLIF) version ' .. splif_version
local debugmode = -1
local res_w = 0
local res_h = 0
local res_override = 0

local quit = false
local fps = 60
local fps_str = ''
local msec = 1000 / fps
local frames = 0
local cur_fps = 0
local start_time
local fps_time
local elapsed_time
local millis = 0
local timedelta = 0
local last_frame = 0
local ppm, width, height
local debug_pause = 1
local seeked = 0
local song_time_end = 0
local load_number
local loading = 1
local init_done = 0
do_seekeffect = 0
local picnum = 0
local spectrum = {}

local mouse_x = 0
local mouse_y = 0
local song_time_end = 0

local mouse_over_slider = 0

local slider_x = 10
local slider_y = 10
local slider_w = 20
local slider_h = 10
local slider_bar_pos = 0

--

local width = 0
local height = 0

local effect_time = 0 -- time spent on this effect
local effect_endtime = 0 -- time to end the effect
local effect_params = {0,0,0,0,0,0,0,0,0,0,0} -- variable list of parameters for randomizer initialization
local effect_layercount = 0 -- how many layers to render for this effect (1-3)
local effect_layers = {0,0,0,0,0,0,0,0,0,0,0} -- list of effect numbers for layers
local effect_blendmodes = {0,0,0,0,0,0,0,0,0,0,0}
local effect_max = 9 -- number of last effect, UPDATE THIS WHEN YOU ADD EFFECTS

local next_effect = 0 -- debug

local millis = 0

local function glutBitmapString(font, str)
        for i = 1, string.len(str) do
                glutBitmapCharacter(font, string.byte(str, i))
        end
end

function engine_spectrum() 
	
	temp = song_spectrum()
	for i = 0, 511 do
		spectrum[i] = ( spectrum[i] * 0.3 ) + (temp[i] *0.7)
	end

	return spectrum;
end

function engine_main() 

	res_override, res_w, res_h, res_hz, res_windowed = demo_getresolution()
	
	for i = 0, 511 do
		spectrum[i] = 0.5
	end

	glutInit(arg)

	if res_override == 1 then
		if res_windowed >= 1 then glutInitWindowSize(res_w, res_h)
		else glutGameModeString(res_w .. "x" .. res_h .. ":32" .. "@" .. res_hz)
		end
	end

	local jit_version = "(N/A)"

	if jit then
		if jit.version then
			jit_version = jit.version
		end
	end

	print('[ ' .. splif_titletext .. ' ]')
	print('[ Running on Lua: "' .. _VERSION .. '" LuaJIT: "' .. jit_version .. '" LuaGL: "' .. luagl.VERSION .. '" LuaGLUT: "' .. luaglut.VERSION .. '" FMOD Ex: "' .. song_getfmodversion() .. '" ]')
	freeimage_version, freeimage_copyright = fi.getInfo()
	print('[ FreeImage: "' .. freeimage_version .. '" (' .. freeimage_copyright .. ') ]')

	glutInitDisplayMode(GLUT_RGB + GLUT_DOUBLE + GLUT_DEPTH + GLUT_MULTISAMPLE)
	if arg then title = arg[0] else title = splif_titletext end
	if res_windowed >= 1 then window = glutCreateWindow(title)
	else window = glutEnterGameMode()
	end

	if res_windowed == 2 then glutFullScreen() end
	
	glutSetCursor(GLUT_CURSOR_NONE)

	glutDisplayFunc(display_func)
	glutKeyboardFunc(keyboard_func)
	glutReshapeFunc(resize_func)
	glutTimerFunc(msec, timer_func, 0)
	
	-- rodent stuff
	glutMouseFunc(mouse_func)
	glutMotionFunc(mouse_motion)
	glutPassiveMotionFunc(mouse_motion)
	
	-- hack for osx tearing and other misc inits

	demosystem_init()

	if res_override == 1 and res_windowed == 0 then
		print('[ Requested screen mode: ' .. res_w .. 'x' .. res_h .. ' ('  .. res_hz .. 'Hz) ]')
	end
	if res_windowed == 0 then print ("[ Screen mode: " .. glutGameModeGet(GLUT_GAME_MODE_WIDTH) .. "x" .. glutGameModeGet(GLUT_GAME_MODE_HEIGHT) .. "x" .. glutGameModeGet(GLUT_GAME_MODE_PIXEL_DEPTH) .. " (" .. glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) .. "Hz) ]") end
	start_time = glutGet(GLUT_ELAPSED_TIME)
	fps_time = start_time

	math.randomseed(os.time())

	print("Are you experienced?")

	load_textures()

	song_play()
	song_time_end = song_getlength()
	glutMainLoop()
	
end

local fire_textures = {}
local water_textures = {}
local fractal_textures = {}
local grancha_textures = {}
local chaka_textures = {}
local balls_textures = {}
local flafra_textures = {}

function load_textures()
	-- fire textures
	for i = 0, 59 do
		fire_textures[i+1] = load_texture("data/fire-" .. i .. ".png")
	end

	-- water textures
	for i = 0, 7 do
		water_textures[i+1] = load_texture("data/water-" .. i .. ".png")
	end

	-- fractal textures
	for i = 0, 60 do
		fractal_textures[i+1] = load_texture("data/fractal-" .. i .. ".png")
	end

	j = 0
	for i = 60, 120 do
		fractal_textures[i+1] = fractal_textures[60-j]
		j = j + 1
	end

	-- grancha textures
	for i = 1, 31 do
		grancha_textures[i] = load_texture("data/gran-" .. i .. ".png")
	end

	for i = 0, 7 do
		chaka_textures[i+1] = load_texture("data/chaka-" .. i .. ".png")
	end

	for i = 0, 20 do
		balls_textures[i+1] = load_texture("data/balls-" .. i .. ".png")
	end

	for i = 0, 32 do
		flafra_textures[i+1] = load_texture("data/flafra-" .. i .. ".png")
	end
end

function load_texture(fname)
	io.write("Loading texture " .. fname .. "...")
	local dib = fi.bitmap()
	assert(dib:load("png", fname))
	assert(dib:convertTo32Bits(dib))
	width = dib:getWidth()
	height = dib:getHeight()
	local ppm = memarray('uchar', width * height * 3)
	i = 0
   for y = 1, height do
      local dst_idx = (height - y) * width * 3
      for x = 0, width - 1 do
	 iR, iG, iB, iA = dib:getRGBA(x,height-y)
         
         ppm[dst_idx + 3*x + 0] = iR
         ppm[dst_idx + 3*x + 1] = iG
         ppm[dst_idx + 3*x + 2] = iB
	 i = i + 3
      end
   end
	if loading == 1 then 
		picnum = picnum + 1
	end

	texnum = memarray('uchar', 1)

	glGenTextures(1, texnum:ptr())
	texture_number = texnum[0]
	glBindTexture(GL_TEXTURE_2D, texture_number)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, ppm:ptr())
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_MODULATE)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)

	print("done. (texture id #" .. texture_number .. ")")
	return texture_number
end

function load_texture_RGBA(fname)
	local dib = fi.bitmap()
	assert(dib:load("png", fname))
	assert(dib:convertTo32Bits(dib))
	width = dib:getWidth()
	height = dib:getHeight()
	local ppm = memarray('uchar', width * height * 4)
	i = 0
   for y = 1, height do
      local dst_idx = (height - y) * width * 4
      for x = 0, width - 1 do
	 iR, iG, iB, iA = dib:getRGBA(x,height-y)
         
         ppm[dst_idx + 4*x + 0] = iR
         ppm[dst_idx + 4*x + 1] = iG
         ppm[dst_idx + 4*x + 2] = iB
         ppm[dst_idx + 4*x + 3] = iA
	 i = i + 4
      end
   end
	return ppm, width, height
end


function load_texture_ALPHA(fname)
   local f
   local width = 0
   local height = 0
   local depth = 0
   local data

   f = assert(io.open(fname, 'rb'))
   assert(f:read('*l') == 'P6')
   width = f:read('*n')
   height = f:read('*n')
   depth = f:read('*l')
   depth = f:read('*l')
   data = f:read('*a')
   f:close()

   local ppm = memarray('uchar', width * height * 4)
   for y = 1, height do
      local dst_idx = (height - y) * width * 4
      local src_idx = (y - 1) * width * 3
      for x = 0, width - 1 do
         ppm[dst_idx + 4*x + 0] = string.byte(data, src_idx + 3*x + 1)
         ppm[dst_idx + 4*x + 1] = string.byte(data, src_idx + 3*x + 2)
         ppm[dst_idx + 4*x + 2] = string.byte(data, src_idx + 3*x + 3)

	 colvalue = ppm[dst_idx + 4*x + 0] + ppm[dst_idx + 4*x + 1] + ppm[dst_idx + 4*x + 2]
	 colvalue = colvalue / 3

         if colvalue == 0 then ppm[dst_idx + 4*x + 3] = 1
	 else
		ppm[dst_idx + 4*x + 3] = 0
	 end
      end
   end

   return ppm, width, height
end

function debug()
	glDisable(GL_BLEND)
	glDisable(GL_TEXTURE_2D)
	glMatrixMode(GL_PROJECTION)
	glPushMatrix()
	glLoadIdentity()
	glOrtho(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT), -3, 3)
	if debugmode == 1 then
		fps_str = 'fps: [' .. cur_fps .. ']'
		glColor3d(1,1,1)
		glRasterPos2d(2,glutGet(GLUT_WINDOW_HEIGHT)-16)
		glutBitmapString(GLUT_BITMAP_8_BY_13, fps_str) 
		glColor3d(0.2,0.2,0.2)
		glRasterPos2d(2,glutGet(GLUT_WINDOW_HEIGHT)-30)
		glutBitmapString(GLUT_BITMAP_8_BY_13, fps_str )
	end
	glPopMatrix()
end

function display_func()
	amillis = song_getmillis()
	if amillis >= song_time_end then
		quit = true
		if res_windowed == 0 then glutLeaveGameMode() end
		glutDestroyWindow(window)
		os.exit(0)
	end

	if quit then return end

	elapsed_time = glutGet(GLUT_ELAPSED_TIME) - fps_time

	spectrum = engine_spectrum()

	width = glutGet(GLUT_WINDOW_WIDTH)
	height = glutGet(GLUT_WINDOW_HEIGHT)

	glClearColor(0,0,0,1);
	glClear(GL_COLOR_BUFFER_BIT + GL_DEPTH_BUFFER_BIT)

	glPushMatrix()
		glEnable(GL_MULTISAMPLE)
		glLoadIdentity()
		glOrtho(0, width, 0, height, -100, 100)
		glMatrixMode(GL_MODELVIEW)

		-- time stuff

		effect_time = effect_time + elapsed_time
		millis = glutGet(GLUT_ELAPSED_TIME)

		if effect_time >= effect_endtime or next_effect == 1 then

			next_effect = 0
			-- init next effect
			effect_time = 0

			effect_endtime = math.random(100*1000,300*1000) -- 7sec - 20sec
			effect_layercount = math.random(3,6)
			for i = 1, effect_layercount do
				new_effectnum = math.random(0,effect_max)

				effect_layers[i] = new_effectnum

				effect_blendmodes[i] = math.random(0,5)
			end

			for i = 1, 9 do
				effect_params[i] = math.random()
			end
		end

		-- render stuff

		glEnable(GL_BLEND)

		for current_layernum = 1, effect_layercount do

			effect_params[current_layernum] = effect_params[current_layernum] * math.cos(current_layernum*0.001*(millis*0.0000001))

			-- blending

			if effect_blendmodes[current_layernum] == 0 then glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR) end
			if effect_blendmodes[current_layernum] == 1 then glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_DST_COLOR) end
			if effect_blendmodes[current_layernum] == 2 then glBlendFunc(GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR) end
			if effect_blendmodes[current_layernum] == 3 then glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_DST_ALPHA) end
			if effect_blendmodes[current_layernum] == 4 then glBlendFunc(GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE) end

			-- effects 

			if effect_layers[current_layernum] == 0 then
				glPushMatrix()
				render_waveform_black(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 1 then
				glPushMatrix()
				render_waveform_invert(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 2 then
				glPushMatrix()
				render_waveform_white(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 3 then
				glPushMatrix()
				render_fireanim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 4 then
				glPushMatrix()
				render_wateranim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 5 then
				glPushMatrix()
				render_fractalanim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 6 then
				glPushMatrix()
				render_granchaanim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 7 then
				glPushMatrix()
				render_chakaanim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 8 then
				glPushMatrix()
				render_ballsanim(spectrum)
				glPopMatrix()
			end
			if effect_layers[current_layernum] == 9 then
				glPushMatrix()
				render_flafraanim(spectrum)
				glPopMatrix()
			end
		end
	glPopMatrix()

	-- RENDERING END

	debug()

	glutSwapBuffers()

	frames = frames + 1
	if elapsed_time > 1000 then
		cur_fps = frames * 1000 / elapsed_time
		fps_time = fps_time + elapsed_time
		frames = 0
	end

end

-- EFFECTS ARE HERE

function render_waveform_black(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	glEnable(GL_TEXTURE_2D)
	beat = beat / 100
	for i = 1, 512 do
	texn = ((i%30)+1)
	glBindTexture(GL_TEXTURE_2D, fire_textures[texn])
		glTranslated(width/2,height/2,0)
		glRotated(beat*70,0,0,1)
		glRotated(math.cos(millis*0.00001),1,0,0)
		glTranslated(-width/2,-height/2,0)

		glColor4d(math.cos(millis*0.0001), math.sin(millis*000015), beat*30, math.sin(i*0.001))
		glBegin(GL_QUADS)
			glTexCoord2d(0,0)
			glVertex3d(0,0,0)
			glTexCoord2d(1,0)
			glVertex3d(width,0,0)
			glTexCoord2d(1,1)
			glVertex3d(width,height/30,0)
			glTexCoord2d(0,1)
			glVertex3d(0,height/30,0)
		glEnd()
	end
end

function render_waveform_invert(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100
	glTranslated(width/2,height/2, 0)
	glRotated(math.cos(millis*0.0001*effect_params[3])*720*beat*20,0,0,1)
	glTranslated(-width/2,-height/2, 0)

	glEnable(GL_TEXTURE_2D)
	for i = 0, 50 do
	glBindTexture(GL_TEXTURE_2D, fire_textures[i+1])
	glTranslated(width/2,height/2, 0)
		glRotated(i*math.cos(millis*0.001+beat*10)*0.1,effect_params[1],math.sin(millis*0.0002+i),1)
	glTranslated(-width/2,-height/2, 0)
		glColor4d(math.cos(millis*0.001)*0.5, math.sin(millis*0.0015)*0.8, (512*0.4)/(i*10), math.cos(i*0.1))
		x = (i*10/512)*width*effect_params[2]*beat*150
		x2 = ((i*10+1)/512)*width*effect_params[3]
		y = (spectrum[i]*50*height*effect_params[4])
		glPushMatrix()
		glBegin(GL_QUADS)
			glTexCoord2d(0,0)
			glVertex3d(x-y,y+x2,0)
			glTexCoord2d(1,0)
			glVertex3d(x2-y,y+x,x)
			glTexCoord2d(1,1)
			glVertex3d(x2,y-x,0)
			glTexCoord2d(0,1)
			glVertex3d(x+y,y+x2,y)
		glEnd()
		glPopMatrix()
	end
end

function render_waveform_white(spectrum)
	beat = 0
	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(width/2,height/2, 0)
	glRotated(math.sin(beat*100+millis*0.00015*effect_params[2])*720+beat*30,math.cos(millis*0.000001),beat,1)
	glTranslated(-width/2,-height/2, 0)
	for i = 0, 50 do
	glTranslated(width/2,height/2, 0)
		glRotated(i*math.sin(millis*0.0007)*0.6,effect_params[1],0,1)
	glTranslated(-width/2,-height/2, 0)
		glColor4d(1-i/50*effect_params[1], 1-i/25+math.cos(millis*0.00001), 1-i/35+beat*200*effect_params[2], math.sin(i*0.6*beat*20))
		x = (i*10/512)*width*effect_params[2]*beat*30
		x2 = ((i*10+1)/512)*width*effect_params[4]
		y = (spectrum[i]*50*height*effect_params[3])
		glPushMatrix()
		glBegin(GL_QUADS)
			glVertex3d(x,y,x)
			glVertex3d(x2-y,y+x2,0)
			glVertex3d(x2,y-x,0)
			glVertex3d(x,y+x,y)
		glEnd()
		glPopMatrix()
	end
end

local fireanim_counter = 0

function render_fireanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100


	fireanim_counter = fireanim_counter + beat*200+millis*0.000001
	glEnable(GL_TEXTURE_2D)
	firenum = fire_textures[(math.ceil(fireanim_counter)%59)+1]
	glBindTexture(GL_TEXTURE_2D, firenum)

	glColor4d(math.cos(millis*0.0001),math.sin(millis*0.00015),math.cos(millis*0.0002),0.9)
	glBegin(GL_QUADS)
		glTexCoord2d(0,0)
		glVertex3d(0,0,0)
		glTexCoord2d(1,0)
		glVertex3d(width,0,0)
		glTexCoord2d(1,1)
		glVertex3d(width,height,0)
		glTexCoord2d(0,1)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local wateranim_counter = 0

function render_wateranim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.cos(millis*0.0001+beat*20))

	wateranim_counter = wateranim_counter + beat*50+millis*0.0000007
	glEnable(GL_TEXTURE_2D)
	waternum = water_textures[(math.ceil(wateranim_counter)%7)+1]
	glBindTexture(GL_TEXTURE_2D, waternum)

	glColor4d(math.sin(millis*0.0001),math.cos(millis*0.00015),math.cos(millis*0.0002),0.8)
	glBegin(GL_QUADS)
		glTexCoord2d(0,0)
		glVertex3d(0,0,0)
		glTexCoord2d(1,0)
		glVertex3d(width,0,0)
		glTexCoord2d(1,1)
		glVertex3d(width,height,0)
		glTexCoord2d(0,1)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local fractalanim_counter = 0

function render_fractalanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.sin(millis*0.0001+beat*20))

	fractalanim_counter = fractalanim_counter + beat*50+millis*0.0000007

	glEnable(GL_TEXTURE_2D)
	fractalnum = fractal_textures[(math.ceil(fractalanim_counter)%120)+1]
	glBindTexture(GL_TEXTURE_2D, fractalnum)

	glColor4d(math.cos(millis*0.00015),math.sin(millis*0.00012),math.sin(millis*0.0004),0.95)
	offset = math.cos(millis*0.00001)*math.sin(millis*0.000015)*0.3*effect_params[2]
	offsety = effect_params[2]
	glBegin(GL_QUADS)
		glTexCoord2d(0+offset,0+offsety)
		glVertex3d(0,0,0)
		glTexCoord2d(1+offset,0+offsety)
		glVertex3d(width,0,0)
		glTexCoord2d(1+offset,1+offsety)
		glVertex3d(width,height,0)
		glTexCoord2d(0+offset,1+offsety)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local granchaanim_counter = 0

function render_granchaanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.cos(millis*0.0001+beat*20))

	granchaanim_counter = granchaanim_counter + beat*140+millis*0.0000007

	glEnable(GL_TEXTURE_2D)
	granchanum = grancha_textures[(math.ceil(granchaanim_counter)%31)+1]
	glBindTexture(GL_TEXTURE_2D, granchanum)

	glColor4d(math.sin(millis*0.00012),math.cos(millis*0.00017),math.sin(millis*0.0002),0.7+(math.sin(millis*0.00015)*0.2))
	offset = math.sin(millis*0.00015)*math.cos(millis*0.0001)*effect_params[3]*beat*30
	offsety = effect_params[3]
	glBegin(GL_QUADS)
		glTexCoord2d(0-offset,0+offsety)
		glVertex3d(0,0,0)
		glTexCoord2d(1+offset,0+offsety)
		glVertex3d(width,0,0)
		glTexCoord2d(1+offset,1+offsety)
		glVertex3d(width,height,0)
		glTexCoord2d(0-offset,1+offsety)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local chakaanim_counter = 0

function render_chakaanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.cos(millis*0.0001+beat*20))

	chakaanim_counter = chakaanim_counter + beat*40+millis*0.0000001

	glEnable(GL_TEXTURE_2D)
	chakanum = chaka_textures[(math.ceil(chakaanim_counter)%7)+1]
	glBindTexture(GL_TEXTURE_2D, chakanum)

	glColor4d(math.cos(millis*0.00018),math.sin(millis*0.00014),math.cos(millis*0.00016),0.8+(math.sin(millis*0.00015)*0.15))
	offset = math.sin(millis*0.00012)*math.cos(millis*0.00017)*effect_params[2]*beat*120
	offsety = effect_params[2]
	glBegin(GL_QUADS)
		glTexCoord2d(0+offset,0+offsety)
		glVertex3d(0,0,0)
		glTexCoord2d(1+offset,0+offsety)
		glVertex3d(width,0,0)
		glTexCoord2d(1+offset,1+offsety)
		glVertex3d(width,height,0)
		glTexCoord2d(0+offset,1+offsety)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local ballsanim_counter = 0

function render_ballsanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.cos(millis*0.0001+beat*20))

	ballsanim_counter = ballsanim_counter + beat*70+millis*0.0000001

	glEnable(GL_TEXTURE_2D)
	ballsnum = balls_textures[(math.ceil(ballsanim_counter)%20)+1]
	glBindTexture(GL_TEXTURE_2D, ballsnum)

	glColor4d(math.sin(millis*0.00014),math.cos(millis*0.00017),math.sin(millis*0.00013),0.8+(math.sin(millis*0.00013)*0.18))
	offset = math.sin(millis*0.00014)*math.sin(millis*0.00014)*effect_params[3]*beat*110
	offsety = effect_params[1]
	glBegin(GL_QUADS)
		glTexCoord2d(0+offset,0+offsety)
		glVertex3d(0,0,0)
		glTexCoord2d(1+offset,0+offsety)
		glVertex3d(width,0,0)
		glTexCoord2d(1+offset,1+offsety)
		glVertex3d(width,height,0)
		glTexCoord2d(0+offset,1+offsety)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

local flafraanim_counter = 0

function render_flafraanim(spectrum)
	beat = 0

	for i = 1, 101 do
		beat = beat + spectrum[i]
	end

	beat = beat / 100

	glTranslated(0,0,math.cos(millis*0.0001+beat*20))

	flafraanim_counter = flafraanim_counter + beat*70+millis*0.00000015

	glEnable(GL_TEXTURE_2D)
	flafranum = flafra_textures[(math.ceil(flafraanim_counter)%32)+1]
	glBindTexture(GL_TEXTURE_2D, flafranum)

	glColor4d(math.cos(millis*0.00014),math.sin(millis*0.00015),math.sin(millis*0.00017),0.8+(math.sin(millis*0.00017)*0.18))
	offset = math.sin(millis*0.00014)*math.cos(millis*0.00012)*effect_params[1]*beat*115
	glBegin(GL_QUADS)
		glTexCoord2d(0+offset,0)
		glVertex3d(0,0,0)
		glTexCoord2d(1+offset,0)
		glVertex3d(width,0,0)
		glTexCoord2d(1+offset,1)
		glVertex3d(width,height,0)
		glTexCoord2d(0+offset,1)
		glVertex3d(0,height,0)
	glEnd()
	glDisable(GL_TEXTURE_2D)
end

-- EFFECTS END

function resize_func(w, h)
	local ratio = w / h
	glMatrixMode(GL_PROJECTION)
	glLoadIdentity()
	if w < h then
		glViewport(0,0,w,w)
		ratio = w/w
	else
		local center_x = 0
		if w > 2560 then 
			center_x = (w / 2) - (2560/2)
			w = 2560
		end
		if h > 1440 then h = 1440
		end
		
		ratio = w / h
		glViewport(center_x,0,w,h)
	end
	gluPerspective(45,ratio,1,10000)
	glMatrixMode(GL_MODELVIEW)
	glLoadIdentity()
	glEnable(GL_DEPTH_TEST)
	glEnable(GL_NORMALIZE)
end

function timer_func()
	if quit then return end

	glutSetWindow(window)
	glutTimerFunc(msec, timer_func, 0)
	glutPostRedisplay()
end

function keyboard_func(key,x,y)
	if key == 27 then
		quit = true
		if res_windowed == 0 then glutLeaveGameMode() end
		glutDestroyWindow(window)
		os.exit(0)
	end
end

function mouse_func(button, state, x , y) 
	--print ("mouse_func button = " .. button .. " state = " .. state .. " x = " .. x .. " y = " .. y)
	mouse_x = x
	mouse_y = y
end

function mouse_entry(state) 
	--print ("mouse_entry state=" .. state)
end

function mouse_motion(x, y) 
	--print ("mouse move x = " .. x .. " y = " .. y)
	mouse_x = x
	mouse_y = y
	
	if debugmode == 1 then
		mouse_over_slider = 0
		
		-- glunproject mouse coordz
	
	end
end

engine_main()




