1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
2 // See the file tools.license for terms.
4 #ifndef tools_metal_render
5 #define tools_metal_render
7 #include <tools/sg/render_manager>
8 #include <tools/sg/render_action>
9 #include <tools/glprims>
10 #include <tools/colorfs>
11 #include <tools/lina/mat3f>
12 #include <tools/num2s>
13 #include <tools/mapmanip>
14 #include <tools/mathf>
15 #include <tools/forit>
17 #include <Metal/Metal.h>
18 #include <MetalKit/MTKView.h>
19 #include <simd/simd.h>
25 class manager : public virtual tools::sg::render_manager {
26 typedef tools::sg::render_manager parent;
28 TOOLS_SCLASS(tools::metal::manager)
29 virtual void* cast(const std::string& a_class) const {
30 if(void* p = tools::cmp_cast<manager>(this,a_class)) {return p;}
34 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) {
35 if(!m_view) return false;
36 create_pipeline_state();
37 //::printf("debug : manager::begin_render : 000 : %d %d\n",a_w,a_h);
38 m_render_command_encoder = 0;
39 m_command_buffer = [m_command_queue commandBuffer];
40 create_render_command_encoder(a_x,a_y,a_w,a_h,a_r,a_g,a_b,a_a);
44 virtual void end_render() {
45 //::printf("debug : manager::end_render : 000\n");
47 [m_render_pipeline_state release];
50 virtual unsigned int create_texture(const tools::img_byte& a_img,bool /*a_NEAREST*/) {
51 //::printf("debug : create_texture : size = %d, w = %d, h = %d, bpp %d\n",
52 // a_img.size(),a_img.width(),a_img.height(),a_img.bpp());
54 tools::img_byte* _img = 0;
55 bool _img_delete = false;
57 if(a_img.bpp()==1) { //exa eiffel-tower.png
59 if(!a_img.bw2x(3,img3)) {
60 m_out << "tools::metal::manager::create_texture : a_imgr.bw2x() failed." << std::endl;
64 if(!img3.rgb2rgba(img4,255)){
65 m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
68 _img = new tools::img_byte;
72 } else if(a_img.bpp()==3) {
74 if(!a_img.rgb2rgba(img4,255)){
75 m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
78 _img = new tools::img_byte;
82 } else if(a_img.bpp()==4) { //exa windusrf.png, text_freetype/font_pixmap.
83 _img = const_cast<tools::img_byte*>(&a_img);
86 m_out << "tools::metal::manager::create_texture :"
87 << " image with bpp " << a_img.bpp() << " not (yet) supported."
89 if(_img_delete) delete _img;
92 if(_img->is_empty()) {
93 if(_img_delete) delete _img;
101 MTLTextureDescriptor* tex_desc = [[MTLTextureDescriptor alloc] init];
102 tex_desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
103 tex_desc.width = _img->width();
104 tex_desc.height = _img->height();
106 id<MTLTexture> texture = [m_device newTextureWithDescriptor:tex_desc];
108 NSUInteger bytes_per_row = _img->bpp() * _img->width();
111 {0,0,0}, // MTLOrigin
112 {_img->width(),_img->height(),1} // MTLSize
115 [texture replaceRegion:region mipmapLevel:0 withBytes:_img->buffer() bytesPerRow:bytes_per_row];
117 m_tex_gstos[m_gen_id] = new tex_gsto(texture,_img->size(),m_out,*this);
118 if(_img_delete) delete _img;
122 virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
123 if(!a_floatn) return 0;
125 m_data_gstos[m_gen_id] = new data_gsto(a_data,a_floatn,m_out,*this);
129 virtual bool is_gsto_id_valid(unsigned int a_id) const {
130 {std::map<unsigned int,tex_gsto*>::const_iterator it = m_tex_gstos.find(a_id);
131 if(it!=m_tex_gstos.end()) return true;}
132 {std::map<unsigned int,data_gsto*>::const_iterator it = m_data_gstos.find(a_id);
133 if(it!=m_data_gstos.end()) return true;}
136 virtual void delete_gsto(unsigned int a_id) {
137 tools::delete_key<unsigned int,tex_gsto>(m_tex_gstos,a_id);
138 tools::delete_key<unsigned int,data_gsto>(m_data_gstos,a_id);
141 virtual tools::sg::gsto_mode get_gsto_mode() const {return tools::sg::gsto_gl_vbo;}
142 virtual void set_gsto_mode(tools::sg::gsto_mode) {}
143 virtual void available_gsto_modes(std::vector<std::string>& a_v) {
145 a_v.push_back(tools::sg::s_gsto_gl_vbo());
147 virtual void available_not_memory_gsto_mode(std::string& a_s) const {
148 a_s = tools::sg::s_gsto_gl_vbo();
150 virtual size_t used_texture_memory() const {
152 std::map<unsigned int,tex_gsto*>::const_iterator it;
153 for(it=m_tex_gstos.begin();it!=m_tex_gstos.end();++it) {sz += (*it).second->m_size;}
156 virtual size_t gstos_size() const {
158 {tools_mforcit(unsigned int,tex_gsto*,m_tex_gstos,it) {sz += (*it).second->m_size;}}
159 {tools_mforcit(unsigned int,data_gsto*,m_data_gstos,it) {sz += (*it).second->m_size;}}
164 manager(std::ostream& a_out)
170 ,m_render_pipeline_state(0)
171 ,m_depth_stencil_state_on(0)
172 ,m_depth_stencil_state_off(0)
174 ,m_render_command_encoder(0)
177 tools::mem::increment(s_class().c_str());
179 m_device = MTLCreateSystemDefaultDevice();
180 m_command_queue = [m_device newCommandQueue];
182 //create_pipeline_state();
184 {MTLDepthStencilDescriptor* depth_stencil_desc = [[MTLDepthStencilDescriptor alloc] init];
185 depth_stencil_desc.depthWriteEnabled = YES;
186 depth_stencil_desc.depthCompareFunction = MTLCompareFunctionLess;
187 m_depth_stencil_state_on = [m_device newDepthStencilStateWithDescriptor:depth_stencil_desc];}
189 {MTLDepthStencilDescriptor* depth_stencil_desc = [[MTLDepthStencilDescriptor alloc] init];
190 depth_stencil_desc.depthWriteEnabled = NO;
191 depth_stencil_desc.depthCompareFunction = MTLCompareFunctionLess;
192 m_depth_stencil_state_off = [m_device newDepthStencilStateWithDescriptor:depth_stencil_desc];}
195 //[m_render_pipeline_state release];
196 [m_depth_stencil_state_on release];
197 [m_depth_stencil_state_off release];
198 [m_command_queue release];
200 tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
201 tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
203 tools::mem::decrement(s_class().c_str());
208 manager(const manager& a_from)
211 ,m_gen_id(a_from.m_gen_id)
215 ,m_render_pipeline_state(0)
216 ,m_depth_stencil_state_on(0)
217 ,m_depth_stencil_state_off(0)
219 ,m_render_command_encoder(0)
222 tools::mem::increment(s_class().c_str());
225 manager& operator=(const manager& a_from){
226 if(&a_from==this) return *this;
227 tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
228 tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
232 void delete_gstos() {
233 tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
234 tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
238 bool find_texture(unsigned int a_id,id<MTLTexture>& a_texture) const {
239 std::map<unsigned int,tex_gsto*>::const_iterator it = m_tex_gstos.find(a_id);
240 if(it==m_tex_gstos.end()) {a_texture = 0;return false;}
241 a_texture = (*it).second->m_texture;
244 bool find_data_gsto(unsigned int a_id,char*& a_data) const {
245 std::map<unsigned int,data_gsto*>::const_iterator it = m_data_gstos.find(a_id);
246 if(it==m_data_gstos.end()) {a_data = 0;return false;}
247 a_data = (*it).second->m_buffer;
251 std::ostream& out() const {return m_out;}
253 id<MTLDevice>& device() {return m_device;}
254 id<MTLRenderCommandEncoder>& render_command_encoder() {return m_render_command_encoder;}
255 id<MTLDepthStencilState>& depth_stencil_state_on() {return m_depth_stencil_state_on;}
256 id<MTLDepthStencilState>& depth_stencil_state_off() {return m_depth_stencil_state_off;}
257 void set_view(MTKView* a_view) {m_view = a_view;}
261 TOOLS_SCLASS(tools::metal::manager::data_gsto)
264 data_gsto(const float* a_floats,size_t a_floatn,std::ostream& a_out,manager& a_mgr)
271 tools::mem::increment(s_class().c_str());
273 m_size = a_floatn*sizeof(float);
274 m_buffer = new char[m_size];
275 ::memcpy(m_buffer,a_floats,m_size);
277 virtual ~data_gsto(){
280 tools::mem::decrement(s_class().c_str());
284 data_gsto(const data_gsto& a_from)
286 ,m_size(a_from.m_size)
291 tools::mem::increment(s_class().c_str());
294 data_gsto& operator=(const data_gsto& a_from){
296 m_size = a_from.m_size;
308 TOOLS_SCLASS(tools::metal::manager::tex_gsto)
311 tex_gsto(id<MTLTexture>& a_texture,size_t a_size,std::ostream& a_out,manager& a_mgr)
312 :m_texture(a_texture)
318 tools::mem::increment(s_class().c_str());
322 [m_texture release]; //is it needed ?
324 tools::mem::decrement(s_class().c_str());
328 tex_gsto(const tex_gsto& a_from)
329 :m_texture(a_from.m_texture)
330 ,m_size(a_from.m_size)
335 tools::mem::increment(s_class().c_str());
338 tex_gsto& operator=(const tex_gsto& a_from){
339 m_texture = a_from.m_texture;
340 m_size = a_from.m_size;
344 id<MTLTexture> m_texture;
350 void create_pipeline_state() {
351 const char shaders_src[] = "\
352 #include <metal_stdlib>\n\
353 #include <simd/simd.h>\n\
355 simd::float4x4 proj_model_matrix;\n\
356 simd::float4x4 normal_matrix;\n\
357 unsigned int light_on;\n\
358 simd::float4 light_color;\n\
359 simd::float3 light_direction;\n\
360 unsigned int texturing;\n\
362 struct vertex_in {\n\
363 simd::float4 position [[attribute(0)]];\n\
364 simd::float4 normal [[attribute(1)]];\n\
365 simd::float4 color [[attribute(2)]];\n\
366 simd::float2 texture_coordinate [[attribute(3)]];\n\
368 struct vertex_out {\n\
369 simd::float4 position [[position]];\n\
370 simd::float3 normal;\n\
371 simd::float4 color;\n\
372 simd::float2 texture_coordinate;\n\
373 unsigned int light_on;\n\
374 simd::float4 light_color;\n\
375 simd::float3 light_direction;\n\
376 unsigned int texturing;\n\
377 /*float pointsize [[point_size]];*/\n\
379 vertex vertex_out vert_shader(vertex_in a_in [[stage_in]],constant uniforms& a_uniforms [[buffer(1)]]) {\n\
382 out.position = a_uniforms.proj_model_matrix * a_in.position;\n\
383 out.normal = simd::normalize((a_uniforms.normal_matrix * a_in.normal).xyz);\n\
384 out.color = a_in.color;\n\
385 out.texture_coordinate = a_in.texture_coordinate;\n\
387 out.light_on = a_uniforms.light_on;\n\
388 out.light_color = a_uniforms.light_color;\n\
389 out.light_direction = a_uniforms.light_direction;\n\
390 out.texturing = a_uniforms.texturing;\n\
394 fragment simd::float4 frag_shader(vertex_out a_in [[stage_in]],simd::texture2d<half> a_color [[texture(0)]]) {\n\
395 if(a_in.texturing) {\n\
396 constexpr simd::sampler texture_sampler(simd::mag_filter::linear,simd::min_filter::linear);\n\
397 const half4 color_sample = a_color.sample(texture_sampler,a_in.texture_coordinate);\n\
398 return simd::float4(color_sample)*a_in.color;\n\
400 if(a_in.light_on) {\n\
401 simd::float4 black(0,0,0,1);\n\
402 /*simd::float4 red(1,0,0,1);*/\n\
403 float _dot = simd::dot(a_in.normal,a_in.light_direction);\n\
406 float cooking = 1.4; /*to have same intensity as GL on desktops.*/\n\
407 simd::float4 diffuse_color = a_in.light_color*_dot*cooking;\n\
408 simd::float4 _color = diffuse_color*a_in.color;\n\
409 /*simd::float4 _color = _dot*a_in.color;*/\n\
410 _color[3] = a_in.color[3];\n\
417 return a_in.color;\n\
423 MTLVertexDescriptor* vert_desc = [MTLVertexDescriptor vertexDescriptor];
424 vert_desc.attributes[0].format = MTLVertexFormatFloat4;
425 vert_desc.attributes[0].bufferIndex = 0;
426 vert_desc.attributes[0].offset = 0;
428 vert_desc.attributes[1].format = MTLVertexFormatFloat4;
429 vert_desc.attributes[1].bufferIndex = 0;
430 vert_desc.attributes[1].offset = sizeof(float)*4;
432 vert_desc.attributes[2].format = MTLVertexFormatFloat4;
433 vert_desc.attributes[2].bufferIndex = 0;
434 vert_desc.attributes[2].offset = sizeof(float)*8;
436 vert_desc.attributes[3].format = MTLVertexFormatFloat2;
437 vert_desc.attributes[3].bufferIndex = 0;
438 vert_desc.attributes[3].offset = sizeof(float)*12;
440 vert_desc.layouts[0].stride = 14*sizeof(float);
441 vert_desc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
443 MTLCompileOptions* opts = [[MTLCompileOptions alloc] init];
444 NSString* src = [[NSString alloc] initWithUTF8String:shaders_src];
445 id<MTLLibrary> library = [m_device newLibraryWithSource:src options:opts error:nullptr];
448 id<MTLFunction> vert_func = [library newFunctionWithName:@"vert_shader"];
449 id<MTLFunction> frag_func = [library newFunctionWithName:@"frag_shader"];
450 MTLRenderPipelineDescriptor* render_pipeline_desc = [[MTLRenderPipelineDescriptor alloc] init];
451 render_pipeline_desc.label = @"pipeline";
452 render_pipeline_desc.vertexFunction = vert_func;
453 render_pipeline_desc.fragmentFunction = frag_func;
454 render_pipeline_desc.vertexDescriptor = vert_desc;
455 render_pipeline_desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
456 render_pipeline_desc.stencilAttachmentPixelFormat = [m_view depthStencilPixelFormat];
457 render_pipeline_desc.depthAttachmentPixelFormat = [m_view depthStencilPixelFormat];
458 m_render_pipeline_state = [m_device newRenderPipelineStateWithDescriptor:render_pipeline_desc error:nullptr];
463 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) {
464 MTLRenderPassDescriptor* render_pass_desc = [m_view currentRenderPassDescriptor];
465 [render_pass_desc setRenderTargetArrayLength:1];
467 MTLRenderPassColorAttachmentDescriptor* color_attachment_desc = [render_pass_desc colorAttachments][0];
468 color_attachment_desc.clearColor = MTLClearColorMake(a_r,a_g,a_b,a_a);
470 m_render_command_encoder = [m_command_buffer renderCommandEncoderWithDescriptor:render_pass_desc];
471 [m_render_command_encoder setRenderPipelineState:m_render_pipeline_state];
473 //double znear = 0.0;
475 //[m_render_command_encoder setViewport:(MTLViewport){double(a_x),double(a_y),2.0*double(a_w),2.0*double(a_h),znear,zfar}];
477 [m_render_command_encoder setDepthStencilState:m_depth_stencil_state_on];
478 //[m_render_command_encoder setDepthClipMode:MTLDepthClipModeClip];
479 [m_render_command_encoder setFrontFacingWinding:MTLWindingCounterClockwise];
480 [m_render_command_encoder setCullMode:MTLCullModeBack];
482 void end_encoding() {
484 if(m_render_command_encoder) [m_render_command_encoder endEncoding];
485 id<MTLDrawable> drawable = [m_view currentDrawable];
486 if(drawable) [m_command_buffer presentDrawable:drawable];
488 [m_command_buffer commit];
489 [m_command_buffer waitUntilCompleted];
490 //[m_command_buffer waitUntilScheduled];
495 unsigned int m_gen_id;
496 std::map<unsigned int,tex_gsto*> m_tex_gstos;
497 std::map<unsigned int,data_gsto*> m_data_gstos;
499 id<MTLDevice> m_device;
500 id<MTLCommandQueue> m_command_queue;
501 id<MTLRenderPipelineState> m_render_pipeline_state;
502 id<MTLDepthStencilState> m_depth_stencil_state_on;
503 id<MTLDepthStencilState> m_depth_stencil_state_off;
504 id<MTLCommandBuffer> m_command_buffer;
505 id<MTLRenderCommandEncoder> m_render_command_encoder;
508 class render : public tools::sg::render_action {
509 TOOLS_ACTION(render,tools::metal::render,tools::sg::render_action)
511 virtual void clear_color(float,float,float,float){}
512 virtual void draw_vertex_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs){
513 if(!tools::gl::is_mode(a_mode)) return;
514 size_t num = a_floatn/3;
517 if(!m_mgr.render_command_encoder()) return;
519 //::printf("debug : draw_vertex_array : 000 : %lu %d\n",num,a_mode);
522 MTLPrimitiveType primitive_type;
523 if(a_mode==tools::gl::points()) {
524 primitive_type = MTLPrimitiveTypePoint;
525 if(!fill_buffer(num,a_xyzs,buffer)) return;
527 } else if(a_mode==tools::gl::lines()) {
528 primitive_type = MTLPrimitiveTypeLine;
529 if(!fill_buffer(num,a_xyzs,buffer)) return;
531 } else if(a_mode==tools::gl::line_loop()) {
532 primitive_type = MTLPrimitiveTypeLineStrip;
533 size_t nxyz = (num+1)*3;
534 float* xyzs = new float[nxyz];
535 {float* pxyzs = xyzs;
536 tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
538 bool status = fill_buffer(num,xyzs,buffer);
542 } else if(a_mode==tools::gl::line_strip()) {
543 primitive_type = MTLPrimitiveTypeLineStrip;
544 if(!fill_buffer(num,a_xyzs,buffer)) return;
546 } else if(a_mode==tools::gl::triangles()) {
547 primitive_type = MTLPrimitiveTypeTriangle;
548 if(!fill_buffer(num,a_xyzs,buffer)) return;
550 } else if(a_mode==tools::gl::triangle_fan()) {
551 primitive_type = MTLPrimitiveTypeTriangle;
553 size_t nxyz = ntri*3*3;
554 float* xyzs = new float[nxyz];
555 {float* pxyzs = xyzs;
556 tools::gl::triangle_fan_to_triangles(num,a_xyzs,pxyzs);}
558 bool status = fill_buffer(num,xyzs,buffer);
562 } else if(a_mode==tools::gl::triangle_strip()) {
563 primitive_type = MTLPrimitiveTypeTriangle;
565 size_t nxyz = ntri*3*3;
566 float* xyzs = new float[nxyz];
567 {float* pxyzs = xyzs;
568 tools::gl::triangle_strip_to_triangles(num,a_xyzs,pxyzs);}
570 bool status = fill_buffer(num,xyzs,buffer);
575 ::printf("debug : draw_vertex_array : mode not handled yet : %lu %d\n",num,a_mode);
580 MTLResourceOptions opts = 0;
581 id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
584 set_uniforms(_uniforms,false);
585 id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
588 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
590 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
594 [m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_on()];
596 [m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_off()];
599 [m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
600 [m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
601 [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
603 [vertex_buffer release];
604 [uniforms_buffer release];
609 virtual void draw_vertex_array_xy(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xys){
610 if(!tools::gl::is_mode(a_mode)) return;
611 size_t num = a_floatn/2;
613 //::printf("debug : draw_vertex_array_xy %lu\n",num);
614 float* xyzs = new float[num*3];
616 tools::gl::cvt_2to3(num,a_xys,pxyzs);
617 draw_vertex_array(a_mode,num*3,xyzs);
621 virtual void draw_vertex_color_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,const float* a_rgbas){
622 if(!tools::gl::is_mode(a_mode)) return;
623 size_t num = a_floatn/3;
626 if(!m_mgr.render_command_encoder()) return;
627 //::printf("debug : draw_vertex_color_array : 000 : num %lu, mode %d\n",num,a_mode);
630 MTLPrimitiveType primitive_type;
631 if(a_mode==tools::gl::points()) {
632 primitive_type = MTLPrimitiveTypePoint;
633 if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
635 } else if(a_mode==tools::gl::lines()) {
636 primitive_type = MTLPrimitiveTypeLine;
637 if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
639 } else if(a_mode==tools::gl::line_loop()) {
640 ::printf("debug : draw_vertex_color_array : line_loop : have to handle a_rgbas\n");
641 primitive_type = MTLPrimitiveTypeLineStrip;
642 size_t nxyz = (num+1)*3;
643 float* xyzs = new float[nxyz];
644 {float* pxyzs = xyzs;
645 tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
647 bool status = fill_buffer(num,xyzs,buffer);
651 } else if(a_mode==tools::gl::line_strip()) {
652 primitive_type = MTLPrimitiveTypeLineStrip;
653 if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
655 } else if(a_mode==tools::gl::triangles()) {
656 primitive_type = MTLPrimitiveTypeTriangle;
657 if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
659 } else if(a_mode==tools::gl::triangle_fan()) {
660 ::printf("debug : draw_vertex_color_array : triangle_fan : have to handle a_rgbas\n");
661 primitive_type = MTLPrimitiveTypeTriangle;
663 size_t nxyz = ntri*3*3;
664 float* xyzs = new float[nxyz];
665 {float* pxyzs = xyzs;
666 tools::gl::triangle_fan_to_triangles(num,a_xyzs,pxyzs);}
668 bool status = fill_buffer(num,xyzs,buffer);
672 } else if(a_mode==tools::gl::triangle_strip()) {
673 ::printf("debug : draw_vertex_color_array : triangle_strip : have to handle a_rgbas\n");
674 primitive_type = MTLPrimitiveTypeTriangle;
676 size_t nxyz = ntri*3*3;
677 float* xyzs = new float[nxyz];
678 {float* pxyzs = xyzs;
679 tools::gl::triangle_strip_to_triangles(num,a_xyzs,pxyzs);}
681 bool status = fill_buffer(num,xyzs,buffer);
686 ::printf("debug : draw_vertex_color_array : mode not handled yet : %lu %d\n",num,a_mode);
691 MTLResourceOptions opts = 0;
692 id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
695 set_uniforms(_uniforms,false);
696 id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
699 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
701 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
704 [m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
705 [m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
706 [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
708 [vertex_buffer release];
709 [uniforms_buffer release];
714 virtual void draw_vertex_normal_array(tools::gl::mode_t a_mode,size_t a_floatn,const float* a_xyzs,const float* a_nms){
715 if(!tools::gl::is_mode(a_mode)) return;
716 size_t num = a_floatn/3;
719 if(!m_mgr.render_command_encoder()) return;
720 //::printf("debug : draw_vertex_normal_array : 000 : num %lu, mode %d\n",num,a_mode);
723 MTLPrimitiveType primitive_type;
724 if(a_mode==tools::gl::points()) {
725 primitive_type = MTLPrimitiveTypePoint;
726 if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
728 } else if(a_mode==tools::gl::lines()) {
729 primitive_type = MTLPrimitiveTypeLine;
730 if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
732 } else if(a_mode==tools::gl::line_loop()) {
733 ::printf("debug : draw_vertex_normal_array : line_loop to handle nms\n");
734 primitive_type = MTLPrimitiveTypeLineStrip;
735 size_t nxyz = (num+1)*3;
736 float* xyzs = new float[nxyz];
737 {float* pxyzs = xyzs;
738 tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
740 bool status = fill_buffer(num,xyzs,buffer);
744 } else if(a_mode==tools::gl::line_strip()) {
745 primitive_type = MTLPrimitiveTypeLineStrip;
746 if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
748 } else if(a_mode==tools::gl::triangles()) {
749 primitive_type = MTLPrimitiveTypeTriangle;
750 if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
752 } else if(a_mode==tools::gl::triangle_fan()) {
753 primitive_type = MTLPrimitiveTypeTriangle;
755 size_t nxyz = ntri*3*3;
756 float* xyzs = new float[nxyz];
757 float* nms = new float[nxyz];
758 {float* pxyzs = xyzs;
760 tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
762 bool status = fill_buffer_nms(num,xyzs,nms,buffer);
767 } else if(a_mode==tools::gl::triangle_strip()) {
768 primitive_type = MTLPrimitiveTypeTriangle;
770 size_t nxyz = ntri*3*3;
771 float* xyzs = new float[nxyz];
772 float* nms = new float[nxyz];
773 {float* pxyzs = xyzs;
775 tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
777 bool status = fill_buffer_nms(num,xyzs,nms,buffer);
783 ::printf("debug : draw_vertex_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
788 MTLResourceOptions opts = 0;
789 id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
792 set_uniforms(_uniforms,false);
793 id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
796 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
798 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
801 [m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
802 [m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
803 [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
805 [vertex_buffer release];
806 [uniforms_buffer release];
811 virtual void draw_vertex_color_normal_array(tools::gl::mode_t a_mode,
812 size_t a_floatn,const float* a_xyzs,const float* a_rgbas,const float* a_nms){
813 if(!tools::gl::is_mode(a_mode)) return;
814 size_t num = a_floatn/3;
817 if(!m_mgr.render_command_encoder()) return;
818 //::printf("debug : draw_vertex_color_normal_array : 000 : num %lu, mode %d\n",num,a_mode);
821 MTLPrimitiveType primitive_type;
822 if(a_mode==tools::gl::points()) {
823 primitive_type = MTLPrimitiveTypePoint;
824 if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
826 } else if(a_mode==tools::gl::lines()) {
827 primitive_type = MTLPrimitiveTypeLine;
828 if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
830 } else if(a_mode==tools::gl::line_loop()) {
831 ::printf("debug : draw_vertex_color_normal_array : line_loop : have to handle rgbas and nms\n");
832 primitive_type = MTLPrimitiveTypeLineStrip;
833 size_t nxyz = (num+1)*3;
834 float* xyzs = new float[nxyz];
835 {float* pxyzs = xyzs;
836 tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
838 bool status = fill_buffer(num,xyzs,buffer);
842 } else if(a_mode==tools::gl::line_strip()) {
843 primitive_type = MTLPrimitiveTypeLineStrip;
844 if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
846 } else if(a_mode==tools::gl::triangles()) {
847 primitive_type = MTLPrimitiveTypeTriangle;
848 if(!fill_buffer_rgbas_nms(num,a_xyzs,a_rgbas,a_nms,buffer)) return;
850 } else if(a_mode==tools::gl::triangle_fan()) {
851 ::printf("debug : draw_vertex_color_normal_array : triangle_fan : have to handle rgbas\n");
852 primitive_type = MTLPrimitiveTypeTriangle;
854 size_t nxyz = ntri*3*3;
855 float* xyzs = new float[nxyz];
856 float* nms = new float[nxyz];
857 {float* pxyzs = xyzs;
859 tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
861 bool status = fill_buffer_nms(num,xyzs,nms,buffer);
866 } else if(a_mode==tools::gl::triangle_strip()) {
867 ::printf("debug : draw_vertex_color_normal_array : triangle_strip : have to handle rgbas\n");
868 primitive_type = MTLPrimitiveTypeTriangle;
870 size_t nxyz = ntri*3*3;
871 float* xyzs = new float[nxyz];
872 float* nms = new float[nxyz];
873 {float* pxyzs = xyzs;
875 tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
877 bool status = fill_buffer_nms(num,xyzs,nms,buffer);
883 ::printf("debug : draw_vertex_color_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
888 MTLResourceOptions opts = 0;
889 id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
892 set_uniforms(_uniforms,false);
893 id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
896 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
898 [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
901 [m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
902 [m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
903 [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
905 [vertex_buffer release];
906 [uniforms_buffer release];
911 virtual void draw_vertex_array_texture(tools::gl::mode_t a_mode,
913 const float* /*a_xyzs*/,
915 const float* /*a_tcs*/) {
916 if(!tools::gl::is_mode(a_mode)) return;
917 size_t num = a_floatn/3;
919 ::printf("debug : draw_vertex_array_texture : dummy : mode %d, num %lu\n",a_mode,a_floatn);
921 //expect 2*num a_tcs.
923 ///////////////////////
924 /// get texture : /////
925 ///////////////////////
928 if(!m_mgr.find_sid(a_id,sid)) {
929 m_out << "tools::metal::render::draw_vertex_array_texture : can't find texture " << sid << "." << std::endl;
933 //::printf("debug : draw_vertex_array_texture : use tex %s\n",sid.c_str());
936 virtual void draw_vertex_normal_array_texture(tools::gl::mode_t a_mode,
939 const float* /*a_nms*/,
941 const float* a_tcs) {
942 if(!tools::gl::is_mode(a_mode)) return;
943 size_t num = a_floatn/3;
946 if(!m_mgr.render_command_encoder()) return;
948 //::printf("debug : draw_vertex_normal_array_texture : dummy : %d %lu\n",a_mode,a_floatn);
950 //expect 2*num a_tcs.
952 ///////////////////////
953 /// get texture : /////
954 ///////////////////////
955 id<MTLTexture> _texture;
956 if(!m_mgr.find_texture(a_id,_texture)) {
957 m_out << "tools::metal::render::draw_vertex_array_texture : can't find texture " << a_id << "." << std::endl;
962 MTLPrimitiveType primitive_type;
963 if(a_mode==tools::gl::points()) {
964 primitive_type = MTLPrimitiveTypePoint;
965 if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
967 } else if(a_mode==tools::gl::lines()) {
968 primitive_type = MTLPrimitiveTypeLine;
969 if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
971 } else if(a_mode==tools::gl::line_loop()) {
972 primitive_type = MTLPrimitiveTypeLineStrip;
973 size_t nxyz = (num+1)*3;
974 float* xyzs = new float[nxyz];
975 float* tcs = new float[(num+1)*2];
976 {float* pxyzs = xyzs;
978 tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
980 bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
985 } else if(a_mode==tools::gl::line_strip()) {
986 primitive_type = MTLPrimitiveTypeLineStrip;
987 if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
989 } else if(a_mode==tools::gl::triangles()) {
990 primitive_type = MTLPrimitiveTypeTriangle;
991 if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
993 } else if(a_mode==tools::gl::triangle_fan()) {
994 primitive_type = MTLPrimitiveTypeTriangle;
996 size_t nxyz = ntri*3*3;
997 float* xyzs = new float[nxyz];
998 float* tcs = new float[ntri*3*2];
999 {float* pxyzs = xyzs;
1001 tools::gl::triangle_fan_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
1003 bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
1008 } else if(a_mode==tools::gl::triangle_strip()) {
1009 primitive_type = MTLPrimitiveTypeTriangle;
1010 size_t ntri = num-2;
1011 size_t nxyz = ntri*3*3;
1012 float* xyzs = new float[nxyz];
1013 float* tcs = new float[ntri*3*2];
1014 {float* pxyzs = xyzs;
1016 tools::gl::triangle_strip_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
1018 bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
1024 ::printf("debug : draw_vertex_array_texture : mode not handled yet : %lu %d\n",num,a_mode);
1029 id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer
1030 length:num*14*sizeof(float)
1031 options:MTLResourceStorageModeShared];
1033 MTLResourceOptions opts = 0;
1035 set_uniforms(_uniforms,true);
1036 id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
1038 [m_mgr.render_command_encoder() setVertexBuffer:vertex_buffer offset:0 atIndex:0];
1039 [m_mgr.render_command_encoder() setVertexBuffer:uniforms_buffer offset:0 atIndex:1];
1040 [m_mgr.render_command_encoder() setFragmentTexture:_texture atIndex:0];
1042 [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
1044 [vertex_buffer release];
1045 [uniforms_buffer release];
1050 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);}
1052 virtual void line_width(float /*a_value*/) {
1054 virtual void point_size(float /*a_value*/) {
1056 virtual void set_polygon_offset(bool /*a_on*/) {
1059 virtual void normal(float a_x,float a_y,float a_z) {m_normal.set_value(a_x,a_y,a_z);}
1061 virtual void set_winding(tools::sg::winding_type a_v) {m_ccw = (a_v==tools::sg::winding_ccw?true:false);}
1063 virtual void set_shade_model(tools::sg::shade_type /*a_v*/) {}
1065 virtual void set_depth_test(bool a_on) {m_depth_test = a_on;}
1067 virtual void set_cull_face(bool /*a_on*/) {}
1069 virtual void load_proj_matrix(const tools::mat4f& a_mtx) {m_proj = a_mtx;}
1070 virtual void load_model_matrix(const tools::mat4f& a_mtx) {
1072 set_normal_matrix();
1075 virtual unsigned int max_lights() {return 1000;}
1077 virtual void enable_light(unsigned int,
1078 float a_dx,float a_dy,float a_dz,
1079 float a_r,float a_g,float a_b,float a_a){
1080 float dl = tools::fsqrt(a_dx*a_dx+a_dy*a_dy+a_dz*a_dz);
1082 m_out << "tools::metal::render::enable_light : null light direction." << std::endl;
1085 m_light_color.set_value(a_r,a_g,a_b,a_a);
1086 m_light_direction.set_value(a_dx/dl,a_dy/dl,a_dz/dl);
1089 virtual void set_lighting(bool a_on) {m_light_on = a_on;}
1091 virtual void set_blend(bool /*a_on*/) {}
1093 virtual void restore_state(unsigned int /*a_ret_num_light*/) {
1094 tools::sg::state& _state = state();
1095 render::load_proj_matrix(_state.m_proj);
1096 render::load_model_matrix(_state.m_model);
1098 set_lighting(_state.m_GL_LIGHTING);
1099 set_blend(_state.m_GL_BLEND);
1101 set_depth_test(_state.m_GL_DEPTH_TEST);
1102 set_cull_face(_state.m_GL_CULL_FACE);
1103 set_polygon_offset(_state.m_GL_POLYGON_OFFSET_FILL);
1105 // if(_state.m_GL_TEXTURE_2D) gl_enable(m_mgr.js(),"TEXTURE_2D");
1106 // else gl_disable(m_mgr.js(),"TEXTURE_2D");
1108 set_winding(_state.m_winding);
1110 color4f(_state.m_color.r(),_state.m_color.g(),_state.m_color.b(),_state.m_color.a());
1112 normal(_state.m_normal.x(),_state.m_normal.y(),_state.m_normal.z());
1114 // The "return of separator" state had ret_num_light.
1115 // The restored state has m_light.
1116 // We have to glDisable lights with index in [m_light,ret_num_light-1]
1117 //for(unsigned int index=_state.m_light;index<a_ret_num_light;index++) {
1118 // ::glDisable(GL_LIGHT0+index);
1121 line_width(_state.m_line_width);
1122 point_size(_state.m_point_size);
1125 /////////////////////////////////////////////////////////////////
1126 /// VBO /////////////////////////////////////////////////////////
1127 /////////////////////////////////////////////////////////////////
1128 virtual void begin_gsto(gstoid a_id) {m_current_data_gsto_id = a_id;}
1130 typedef tools::sg::bufpos bufpos;
1131 virtual void draw_gsto_v(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs) {
1132 if(!m_current_data_gsto_id) return;
1134 if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
1135 m_out << "tools::metal::render::draw_gsto_v : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
1138 float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
1139 size_t a_floatn = a_elems*3;
1140 draw_vertex_array(a_mode,a_floatn,a_xyzs);
1143 virtual void draw_gsto_vc(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs,bufpos a_pos_rgbas){
1144 if(!m_current_data_gsto_id) return;
1146 if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
1147 m_out << "tools::metal::render::draw_gsto_vc : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
1150 float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
1151 float* a_rgbas = (float*)(_buffer+a_pos_rgbas);
1152 size_t a_floatn = a_elems*3;
1153 draw_vertex_color_array(a_mode,a_floatn,a_xyzs,a_rgbas);
1156 virtual void draw_gsto_vn(tools::gl::mode_t a_mode,size_t a_elems,bufpos a_pos_xyzs,bufpos a_pos_nms){
1157 if(!m_current_data_gsto_id) return;
1159 if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
1160 m_out << "tools::metal::render::draw_gsto_vn : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
1163 float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
1164 float* a_nms = (float*)(_buffer+a_pos_nms);
1165 size_t a_floatn = a_elems*3;
1166 draw_vertex_normal_array(a_mode,a_floatn,a_xyzs,a_nms);
1169 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){
1170 if(!m_current_data_gsto_id) return;
1172 if(!m_mgr.find_data_gsto(m_current_data_gsto_id,_buffer)) {
1173 m_out << "tools::metal::render::draw_gsto_vcn : can't find data_gsto " << m_current_data_gsto_id << "." << std::endl;
1176 float* a_xyzs = (float*)(_buffer+a_pos_xyzs);
1177 float* a_rgbas = (float*)(_buffer+a_pos_rgbas);
1178 float* a_nms = (float*)(_buffer+a_pos_nms);
1179 size_t a_floatn = a_elems*3;
1180 draw_vertex_color_normal_array(a_mode,a_floatn,a_xyzs,a_rgbas,a_nms);
1183 virtual void end_gsto() {m_current_data_gsto_id = 0;}
1185 /////////////////////////////////////////////////////////////////
1186 /////////////////////////////////////////////////////////////////
1187 /////////////////////////////////////////////////////////////////
1188 virtual void set_point_smooth(bool) {}
1189 virtual void set_line_smooth(bool) {}
1190 /////////////////////////////////////////////////////////////////
1191 /////////////////////////////////////////////////////////////////
1192 /////////////////////////////////////////////////////////////////
1193 virtual tools::sg::render_manager& render_manager() {return m_mgr;}
1195 render(manager& a_mgr,std::ostream& a_out,unsigned int a_ww,unsigned int a_wh)
1196 :parent(a_out,a_ww,a_wh)
1198 ,m_current_data_gsto_id(0)
1199 ,m_light_color(tools::colorf_white())
1200 ,m_light_direction(tools::vec3f(0,0,-1))
1205 m_proj.set_identity();
1206 m_model.set_identity();
1207 m_normal_matrix.set_identity();
1211 render(const render& a_from)
1213 ,m_mgr(a_from.m_mgr)
1214 ,m_current_data_gsto_id(0)
1215 ,m_light_color(a_from.m_light_color)
1216 ,m_light_direction(a_from.m_light_direction)
1217 ,m_proj(a_from.m_proj)
1218 ,m_model(a_from.m_model)
1219 ,m_normal_matrix(a_from.m_normal_matrix)
1220 ,m_color(a_from.m_color)
1221 ,m_normal(a_from.m_normal)
1222 ,m_light_on(a_from.m_light_on)
1223 ,m_ccw(a_from.m_ccw)
1224 ,m_depth_test(a_from.m_depth_test)
1226 render& operator=(const render& a_from){
1227 parent::operator=(a_from);
1228 m_current_data_gsto_id = 0;
1229 m_light_color = a_from.m_light_color;
1230 m_light_direction = a_from.m_light_direction;
1231 m_proj = a_from.m_proj;
1232 m_model = a_from.m_model;
1233 m_normal_matrix = a_from.m_normal_matrix;
1234 m_color = a_from.m_color;
1235 m_normal = a_from.m_normal;
1236 m_light_on = a_from.m_light_on;
1237 m_ccw = a_from.m_ccw;
1238 m_depth_test = a_from.m_depth_test;
1242 void set_normal_matrix() {
1243 tools::mat4f tmp(m_model);
1245 if(!tmp.invert(m_normal_matrix)) {
1246 m_out << "tools::metal::render::set_normal_matrix : can't invert model matrix." << std::endl;
1248 m_normal_matrix.transpose();
1251 bool fill_buffer(size_t a_num,const float* a_xyzs,float*& a_buffer) {
1252 a_buffer = new float[a_num*14];
1253 float* pos = a_buffer;
1254 for(size_t index=0;index<a_num;index++) {
1255 *pos = a_xyzs[3*index+0];pos++;
1256 *pos = a_xyzs[3*index+1];pos++;
1257 *pos = a_xyzs[3*index+2];pos++;
1260 *pos = m_normal.x();pos++;
1261 *pos = m_normal.y();pos++;
1262 *pos = m_normal.z();pos++;
1265 *pos = m_color.r();pos++;
1266 *pos = m_color.g();pos++;
1267 *pos = m_color.b();pos++;
1268 *pos = m_color.a();pos++;
1275 bool fill_buffer_nms(size_t a_num,const float* a_xyzs,const float* a_nms,float*& a_buffer) {
1276 a_buffer = new float[a_num*14];
1277 float* pos = a_buffer;
1278 for(size_t index=0;index<a_num;index++) {
1279 *pos = a_xyzs[3*index+0];pos++;
1280 *pos = a_xyzs[3*index+1];pos++;
1281 *pos = a_xyzs[3*index+2];pos++;
1284 *pos = a_nms[3*index+0];pos++;
1285 *pos = a_nms[3*index+1];pos++;
1286 *pos = a_nms[3*index+2];pos++;
1289 *pos = m_color.r();pos++;
1290 *pos = m_color.g();pos++;
1291 *pos = m_color.b();pos++;
1292 *pos = m_color.a();pos++;
1300 bool fill_buffer_rgbas(size_t a_num,const float* a_xyzs,const float* a_rgbas,float*& a_buffer) {
1301 a_buffer = new float[a_num*14];
1302 float* pos = a_buffer;
1303 for(size_t index=0;index<a_num;index++) {
1304 *pos = a_xyzs[3*index+0];pos++;
1305 *pos = a_xyzs[3*index+1];pos++;
1306 *pos = a_xyzs[3*index+2];pos++;
1309 *pos = m_normal.x();pos++;
1310 *pos = m_normal.y();pos++;
1311 *pos = m_normal.z();pos++;
1314 *pos = a_rgbas[4*index+0];pos++;
1315 *pos = a_rgbas[4*index+1];pos++;
1316 *pos = a_rgbas[4*index+2];pos++;
1317 *pos = a_rgbas[4*index+3];pos++;
1325 bool fill_buffer_rgbas_nms(size_t a_num,const float* a_xyzs,const float* a_rgbas,const float* a_nms,float*& a_buffer) {
1326 a_buffer = new float[a_num*14];
1327 float* pos = a_buffer;
1328 for(size_t index=0;index<a_num;index++) {
1329 *pos = a_xyzs[3*index+0];pos++;
1330 *pos = a_xyzs[3*index+1];pos++;
1331 *pos = a_xyzs[3*index+2];pos++;
1334 *pos = a_nms[3*index+0];pos++;
1335 *pos = a_nms[3*index+1];pos++;
1336 *pos = a_nms[3*index+2];pos++;
1339 *pos = a_rgbas[4*index+0];pos++;
1340 *pos = a_rgbas[4*index+1];pos++;
1341 *pos = a_rgbas[4*index+2];pos++;
1342 *pos = a_rgbas[4*index+3];pos++;
1350 bool fill_buffer_texture(size_t a_num,const float* a_xyzs,const float* a_tcs,float*& a_buffer) {
1351 a_buffer = new float[a_num*14];
1352 float* pos = a_buffer;
1353 for(size_t index=0;index<a_num;index++) {
1354 *pos = a_xyzs[3*index+0];pos++;
1355 *pos = a_xyzs[3*index+1];pos++;
1356 *pos = a_xyzs[3*index+2];pos++;
1364 *pos = m_color.r();pos++;
1365 *pos = m_color.g();pos++;
1366 *pos = m_color.b();pos++;
1367 *pos = m_color.a();pos++;
1369 *pos = a_tcs[2*index+0];pos++;
1370 *pos = a_tcs[2*index+1];pos++;
1376 simd::float4x4 proj_model_matrix;
1377 simd::float4x4 normal_matrix;
1378 unsigned int light_on;
1379 simd::float4 light_color;
1380 simd::float3 light_direction;
1381 unsigned int texturing;
1384 void set_uniforms(uniforms& a_uniforms,bool a_texturing) {
1385 // Metal NDC is [-1,1]x[-1,1]x[0,1]
1386 // OpenGL NDC is [-1,1]x[-1,1]x[-1,1]
1387 tools::mat4f z_gl_to_metal;
1388 z_gl_to_metal.set_translate(0,0,0.5);
1389 z_gl_to_metal.mul_scale(1,1,0.5);
1395 ::memcpy(&(a_uniforms.proj_model_matrix),pm.data(),16*sizeof(float));
1396 ::memcpy(&(a_uniforms.normal_matrix),m_normal_matrix.data(),16*sizeof(float));
1397 a_uniforms.light_on = m_light_on?1:0;
1398 ::memcpy(&(a_uniforms.light_color),m_light_color.data(),4*sizeof(float));
1399 ::memcpy(&(a_uniforms.light_direction),m_light_direction.data(),3*sizeof(float));
1400 a_uniforms.texturing = a_texturing?1:0;
1405 gstoid m_current_data_gsto_id;
1407 tools::colorf m_light_color;
1408 tools::vec3f m_light_direction;
1410 // to be restored in restore_state() :
1411 tools::mat4f m_proj;
1412 tools::mat4f m_model;
1413 tools::mat4f m_normal_matrix;
1414 tools::colorf m_color;
1415 tools::vec3f m_normal;