# HG changeset patch
# User mmuetzel <markus.muetzel@gmx.de>
# Date 1457967111 -3600
#      Mon Mar 14 15:51:51 2016 +0100
# Node ID 302a9cd59c0ba9f50b608125876e46448f69b9aa
# Parent  de155ca994d44fc6601c24fd482d8654f24ef910
implement object class "light"

diff -r de155ca994d4 -r 302a9cd59c0b libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc	Sun Mar 13 08:46:59 2016 -0700
+++ b/libinterp/corefcn/gl-render.cc	Mon Mar 14 15:51:51 2016 +0100
@@ -624,6 +624,8 @@
     draw_surface (dynamic_cast<const surface::properties&> (props));
   else if (go.isa ("patch"))
     draw_patch (dynamic_cast<const patch::properties&> (props));
+  else if (go.isa ("light"))
+    draw_light (dynamic_cast<const light::properties&> (props));
   else if (go.isa ("hggroup"))
     draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
   else if (go.isa ("text"))
@@ -1623,6 +1625,17 @@
 
   draw_axes_children (props);
 
+  // enable ambient lights
+  glEnable (GL_LIGHTING);
+  glEnable (GL_LIGHT0);
+  float cb[4] = { 1.0, 1.0, 1.0, 1.0 };
+  Matrix ambient_lcolor = props.get_ambientlightcolor_rgb ();
+  for (int i = 0; i < 3; i++)
+    cb[i] = ambient_lcolor(i);
+  
+  glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
+  glDisable (GL_LIGHTING);
+
 #else
   // This shouldn't happen because construction of opengl_renderer
   // objects is supposed to be impossible if OpenGL is not available.
@@ -2398,10 +2411,12 @@
   bool has_z = (v.columns () > 2);
   bool has_facecolor = false;
   bool has_facealpha = false;
+  bool has_normals = (n.rows () == nv);
 
   int fc_mode = ((props.facecolor_is ("none")
                   || props.facecolor_is_rgb ()) ? 0 :
                  (props.facecolor_is ("flat") ? 1 : 2));
+  // FIXME: fl_mode should only be >0 if there is a light object in the same axes
   int fl_mode = (props.facelighting_is ("none") ? 0 :
                  (props.facelighting_is ("flat") ? 1 : 2));
   int fa_mode = (props.facealpha_is_double () ? 0 :
@@ -2409,6 +2424,7 @@
   int ec_mode = ((props.edgecolor_is ("none")
                   || props.edgecolor_is_rgb ()) ? 0 :
                  (props.edgecolor_is ("flat") ? 1 : 2));
+  // FIXME: el_mode should only be >0 if there is a light object in the same axes
   int el_mode = (props.edgelighting_is ("none") ? 0 :
                  (props.edgelighting_is ("flat") ? 1 : 2));
   int ea_mode = (props.edgealpha_is_double () ? 0 :
@@ -2495,8 +2511,10 @@
         vv(0) = v(idx,0); vv(1) = v(idx,1);
         if (has_z)
           vv(2) = v(idx,2);
-        // FIXME: uncomment when patch object has normal computation
-        //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2);
+        if (has_normals)
+          {
+            nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2);
+          }
         if (c.numel () > 0)
           {
             cc.resize (1, 3);
@@ -2814,6 +2832,37 @@
 }
 
 void
+opengl_renderer::draw_light (const light::properties &props)
+{
+#if defined (HAVE_OPENGL)
+
+  // enable light source
+  glEnable (GL_LIGHT0); // Ambient lighting is in GL_LIGHT0
+  
+  // light components
+  float pos[4] = { 0, 0, 0, 0 }; // X,Y,Z,attenuation
+  Matrix lpos = props.get_position ().matrix_value ();
+  for (int i = 0; i < 3; i++)
+    pos[i] = lpos(i);
+  glLightfv (GL_LIGHT0, GL_POSITION, pos);
+
+  float cb[4] = { 1, 1, 1, 1 };
+  Matrix lcolor = props.get_color ().matrix_value ();
+  for (int i = 0; i < 3; i++)
+    cb[i] = lcolor(i);
+
+  glLightfv (GL_LIGHT0, GL_DIFFUSE,  cb);
+  glLightfv (GL_LIGHT0, GL_SPECULAR, cb);
+
+#else
+  // This shouldn't happen because construction of opengl_renderer
+  // objects is supposed to be impossible if OpenGL is not available.
+
+  panic_impossible ();
+#endif
+}
+
+void
 opengl_renderer::draw_hggroup (const hggroup::properties &props)
 {
   draw (props.get_children ());
diff -r de155ca994d4 -r 302a9cd59c0b libinterp/corefcn/gl-render.h
--- a/libinterp/corefcn/gl-render.h	Sun Mar 13 08:46:59 2016 -0700
+++ b/libinterp/corefcn/gl-render.h	Mon Mar 14 15:51:51 2016 +0100
@@ -64,6 +64,7 @@
   virtual void draw_line (const line::properties& props);
   virtual void draw_surface (const surface::properties& props);
   virtual void draw_patch (const patch::properties& props);
+  virtual void draw_light (const light::properties& props);
   virtual void draw_hggroup (const hggroup::properties& props);
   virtual void draw_text (const text::properties& props);
   virtual void draw_image (const image::properties& props);
diff -r de155ca994d4 -r 302a9cd59c0b libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Sun Mar 13 08:46:59 2016 -0700
+++ b/libinterp/corefcn/graphics.cc	Mon Mar 14 15:51:51 2016 +0100
@@ -535,6 +535,18 @@
   return retval;
 }
 
+static Matrix
+default_light_position (void)
+{
+  Matrix m (1, 3);
+
+  m(0) = 1.0;
+  m(1) = 0.0;
+  m(2) = 1.0;
+
+  return m;
+}
+
 static double
 convert_font_size (double font_size, const caseless_str& from_units,
                    const caseless_str& to_units, double parent_height = 0)
@@ -1097,6 +1109,8 @@
     go = new text (h, p);
   else if (type.compare ("image"))
     go = new image (h, p);
+  else if (type.compare ("light"))
+    go = new light (h, p);
   else if (type.compare ("patch"))
     go = new patch (h, p);
   else if (type.compare ("surface"))
@@ -8075,7 +8089,7 @@
   if (fvc.is_undefined () || fvc.is_empty ())
     return Matrix ();
   else
-    return convert_cdata (*this, fvc,cdatamapping_is ("scaled"), 2);
+    return convert_cdata (*this, fvc, cdatamapping_is ("scaled"), 2);
 }
 
 static bool updating_patch_data = false;
