Files
geant4/source/externals/g4tools/include/toolx/sg/GL_manager
T
2025-12-05 08:54:02 +01:00

1130 lines
38 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef toolx_sg_GL_manager
#define toolx_sg_GL_manager
#ifndef GL_VERSION_1_1
#error You have to include OpenGL header(s) before including this file.
#endif
#include <tools/sg/render_manager>
#include <tools/mapmanip>
#include <tools/carray>
#include <tools/num2s>
#ifdef TOOLS_USE_GL_VERSION_3_2
#include <tools/lina/mat4f>
#endif
#include <sstream>
#include <cmath> //::sqrt
namespace toolx {
namespace sg {
template <class GL_FUNCTIONS>
class gsto_elem: protected GL_FUNCTIONS {
TOOLS_T_SCLASS(GL_FUNCTIONS,toolx::sg::gsto_elem)
using parent_gl_functions = GL_FUNCTIONS;
public:
enum kind {
kind_texture,
kind_buffer,
kind_list,
kind_memory
};
public:
#ifdef TOOLS_USE_GL_VERSION_3_2
gsto_elem(kind a_kind,unsigned int a_gl_id,size_t a_size,const float* a_data,unsigned int a_vao_id = 0)
:m_gl_id(a_gl_id)
,m_vao_id(a_vao_id)
#else
gsto_elem(kind a_kind,unsigned int a_gl_id,size_t a_size,const float* a_data)
:m_gl_id(a_gl_id)
#endif
,m_kind(a_kind)
,m_size(a_size)
,m_data(0)
{
if(a_data) {
size_t num = m_size/sizeof(float);
m_data = new float[num];
::memcpy(m_data,a_data,m_size);
}
}
virtual ~gsto_elem() {
if(m_kind==kind_texture) {
parent_gl_functions::gl__DeleteTextures(1,&m_gl_id);
} else if(m_kind==kind_buffer) {
#ifdef TOOLS_USE_GL_VERSION_3_2
parent_gl_functions::gl__DeleteBuffers(1,&m_gl_id);
parent_gl_functions::gl__DeleteVertexArrays(1,&m_vao_id);
#endif
} else if(m_kind==kind_list) {
if(m_gl_id) {
#ifndef TOOLS_USE_GL_VERSION_3_2
parent_gl_functions::gl__DeleteLists(m_gl_id,1);
#endif
}
}
if(m_data) {
delete [] m_data;
}
}
private:
gsto_elem(const gsto_elem& a_from)
:parent_gl_functions(a_from)
,m_gl_id(a_from.m_gl_id)
#ifdef TOOLS_USE_GL_VERSION_3_2
,m_vao_id(a_from.m_vao_id)
#endif
,m_kind(a_from.m_kind)
,m_size(a_from.m_size)
,m_data(0)
{
if(a_from.m_data) {
size_t num = m_size/sizeof(float);
m_data = new float[num];
::memcpy(m_data,a_from.m_data,m_size);
}
}
gsto_elem& operator=(const gsto_elem& a_from){
if(&a_from==this) return *this;
m_gl_id = a_from.m_gl_id;
#ifdef TOOLS_USE_GL_VERSION_3_2
m_vao_id = a_from.m_vao_id;
#endif
m_kind = a_from.m_kind;
m_size = a_from.m_size;
if(m_data) {
delete [] m_data;
m_data = 0;
}
if(a_from.m_data) {
size_t num = m_size/sizeof(float);
m_data = new float[num];
::memcpy(m_data,a_from.m_data,m_size);
}
return *this;
}
public:
bool is_valid() /*const*/ {
if(!parent_gl_functions::initialize()) return false;
if(m_kind==kind_texture) {
return (parent_gl_functions::gl__IsTexture(m_gl_id)==GL_TRUE?true:false);
} else if(m_kind==kind_buffer) {
#ifdef TOOLS_USE_GL_VERSION_3_2
return (parent_gl_functions::gl__IsBuffer(m_gl_id)==GL_TRUE?true:false); //If ok, then VAO is ok too.
#endif
} else if(m_kind==kind_list) {
#ifndef TOOLS_USE_GL_VERSION_3_2
return (parent_gl_functions::gl__IsList(m_gl_id)==GL_TRUE?true:false);
#endif
} else if(m_kind==kind_memory) {
return true;
}
return false;
}
void bind() /*const*/ {
parent_gl_functions::initialize();
if(m_kind==kind_texture) {
parent_gl_functions::gl__BindTexture(GL_TEXTURE_2D,m_gl_id);
} else if(m_kind==kind_buffer) {
#ifdef TOOLS_USE_GL_VERSION_3_2
parent_gl_functions::gl__BindVertexArray(m_vao_id);
parent_gl_functions::gl__BindBuffer(GL_ARRAY_BUFFER,m_gl_id);
#endif
}
}
public:
unsigned int m_gl_id;
#ifdef TOOLS_USE_GL_VERSION_3_2
unsigned int m_vao_id;
#endif
kind m_kind;
size_t m_size;
float* m_data;
};
template <class GL_FUNCTIONS>
class GL_manager_T : public virtual tools::sg::render_manager, protected GL_FUNCTIONS {
typedef tools::sg::render_manager parent;
using parent_gl_functions = GL_FUNCTIONS;
typedef gsto_elem<GL_FUNCTIONS> gsto_t;
typedef typename std::map<unsigned int, gsto_t*>::const_iterator gstos_it_t;
public:
TOOLS_T_SCLASS(GL_FUNCTIONS,toolx::sg::GL_manager_T)
virtual void* cast(const std::string& a_class) const {
if(void* p = tools::cmp_cast<GL_manager_T>(this,a_class)) {return p;}
else return 0;
}
public:
virtual bool begin_render(int a_x,int a_y,unsigned int a_ww,unsigned int a_wh,
float a_r,float a_g,float a_b,float a_a,bool a_clear = true) {
if (!parent_gl_functions::initialize()) {
m_out << "toolx::sg::GL_manager_T::begin_render: parent_gl_functions::initialize() failed." << std::endl;
return false;
}
if(m_gl_version.empty()) {
{m_gl_version.clear();
const char* _sv = (const char*)parent_gl_functions::gl__GetString(GL_VERSION);
if(_sv) m_gl_version = _sv;}
#ifdef TOOLS_USE_GL_VERSION_3_2
{m_gl_shading_language_version.clear();
const char* _sv = (const char*)parent_gl_functions::gl__GetString(GL_SHADING_LANGUAGE_VERSION);
if(_sv) m_gl_shading_language_version = _sv;}
#endif
{m_gl_vendor.clear();
const char* _sv = (const char*)parent_gl_functions::gl__GetString(GL_VENDOR);
if(_sv) m_gl_vendor = _sv;}
{m_gl_renderer.clear();
const char* _sv = (const char*)parent_gl_functions::gl__GetString(GL_RENDERER);
if(_sv) m_gl_renderer = _sv;}
{m_gl_extensions.clear();
const char* _sv = (const char*)parent_gl_functions::gl__GetString(GL_EXTENSIONS);
if(_sv) m_gl_extensions = _sv;}
m_gl_max_texture_size = 0;
parent_gl_functions::gl__GetIntegerv(GL_MAX_TEXTURE_SIZE, &m_gl_max_texture_size);
}
clear_gl_errors();
#ifdef TOOLS_USE_GL_VERSION_3_2
// to avoid a 0x506 error message :
if(parent_gl_functions::gl__CheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE) {
return false;
}
if(!create_shader_program()) {
dump_if_gl_errors(m_out,"toolx::sg::GL_manager_T::create_shader_program :");
m_out << "toolx::sg::GL_manager_T::begin_render : create_shader_program() failed." << std::endl;
return false;
}
use_shader_program();
// WARNING : the values set here must match the default values in sg::state.
//WARNING : the below glEnable/glDisable corresponds
// to defaults in tools::sg::state.
parent_gl_functions::gl__Enable(GL_DEPTH_TEST);
parent_gl_functions::gl__FrontFace(GL_CCW);
parent_gl_functions::gl__Enable(GL_CULL_FACE);
parent_gl_functions::gl__Disable(GL_POLYGON_OFFSET_FILL);
parent_gl_functions::gl__DepthFunc(GL_LESS);
parent_gl_functions::gl__DepthMask(GL_TRUE);
parent_gl_functions::gl__Disable(GL_BLEND); //must be in sync with tools::sg::state.m_GL_BLEND and sg::blend node default.
parent_gl_functions::gl__BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
parent_gl_functions::gl__LineWidth(1.0f);
parent_gl_functions::gl__Uniform1f(g_point_size_location(),1.0f);
parent_gl_functions::gl__Viewport(a_x,a_y,a_ww,a_wh);
if(a_clear) {
parent_gl_functions::gl__ClearColor(a_r,a_g,a_b,a_a);
parent_gl_functions::gl__Clear(GL_COLOR_BUFFER_BIT);
parent_gl_functions::gl__Clear(GL_DEPTH_BUFFER_BIT);
}
tools::mat4f ID4;ID4.set_identity();
parent_gl_functions::gl__UniformMatrix4fv(g_model_proj_matrix_location(),1,GL_FALSE,ID4.data());
parent_gl_functions::gl__UniformMatrix4fv(g_normal_matrix_location(),1,GL_FALSE,ID4.data());
#else //not TOOLS_USE_GL_VERSION_3_2
#ifdef __APPLE__
#ifdef __COREFOUNDATION__ //Cocoa.h included: we build a Cocoa application.
// to avoid a 0x506 error message :
if(parent_gl_functions::gl__CheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE) { //It is a GL_VERSION_3_0 function.
return false;
}
#endif
#endif
// WARNING : the values set here must match the default values in sg::state.
parent_gl_functions::gl__Disable(GL_POLYGON_STIPPLE); //CoinGL : reading a .wrl having Material::transparency may enable GL_POLYGON_STIPPLE.
parent_gl_functions::gl__Enable(GL_NORMALIZE);
parent_gl_functions::gl__ShadeModel(GL_FLAT);
parent_gl_functions::gl__Enable(GL_COLOR_MATERIAL);
parent_gl_functions::gl__Disable(GL_BLEND); //must be in sync with tools::sg::state.m_GL_BLEND and sg::blend node default.
parent_gl_functions::gl__BlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//WARNING : the below glEnable/glDisable corresponds
// to defaults in tools::sg::state.
parent_gl_functions::gl__Enable(GL_DEPTH_TEST);
parent_gl_functions::gl__Disable(GL_LIGHTING);
parent_gl_functions::gl__FrontFace(GL_CCW);
parent_gl_functions::gl__Enable(GL_CULL_FACE);
parent_gl_functions::gl__Disable(GL_POLYGON_OFFSET_FILL);
parent_gl_functions::gl__Disable(GL_TEXTURE_2D);
parent_gl_functions::gl__DepthFunc(GL_LESS);
parent_gl_functions::gl__DepthMask(GL_TRUE);
parent_gl_functions::gl__Disable(GL_POINT_SMOOTH);
parent_gl_functions::gl__PointSize(1);
parent_gl_functions::gl__Disable(GL_LINE_SMOOTH); //NOTE : it does not work on all platforms !
parent_gl_functions::gl__LineWidth(1);
parent_gl_functions::gl__Viewport(a_x,a_y,a_ww,a_wh);
if(a_clear) {
parent_gl_functions::gl__ClearColor(a_r,a_g,a_b,0);
parent_gl_functions::gl__Clear(GL_COLOR_BUFFER_BIT);
parent_gl_functions::gl__Clear(GL_DEPTH_BUFFER_BIT);
}
parent_gl_functions::gl__MatrixMode(GL_PROJECTION);
parent_gl_functions::gl__LoadIdentity();
parent_gl_functions::gl__MatrixMode(GL_MODELVIEW);
parent_gl_functions::gl__LoadIdentity();
{parent_gl_functions::gl__Color4f(a_r,a_g,a_b,::sqrt(a_a));
float xyzs[12];
xyzs[0] = -1;xyzs[ 1] = -1;xyzs[ 2] = 0;
xyzs[3] = 1;xyzs[ 4] = -1;xyzs[ 5] = 0;
xyzs[6] = 1;xyzs[ 7] = 1;xyzs[ 8] = 0;
xyzs[9] = -1;xyzs[10] = 1;xyzs[11] = 0;
parent_gl_functions::gl__Disable(GL_DEPTH_TEST);
parent_gl_functions::gl__EnableClientState(GL_VERTEX_ARRAY);
parent_gl_functions::gl__VertexPointer(3,GL_FLOAT,0,xyzs);
parent_gl_functions::gl__DrawArrays(GL_TRIANGLE_FAN,0,4);
parent_gl_functions::gl__DisableClientState(GL_VERTEX_ARRAY);
parent_gl_functions::gl__Enable(GL_DEPTH_TEST);}
#endif //not TOOLS_USE_GL_VERSION_3_2
return true;
}
virtual void end_render() {
#ifdef TOOLS_USE_GL_VERSION_3_2
reset_shader_locations();
#endif
dump_if_gl_errors(m_out,"toolx::sg::GL_manager_T::end_render :");
}
////////////////////////////////////////////////
/// texture : //////////////////////////////////
////////////////////////////////////////////////
virtual unsigned int create_texture(const tools::img_byte& a_img,bool a_NEAREST) {
tools::img_byte* _img = 0;
bool _img_delete = false;
if(a_img.bytes_per_pixel()==1) { //exa eiffel-tower.png
_img = new tools::img_byte;
_img_delete = true;
if(!a_img.bw2x(3,*_img)) {
m_out << "toolx::sg::GL_manager_T::create_texture :"
<< " a_imgr.bw2x() failed."
<< std::endl;
delete _img;
return 0;
}
} else if(a_img.bytes_per_pixel()==3) {
_img = const_cast<tools::img_byte*>(&a_img);
} else if(a_img.bytes_per_pixel()==4) { //exa windusrf.png, text_freetype/font_pixmap.
_img = const_cast<tools::img_byte*>(&a_img);
} else {
//should not happen.
m_out << "toolx::sg::GL_manager_T::create_texture :"
<< " image with bytes_per_pixel " << a_img.bytes_per_pixel() << " not (yet) supported."
<< std::endl;
return 0;
}
if(_img->is_empty()) {
m_out << "toolx::sg::GL_manager_T::create_texture : img_byte is empty." << std::endl;
if(_img_delete) delete _img;
return 0;
}
{int sz;
parent_gl_functions::gl__GetIntegerv(GL_MAX_TEXTURE_SIZE,&sz);
if(!sz) {
m_out << "toolx::sg::GL_manager_T::create_texture : warning : GL_MAX_TEXTURE_SIZE is zero." << std::endl;
} else {
tools::img_byte* res = new tools::img_byte;
if(_img->check_gl_limit(sz,*res)) {
if(res->is_empty()) { //_img does not exceed.
delete res;
} else {
m_out << "toolx::sg::GL_manager_T::create_texture:"
<< " warning : img size (" << _img->size() << ") > GL_MAX_TEXTURE_SIZE (" << sz << "), we use a reduced one." << std::endl;
if(_img_delete) delete _img;
_img = res;
_img_delete = true;
}
} else {
m_out << "toolx::sg::GL_manager_T::create_texture :"
<< " warning : img size (" << _img->size() << ") > GL_MAX_TEXTURE_SIZE (" << sz << ") but can't reduce it."
<< std::endl;
delete res;
if(_img_delete) delete _img;
return false;
}
}}
if(_img->is_empty()) {
m_out << "toolx::sg::GL_manager_T::create_texture : img_byte is empty." << std::endl;
if(_img_delete) delete _img;
return 0;
}
unsigned int gl_id;
parent_gl_functions::gl__GenTextures(1,&gl_id);
if(!gl_id) {
m_out << "toolx::sg::GL_manager_T::create_texture : glGenTextures failed ()." << std::endl;
if(_img_delete) delete _img;
return 0;
}
unsigned int gsto_size = _img->size();
if(_img->bytes_per_pixel()==3) {
parent_gl_functions::gl__BindTexture(GL_TEXTURE_2D,gl_id);
parent_gl_functions::gl__TexImage2D(GL_TEXTURE_2D,0,GL_RGB,_img->width(),_img->height(),0,GL_RGB,GL_UNSIGNED_BYTE,_img->buffer());
if(_img_delete) delete _img;
} else if(_img->bytes_per_pixel()==4) {
parent_gl_functions::gl__BindTexture(GL_TEXTURE_2D,gl_id);
parent_gl_functions::gl__TexImage2D(GL_TEXTURE_2D,0,GL_RGBA,_img->width(),_img->height(),0,GL_RGBA,GL_UNSIGNED_BYTE,_img->buffer());
if(_img_delete) delete _img;
} else {
m_out << "toolx::sg::GL_manager_T::create_texture : img.bytes_per_pixel() " << _img->bytes_per_pixel() << " not handled." << std::endl;
if(_img_delete) delete _img;
parent_gl_functions::gl__DeleteTextures(1,&gl_id);
gl_id = 0;
return false;
}
if(a_NEAREST) {
parent_gl_functions::gl__TexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //good to see astro images pixels.
parent_gl_functions::gl__TexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //idem.
} else {
parent_gl_functions::gl__TexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
parent_gl_functions::gl__TexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
parent_gl_functions::gl__BindTexture(GL_TEXTURE_2D,0);
if(dump_if_gl_errors(m_out,"toolx::sg::GL_manager_T::create_texture :")) {
parent_gl_functions::gl__DeleteTextures(1,&gl_id);
gl_id = 0;
clear_gl_errors();
return 0;
}
unsigned int _id = m_gen_id;m_gen_id++;
m_gstos[_id] = new gsto_t(gsto_t::kind_texture,gl_id,gsto_size,0);
return _id;
}
////////////////////////////////////////////////
/// gsto ///////////////////////////////////////
////////////////////////////////////////////////
virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
if(!a_floatn) return 0;
switch(m_gsto_mode) {
case tools::sg::gsto_gl_vbo:{
#ifdef TOOLS_USE_GL_VERSION_3_2
GLuint vao_id = 0;
parent_gl_functions::gl__GenVertexArrays(1,&vao_id);
if(!vao_id) {
m_out << "toolx::sg::GL_manager_T::create_gsto_from_data : glGenVertexArray failed ()." << std::endl;
return 0;
}
parent_gl_functions::gl__BindVertexArray(vao_id);
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
GLuint gl_id = 0;
parent_gl_functions::gl__GenBuffers(1,&gl_id);
if(!gl_id) {
parent_gl_functions::gl__DeleteVertexArrays(1,&vao_id);
m_out << "toolx::sg::GL_manager_T::create_gsto_from_data : glGenBuffers failed ()." << std::endl;
return 0;
}
parent_gl_functions::gl__BindBuffer(GL_ARRAY_BUFFER,gl_id);
parent_gl_functions::gl__BufferData(GL_ARRAY_BUFFER,a_floatn*sizeof(float),a_data,GL_STATIC_DRAW);
parent_gl_functions::gl__BindBuffer(GL_ARRAY_BUFFER,0);
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
parent_gl_functions::gl__BindVertexArray(0);
if(dump_if_gl_errors(m_out,"toolx::sg::GL_manager_T::create_gsto_from_data :")) {
m_out << "toolx::sg::GL_manager_T::create_gsto_from_data :"
<< " a_floatn = " << a_floatn << ", a_data = " << a_data
<< ", vao_id " << vao_id << ", gl_id " << gl_id
<< std::endl;
parent_gl_functions::gl__DeleteBuffers(1,&gl_id);
parent_gl_functions::gl__DeleteVertexArrays(1,&vao_id);
clear_gl_errors();
return 0;
}
unsigned int _id = m_gen_id;m_gen_id++;
m_gstos[_id] = new gsto_t(gsto_t::kind_buffer,gl_id,a_floatn*sizeof(float),0,vao_id);
return _id;
#else
m_out << "toolx::sg::GL_manager_T::create_gsto_from_data :"
<< " gsto mode is gl_vbo but class not compiled with TOOLS_USE_GL_VERSION_3_2."
<< std::endl;
return 0;
#endif
}break;
case tools::sg::gsto_gl_list:{
unsigned int gl_id = 0;
unsigned int _id = m_gen_id;m_gen_id++;
m_gstos[_id] = new gsto_t(gsto_t::kind_list,gl_id,a_floatn*sizeof(float),a_data);
return _id;
}break;
case tools::sg::gsto_memory:{
unsigned int gl_id = 0;
unsigned int _id = m_gen_id;m_gen_id++;
m_gstos[_id] = new gsto_t(gsto_t::kind_memory,gl_id,a_floatn*sizeof(float),a_data);
return _id;
}break;
}
return 0;
}
virtual bool is_gsto_id_valid(unsigned int a_id) const {
gstos_it_t it = m_gstos.find(a_id);
if(it==m_gstos.end()) return false;
return (*it).second->is_valid();
}
virtual void delete_gsto(unsigned int a_id){
tools::delete_key<unsigned int,gsto_t>(m_gstos,a_id);
}
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
float* gsto_data(unsigned int a_id) const {
gstos_it_t it = m_gstos.find(a_id);
if(it==m_gstos.end()) return 0;
return (*it).second->m_data;
}
unsigned int gsto_gl_list_id(unsigned int a_id,bool& a_created) {
gstos_it_t it = m_gstos.find(a_id);
if(it==m_gstos.end()) {a_created = false;return 0;}
if((*it).second->m_kind!=gsto_t::kind_list) {a_created = false;return 0;}
if((*it).second->m_gl_id) {
a_created = false;
return (*it).second->m_gl_id;
} else {
#ifndef TOOLS_USE_GL_VERSION_3_2
unsigned int _id = parent_gl_functions::gl__GenLists(1);
if(!_id) {a_created = false;return 0;}
a_created = true;
(*it).second->m_gl_id = _id;
return _id;
#else
a_created = false;
return 0;
#endif
}
}
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
virtual tools::sg::gsto_mode get_gsto_mode() const {return m_gsto_mode;}
virtual void set_gsto_mode(tools::sg::gsto_mode a_v) {
if(a_v==m_gsto_mode) return;
tools::safe_clear<unsigned int,gsto_t>(m_gstos);
switch(a_v) {
case tools::sg::gsto_gl_vbo:{
#ifdef TOOLS_USE_GL_VERSION_3_2
m_gsto_mode = a_v;
#else
m_gsto_mode = tools::sg::gsto_memory;
#endif
}break;
case tools::sg::gsto_gl_list:{
#ifndef TOOLS_USE_GL_VERSION_3_2
m_gsto_mode = a_v;
#else
m_gsto_mode = tools::sg::gsto_memory;
#endif
}break;
case tools::sg::gsto_memory:{
m_gsto_mode = tools::sg::gsto_memory;
}break;
}
}
virtual void available_gsto_modes(std::vector<std::string>& a_vs) {
a_vs.clear();
#ifdef TOOLS_USE_GL_VERSION_3_2
a_vs.push_back(tools::sg::s_gsto_gl_vbo());
#endif
#ifndef TOOLS_USE_GL_VERSION_3_2
a_vs.push_back(tools::sg::s_gsto_gl_list());
#endif
a_vs.push_back(tools::sg::s_gsto_memory());
}
virtual void available_not_memory_gsto_mode(std::string& a_v) const {
a_v.clear();
#ifdef TOOLS_USE_GL_VERSION_3_2
a_v = tools::sg::s_gsto_gl_vbo();
#else
a_v = tools::sg::s_gsto_gl_list();
#endif
}
virtual size_t used_texture_memory() const {
size_t sz = 0;
gstos_it_t it;
for(it=m_gstos.begin();it!=m_gstos.end();++it) {
if((*it).second->m_kind==gsto_t::kind_texture) sz += (*it).second->m_size;
}
return sz;
}
virtual size_t gstos_size() const {
size_t sz = 0;
gstos_it_t it;
for(it=m_gstos.begin();it!=m_gstos.end();++it) sz += (*it).second->m_size;
return sz;
}
public:
GL_manager_T(std::ostream& a_out)
:m_out(a_out)
,m_gen_id(1)
,m_gsto_mode(tools::sg::gsto_memory)
#ifdef TOOLS_USE_GL_VERSION_3_2
,m_fragment_shader(0)
,m_vertex_shader(0)
,m_shader_program(0)
#endif
,m_gl_max_texture_size(0)
{}
virtual ~GL_manager_T(){
#ifdef TOOLS_USE_GL_VERSION_3_2
delete_shader_program();
#endif
tools::safe_clear<unsigned int,gsto_t>(m_gstos);
}
public:
GL_manager_T(const GL_manager_T& a_from)
:parent(a_from)
,parent_gl_functions(a_from)
,m_out(a_from.m_out)
,m_gen_id(a_from.m_gen_id)
,m_gsto_mode(a_from.m_gsto_mode)
,m_gl_max_texture_size(0)
{}
GL_manager_T& operator=(const GL_manager_T& a_from){
if(&a_from==this) return *this;
m_gen_id = a_from.m_gen_id;
m_gsto_mode = a_from.m_gsto_mode;
tools::safe_clear<unsigned int,gsto_t>(m_gstos);
return *this;
}
public:
void bind_gsto(unsigned int a_id) {
gstos_it_t it = m_gstos.find(a_id);
if(it==m_gstos.end()) return;
(*it).second->bind();
}
void unbind_gsto() {
#ifdef TOOLS_USE_GL_VERSION_3_2
parent_gl_functions::gl__BindBuffer(GL_ARRAY_BUFFER,0);
parent_gl_functions::gl__BindVertexArray(0);
#endif
}
void delete_gstos() {
tools::safe_clear<unsigned int,gsto_t>(m_gstos);
}
public:
unsigned char* get_rgbas(unsigned int a_w,unsigned int a_h) {
unsigned char* rgbas = new unsigned char[4 * a_w * a_h];
if(!rgbas) return 0;
parent_gl_functions::gl__PixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
parent_gl_functions::gl__ReadPixels(0,0,a_w,a_h,GL_RGBA,GL_UNSIGNED_BYTE,rgbas);
return rgbas;
}
unsigned char* get_rgbs(unsigned int a_w,unsigned int a_h) {
unsigned char* rgbs = new unsigned char[3 * a_w * a_h];
if(!rgbs) return 0;
parent_gl_functions::gl__PixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
parent_gl_functions::gl__ReadPixels(0,0,a_w,a_h,GL_RGB,GL_UNSIGNED_BYTE,rgbs);
return rgbs;
}
#ifdef TOOLS_USE_GL_VERSION_3_2
bool create_shader_program() {
if(m_shader_program) return true; //done
unsigned int gl_glsl_major_version = 0;
unsigned int gl_glsl_minor_version = 0;
if(!get_version_numbers(m_out,m_gl_shading_language_version,gl_glsl_major_version,gl_glsl_minor_version)) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " can't get version numnbers for GL_SHADING_LANGUAGE_VERSION."
<< std::endl;
return false;
}
unsigned int glsl_shader_processor_version = gl_glsl_major_version*100+gl_glsl_minor_version;
if(glsl_shader_processor_version<150) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " glsl_shader_processor_version is " << glsl_shader_processor_version
<< ", but only the ones greater or equal to 150 are supported."
<< std::endl;
return false;
}
{unsigned int gl_major_version = 0;
unsigned int gl_minor_version = 0;
if(!get_version_numbers(m_out,m_gl_version,gl_major_version,gl_minor_version)) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " can't get version numbers for GL_VERSION."
<< std::endl;
gl_major_version = 0;
gl_minor_version = 0;
}
m_out << "toolx::sg::GL_manager_T::create_shader_program: infos:" << std::endl
<< " GL_VERSION " << gl_major_version << "." << gl_minor_version << std::endl
<< " GL_SHADING_LANGUAGE_VERSION " << gl_glsl_major_version << "." << gl_glsl_minor_version << std::endl
<< " shader processor version " << glsl_shader_processor_version
<< std::endl;}
////////////////////////////////////////////////////
////////////////////////////////////////////////////
static const GLchar* str_fs_150 = "\
#version 150\n\
uniform sampler2D sampler;\n\
in vec4 frag_color;\n\
in float frag_tex_on;\n\
\n\
in vec2 frag_tex_coords;\n\
out vec4 _gl_FragColor;\n\
void main(void) {\n\
if(frag_tex_on==1.0) {\n\
_gl_FragColor = frag_color*texture(sampler,vec2(frag_tex_coords.s,frag_tex_coords.t));\n\
} else {\n\
_gl_FragColor = frag_color;\n\
}\n\
}\n\
";
m_fragment_shader = parent_gl_functions::gl__CreateShader(GL_FRAGMENT_SHADER);
if(!m_fragment_shader) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " glCreateShader(GL_FRAGMENT_SHADER) failed."
<< std::endl;
return false;
}
char* str_fs = (char*)str_fs_150;
parent_gl_functions::gl__ShaderSource(m_fragment_shader,1,&str_fs,NULL);
parent_gl_functions::gl__CompileShader(m_fragment_shader);
{GLint status;
parent_gl_functions::gl__GetShaderiv(m_fragment_shader,GL_COMPILE_STATUS,&status);
if(status==GL_FALSE) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " compilation of the fragment shader failed."
<< std::endl;
{GLsizei log_size;
char shader_log[4096];
parent_gl_functions::gl__GetShaderInfoLog(m_fragment_shader,1024,&log_size,shader_log);
m_out << "toolx::sg::GL_manager_T::create_shader_program: fragment shader_log size " << log_size << std::endl;
m_out << std::string(shader_log) << std::endl;}
parent_gl_functions::gl__DeleteShader(m_fragment_shader);
m_fragment_shader = 0;
return false;
}}
////////////////////////////////////////////////////
////////////////////////////////////////////////////
static const GLchar* str_vs_150 = "\
#version 150\n\
in vec3 one_pos;\n\
in vec3 one_normal;\n\
in vec4 one_color;\n\
in vec2 one_tex;\n\
uniform mat4 model_proj_matrix;\n\
uniform mat4 normal_matrix;\n\
uniform vec4 color;\n\
uniform bool pos_color;\n\
uniform vec3 normal;\n\
uniform bool pos_normal;\n\
uniform bool tex_on;\n\
uniform bool light_on;\n\
uniform vec3 light_direction;\n\
uniform vec4 light_color;\n\
uniform vec4 light_ambient;\n\
uniform float point_size;\n\
\n\
out float frag_tex_on;\n\
out vec4 frag_color;\n\
out vec2 frag_tex_coords;\n\
\n\
void main(void) {\n\
frag_tex_on = 0.0;\n\
if(tex_on) frag_tex_on = 1.0;\n\
frag_tex_coords = one_tex;\n\
if(tex_on) {\n\
frag_color = color;\n\
} else {\n\
frag_color = color;\n\
if(pos_color) frag_color = one_color;\n\
}\n\
/*frag_color = clamp(frag_color,0,1);*/\n\
\n\
if(light_on) {\n\
vec3 _normal = normal;\n\
if(pos_normal) _normal = one_normal;\n\
vec3 frag_normal = vec3(normalize(normal_matrix*vec4(_normal,0)));\n\
/* at this point, light_direction should be normalized.*/\n\
vec4 ambient_color = light_ambient;\n\
/*ambient_color = clamp(ambient_color,0,1);*/\n\
float cooking = 1.4; /*to have same intensity as GL-1.1.*/\n\
float _dot = dot(frag_normal,light_direction);\n\
if(_dot<0.0) {\n\
_dot *= -1.0;\n\
vec4 diffuse_color = light_color*_dot*cooking;\n\
/*diffuse_color = clamp(diffuse_color,0,1);*/\n\
vec4 _color = (ambient_color+diffuse_color)*frag_color;\n\
frag_color = vec4(_color.rgb,frag_color.a);\n\
} else {\n\
frag_color = ambient_color*frag_color*cooking;\n\
}\n\
}\n\
gl_PointSize = point_size;\n\
gl_Position = model_proj_matrix * vec4(one_pos,1);\n\
}\n\
";
m_vertex_shader = parent_gl_functions::gl__CreateShader(GL_VERTEX_SHADER);
if(!m_vertex_shader) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " glCreateShader(GL_VERTEX_SHADER) failed."
<< std::endl;
parent_gl_functions::gl__DeleteShader(m_fragment_shader);
m_fragment_shader = 0;
return false;
}
char* str_vs = (char*)str_vs_150;
parent_gl_functions::gl__ShaderSource(m_vertex_shader,1,&str_vs,NULL);
parent_gl_functions::gl__CompileShader(m_vertex_shader);
{GLint status;
parent_gl_functions::gl__GetShaderiv(m_vertex_shader,GL_COMPILE_STATUS,&status);
if(status==GL_FALSE) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " compilation of the vertex shader failed."
<< std::endl;
{GLsizei log_size;
char shader_log[4096];
parent_gl_functions::gl__GetShaderInfoLog(m_fragment_shader,1024,&log_size,shader_log);
m_out << "toolx::sg::GL_manager_T::create_shader_program: vertex shader_log size " << log_size << std::endl;
m_out << std::string(shader_log) << std::endl;}
parent_gl_functions::gl__DeleteShader(m_vertex_shader);
parent_gl_functions::gl__DeleteShader(m_fragment_shader);
m_vertex_shader = 0;
m_fragment_shader = 0;
return false;
}}
m_shader_program = parent_gl_functions::gl__CreateProgram();
parent_gl_functions::gl__AttachShader(m_shader_program,m_fragment_shader);
parent_gl_functions::gl__AttachShader(m_shader_program,m_vertex_shader);
parent_gl_functions::gl__LinkProgram(m_shader_program);
{GLint status;
parent_gl_functions::gl__GetProgramiv(m_shader_program,GL_LINK_STATUS,&status);
if(status==GL_FALSE) {
m_out << "toolx::sg::GL_manager_T::create_shader_program :"
<< " link program failed."
<< std::endl;
parent_gl_functions::gl__DetachShader(m_shader_program,m_fragment_shader);
parent_gl_functions::gl__DetachShader(m_shader_program,m_vertex_shader);
parent_gl_functions::gl__DeleteProgram(m_shader_program);
parent_gl_functions::gl__DeleteShader(m_vertex_shader);
parent_gl_functions::gl__DeleteShader(m_fragment_shader);
m_vertex_shader = 0;
m_fragment_shader = 0;
m_shader_program = 0;
return false;
}}
return true;
}
void delete_shader_program() {
if(!m_shader_program) return;
parent_gl_functions::gl__DetachShader(m_shader_program,m_fragment_shader);
parent_gl_functions::gl__DetachShader(m_shader_program,m_vertex_shader);
parent_gl_functions::gl__DeleteProgram(m_shader_program);
parent_gl_functions::gl__DeleteShader(m_vertex_shader);
parent_gl_functions::gl__DeleteShader(m_fragment_shader);
m_vertex_shader = 0;
m_fragment_shader = 0;
m_shader_program = 0;
}
#define GET_UNIFORM_LOCATION(a__var,a__name)\
m_##a__var = parent_gl_functions::gl__GetUniformLocation(m_shader_program,a__name);\
if(m_##a__var==(-1)) {\
m_out << "toolx::sg::GL_manager_T::use_shader_program : glGetUniformLocation(" << a__name << ") failed." << std::endl;\
}
#define GET_ATTRIB_LOCATION(a__var,a__name)\
m_##a__var = parent_gl_functions::gl__GetAttribLocation(m_shader_program,a__name);\
if(m_##a__var==(-1)) {\
m_out << "toolx::sg::GL_manager_T::use_shader_program : glGetAttribLocation(" << a__name << ") failed." << std::endl;\
}
GLint g_sampler_location() {return m_g_sampler;}
GLint g_tex_on_location() {return m_g_tex_on;}
GLint g_point_size_location() {return m_g_point_size;}
GLint g_one_pos_location() {return m_g_one_pos;}
GLint g_one_normal_location() {return m_g_one_normal;}
GLint g_one_color_location() {return m_g_one_color;}
GLint g_one_tex_location() {return m_g_one_tex;}
GLint g_model_proj_matrix_location() {return m_g_model_proj_matrix;}
GLint g_normal_matrix_location() {return m_g_normal_matrix;}
GLint g_color_location() {return m_g_color;}
GLint g_pos_color_location() {return m_g_pos_color;}
GLint g_normal_location() {return m_g_normal;}
GLint g_pos_normal_location() {return m_g_pos_normal;}
GLint g_light_on_location() {return m_g_light_on;}
GLint g_light_direction_location() {return m_g_light_direction;}
GLint g_light_color_location() {return m_g_light_color;}
GLint g_light_ambient_location() {return m_g_light_ambient;}
void use_shader_program() {
if(!m_shader_program) return;
parent_gl_functions::gl__UseProgram(m_shader_program);
// used by renderer :
GET_UNIFORM_LOCATION(g_sampler,"sampler")
GET_UNIFORM_LOCATION(g_tex_on,"tex_on")
GET_UNIFORM_LOCATION(g_point_size,"point_size")
GET_ATTRIB_LOCATION(g_one_pos,"one_pos")
GET_ATTRIB_LOCATION(g_one_normal,"one_normal")
GET_ATTRIB_LOCATION(g_one_color,"one_color")
GET_ATTRIB_LOCATION(g_one_tex,"one_tex")
GET_UNIFORM_LOCATION(g_model_proj_matrix,"model_proj_matrix")
GET_UNIFORM_LOCATION(g_normal_matrix,"normal_matrix")
GET_UNIFORM_LOCATION(g_color,"color")
GET_UNIFORM_LOCATION(g_pos_color,"pos_color")
GET_UNIFORM_LOCATION(g_normal,"normal")
GET_UNIFORM_LOCATION(g_pos_normal,"pos_normal")
GET_UNIFORM_LOCATION(g_light_on,"light_on")
GET_UNIFORM_LOCATION(g_light_direction,"light_direction")
GET_UNIFORM_LOCATION(g_light_color,"light_color")
GET_UNIFORM_LOCATION(g_light_ambient,"light_ambient")
parent_gl_functions::gl__Uniform1i(m_g_tex_on,0);
parent_gl_functions::gl__Uniform1f(m_g_point_size,1);
parent_gl_functions::gl__Uniform4f(m_g_color,1,1,1,1);
parent_gl_functions::gl__Uniform1i(m_g_pos_color,false);
parent_gl_functions::gl__Uniform3f(m_g_normal,0,0,1);
parent_gl_functions::gl__Uniform1i(m_g_pos_normal,false);
parent_gl_functions::gl__Uniform1i(m_g_light_on,0);
parent_gl_functions::gl__Uniform4f(m_g_light_color,1,1,1,0);
parent_gl_functions::gl__Uniform3f(m_g_light_direction,0,0,-1);
}
void reset_shader_locations() {
m_g_sampler = -1;
m_g_tex_on = -1;
m_g_point_size = -1;
m_g_one_pos = -1;
m_g_one_normal = -1;
m_g_one_color = -1;
m_g_one_tex = -1;
m_g_model_proj_matrix = -1;
m_g_normal_matrix = -1;
m_g_color = -1;
m_g_pos_color = -1;
m_g_normal = -1;
m_g_pos_normal = -1;
m_g_light_on = -1;
m_g_light_direction = -1;
m_g_light_color = -1;
m_g_light_ambient = -1;
}
#undef GET_ATTRIB_LOCATION
#undef GET_UNIFORM_LOCATION
#endif //TOOLS_USE_GL_VERSION_3_2
protected:
/*static*/ void clear_gl_errors() {
GLenum glerror = parent_gl_functions::gl__GetError();
while(glerror!=GL_NO_ERROR) {
glerror = parent_gl_functions::gl__GetError();
}
}
/*static*/ bool dump_if_gl_errors(std::ostream& a_out,const std::string& a_head) {
bool retval = false;
GLenum glerror = parent_gl_functions::gl__GetError();
if(glerror!=GL_NO_ERROR) {
a_out << a_head
<< " we have gl errors :"
<< std::endl;
retval = true;
}
while(glerror!=GL_NO_ERROR) {
//#define GL_NO_ERROR 0
//#define GL_INVALID_ENUM 0x0500
//#define GL_INVALID_VALUE 0x0501
//#define GL_INVALID_OPERATION 0x0502
//#define GL_STACK_OVERFLOW 0x0503
//#define GL_STACK_UNDERFLOW 0x0504
//#define GL_OUT_OF_MEMORY 0x0505
//#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
std::ostringstream oss;
oss << "0x" << std::hex << glerror;
a_out << oss.str() << std::endl;
glerror = parent_gl_functions::gl__GetError();
}
return retval;
}
static bool s2vers(const std::string& a_string,std::vector<unsigned int>& a_versions) {
// a_string is of the form "<number>[.<number>.<number>] <comment>, extract <numbers>.
// Examples : "1.0.2" "2.1 ATI-4.8.101"
a_versions.clear();
if(a_string.empty()) return false;
char* pos = (char*)a_string.c_str();
while((*pos!='\0')&&(*pos!=' ')) {
char* s;
long v = ::strtol(pos,&s,10);
if(s==pos) {
a_versions.clear();
return false;
}
if(v<0) {
a_versions.clear();
return false;
}
a_versions.push_back((unsigned int)v);
pos = s; //Could be at end.
if(*pos=='\0') break;
if(*pos==' ') break;
if(*pos!='.') {
a_versions.clear();
return false;
}
// Next char is '.', skip it:
pos++;
}
return true;
}
/*static*/ bool get_version_numbers(std::ostream& a_out,const std::string& a_version,unsigned int& a_major,unsigned int& a_minor) {
a_major = 0;
a_minor = 0;
std::vector<unsigned int> verss;
if(!s2vers(a_version,verss)) {
a_out << "toolx::sg::GL_manager_T::get_version_numbers :"
<< " toolx::sg::GL_manager_T::s2vers() failed on \"" << a_version << "\"."
<< std::endl;
return false;
}
if(verss.size()==1) {
a_major = verss[0];
a_minor = 0;
} else if(verss.size()>=2) {
a_major = verss[0];
a_minor = verss[1];
} else {
a_out << "toolx::sg::GL_manager_T::get_version_numbers :"
<< " can't extract major/minor version number from \"" << a_version << "\"."
<< std::endl;
return false;
}
return true;
}
protected:
std::ostream& m_out;
std::map<unsigned int,gsto_t*> m_gstos;
unsigned int m_gen_id;
tools::sg::gsto_mode m_gsto_mode;
#ifdef TOOLS_USE_GL_VERSION_3_2
GLuint m_fragment_shader;
GLuint m_vertex_shader;
GLuint m_shader_program;
//locations:
GLint m_g_sampler;
GLint m_g_tex_on;
GLint m_g_point_size;
GLint m_g_one_pos;
GLint m_g_one_normal;
GLint m_g_one_color;
GLint m_g_one_tex;
GLint m_g_model_proj_matrix;
GLint m_g_normal_matrix;
GLint m_g_color;
GLint m_g_pos_color;
GLint m_g_normal;
GLint m_g_pos_normal;
GLint m_g_light_on;
GLint m_g_light_direction;
GLint m_g_light_color;
GLint m_g_light_ambient;
#endif //TOOLS_USE_GL_VERSION_3_2
std::string m_gl_version;
#ifdef TOOLS_USE_GL_VERSION_3_2
std::string m_gl_shading_language_version;
#endif
std::string m_gl_vendor;
std::string m_gl_renderer;
std::string m_gl_extensions;
GLint m_gl_max_texture_size;
};
}}
#endif