1425 lines
49 KiB
Plaintext
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
|