Files
geant4/source/externals/g4tools/include/tools/metal/render.hm
T
2021-06-25 16:12:29 +02:00

1425 lines
49 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_metal_render
#define tools_metal_render
#include <tools/sg/render_manager>
#include <tools/sg/render_action>
#include <tools/glprims>
#include <tools/colorfs>
#include <tools/lina/mat3f>
#include <tools/num2s>
#include <tools/mapmanip>
#include <tools/mathf>
#include <tools/forit>
#include <Metal/Metal.h>
#include <MetalKit/MTKView.h>
#include <simd/simd.h>
#include <cstring>
namespace tools {
namespace metal {
class manager : public virtual tools::sg::render_manager {
typedef tools::sg::render_manager parent;
public:
TOOLS_SCLASS(tools::metal::manager)
virtual void* cast(const std::string& a_class) const {
if(void* p = tools::cmp_cast<manager>(this,a_class)) {return p;}
else return 0;
}
public:
virtual bool begin_render(int a_x,int a_y,unsigned int a_w,unsigned int a_h,float a_r,float a_g,float a_b,float a_a,bool = true) {
if(!m_view) return false;
create_pipeline_state();
//::printf("debug : manager::begin_render : 000 : %d %d\n",a_w,a_h);
m_render_command_encoder = 0;
m_command_buffer = [m_command_queue commandBuffer];
create_render_command_encoder(a_x,a_y,a_w,a_h,a_r,a_g,a_b,a_a);
return true;
}
virtual void end_render() {
//::printf("debug : manager::end_render : 000\n");
end_encoding();
[m_render_pipeline_state release];
}
virtual unsigned int create_texture(const tools::img_byte& a_img,bool /*a_NEAREST*/) {
//::printf("debug : create_texture : size = %d, w = %d, h = %d, bpp %d\n",
// a_img.size(),a_img.width(),a_img.height(),a_img.bpp());
tools::img_byte* _img = 0;
bool _img_delete = false;
if(a_img.bpp()==1) { //exa eiffel-tower.png
tools::img_byte img3;
if(!a_img.bw2x(3,img3)) {
m_out << "tools::metal::manager::create_texture : a_imgr.bw2x() failed." << std::endl;
return 0;
}
tools::img_byte img4;
if(!img3.rgb2rgba(img4,255)){
m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
return 0;
}
_img = new tools::img_byte;
_img_delete = true;
_img->transfer(img4);
} else if(a_img.bpp()==3) {
tools::img_byte img4;
if(!a_img.rgb2rgba(img4,255)){
m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
return 0;
}
_img = new tools::img_byte;
_img_delete = true;
_img->transfer(img4);
} else if(a_img.bpp()==4) { //exa windusrf.png, text_freetype/font_pixmap.
_img = const_cast<tools::img_byte*>(&a_img);
} else {
//should not happen.
m_out << "tools::metal::manager::create_texture :"
<< " image with bpp " << a_img.bpp() << " not (yet) supported."
<< std::endl;
if(_img_delete) delete _img;
return 0;
}
if(_img->is_empty()) {
if(_img_delete) delete _img;
return 0;
}
_img->rgba2bgra();
m_gen_id++;
MTLTextureDescriptor* tex_desc = [[MTLTextureDescriptor alloc] init];
tex_desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
tex_desc.width = _img->width();
tex_desc.height = _img->height();
id<MTLTexture> texture = [m_device newTextureWithDescriptor:tex_desc];
NSUInteger bytes_per_row = _img->bpp() * _img->width();
MTLRegion region = {
{0,0,0}, // MTLOrigin
{_img->width(),_img->height(),1} // MTLSize
};
[texture replaceRegion:region mipmapLevel:0 withBytes:_img->buffer() bytesPerRow:bytes_per_row];
m_tex_gstos[m_gen_id] = new tex_gsto(texture,_img->size(),m_out,*this);
if(_img_delete) delete _img;
return m_gen_id;
}
virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
if(!a_floatn) return 0;
m_gen_id++;
m_data_gstos[m_gen_id] = new data_gsto(a_data,a_floatn,m_out,*this);
return m_gen_id;
}
virtual bool is_gsto_id_valid(unsigned int a_id) const {
{std::map<unsigned int,tex_gsto*>::const_iterator it = m_tex_gstos.find(a_id);
if(it!=m_tex_gstos.end()) return true;}
{std::map<unsigned int,data_gsto*>::const_iterator it = m_data_gstos.find(a_id);
if(it!=m_data_gstos.end()) return true;}
return false;
}
virtual void delete_gsto(unsigned int a_id) {
tools::delete_key<unsigned int,tex_gsto>(m_tex_gstos,a_id);
tools::delete_key<unsigned int,data_gsto>(m_data_gstos,a_id);
}
virtual tools::sg::gsto_mode get_gsto_mode() const {return tools::sg::gsto_gl_vbo;}
virtual void set_gsto_mode(tools::sg::gsto_mode) {}
virtual void available_gsto_modes(std::vector<std::string>& a_v) {
a_v.clear();
a_v.push_back(tools::sg::s_gsto_gl_vbo());
}
virtual void available_not_memory_gsto_mode(std::string& a_s) const {
a_s = tools::sg::s_gsto_gl_vbo();
}
virtual size_t used_texture_memory() const {
size_t sz = 0;
std::map<unsigned int,tex_gsto*>::const_iterator it;
for(it=m_tex_gstos.begin();it!=m_tex_gstos.end();++it) {sz += (*it).second->m_size;}
return sz;
}
virtual size_t gstos_size() const {
size_t sz = 0;
{tools_mforcit(unsigned int,tex_gsto*,m_tex_gstos,it) {sz += (*it).second->m_size;}}
{tools_mforcit(unsigned int,data_gsto*,m_data_gstos,it) {sz += (*it).second->m_size;}}
return sz;
}
public:
manager(std::ostream& a_out)
:m_out(a_out)
,m_gen_id(0)
,m_view(0)
,m_device(0)
,m_command_queue(0)
,m_render_pipeline_state(0)
,m_depth_stencil_state_on(0)
,m_depth_stencil_state_off(0)
,m_command_buffer(0)
,m_render_command_encoder(0)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
m_device = MTLCreateSystemDefaultDevice();
m_command_queue = [m_device newCommandQueue];
//create_pipeline_state();
{MTLDepthStencilDescriptor* depth_stencil_desc = [[MTLDepthStencilDescriptor alloc] init];
depth_stencil_desc.depthWriteEnabled = YES;
depth_stencil_desc.depthCompareFunction = MTLCompareFunctionLess;
m_depth_stencil_state_on = [m_device newDepthStencilStateWithDescriptor:depth_stencil_desc];}
{MTLDepthStencilDescriptor* depth_stencil_desc = [[MTLDepthStencilDescriptor alloc] init];
depth_stencil_desc.depthWriteEnabled = NO;
depth_stencil_desc.depthCompareFunction = MTLCompareFunctionLess;
m_depth_stencil_state_off = [m_device newDepthStencilStateWithDescriptor:depth_stencil_desc];}
}
virtual ~manager(){
//[m_render_pipeline_state release];
[m_depth_stencil_state_on release];
[m_depth_stencil_state_off release];
[m_command_queue release];
tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
#ifdef TOOLS_MEM
tools::mem::decrement(s_class().c_str());
#endif
}
private:
public:
manager(const manager& a_from)
:parent(a_from)
,m_out(a_from.m_out)
,m_gen_id(a_from.m_gen_id)
,m_view(0)
,m_device(0)
,m_command_queue(0)
,m_render_pipeline_state(0)
,m_depth_stencil_state_on(0)
,m_depth_stencil_state_off(0)
,m_command_buffer(0)
,m_render_command_encoder(0)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
manager& operator=(const manager& a_from){
if(&a_from==this) return *this;
tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
return *this;
}
public:
void delete_gstos() {
tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
}
public:
bool find_texture(unsigned int a_id,id<MTLTexture>& a_texture) const {
std::map<unsigned int,tex_gsto*>::const_iterator it = m_tex_gstos.find(a_id);
if(it==m_tex_gstos.end()) {a_texture = 0;return false;}
a_texture = (*it).second->m_texture;
return true;
}
bool find_data_gsto(unsigned int a_id,char*& a_data) const {
std::map<unsigned int,data_gsto*>::const_iterator it = m_data_gstos.find(a_id);
if(it==m_data_gstos.end()) {a_data = 0;return false;}
a_data = (*it).second->m_buffer;
return true;
}
std::ostream& out() const {return m_out;}
id<MTLDevice>& device() {return m_device;}
id<MTLRenderCommandEncoder>& render_command_encoder() {return m_render_command_encoder;}
id<MTLDepthStencilState>& depth_stencil_state_on() {return m_depth_stencil_state_on;}
id<MTLDepthStencilState>& depth_stencil_state_off() {return m_depth_stencil_state_off;}
void set_view(MTKView* a_view) {m_view = a_view;}
protected:
class data_gsto {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::metal::manager::data_gsto)
#endif
public:
data_gsto(const float* a_floats,size_t a_floatn,std::ostream& a_out,manager& a_mgr)
:m_buffer(0)
,m_size(0)
,m_out(a_out)
,m_mgr(a_mgr)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
m_size = a_floatn*sizeof(float);
m_buffer = new char[m_size];
::memcpy(m_buffer,a_floats,m_size);
}
virtual ~data_gsto(){
delete [] m_buffer;
#ifdef TOOLS_MEM
tools::mem::decrement(s_class().c_str());
#endif
}
private:
data_gsto(const data_gsto& a_from)
:m_buffer(0)
,m_size(a_from.m_size)
,m_out(a_from.m_out)
,m_mgr(a_from.m_mgr)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
data_gsto& operator=(const data_gsto& a_from){
m_buffer = 0;
m_size = a_from.m_size;
return *this;
}
public:
char* m_buffer;
size_t m_size;
std::ostream& m_out;
manager& m_mgr;
};
class tex_gsto {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::metal::manager::tex_gsto)
#endif
public:
tex_gsto(id<MTLTexture>& a_texture,size_t a_size,std::ostream& a_out,manager& a_mgr)
:m_texture(a_texture)
,m_size(a_size)
,m_out(a_out)
,m_mgr(a_mgr)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
virtual ~tex_gsto(){
[m_texture release]; //is it needed ?
#ifdef TOOLS_MEM
tools::mem::decrement(s_class().c_str());
#endif
}
private:
tex_gsto(const tex_gsto& a_from)
:m_texture(a_from.m_texture)
,m_size(a_from.m_size)
,m_out(a_from.m_out)
,m_mgr(a_from.m_mgr)
{
#ifdef TOOLS_MEM
tools::mem::increment(s_class().c_str());
#endif
}
tex_gsto& operator=(const tex_gsto& a_from){
m_texture = a_from.m_texture;
m_size = a_from.m_size;
return *this;
}
public:
id<MTLTexture> m_texture;
size_t m_size;
std::ostream& m_out;
manager& m_mgr;
};
private:
void create_pipeline_state() {
const char shaders_src[] = "\
#include <metal_stdlib>\n\
#include <simd/simd.h>\n\
struct uniforms {\n\
simd::float4x4 proj_model_matrix;\n\
simd::float4x4 normal_matrix;\n\
unsigned int light_on;\n\
simd::float4 light_color;\n\
simd::float3 light_direction;\n\
unsigned int texturing;\n\
};\n\
struct vertex_in {\n\
simd::float4 position [[attribute(0)]];\n\
simd::float4 normal [[attribute(1)]];\n\
simd::float4 color [[attribute(2)]];\n\
simd::float2 texture_coordinate [[attribute(3)]];\n\
};\n\
struct vertex_out {\n\
simd::float4 position [[position]];\n\
simd::float3 normal;\n\
simd::float4 color;\n\
simd::float2 texture_coordinate;\n\
unsigned int light_on;\n\
simd::float4 light_color;\n\
simd::float3 light_direction;\n\
unsigned int texturing;\n\
/*float pointsize [[point_size]];*/\n\
};\n\
vertex vertex_out vert_shader(vertex_in a_in [[stage_in]],constant uniforms& a_uniforms [[buffer(1)]]) {\n\
vertex_out out;\n\
\n\
out.position = a_uniforms.proj_model_matrix * a_in.position;\n\
out.normal = simd::normalize((a_uniforms.normal_matrix * a_in.normal).xyz);\n\
out.color = a_in.color;\n\
out.texture_coordinate = a_in.texture_coordinate;\n\
\n\
out.light_on = a_uniforms.light_on;\n\
out.light_color = a_uniforms.light_color;\n\
out.light_direction = a_uniforms.light_direction;\n\
out.texturing = a_uniforms.texturing;\n\
\n\
return out;\n\
}\n\
fragment simd::float4 frag_shader(vertex_out a_in [[stage_in]],simd::texture2d<half> a_color [[texture(0)]]) {\n\
if(a_in.texturing) {\n\
constexpr simd::sampler texture_sampler(simd::mag_filter::linear,simd::min_filter::linear);\n\
const half4 color_sample = a_color.sample(texture_sampler,a_in.texture_coordinate);\n\
return simd::float4(color_sample)*a_in.color;\n\
} else {\n\
if(a_in.light_on) {\n\
simd::float4 black(0,0,0,1);\n\
/*simd::float4 red(1,0,0,1);*/\n\
float _dot = simd::dot(a_in.normal,a_in.light_direction);\n\
if(_dot<0.0) {\n\
_dot *= -1;\n\
float cooking = 1.4; /*to have same intensity as GL on desktops.*/\n\
simd::float4 diffuse_color = a_in.light_color*_dot*cooking;\n\
simd::float4 _color = diffuse_color*a_in.color;\n\
/*simd::float4 _color = _dot*a_in.color;*/\n\
_color[3] = a_in.color[3];\n\
return _color;\n\
} else {\n\
return black;\n\
/*return red;*/\n\
}\n\
} else {\n\
return a_in.color;\n\
}\n\
}\n\
}\n\
";
MTLVertexDescriptor* vert_desc = [MTLVertexDescriptor vertexDescriptor];
vert_desc.attributes[0].format = MTLVertexFormatFloat4;
vert_desc.attributes[0].bufferIndex = 0;
vert_desc.attributes[0].offset = 0;
vert_desc.attributes[1].format = MTLVertexFormatFloat4;
vert_desc.attributes[1].bufferIndex = 0;
vert_desc.attributes[1].offset = sizeof(float)*4;
vert_desc.attributes[2].format = MTLVertexFormatFloat4;
vert_desc.attributes[2].bufferIndex = 0;
vert_desc.attributes[2].offset = sizeof(float)*8;
vert_desc.attributes[3].format = MTLVertexFormatFloat2;
vert_desc.attributes[3].bufferIndex = 0;
vert_desc.attributes[3].offset = sizeof(float)*12;
vert_desc.layouts[0].stride = 14*sizeof(float);
vert_desc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
MTLCompileOptions* opts = [[MTLCompileOptions alloc] init];
NSString* src = [[NSString alloc] initWithUTF8String:shaders_src];
id<MTLLibrary> library = [m_device newLibraryWithSource:src options:opts error:nullptr];
[src release];
[opts release];
id<MTLFunction> vert_func = [library newFunctionWithName:@"vert_shader"];
id<MTLFunction> frag_func = [library newFunctionWithName:@"frag_shader"];
MTLRenderPipelineDescriptor* render_pipeline_desc = [[MTLRenderPipelineDescriptor alloc] init];
render_pipeline_desc.label = @"pipeline";
render_pipeline_desc.vertexFunction = vert_func;
render_pipeline_desc.fragmentFunction = frag_func;
render_pipeline_desc.vertexDescriptor = vert_desc;
render_pipeline_desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
render_pipeline_desc.stencilAttachmentPixelFormat = [m_view depthStencilPixelFormat];
render_pipeline_desc.depthAttachmentPixelFormat = [m_view depthStencilPixelFormat];
m_render_pipeline_state = [m_device newRenderPipelineStateWithDescriptor:render_pipeline_desc error:nullptr];
[library release];
[vert_func release];
[frag_func release];
}
void create_render_command_encoder(int /*a_x*/,int /*a_y*/,unsigned int /*a_w*/,unsigned int /*a_h*/,float a_r,float a_g,float a_b,float a_a) {
MTLRenderPassDescriptor* render_pass_desc = [m_view currentRenderPassDescriptor];
[render_pass_desc setRenderTargetArrayLength:1];
MTLRenderPassColorAttachmentDescriptor* color_attachment_desc = [render_pass_desc colorAttachments][0];
color_attachment_desc.clearColor = MTLClearColorMake(a_r,a_g,a_b,a_a);
m_render_command_encoder = [m_command_buffer renderCommandEncoderWithDescriptor:render_pass_desc];
[m_render_command_encoder setRenderPipelineState:m_render_pipeline_state];
//double znear = 0.0;
//double zfar = 1.0;
//[m_render_command_encoder setViewport:(MTLViewport){double(a_x),double(a_y),2.0*double(a_w),2.0*double(a_h),znear,zfar}];
[m_render_command_encoder setDepthStencilState:m_depth_stencil_state_on];
//[m_render_command_encoder setDepthClipMode:MTLDepthClipModeClip];
[m_render_command_encoder setFrontFacingWinding:MTLWindingCounterClockwise];
[m_render_command_encoder setCullMode:MTLCullModeBack];
}
void end_encoding() {
if(m_view) {
if(m_render_command_encoder) [m_render_command_encoder endEncoding];
id<MTLDrawable> drawable = [m_view currentDrawable];
if(drawable) [m_command_buffer presentDrawable:drawable];
}
[m_command_buffer commit];
[m_command_buffer waitUntilCompleted];
//[m_command_buffer waitUntilScheduled];
}
protected:
std::ostream& m_out;
unsigned int m_gen_id;
std::map<unsigned int,tex_gsto*> m_tex_gstos;
std::map<unsigned int,data_gsto*> m_data_gstos;
MTKView* m_view;
id<MTLDevice> m_device;
id<MTLCommandQueue> m_command_queue;
id<MTLRenderPipelineState> m_render_pipeline_state;
id<MTLDepthStencilState> m_depth_stencil_state_on;
id<MTLDepthStencilState> m_depth_stencil_state_off;
id<MTLCommandBuffer> m_command_buffer;
id<MTLRenderCommandEncoder> m_render_command_encoder;
};
class render : public tools::sg::render_action {
TOOLS_ACTION(render,tools::metal::render,tools::sg::render_action)
public:
virtual void clear_color(float,float,float,float){}
virtual void draw_vertex_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs){
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
if(!m_mgr.render_command_encoder()) return;
//::printf("debug : draw_vertex_array : 000 : %lu %d\n",num,a_mode);
float* buffer = 0;
MTLPrimitiveType primitive_type;
if(a_mode==tools::gl::points()) {
primitive_type = MTLPrimitiveTypePoint;
if(!fill_buffer(num,a_xyzs,buffer)) return;
} else if(a_mode==tools::gl::lines()) {
primitive_type = MTLPrimitiveTypeLine;
if(!fill_buffer(num,a_xyzs,buffer)) return;
} else if(a_mode==tools::gl::line_loop()) {
primitive_type = MTLPrimitiveTypeLineStrip;
size_t nxyz = (num+1)*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::line_strip()) {
primitive_type = MTLPrimitiveTypeLineStrip;
if(!fill_buffer(num,a_xyzs,buffer)) return;
} else if(a_mode==tools::gl::triangles()) {
primitive_type = MTLPrimitiveTypeTriangle;
if(!fill_buffer(num,a_xyzs,buffer)) return;
} else if(a_mode==tools::gl::triangle_fan()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::triangle_fan_to_triangles(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::triangle_strip()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::triangle_strip_to_triangles(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else {
::printf("debug : draw_vertex_array : mode not handled yet : %lu %d\n",num,a_mode);
return;
}
if(!buffer) return;
MTLResourceOptions opts = 0;
id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
uniforms _uniforms;
set_uniforms(_uniforms,false);
id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
if(m_ccw) {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
} else {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
}
if(m_depth_test) {
[m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_on()];
} else {
[m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_off()];
}
[m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
[m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
[vertex_buffer release];
[uniforms_buffer release];
delete [] buffer;
}
virtual void draw_vertex_array_xy(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xys){
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/2;
if(!num) return;
//::printf("debug : draw_vertex_array_xy %lu\n",num);
float* xyzs = new float[num*3];
float* pxyzs = xyzs;
tools::gl::cvt_2to3(num,a_xys,pxyzs);
draw_vertex_array(a_mode,num*3,xyzs);
delete [] xyzs;
}
virtual void draw_vertex_color_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,const float* a_rgbas){
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
if(!m_mgr.render_command_encoder()) return;
//::printf("debug : draw_vertex_color_array : 000 : num %lu, mode %d\n",num,a_mode);
float* buffer = 0;
MTLPrimitiveType primitive_type;
if(a_mode==tools::gl::points()) {
primitive_type = MTLPrimitiveTypePoint;
if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
} else if(a_mode==tools::gl::lines()) {
primitive_type = MTLPrimitiveTypeLine;
if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
} else if(a_mode==tools::gl::line_loop()) {
::printf("debug : draw_vertex_color_array : line_loop : have to handle a_rgbas\n");
primitive_type = MTLPrimitiveTypeLineStrip;
size_t nxyz = (num+1)*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::line_strip()) {
primitive_type = MTLPrimitiveTypeLineStrip;
if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
} else if(a_mode==tools::gl::triangles()) {
primitive_type = MTLPrimitiveTypeTriangle;
if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
} else if(a_mode==tools::gl::triangle_fan()) {
::printf("debug : draw_vertex_color_array : triangle_fan : have to handle a_rgbas\n");
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::triangle_fan_to_triangles(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::triangle_strip()) {
::printf("debug : draw_vertex_color_array : triangle_strip : have to handle a_rgbas\n");
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::triangle_strip_to_triangles(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else {
::printf("debug : draw_vertex_color_array : mode not handled yet : %lu %d\n",num,a_mode);
return;
}
if(!buffer) return;
MTLResourceOptions opts = 0;
id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
uniforms _uniforms;
set_uniforms(_uniforms,false);
id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
if(m_ccw) {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
} else {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
}
[m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
[m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
[vertex_buffer release];
[uniforms_buffer release];
delete [] buffer;
}
virtual void draw_vertex_normal_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,const float* a_nms){
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
if(!m_mgr.render_command_encoder()) return;
//::printf("debug : draw_vertex_normal_array : 000 : num %lu, mode %d\n",num,a_mode);
float* buffer = 0;
MTLPrimitiveType primitive_type;
if(a_mode==tools::gl::points()) {
primitive_type = MTLPrimitiveTypePoint;
if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
} else if(a_mode==tools::gl::lines()) {
primitive_type = MTLPrimitiveTypeLine;
if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
} else if(a_mode==tools::gl::line_loop()) {
::printf("debug : draw_vertex_normal_array : line_loop to handle nms\n");
primitive_type = MTLPrimitiveTypeLineStrip;
size_t nxyz = (num+1)*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::line_strip()) {
primitive_type = MTLPrimitiveTypeLineStrip;
if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
} else if(a_mode==tools::gl::triangles()) {
primitive_type = MTLPrimitiveTypeTriangle;
if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
} else if(a_mode==tools::gl::triangle_fan()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* nms = new float[nxyz];
{float* pxyzs = xyzs;
float* pnms = nms;
tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
num = nxyz/3;
bool status = fill_buffer_nms(num,xyzs,nms,buffer);
delete [] xyzs;
delete [] nms;
if(!status) return;
} else if(a_mode==tools::gl::triangle_strip()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* nms = new float[nxyz];
{float* pxyzs = xyzs;
float* pnms = nms;
tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
num = nxyz/3;
bool status = fill_buffer_nms(num,xyzs,nms,buffer);
delete [] xyzs;
delete [] nms;
if(!status) return;
} else {
::printf("debug : draw_vertex_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
return;
}
if(!buffer) return;
MTLResourceOptions opts = 0;
id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
uniforms _uniforms;
set_uniforms(_uniforms,false);
id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
if(m_ccw) {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
} else {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
}
[m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
[m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
[vertex_buffer release];
[uniforms_buffer release];
delete [] buffer;
}
virtual void draw_vertex_color_normal_array(tools::gl::mode_t a_mode,
size_t a_floatn,const float* a_xyzs,const float* a_rgbas,const float* a_nms){
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
if(!m_mgr.render_command_encoder()) return;
//::printf("debug : draw_vertex_color_normal_array : 000 : num %lu, mode %d\n",num,a_mode);
float* buffer = 0;
MTLPrimitiveType primitive_type;
if(a_mode==tools::gl::points()) {
primitive_type = MTLPrimitiveTypePoint;
if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
} else if(a_mode==tools::gl::lines()) {
primitive_type = MTLPrimitiveTypeLine;
if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
} else if(a_mode==tools::gl::line_loop()) {
::printf("debug : draw_vertex_color_normal_array : line_loop : have to handle rgbas and nms\n");
primitive_type = MTLPrimitiveTypeLineStrip;
size_t nxyz = (num+1)*3;
float* xyzs = new float[nxyz];
{float* pxyzs = xyzs;
tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer(num,xyzs,buffer);
delete [] xyzs;
if(!status) return;
} else if(a_mode==tools::gl::line_strip()) {
primitive_type = MTLPrimitiveTypeLineStrip;
if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
} else if(a_mode==tools::gl::triangles()) {
primitive_type = MTLPrimitiveTypeTriangle;
if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
} else if(a_mode==tools::gl::triangle_fan()) {
::printf("debug : draw_vertex_color_normal_array : triangle_fan : have to handle rgbas\n");
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* nms = new float[nxyz];
{float* pxyzs = xyzs;
float* pnms = nms;
tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
num = nxyz/3;
bool status = fill_buffer_nms(num,xyzs,nms,buffer);
delete [] xyzs;
delete [] nms;
if(!status) return;
} else if(a_mode==tools::gl::triangle_strip()) {
::printf("debug : draw_vertex_color_normal_array : triangle_strip : have to handle rgbas\n");
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* nms = new float[nxyz];
{float* pxyzs = xyzs;
float* pnms = nms;
tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
num = nxyz/3;
bool status = fill_buffer_nms(num,xyzs,nms,buffer);
delete [] xyzs;
delete [] nms;
if(!status) return;
} else {
::printf("debug : draw_vertex_color_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
return;
}
if(!buffer) return;
MTLResourceOptions opts = 0;
id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
uniforms _uniforms;
set_uniforms(_uniforms,false);
id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
if(m_ccw) {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
} else {
[m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
}
[m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
[m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
[vertex_buffer release];
[uniforms_buffer release];
delete [] buffer;
}
virtual void draw_vertex_array_texture(tools::gl::mode_t a_mode,
size_t a_floatn,
const float* /*a_xyzs*/,
gstoid /*a_id*/,
const float* /*a_tcs*/) {
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
::printf("debug : draw_vertex_array_texture : dummy : mode %d, num %lu\n",a_mode,a_floatn);
//expect 2*num a_tcs.
///////////////////////
/// get texture : /////
///////////////////////
/*
std::string sid;
if(!m_mgr.find_sid(a_id,sid)) {
m_out << "tools::metal::render::draw_vertex_array_texture : can't find texture " << sid << "." << std::endl;
return;
}
*/
//::printf("debug : draw_vertex_array_texture : use tex %s\n",sid.c_str());
}
virtual void draw_vertex_normal_array_texture(tools::gl::mode_t a_mode,
size_t a_floatn,
const float* a_xyzs,
const float* /*a_nms*/,
gstoid a_id,
const float* a_tcs) {
if(!tools::gl::is_mode(a_mode)) return;
size_t num = a_floatn/3;
if(!num) return;
if(!m_mgr.render_command_encoder()) return;
//::printf("debug : draw_vertex_normal_array_texture : dummy : %d %lu\n",a_mode,a_floatn);
//expect 2*num a_tcs.
///////////////////////
/// get texture : /////
///////////////////////
id<MTLTexture> _texture;
if(!m_mgr.find_texture(a_id,_texture)) {
m_out << "tools::metal::render::draw_vertex_array_texture : can't find texture " << a_id << "." << std::endl;
return;
}
float* buffer = 0;
MTLPrimitiveType primitive_type;
if(a_mode==tools::gl::points()) {
primitive_type = MTLPrimitiveTypePoint;
if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
} else if(a_mode==tools::gl::lines()) {
primitive_type = MTLPrimitiveTypeLine;
if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
} else if(a_mode==tools::gl::line_loop()) {
primitive_type = MTLPrimitiveTypeLineStrip;
size_t nxyz = (num+1)*3;
float* xyzs = new float[nxyz];
float* tcs = new float[(num+1)*2];
{float* pxyzs = xyzs;
//float* ptcs = tcs;
tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
num = nxyz/3;
bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
delete [] xyzs;
delete [] tcs;
if(!status) return;
} else if(a_mode==tools::gl::line_strip()) {
primitive_type = MTLPrimitiveTypeLineStrip;
if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
} else if(a_mode==tools::gl::triangles()) {
primitive_type = MTLPrimitiveTypeTriangle;
if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
} else if(a_mode==tools::gl::triangle_fan()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* tcs = new float[ntri*3*2];
{float* pxyzs = xyzs;
float* ptcs = tcs;
tools::gl::triangle_fan_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
num = nxyz/3;
bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
delete [] xyzs;
delete [] tcs;
if(!status) return;
} else if(a_mode==tools::gl::triangle_strip()) {
primitive_type = MTLPrimitiveTypeTriangle;
size_t ntri = num-2;
size_t nxyz = ntri*3*3;
float* xyzs = new float[nxyz];
float* tcs = new float[ntri*3*2];
{float* pxyzs = xyzs;
float* ptcs = tcs;
tools::gl::triangle_strip_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
num = nxyz/3;
bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
delete [] xyzs;
delete [] tcs;
if(!status) return;
} else {
::printf("debug : draw_vertex_array_texture : mode not handled yet : %lu %d\n",num,a_mode);
return;
}
if(!buffer) return;
id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer
length:num*14*sizeof(float)
options:MTLResourceStorageModeShared];
MTLResourceOptions opts = 0;
uniforms _uniforms;
set_uniforms(_uniforms,true);
id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
[m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
[m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
[m_mgr.render_command_encoder() setFragmentTexture:_texture atIndex:0];
[m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
[vertex_buffer release];
[uniforms_buffer release];
delete [] buffer;
}
virtual void color4f(float a_r,float a_g,float a_b,float a_a) {m_color.set_value(a_r,a_g,a_b,a_a);}
virtual void line_width(float /*a_value*/) {
}
virtual void point_size(float /*a_value*/) {
}
virtual void set_polygon_offset(bool /*a_on*/) {
}
virtual void normal(float a_x,float a_y,float a_z) {m_normal.set_value(a_x,a_y,a_z);}
virtual void set_winding(tools::sg::winding_type a_v) {m_ccw = (a_v==tools::sg::winding_ccw?true:false);}
virtual void set_shade_model(tools::sg::shade_type /*a_v*/) {}
virtual void set_depth_test(bool a_on) {m_depth_test = a_on;}
virtual void set_cull_face(bool /*a_on*/) {}
virtual void load_proj_matrix(const tools::mat4f& a_mtx) {m_proj = a_mtx;}
virtual void load_model_matrix(const tools::mat4f& a_mtx) {
m_model = a_mtx;
set_normal_matrix();
}
virtual unsigned int max_lights() {return 1000;}
virtual void enable_light(unsigned int,
float a_dx,float a_dy,float a_dz,
float a_r,float a_g,float a_b,float a_a){
float dl = tools::fsqrt(a_dx*a_dx+a_dy*a_dy+a_dz*a_dz);
if(!dl) {
m_out << "tools::metal::render::enable_light : null light direction." << std::endl;
return;
}
m_light_color.set_value(a_r,a_g,a_b,a_a);
m_light_direction.set_value(a_dx/dl,a_dy/dl,a_dz/dl);
m_light_on = true;
}
virtual void set_lighting(bool a_on) {m_light_on = a_on;}
virtual void set_blend(bool /*a_on*/) {}
virtual void restore_state(unsigned int /*a_ret_num_light*/) {
tools::sg::state& _state = state();
render::load_proj_matrix(_state.m_proj);
render::load_model_matrix(_state.m_model);
set_lighting(_state.m_GL_LIGHTING);
set_blend(_state.m_GL_BLEND);
set_depth_test(_state.m_GL_DEPTH_TEST);
set_cull_face(_state.m_GL_CULL_FACE);
set_polygon_offset(_state.m_GL_POLYGON_OFFSET_FILL);
// if(_state.m_GL_TEXTURE_2D) gl_enable(m_mgr.js(),"TEXTURE_2D");
// else gl_disable(m_mgr.js(),"TEXTURE_2D");
set_winding(_state.m_winding);
color4f(_state.m_color.r(),_state.m_color.g(),_state.m_color.b(),_state.m_color.a());
normal(_state.m_normal.x(),_state.m_normal.y(),_state.m_normal.z());
// The "return of separator" state had ret_num_light.
// The restored state has m_light.
// We have to glDisable lights with index in [m_light,ret_num_light-1]
//for(unsigned int index=_state.m_light;index<a_ret_num_light;index++) {
// ::glDisable(GL_LIGHT0+index);
//}
line_width(_state.m_line_width);
point_size(_state.m_point_size);
}
/////////////////////////////////////////////////////////////////
/// VBO /////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
virtual void begin_gsto(gstoid a_id) {m_current_data_gsto_id = a_id;}
typedef tools::sg::bufpos bufpos;
virtual void draw_gsto_v(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs) {
if(!m_current_data_gsto_id) return;
char* _buffer;
if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
m_out << "tools::metal::render::draw_gsto_v : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
return;
}
float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
size_t a_floatn = a_elems*3;
draw_vertex_array(a_mode,a_floatn,a_xyzs);
}
virtual void draw_gsto_vc(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs,bufpos a_pos_rgbas){
if(!m_current_data_gsto_id) return;
char* _buffer;
if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
m_out << "tools::metal::render::draw_gsto_vc : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
return;
}
float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
float* a_rgbas = (float*)(_buffer+a_pos_rgbas);
size_t a_floatn = a_elems*3;
draw_vertex_color_array(a_mode,a_floatn,a_xyzs,a_rgbas);
}
virtual void draw_gsto_vn(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs,bufpos a_pos_nms){
if(!m_current_data_gsto_id) return;
char* _buffer;
if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
m_out << "tools::metal::render::draw_gsto_vn : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
return;
}
float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
float* a_nms = (float*)(_buffer+a_pos_nms);
size_t a_floatn = a_elems*3;
draw_vertex_normal_array(a_mode,a_floatn,a_xyzs,a_nms);
}
virtual void draw_gsto_vcn(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs,bufpos a_pos_rgbas,bufpos a_pos_nms){
if(!m_current_data_gsto_id) return;
char* _buffer;
if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
m_out << "tools::metal::render::draw_gsto_vcn : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
return;
}
float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
float* a_rgbas = (float*)(_buffer+a_pos_rgbas);
float* a_nms = (float*)(_buffer+a_pos_nms);
size_t a_floatn = a_elems*3;
draw_vertex_color_normal_array(a_mode,a_floatn,a_xyzs,a_rgbas,a_nms);
}
virtual void end_gsto() {m_current_data_gsto_id = 0;}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
virtual void set_point_smooth(bool) {}
virtual void set_line_smooth(bool) {}
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
virtual tools::sg::render_manager& render_manager() {return m_mgr;}
public:
render(manager& a_mgr,std::ostream& a_out,unsigned int a_ww,unsigned int a_wh)
:parent(a_out,a_ww,a_wh)
,m_mgr(a_mgr)
,m_current_data_gsto_id(0)
,m_light_color(tools::colorf_white())
,m_light_direction(tools::vec3f(0,0,-1))
,m_light_on(false)
,m_ccw(true)
,m_depth_test(true)
{
m_proj.set_identity();
m_model.set_identity();
m_normal_matrix.set_identity();
}
virtual ~render(){}
protected:
render(const render& a_from)
:parent(a_from)
,m_mgr(a_from.m_mgr)
,m_current_data_gsto_id(0)
,m_light_color(a_from.m_light_color)
,m_light_direction(a_from.m_light_direction)
,m_proj(a_from.m_proj)
,m_model(a_from.m_model)
,m_normal_matrix(a_from.m_normal_matrix)
,m_color(a_from.m_color)
,m_normal(a_from.m_normal)
,m_light_on(a_from.m_light_on)
,m_ccw(a_from.m_ccw)
,m_depth_test(a_from.m_depth_test)
{}
render& operator=(const render& a_from){
parent::operator=(a_from);
m_current_data_gsto_id = 0;
m_light_color = a_from.m_light_color;
m_light_direction = a_from.m_light_direction;
m_proj = a_from.m_proj;
m_model = a_from.m_model;
m_normal_matrix = a_from.m_normal_matrix;
m_color = a_from.m_color;
m_normal = a_from.m_normal;
m_light_on = a_from.m_light_on;
m_ccw = a_from.m_ccw;
m_depth_test = a_from.m_depth_test;
return *this;
}
protected:
void set_normal_matrix() {
tools::mat4f tmp(m_model);
tmp.no_translate();
if(!tmp.invert(m_normal_matrix)) {
m_out << "tools::metal::render::set_normal_matrix : can't invert model matrix." << std::endl;
}
m_normal_matrix.transpose();
}
bool fill_buffer(size_t a_num,const float* a_xyzs,float*& a_buffer) {
a_buffer = new float[a_num*14];
float* pos = a_buffer;
for(size_t index=0;index<a_num;index++) {
*pos = a_xyzs[3*index+0];pos++;
*pos = a_xyzs[3*index+1];pos++;
*pos = a_xyzs[3*index+2];pos++;
*pos = 1;pos++;
*pos = m_normal.x();pos++;
*pos = m_normal.y();pos++;
*pos = m_normal.z();pos++;
*pos = 1;pos++;
*pos = m_color.r();pos++;
*pos = m_color.g();pos++;
*pos = m_color.b();pos++;
*pos = m_color.a();pos++;
*pos = 0;pos++;
*pos = 0;pos++;
}
return true;
}
bool fill_buffer_nms(size_t a_num,const float* a_xyzs,const float* a_nms,float*& a_buffer) {
a_buffer = new float[a_num*14];
float* pos = a_buffer;
for(size_t index=0;index<a_num;index++) {
*pos = a_xyzs[3*index+0];pos++;
*pos = a_xyzs[3*index+1];pos++;
*pos = a_xyzs[3*index+2];pos++;
*pos = 1;pos++;
*pos = a_nms[3*index+0];pos++;
*pos = a_nms[3*index+1];pos++;
*pos = a_nms[3*index+2];pos++;
*pos = 1;pos++;
*pos = m_color.r();pos++;
*pos = m_color.g();pos++;
*pos = m_color.b();pos++;
*pos = m_color.a();pos++;
*pos = 0;pos++;
*pos = 0;pos++;
}
return true;
}
bool fill_buffer_rgbas(size_t a_num,const float* a_xyzs,const float* a_rgbas,float*& a_buffer) {
a_buffer = new float[a_num*14];
float* pos = a_buffer;
for(size_t index=0;index<a_num;index++) {
*pos = a_xyzs[3*index+0];pos++;
*pos = a_xyzs[3*index+1];pos++;
*pos = a_xyzs[3*index+2];pos++;
*pos = 1;pos++;
*pos = m_normal.x();pos++;
*pos = m_normal.y();pos++;
*pos = m_normal.z();pos++;
*pos = 1;pos++;
*pos = a_rgbas[4*index+0];pos++;
*pos = a_rgbas[4*index+1];pos++;
*pos = a_rgbas[4*index+2];pos++;
*pos = a_rgbas[4*index+3];pos++;
*pos = 0;pos++;
*pos = 0;pos++;
}
return true;
}
bool fill_buffer_rgbas_nms(size_t a_num,const float* a_xyzs,const float* a_rgbas,const float* a_nms,float*& a_buffer) {
a_buffer = new float[a_num*14];
float* pos = a_buffer;
for(size_t index=0;index<a_num;index++) {
*pos = a_xyzs[3*index+0];pos++;
*pos = a_xyzs[3*index+1];pos++;
*pos = a_xyzs[3*index+2];pos++;
*pos = 1;pos++;
*pos = a_nms[3*index+0];pos++;
*pos = a_nms[3*index+1];pos++;
*pos = a_nms[3*index+2];pos++;
*pos = 1;pos++;
*pos = a_rgbas[4*index+0];pos++;
*pos = a_rgbas[4*index+1];pos++;
*pos = a_rgbas[4*index+2];pos++;
*pos = a_rgbas[4*index+3];pos++;
*pos = 0;pos++;
*pos = 0;pos++;
}
return true;
}
bool fill_buffer_texture(size_t a_num,const float* a_xyzs,const float* a_tcs,float*& a_buffer) {
a_buffer = new float[a_num*14];
float* pos = a_buffer;
for(size_t index=0;index<a_num;index++) {
*pos = a_xyzs[3*index+0];pos++;
*pos = a_xyzs[3*index+1];pos++;
*pos = a_xyzs[3*index+2];pos++;
*pos = 1;pos++;
*pos = 0;pos++;
*pos = 0;pos++;
*pos = 1;pos++;
*pos = 1;pos++;
*pos = m_color.r();pos++;
*pos = m_color.g();pos++;
*pos = m_color.b();pos++;
*pos = m_color.a();pos++;
*pos = a_tcs[2*index+0];pos++;
*pos = a_tcs[2*index+1];pos++;
}
return true;
}
struct uniforms {
simd::float4x4 proj_model_matrix;
simd::float4x4 normal_matrix;
unsigned int light_on;
simd::float4 light_color;
simd::float3 light_direction;
unsigned int texturing;
};
void set_uniforms(uniforms& a_uniforms,bool a_texturing) {
// Metal NDC is [-1,1]x[-1,1]x[0,1]
// OpenGL NDC is [-1,1]x[-1,1]x[-1,1]
tools::mat4f z_gl_to_metal;
z_gl_to_metal.set_translate(0,0,0.5);
z_gl_to_metal.mul_scale(1,1,0.5);
tools::mat4f pm;
pm.set_identity();
pm = z_gl_to_metal;
pm *= m_proj;
pm *= m_model;
::memcpy(&(a_uniforms.proj_model_matrix),pm.data(),16*sizeof(float));
::memcpy(&(a_uniforms.normal_matrix),m_normal_matrix.data(),16*sizeof(float));
a_uniforms.light_on = m_light_on?1:0;
::memcpy(&(a_uniforms.light_color),m_light_color.data(),4*sizeof(float));
::memcpy(&(a_uniforms.light_direction),m_light_direction.data(),3*sizeof(float));
a_uniforms.texturing = a_texturing?1:0;
}
protected:
manager& m_mgr;
gstoid m_current_data_gsto_id;
tools::colorf m_light_color;
tools::vec3f m_light_direction;
// to be restored in restore_state() :
tools::mat4f m_proj;
tools::mat4f m_model;
tools::mat4f m_normal_matrix;
tools::colorf m_color;
tools::vec3f m_normal;
bool m_light_on;
bool m_ccw;
bool m_depth_test;
};
}}
#endif