#ifndef _PIUMA_RENDER_SHADER_H_
#define _PIUMA_RENDER_SHADER_H_

#include "../lib/types.h"
#include "GL/glcorearb.h"

/*
I put the uniform ids of all the shaders in the r_shader structure. Then I use only the
ones I need. Yeah, it's not very flexible.

I would like to have automatic syncronization between shader and C++ code.
There are 3 ways to do that:
- Parse shader code and auto-generate C++ structures and code;
- Parse C++ structures and generate a shader source, or update an existing one;
- Use a language than let me define shader code directly in that language, then it's compiled
  directly to GPU ASM, or it generates GLSL code that is then given to the GPU driver. This is
  the ideal solution, but yeah, that language is not C++... if it event exists. Let's hope for
  a better future.
*/

#define R_SHADER_TEXTURES_MAX 4
#define R_SHADER_COLOR_MAX 4

struct r_shader
{
	GLuint id;

	// Common state
	GLint time;
	GLint width;
	GLint height;

	// View and camera
	GLint view_matrix;
	GLint view_matrix_inverse;
	GLint model_matrix;
	GLint camera_position;

	// For arrays, the name in the shader is in the format [name][index].
	// Example: color[4] will be: color0, color1, color2, color3

	// Generic parameters that can be used for different purpose based on the shader needs.
	// Example: texture1 could be a diffuse texture, texture2 an emissive texture, texture3 bump mapping
	GLint color[R_SHADER_COLOR_MAX];
	GLint has_texture     [R_SHADER_TEXTURES_MAX]; // Is textureX assigned or not?
	GLint texture         [R_SHADER_TEXTURES_MAX]; // Actual texture
	GLint texture_channels[R_SHADER_TEXTURES_MAX]; // Number of channels in the texture data

	// Lights and shadows
	// @Cleanup: maybe merge this with the generic texture parameter?
	GLint lights;
	GLint has_shadow_map;
	GLint shadow_map;
	GLint shadow_matrix;

	// Environment map
	GLint has_environment_map;
	GLint environment_map;

	// PBR material
	GLint has_albedo_texture;
	GLint albedo_texture;
	GLint albedo_factor;
	GLint has_metallic_texture;
	GLint metallic_texture;
	GLint metallic_factor;
	GLint has_roughness_texture;
	GLint roughness_texture;
	GLint roughness_factor;
	GLint has_normal_texture;
	GLint normal_texture;
	GLint has_emissive_texture;
	GLint emissive_texture;
	GLint emissive_factor;
};


bool r_shader_from_files(r_shader *shader, const char *vertex, const char *fragment, const char *geometry = NULL, const char *tesseletion_control = NULL, const char *tesseletion_evaluation = NULL, const char *compute = NULL);
bool r_shader_from_text(r_shader *shader, const char *vertex, const char *fragment, const char *geometry = NULL, const char *tesseletion_control = NULL, const char *tesseletion_evaluation = NULL, const char *compute = NULL);

void r_shader_delete(r_shader *shader);



#endif
