g4tools  5.4.0
render.hm
Go to the documentation of this file.
1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
2 // See the file tools.license for terms.
3 
4 #ifndef tools_metal_render
5 #define tools_metal_render
6 
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>
16 
17 #include <Metal/Metal.h>
18 #include <MetalKit/MTKView.h>
19 #include <simd/simd.h>
20 #include <cstring>
21 
22 namespace tools {
23 namespace metal {
24 
25 class manager : public virtual tools::sg::render_manager {
26  typedef tools::sg::render_manager parent;
27 public:
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;}
31  else return 0;
32  }
33 public:
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);
41  return true;
42  }
43 
44  virtual void end_render() {
45  //::printf("debug : manager::end_render : 000\n");
46  end_encoding();
47  [m_render_pipeline_state release];
48  }
49 
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());
53 
54  tools::img_byte* _img = 0;
55  bool _img_delete = false;
56 
57  if(a_img.bpp()==1) { //exa eiffel-tower.png
58  tools::img_byte img3;
59  if(!a_img.bw2x(3,img3)) {
60  m_out << "tools::metal::manager::create_texture : a_imgr.bw2x() failed." << std::endl;
61  return 0;
62  }
63  tools::img_byte img4;
64  if(!img3.rgb2rgba(img4,255)){
65  m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
66  return 0;
67  }
68  _img = new tools::img_byte;
69  _img_delete = true;
70  _img->transfer(img4);
71 
72  } else if(a_img.bpp()==3) {
73  tools::img_byte img4;
74  if(!a_img.rgb2rgba(img4,255)){
75  m_out << "tools::metal::manager::create_texture : rgb2rgba failed." << std::endl;
76  return 0;
77  }
78  _img = new tools::img_byte;
79  _img_delete = true;
80  _img->transfer(img4);
81 
82  } else if(a_img.bpp()==4) { //exa windusrf.png, text_freetype/font_pixmap.
83  _img = const_cast<tools::img_byte*>(&a_img);
84  } else {
85  //should not happen.
86  m_out << "tools::metal::manager::create_texture :"
87  << " image with bpp " << a_img.bpp() << " not (yet) supported."
88  << std::endl;
89  if(_img_delete) delete _img;
90  return 0;
91  }
92  if(_img->is_empty()) {
93  if(_img_delete) delete _img;
94  return 0;
95  }
96 
97  _img->rgba2bgra();
98 
99  m_gen_id++;
100 
101  MTLTextureDescriptor* tex_desc = [[MTLTextureDescriptor alloc] init];
102  tex_desc.pixelFormat = MTLPixelFormatBGRA8Unorm;
103  tex_desc.width = _img->width();
104  tex_desc.height = _img->height();
105 
106  id<MTLTexture> texture = [m_device newTextureWithDescriptor:tex_desc];
107 
108  NSUInteger bytes_per_row = _img->bpp() * _img->width();
109 
110  MTLRegion region = {
111  {0,0,0}, // MTLOrigin
112  {_img->width(),_img->height(),1} // MTLSize
113  };
114 
115  [texture replaceRegion:region mipmapLevel:0 withBytes:_img->buffer() bytesPerRow:bytes_per_row];
116 
117  m_tex_gstos[m_gen_id] = new tex_gsto(texture,_img->size(),m_out,*this);
118  if(_img_delete) delete _img;
119  return m_gen_id;
120  }
121 
122  virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
123  if(!a_floatn) return 0;
124  m_gen_id++;
125  m_data_gstos[m_gen_id] = new data_gsto(a_data,a_floatn,m_out,*this);
126  return m_gen_id;
127  }
128 
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;}
134  return false;
135  }
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);
139  }
140 
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) {
144  a_v.clear();
145  a_v.push_back(tools::sg::s_gsto_gl_vbo());
146  }
147  virtual void available_not_memory_gsto_mode(std::string& a_s) const {
148  a_s = tools::sg::s_gsto_gl_vbo();
149  }
150  virtual size_t used_texture_memory() const {
151  size_t sz = 0;
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;}
154  return sz;
155  }
156  virtual size_t gstos_size() const {
157  size_t sz = 0;
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;}}
160  return sz;
161  }
162 
163 public:
164  manager(std::ostream& a_out)
165  :m_out(a_out)
166  ,m_gen_id(0)
167  ,m_view(0)
168  ,m_device(0)
169  ,m_command_queue(0)
170  ,m_render_pipeline_state(0)
171  ,m_depth_stencil_state_on(0)
172  ,m_depth_stencil_state_off(0)
173  ,m_command_buffer(0)
174  ,m_render_command_encoder(0)
175  {
176 #ifdef TOOLS_MEM
177  tools::mem::increment(s_class().c_str());
178 #endif
179  m_device = MTLCreateSystemDefaultDevice();
180  m_command_queue = [m_device newCommandQueue];
181 
182  //create_pipeline_state();
183 
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];}
188 
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];}
193  }
194  virtual ~manager(){
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];
199 
200  tools::safe_clear<unsigned int,tex_gsto>(m_tex_gstos);
201  tools::safe_clear<unsigned int,data_gsto>(m_data_gstos);
202 #ifdef TOOLS_MEM
203  tools::mem::decrement(s_class().c_str());
204 #endif
205  }
206 private:
207 public:
208  manager(const manager& a_from)
209  :parent(a_from)
210  ,m_out(a_from.m_out)
211  ,m_gen_id(a_from.m_gen_id)
212  ,m_view(0)
213  ,m_device(0)
214  ,m_command_queue(0)
215  ,m_render_pipeline_state(0)
216  ,m_depth_stencil_state_on(0)
217  ,m_depth_stencil_state_off(0)
218  ,m_command_buffer(0)
219  ,m_render_command_encoder(0)
220  {
221 #ifdef TOOLS_MEM
222  tools::mem::increment(s_class().c_str());
223 #endif
224  }
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);
229  return *this;
230  }
231 public:
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);
235  }
236 
237 public:
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;
242  return true;
243  }
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;
248  return true;
249  }
250 
251  std::ostream& out() const {return m_out;}
252 
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;}
258 protected:
259  class data_gsto {
260 #ifdef TOOLS_MEM
261  TOOLS_SCLASS(tools::metal::manager::data_gsto)
262 #endif
263  public:
264  data_gsto(const float* a_floats,size_t a_floatn,std::ostream& a_out,manager& a_mgr)
265  :m_buffer(0)
266  ,m_size(0)
267  ,m_out(a_out)
268  ,m_mgr(a_mgr)
269  {
270 #ifdef TOOLS_MEM
271  tools::mem::increment(s_class().c_str());
272 #endif
273  m_size = a_floatn*sizeof(float);
274  m_buffer = new char[m_size];
275  ::memcpy(m_buffer,a_floats,m_size);
276  }
277  virtual ~data_gsto(){
278  delete [] m_buffer;
279 #ifdef TOOLS_MEM
280  tools::mem::decrement(s_class().c_str());
281 #endif
282  }
283  private:
284  data_gsto(const data_gsto& a_from)
285  :m_buffer(0)
286  ,m_size(a_from.m_size)
287  ,m_out(a_from.m_out)
288  ,m_mgr(a_from.m_mgr)
289  {
290 #ifdef TOOLS_MEM
291  tools::mem::increment(s_class().c_str());
292 #endif
293  }
294  data_gsto& operator=(const data_gsto& a_from){
295  m_buffer = 0;
296  m_size = a_from.m_size;
297  return *this;
298  }
299  public:
300  char* m_buffer;
301  size_t m_size;
302  std::ostream& m_out;
303  manager& m_mgr;
304  };
305 
306  class tex_gsto {
307 #ifdef TOOLS_MEM
308  TOOLS_SCLASS(tools::metal::manager::tex_gsto)
309 #endif
310  public:
311  tex_gsto(id<MTLTexture>& a_texture,size_t a_size,std::ostream& a_out,manager& a_mgr)
312  :m_texture(a_texture)
313  ,m_size(a_size)
314  ,m_out(a_out)
315  ,m_mgr(a_mgr)
316  {
317 #ifdef TOOLS_MEM
318  tools::mem::increment(s_class().c_str());
319 #endif
320  }
321  virtual ~tex_gsto(){
322  [m_texture release]; //is it needed ?
323 #ifdef TOOLS_MEM
324  tools::mem::decrement(s_class().c_str());
325 #endif
326  }
327  private:
328  tex_gsto(const tex_gsto& a_from)
329  :m_texture(a_from.m_texture)
330  ,m_size(a_from.m_size)
331  ,m_out(a_from.m_out)
332  ,m_mgr(a_from.m_mgr)
333  {
334 #ifdef TOOLS_MEM
335  tools::mem::increment(s_class().c_str());
336 #endif
337  }
338  tex_gsto& operator=(const tex_gsto& a_from){
339  m_texture = a_from.m_texture;
340  m_size = a_from.m_size;
341  return *this;
342  }
343  public:
344  id<MTLTexture> m_texture;
345  size_t m_size;
346  std::ostream& m_out;
347  manager& m_mgr;
348  };
349 private:
350  void create_pipeline_state() {
351  const char shaders_src[] = "\
352  #include <metal_stdlib>\n\
353  #include <simd/simd.h>\n\
354  struct uniforms {\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\
361  };\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\
367  };\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\
378  };\n\
379  vertex vertex_out vert_shader(vertex_in a_in [[stage_in]],constant uniforms& a_uniforms [[buffer(1)]]) {\n\
380  vertex_out out;\n\
381 \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\
386 \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\
391 \n\
392  return out;\n\
393  }\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\
399  } else {\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\
404  if(_dot<0.0) {\n\
405  _dot *= -1;\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\
411  return _color;\n\
412  } else {\n\
413  return black;\n\
414  /*return red;*/\n\
415  }\n\
416  } else {\n\
417  return a_in.color;\n\
418  }\n\
419  }\n\
420  }\n\
421 ";
422 
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;
427 
428  vert_desc.attributes[1].format = MTLVertexFormatFloat4;
429  vert_desc.attributes[1].bufferIndex = 0;
430  vert_desc.attributes[1].offset = sizeof(float)*4;
431 
432  vert_desc.attributes[2].format = MTLVertexFormatFloat4;
433  vert_desc.attributes[2].bufferIndex = 0;
434  vert_desc.attributes[2].offset = sizeof(float)*8;
435 
436  vert_desc.attributes[3].format = MTLVertexFormatFloat2;
437  vert_desc.attributes[3].bufferIndex = 0;
438  vert_desc.attributes[3].offset = sizeof(float)*12;
439 
440  vert_desc.layouts[0].stride = 14*sizeof(float);
441  vert_desc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
442 
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];
446  [src release];
447  [opts release];
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];
459  [library release];
460  [vert_func release];
461  [frag_func release];
462  }
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];
466 
467  MTLRenderPassColorAttachmentDescriptor* color_attachment_desc = [render_pass_desc colorAttachments][0];
468  color_attachment_desc.clearColor = MTLClearColorMake(a_r,a_g,a_b,a_a);
469 
470  m_render_command_encoder = [m_command_buffer renderCommandEncoderWithDescriptor:render_pass_desc];
471  [m_render_command_encoder setRenderPipelineState:m_render_pipeline_state];
472 
473  //double znear = 0.0;
474  //double zfar = 1.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}];
476 
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];
481  }
482  void end_encoding() {
483  if(m_view) {
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];
487  }
488  [m_command_buffer commit];
489  [m_command_buffer waitUntilCompleted];
490  //[m_command_buffer waitUntilScheduled];
491  }
492 
493 protected:
494  std::ostream& m_out;
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;
498  MTKView* m_view;
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;
506 };
507 
508 class render : public tools::sg::render_action {
509  TOOLS_ACTION(render,tools::metal::render,tools::sg::render_action)
510 public:
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;
515  if(!num) return;
516 
517  if(!m_mgr.render_command_encoder()) return;
518 
519  //::printf("debug : draw_vertex_array : 000 : %lu %d\n",num,a_mode);
520 
521  float* buffer = 0;
522  MTLPrimitiveType primitive_type;
523  if(a_mode==tools::gl::points()) {
524  primitive_type = MTLPrimitiveTypePoint;
525  if(!fill_buffer(num,a_xyzs,buffer)) return;
526 
527  } else if(a_mode==tools::gl::lines()) {
528  primitive_type = MTLPrimitiveTypeLine;
529  if(!fill_buffer(num,a_xyzs,buffer)) return;
530 
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);}
537  num = nxyz/3;
538  bool status = fill_buffer(num,xyzs,buffer);
539  delete [] xyzs;
540  if(!status) return;
541 
542  } else if(a_mode==tools::gl::line_strip()) {
543  primitive_type = MTLPrimitiveTypeLineStrip;
544  if(!fill_buffer(num,a_xyzs,buffer)) return;
545 
546  } else if(a_mode==tools::gl::triangles()) {
547  primitive_type = MTLPrimitiveTypeTriangle;
548  if(!fill_buffer(num,a_xyzs,buffer)) return;
549 
550  } else if(a_mode==tools::gl::triangle_fan()) {
551  primitive_type = MTLPrimitiveTypeTriangle;
552  size_t ntri = num-2;
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);}
557  num = nxyz/3;
558  bool status = fill_buffer(num,xyzs,buffer);
559  delete [] xyzs;
560  if(!status) return;
561 
562  } else if(a_mode==tools::gl::triangle_strip()) {
563  primitive_type = MTLPrimitiveTypeTriangle;
564  size_t ntri = num-2;
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);}
569  num = nxyz/3;
570  bool status = fill_buffer(num,xyzs,buffer);
571  delete [] xyzs;
572  if(!status) return;
573 
574  } else {
575  ::printf("debug : draw_vertex_array : mode not handled yet : %lu %d\n",num,a_mode);
576  return;
577  }
578  if(!buffer) return;
579 
580  MTLResourceOptions opts = 0;
581  id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
582 
583  uniforms _uniforms;
584  set_uniforms(_uniforms,false);
585  id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
586 
587  if(m_ccw) {
588  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
589  } else {
590  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
591  }
592 
593  if(m_depth_test) {
594  [m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_on()];
595  } else {
596  [m_mgr.render_command_encoder() setDepthStencilState:m_mgr.depth_stencil_state_off()];
597  }
598 
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];
602 
603  [vertex_buffer release];
604  [uniforms_buffer release];
605 
606  delete [] buffer;
607  }
608 
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;
612  if(!num) return;
613  //::printf("debug : draw_vertex_array_xy %lu\n",num);
614  float* xyzs = new float[num*3];
615  float* pxyzs = xyzs;
616  tools::gl::cvt_2to3(num,a_xys,pxyzs);
617  draw_vertex_array(a_mode,num*3,xyzs);
618  delete [] xyzs;
619  }
620 
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;
624  if(!num) return;
625 
626  if(!m_mgr.render_command_encoder()) return;
627  //::printf("debug : draw_vertex_color_array : 000 : num %lu, mode %d\n",num,a_mode);
628 
629  float* buffer = 0;
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;
634 
635  } else if(a_mode==tools::gl::lines()) {
636  primitive_type = MTLPrimitiveTypeLine;
637  if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
638 
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);}
646  num = nxyz/3;
647  bool status = fill_buffer(num,xyzs,buffer);
648  delete [] xyzs;
649  if(!status) return;
650 
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;
654 
655  } else if(a_mode==tools::gl::triangles()) {
656  primitive_type = MTLPrimitiveTypeTriangle;
657  if(!fill_buffer_rgbas(num,a_xyzs,a_rgbas,buffer)) return;
658 
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;
662  size_t ntri = num-2;
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);}
667  num = nxyz/3;
668  bool status = fill_buffer(num,xyzs,buffer);
669  delete [] xyzs;
670  if(!status) return;
671 
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;
675  size_t ntri = num-2;
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);}
680  num = nxyz/3;
681  bool status = fill_buffer(num,xyzs,buffer);
682  delete [] xyzs;
683  if(!status) return;
684 
685  } else {
686  ::printf("debug : draw_vertex_color_array : mode not handled yet : %lu %d\n",num,a_mode);
687  return;
688  }
689  if(!buffer) return;
690 
691  MTLResourceOptions opts = 0;
692  id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
693 
694  uniforms _uniforms;
695  set_uniforms(_uniforms,false);
696  id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
697 
698  if(m_ccw) {
699  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
700  } else {
701  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
702  }
703 
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];
707 
708  [vertex_buffer release];
709  [uniforms_buffer release];
710 
711  delete [] buffer;
712  }
713 
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;
717  if(!num) return;
718 
719  if(!m_mgr.render_command_encoder()) return;
720  //::printf("debug : draw_vertex_normal_array : 000 : num %lu, mode %d\n",num,a_mode);
721 
722  float* buffer = 0;
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;
727 
728  } else if(a_mode==tools::gl::lines()) {
729  primitive_type = MTLPrimitiveTypeLine;
730  if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
731 
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);}
739  num = nxyz/3;
740  bool status = fill_buffer(num,xyzs,buffer);
741  delete [] xyzs;
742  if(!status) return;
743 
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;
747 
748  } else if(a_mode==tools::gl::triangles()) {
749  primitive_type = MTLPrimitiveTypeTriangle;
750  if(!fill_buffer_nms(num,a_xyzs,a_nms,buffer)) return;
751 
752  } else if(a_mode==tools::gl::triangle_fan()) {
753  primitive_type = MTLPrimitiveTypeTriangle;
754  size_t ntri = num-2;
755  size_t nxyz = ntri*3*3;
756  float* xyzs = new float[nxyz];
757  float* nms = new float[nxyz];
758  {float* pxyzs = xyzs;
759  float* pnms = nms;
760  tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
761  num = nxyz/3;
762  bool status = fill_buffer_nms(num,xyzs,nms,buffer);
763  delete [] xyzs;
764  delete [] nms;
765  if(!status) return;
766 
767  } else if(a_mode==tools::gl::triangle_strip()) {
768  primitive_type = MTLPrimitiveTypeTriangle;
769  size_t ntri = num-2;
770  size_t nxyz = ntri*3*3;
771  float* xyzs = new float[nxyz];
772  float* nms = new float[nxyz];
773  {float* pxyzs = xyzs;
774  float* pnms = nms;
775  tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
776  num = nxyz/3;
777  bool status = fill_buffer_nms(num,xyzs,nms,buffer);
778  delete [] xyzs;
779  delete [] nms;
780  if(!status) return;
781 
782  } else {
783  ::printf("debug : draw_vertex_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
784  return;
785  }
786  if(!buffer) return;
787 
788  MTLResourceOptions opts = 0;
789  id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
790 
791  uniforms _uniforms;
792  set_uniforms(_uniforms,false);
793  id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
794 
795  if(m_ccw) {
796  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
797  } else {
798  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
799  }
800 
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];
804 
805  [vertex_buffer release];
806  [uniforms_buffer release];
807 
808  delete [] buffer;
809  }
810 
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;
815  if(!num) return;
816 
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);
819 
820  float* buffer = 0;
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;
825 
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;
829 
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);}
837  num = nxyz/3;
838  bool status = fill_buffer(num,xyzs,buffer);
839  delete [] xyzs;
840  if(!status) return;
841 
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;
845 
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;
849 
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;
853  size_t ntri = num-2;
854  size_t nxyz = ntri*3*3;
855  float* xyzs = new float[nxyz];
856  float* nms = new float[nxyz];
857  {float* pxyzs = xyzs;
858  float* pnms = nms;
859  tools::gl::triangle_fan_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
860  num = nxyz/3;
861  bool status = fill_buffer_nms(num,xyzs,nms,buffer);
862  delete [] xyzs;
863  delete [] nms;
864  if(!status) return;
865 
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;
869  size_t ntri = num-2;
870  size_t nxyz = ntri*3*3;
871  float* xyzs = new float[nxyz];
872  float* nms = new float[nxyz];
873  {float* pxyzs = xyzs;
874  float* pnms = nms;
875  tools::gl::triangle_strip_to_triangles_nms(num,a_xyzs,a_nms,pxyzs,pnms);}
876  num = nxyz/3;
877  bool status = fill_buffer_nms(num,xyzs,nms,buffer);
878  delete [] xyzs;
879  delete [] nms;
880  if(!status) return;
881 
882  } else {
883  ::printf("debug : draw_vertex_color_normal_array : mode not handled yet : %lu %d\n",num,a_mode);
884  return;
885  }
886  if(!buffer) return;
887 
888  MTLResourceOptions opts = 0;
889  id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer length:num*14*sizeof(float) options:opts];
890 
891  uniforms _uniforms;
892  set_uniforms(_uniforms,false);
893  id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
894 
895  if(m_ccw) {
896  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingCounterClockwise];
897  } else {
898  [m_mgr.render_command_encoder() setFrontFacingWinding:MTLWindingClockwise];
899  }
900 
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];
904 
905  [vertex_buffer release];
906  [uniforms_buffer release];
907 
908  delete [] buffer;
909  }
910 
911  virtual void draw_vertex_array_texture(tools::gl::mode_t a_mode,
912  size_t a_floatn,
913  const float* /*a_xyzs*/,
914  gstoid /*a_id*/,
915  const float* /*a_tcs*/) {
916  if(!tools::gl::is_mode(a_mode)) return;
917  size_t num = a_floatn/3;
918  if(!num) return;
919  ::printf("debug : draw_vertex_array_texture : dummy : mode %d, num %lu\n",a_mode,a_floatn);
920 
921  //expect 2*num a_tcs.
922 
923  ///////////////////////
924  /// get texture : /////
925  ///////////////////////
926  /*
927  std::string sid;
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;
930  return;
931  }
932  */
933  //::printf("debug : draw_vertex_array_texture : use tex %s\n",sid.c_str());
934  }
935 
936  virtual void draw_vertex_normal_array_texture(tools::gl::mode_t a_mode,
937  size_t a_floatn,
938  const float* a_xyzs,
939  const float* /*a_nms*/,
940  gstoid a_id,
941  const float* a_tcs) {
942  if(!tools::gl::is_mode(a_mode)) return;
943  size_t num = a_floatn/3;
944  if(!num) return;
945 
946  if(!m_mgr.render_command_encoder()) return;
947 
948  //::printf("debug : draw_vertex_normal_array_texture : dummy : %d %lu\n",a_mode,a_floatn);
949 
950  //expect 2*num a_tcs.
951 
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;
958  return;
959  }
960 
961  float* buffer = 0;
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;
966 
967  } else if(a_mode==tools::gl::lines()) {
968  primitive_type = MTLPrimitiveTypeLine;
969  if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
970 
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;
977  //float* ptcs = tcs;
978  tools::gl::line_loop_to_line_strip(num,a_xyzs,pxyzs);}
979  num = nxyz/3;
980  bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
981  delete [] xyzs;
982  delete [] tcs;
983  if(!status) return;
984 
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;
988 
989  } else if(a_mode==tools::gl::triangles()) {
990  primitive_type = MTLPrimitiveTypeTriangle;
991  if(!fill_buffer_texture(num,a_xyzs,a_tcs,buffer)) return;
992 
993  } else if(a_mode==tools::gl::triangle_fan()) {
994  primitive_type = MTLPrimitiveTypeTriangle;
995  size_t ntri = num-2;
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;
1000  float* ptcs = tcs;
1001  tools::gl::triangle_fan_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
1002  num = nxyz/3;
1003  bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
1004  delete [] xyzs;
1005  delete [] tcs;
1006  if(!status) return;
1007 
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;
1015  float* ptcs = tcs;
1016  tools::gl::triangle_strip_to_triangles_texture(num,a_xyzs,a_tcs,pxyzs,ptcs);}
1017  num = nxyz/3;
1018  bool status = fill_buffer_texture(num,xyzs,tcs,buffer);
1019  delete [] xyzs;
1020  delete [] tcs;
1021  if(!status) return;
1022 
1023  } else {
1024  ::printf("debug : draw_vertex_array_texture : mode not handled yet : %lu %d\n",num,a_mode);
1025  return;
1026  }
1027  if(!buffer) return;
1028 
1029  id<MTLBuffer> vertex_buffer = [m_mgr.device() newBufferWithBytes:buffer
1030  length:num*14*sizeof(float)
1031  options:MTLResourceStorageModeShared];
1032 
1033  MTLResourceOptions opts = 0;
1034  uniforms _uniforms;
1035  set_uniforms(_uniforms,true);
1036  id<MTLBuffer> uniforms_buffer = [m_mgr.device() newBufferWithBytes:(void*)&_uniforms length:sizeof(uniforms) options:opts];
1037 
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];
1041 
1042  [m_mgr.render_command_encoder() drawPrimitives:primitive_type vertexStart:0 vertexCount:num];
1043 
1044  [vertex_buffer release];
1045  [uniforms_buffer release];
1046 
1047  delete [] buffer;
1048  }
1049 
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);}
1051 
1052  virtual void line_width(float /*a_value*/) {
1053  }
1054  virtual void point_size(float /*a_value*/) {
1055  }
1056  virtual void set_polygon_offset(bool /*a_on*/) {
1057  }
1058 
1059  virtual void normal(float a_x,float a_y,float a_z) {m_normal.set_value(a_x,a_y,a_z);}
1060 
1061  virtual void set_winding(tools::sg::winding_type a_v) {m_ccw = (a_v==tools::sg::winding_ccw?true:false);}
1062 
1063  virtual void set_shade_model(tools::sg::shade_type /*a_v*/) {}
1064 
1065  virtual void set_depth_test(bool a_on) {m_depth_test = a_on;}
1066 
1067  virtual void set_cull_face(bool /*a_on*/) {}
1068 
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) {
1071  m_model = a_mtx;
1072  set_normal_matrix();
1073  }
1074 
1075  virtual unsigned int max_lights() {return 1000;}
1076 
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);
1081  if(!dl) {
1082  m_out << "tools::metal::render::enable_light : null light direction." << std::endl;
1083  return;
1084  }
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);
1087  m_light_on = true;
1088  }
1089  virtual void set_lighting(bool a_on) {m_light_on = a_on;}
1090 
1091  virtual void set_blend(bool /*a_on*/) {}
1092 
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);
1097 
1098  set_lighting(_state.m_GL_LIGHTING);
1099  set_blend(_state.m_GL_BLEND);
1100 
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);
1104 
1105 // if(_state.m_GL_TEXTURE_2D) gl_enable(m_mgr.js(),"TEXTURE_2D");
1106 // else gl_disable(m_mgr.js(),"TEXTURE_2D");
1107 
1108  set_winding(_state.m_winding);
1109 
1110  color4f(_state.m_color.r(),_state.m_color.g(),_state.m_color.b(),_state.m_color.a());
1111 
1112  normal(_state.m_normal.x(),_state.m_normal.y(),_state.m_normal.z());
1113 
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);
1119  //}
1120 
1121  line_width(_state.m_line_width);
1122  point_size(_state.m_point_size);
1123  }
1124 
1125  /////////////////////////////////////////////////////////////////
1126  /// VBO /////////////////////////////////////////////////////////
1127  /////////////////////////////////////////////////////////////////
1128  virtual void begin_gsto(gstoid a_id) {m_current_data_gsto_id = a_id;}
1129 
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;
1133  char* _buffer;
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;
1136  return;
1137  }
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);
1141  }
1142 
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;
1145  char* _buffer;
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;
1148  return;
1149  }
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);
1154  }
1155 
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;
1158  char* _buffer;
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;
1161  return;
1162  }
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);
1167  }
1168 
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;
1171  char* _buffer;
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;
1174  return;
1175  }
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);
1181  }
1182 
1183  virtual void end_gsto() {m_current_data_gsto_id = 0;}
1184 
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;}
1194 public:
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)
1197  ,m_mgr(a_mgr)
1198  ,m_current_data_gsto_id(0)
1199  ,m_light_color(tools::colorf_white())
1200  ,m_light_direction(tools::vec3f(0,0,-1))
1201  ,m_light_on(false)
1202  ,m_ccw(true)
1203  ,m_depth_test(true)
1204  {
1205  m_proj.set_identity();
1206  m_model.set_identity();
1207  m_normal_matrix.set_identity();
1208  }
1209  virtual ~render(){}
1210 protected:
1211  render(const render& a_from)
1212  :parent(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)
1225  {}
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;
1239  return *this;
1240  }
1241 protected:
1242  void set_normal_matrix() {
1243  tools::mat4f tmp(m_model);
1244  tmp.no_translate();
1245  if(!tmp.invert(m_normal_matrix)) {
1246  m_out << "tools::metal::render::set_normal_matrix : can't invert model matrix." << std::endl;
1247  }
1248  m_normal_matrix.transpose();
1249  }
1250 
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++;
1258  *pos = 1;pos++;
1259 
1260  *pos = m_normal.x();pos++;
1261  *pos = m_normal.y();pos++;
1262  *pos = m_normal.z();pos++;
1263  *pos = 1;pos++;
1264 
1265  *pos = m_color.r();pos++;
1266  *pos = m_color.g();pos++;
1267  *pos = m_color.b();pos++;
1268  *pos = m_color.a();pos++;
1269 
1270  *pos = 0;pos++;
1271  *pos = 0;pos++;
1272  }
1273  return true;
1274  }
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++;
1282  *pos = 1;pos++;
1283 
1284  *pos = a_nms[3*index+0];pos++;
1285  *pos = a_nms[3*index+1];pos++;
1286  *pos = a_nms[3*index+2];pos++;
1287  *pos = 1;pos++;
1288 
1289  *pos = m_color.r();pos++;
1290  *pos = m_color.g();pos++;
1291  *pos = m_color.b();pos++;
1292  *pos = m_color.a();pos++;
1293 
1294  *pos = 0;pos++;
1295  *pos = 0;pos++;
1296  }
1297  return true;
1298  }
1299 
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++;
1307  *pos = 1;pos++;
1308 
1309  *pos = m_normal.x();pos++;
1310  *pos = m_normal.y();pos++;
1311  *pos = m_normal.z();pos++;
1312  *pos = 1;pos++;
1313 
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++;
1318 
1319  *pos = 0;pos++;
1320  *pos = 0;pos++;
1321  }
1322  return true;
1323  }
1324 
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++;
1332  *pos = 1;pos++;
1333 
1334  *pos = a_nms[3*index+0];pos++;
1335  *pos = a_nms[3*index+1];pos++;
1336  *pos = a_nms[3*index+2];pos++;
1337  *pos = 1;pos++;
1338 
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++;
1343 
1344  *pos = 0;pos++;
1345  *pos = 0;pos++;
1346  }
1347  return true;
1348  }
1349 
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++;
1357  *pos = 1;pos++;
1358 
1359  *pos = 0;pos++;
1360  *pos = 0;pos++;
1361  *pos = 1;pos++;
1362  *pos = 1;pos++;
1363 
1364  *pos = m_color.r();pos++;
1365  *pos = m_color.g();pos++;
1366  *pos = m_color.b();pos++;
1367  *pos = m_color.a();pos++;
1368 
1369  *pos = a_tcs[2*index+0];pos++;
1370  *pos = a_tcs[2*index+1];pos++;
1371  }
1372  return true;
1373  }
1374 
1375  struct uniforms {
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;
1382  };
1383 
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);
1390  tools::mat4f pm;
1391  pm.set_identity();
1392  pm = z_gl_to_metal;
1393  pm *= m_proj;
1394  pm *= m_model;
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;
1401  }
1402 
1403 protected:
1404  manager& m_mgr;
1405  gstoid m_current_data_gsto_id;
1406 
1407  tools::colorf m_light_color;
1408  tools::vec3f m_light_direction;
1409 
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;
1416  bool m_light_on;
1417  bool m_ccw;
1418  bool m_depth_test;
1419 };
1420 
1421 }}
1422 
1423 
1424 #endif