@@ -9500,6 +9514,7 @@
   plist_map["image"] = image::properties::factory_defaults ();
   plist_map["patch"] = patch::properties::factory_defaults ();
   plist_map["surface"] = surface::properties::factory_defaults ();
+  plist_map["light"] = light::properties::factory_defaults ();
   plist_map["hggroup"] = hggroup::properties::factory_defaults ();
   plist_map["uimenu"] = uimenu::properties::factory_defaults ();
   plist_map["uicontrol"] = uicontrol::properties::factory_defaults ();
@@ -10325,6 +10340,15 @@
   GO_BODY (patch);
 }
 
+DEFUN (__go_light__, args, ,
+       "-*- texinfo -*-\n\
+@deftypefn {} {} __go_light__ (@var{parent})\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  GO_BODY (light);
+}
+
 DEFUN (__go_hggroup__, args, ,
        "-*- texinfo -*-\n\
 @deftypefn {} {} __go_hggroup__ (@var{parent})\n\
diff -r de155ca994d4 -r 302a9cd59c0b libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Sun Mar 13 08:46:59 2016 -0700
+++ b/libinterp/corefcn/graphics.in.h	Mon Mar 14 15:51:51 2016 +0100
@@ -4811,6 +4811,55 @@
 
 // ---------------------------------------------------------------------
 
+class OCTINTERP_API light : public base_graphics_object
+{
+public:
+  class OCTINTERP_API properties : public base_properties
+  {
+    // See the genprops.awk script for an explanation of the
+    // properties declarations.
+    // Programming note: Keep property list sorted if new ones are added.
+
+    BEGIN_PROPERTIES (light)
+      color_property color , color_values (1, 1, 1)
+      array_property position , default_light_position ()
+      radio_property style , "{infinite}|local"
+    END_PROPERTIES
+
+  protected:
+    void init (void)
+    {
+      position.add_constraint (dim_vector (1, 3));
+    }
+  };
+
+private:
+  properties xproperties;
+
+public:
+  light (const graphics_handle& mh, const graphics_handle& p)
+    : base_graphics_object (), xproperties (mh, p)
+  { }
+
+  ~light (void) { }
+
+  base_properties& get_properties (void) { return xproperties; }
+
+  const base_properties& get_properties (void) const { return xproperties; }
+
+  bool valid_object (void) const { return true; }
+
+  bool has_readonly_property (const caseless_str& pname) const
+  {
+    bool retval = xproperties.has_readonly_property (pname);
+    if (! retval)
+      retval = base_properties::has_readonly_property (pname);
+    return retval;
+  }
+};
+
+// ---------------------------------------------------------------------
+
 class OCTINTERP_API patch : public base_graphics_object
 {
 public:
diff -r de155ca994d4 -r 302a9cd59c0b scripts/help/__unimplemented__.m
--- a/scripts/help/__unimplemented__.m	Sun Mar 13 08:46:59 2016 -0700
+++ b/scripts/help/__unimplemented__.m	Mon Mar 14 15:51:51 2016 +0100
@@ -712,7 +712,6 @@
   "libisloaded",
   "libpointer",
   "libstruct",
-  "light",
   "lightangle",
   "lighting",
   "linkdata",
