Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / scenegraph.C
diff --git a/cinelerra-5.1/cinelerra/scenegraph.C b/cinelerra-5.1/cinelerra/scenegraph.C
new file mode 100644 (file)
index 0000000..69cb550
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+#include "affine.h"
+#include "clip.h"
+#include <math.h>
+#include "overlayframe.h"
+#include "scenegraph.h"
+#include <string.h>
+
+
+#define PRINT_INDENT for(int i = 0; i < indent; i++) printf(" ");
+
+
+SceneNode::SceneNode()
+{
+       reset();
+}
+
+SceneNode::SceneNode(const char *title)
+{
+       reset();
+       strcpy(this->title, title);
+}
+
+SceneNode::SceneNode(VFrame *image, int private_image, float x, float y)
+{
+       reset();
+       this->image = image;
+       if(this->image) this->private_image = private_image;
+       this->x = x;
+       this->y = y;
+}
+
+SceneNode::~SceneNode()
+{
+       nodes.remove_all_objects();
+       if(private_image) delete image;
+}
+
+void SceneNode::reset()
+{
+       parent = 0;
+       scene = 0;
+       x = y = z = rx = ry = rz = 0;
+       sx = sy = sz = 1;
+       hidden = 0;
+       image = 0;
+       private_image = 0;
+       flip = 0;
+       title[0] = 0;
+}
+
+void SceneNode::append(SceneNode *node)
+{
+       node->parent = this;
+       node->scene = this->scene;
+       nodes.append(node);
+}
+
+void SceneNode::copy_ref(SceneNode *node)
+{
+       if(private_image) delete image;
+       private_image = 0;
+       x = node->x;
+       y = node->y;
+       z = node->z;
+       rx = node->rx;
+       ry = node->ry;
+       rz = node->rz;
+       sx = node->sx;
+       sy = node->sy;
+       sz = node->sz;
+       hidden = node->hidden;
+       image = node->image;
+       flip = node->flip;
+}
+
+SceneNode* SceneNode::get_node(int number)
+{
+       return nodes.get(number);
+}
+
+int SceneNode::get_memory_usage()
+{
+       if(image)
+               return image->get_memory_usage();
+       else
+               return 0;
+}
+
+void SceneNode::render(VFrame *frame, int do_camera)
+{
+       const int debug = 0;
+       if(debug) printf("SceneNode::render %d this=%p title=%s image=%p x=%f y=%f frame=%p do_camera=%d\n", 
+               __LINE__, 
+               this,
+               title,
+               image,
+               this->x,
+               this->y,
+               frame,
+               do_camera);
+
+       VFrame *temp = 0;
+       VFrame *temp2 = 0;
+       if(image)
+       {
+               float x = this->x;
+               float y = this->y;
+               float sx = this->sx;
+               float sy = this->sy;
+               float ry = this->ry;
+               if(parent) 
+                       parent->transform_coord(&x, &y, &sx, &sy, &ry);
+
+               if(do_camera) scene->transform_camera(frame, 
+                       &x, 
+                       &y, 
+                       &sx, 
+                       &sy, 
+                       get_flip());
+
+               if(debug) printf("SceneNode::render %d at_y=%f\n", 
+                       __LINE__, 
+                       ((SceneCamera*)scene->cameras.get(0))->at_y);
+
+// Render everything into a temporary, then overlay the temporary
+//             if(!EQUIV(ry, 0) || get_flip())
+//             {
+               temp = new VFrame(image->get_w(), 
+                       image->get_h(), 
+                       image->get_color_model());
+//             }
+               if(debug) printf("SceneNode::render %d\n", __LINE__);
+
+
+// 1st comes our image
+               temp->copy_from(image);
+
+// Then come the subnodes without camera transforms
+               if(debug) printf("SceneNode::render %d this=%p nodes=%d\n", __LINE__, this, nodes.size());
+               for(int i = 0; i < nodes.size(); i++)
+                       nodes.get(i)->render(temp, 0);
+
+
+
+               if(debug) printf("SceneNode::render %d\n", __LINE__);
+
+// Then comes rotation into temp2
+               VFrame *src = temp;
+               if(!EQUIV(ry, 0))
+               {
+                       src = temp2 = new VFrame(image->get_w(), 
+                               image->get_h(), 
+                               image->get_color_model());
+                       if(!scene->affine) scene->affine = 
+                               new AffineEngine(scene->cpus, scene->cpus);
+                       scene->affine->rotate(temp2,
+                               temp,
+                               ry);
+                       if(debug) printf("SceneNode::render %d ry=%f\n", __LINE__, ry);
+               }
+
+// Then comes flipping
+               if(get_flip())
+                       src->flip_horiz();
+
+               if(debug) printf("SceneNode::render %d src=%p x=%f y=%f sx=%f sy=%f\n", 
+                       __LINE__, 
+                       src,
+                       x,
+                       y,
+                       sx,
+                       sy);
+
+// Overlay on the output frame
+               if(!scene->overlayer) scene->overlayer = new OverlayFrame(scene->cpus);
+
+               if(get_flip())
+               {
+                       scene->overlayer->overlay(frame, 
+                               src, 
+                               0, 
+                               0, 
+                               image->get_w(), 
+                               image->get_h(), 
+                               frame->get_w() - x - image->get_w() * sx, 
+                               y, 
+                               frame->get_w() - x, 
+                               y + image->get_h() * sy, 
+                               1,
+                               TRANSFER_NORMAL,
+                               NEAREST_NEIGHBOR);
+               }
+               else
+               {
+                       if(debug) printf("SceneNode::render %d image=%p src=%p frame=%p\n", 
+                               __LINE__, 
+                               image,
+                               src,
+                               frame);
+                       scene->overlayer->overlay(frame, 
+                               src, 
+                               0, 
+                               0, 
+                               image->get_w(), 
+                               image->get_h(), 
+                               x, 
+                               y, 
+                               x + image->get_w() * sx, 
+                               y + image->get_h() * sy, 
+                               1,
+                               TRANSFER_NORMAL,
+                               NEAREST_NEIGHBOR);
+               }
+
+               if(debug) printf("SceneNode::render %d\n", __LINE__);
+
+       }
+       else
+       {
+               for(int i = 0; i < nodes.size(); i++)
+                       nodes.get(i)->render(frame, 1);
+       }
+
+       if(debug) printf("SceneNode::render %d this=%p title=%s\n", __LINE__, this, title);
+
+       if(temp) delete temp;
+       if(temp2) delete temp2;
+}
+
+int SceneNode::get_flip()
+{
+       if(flip) return 1;
+       if(parent && !parent->image) return parent->get_flip();
+       return 0;
+}
+
+
+void SceneNode::transform_coord(
+       float *x, 
+       float *y, 
+       float *sx, 
+       float *sy, 
+       float *ry)
+{
+// Rotate it
+//     if(!EQUIV(this->ry, 0))
+//     {
+//             float pivot_x = 0;
+//             float pivot_y = 0;
+//             if(image)
+//             {
+//                     pivot_x = image->get_w() / 2;
+//                     pivot_y = image->get_h() / 2;
+//             }
+// 
+//             float rel_x = *x - pivot_x;
+//             float rel_y = *y - pivot_y;
+//             float angle = atan2(rel_y, rel_x);
+//             float mag = sqrt(rel_x * rel_x + rel_y * rel_y);
+//             angle += this->ry * 2 * M_PI / 360;
+//             *x = mag * cos(angle) + pivot_x;
+//             *y = mag * sin(angle) + pivot_y;
+//     }
+
+// Nodes with images reset the transformation
+       if(!image)
+       {
+// Scale it
+               *x *= this->sx;
+               *y *= this->sy;
+               *sx *= this->sx;
+               *sy *= this->sy;
+
+// Translate it
+               *x += this->x;
+               *y += this->y;
+
+
+// Accumulate rotation
+               *ry += this->ry;
+
+               if(parent)
+               {
+                       parent->transform_coord(x, y, sx, sy, ry);
+               }
+       }
+}
+
+void SceneNode::dump(int indent)
+{
+       PRINT_INDENT
+       printf("SceneNode::dump %d this=%p title=%s\n", __LINE__, this, title);
+       PRINT_INDENT
+       printf("  image=%p private_image=%d hidden=%d flip=%d\n",
+               image,
+               private_image,
+               hidden,
+               flip);
+       PRINT_INDENT
+       printf("  x=%f y=%f z=%f sz=%f sy=%f sz=%f rx=%f ry=%f rz=%f\n",
+               x, y, z, sz, sy, sz, rx, ry, rz);
+       PRINT_INDENT
+       printf("  nodes=%d\n", nodes.size());
+       for(int i = 0; i < nodes.size(); i++)
+       {
+               nodes.get(i)->dump(indent + 4);
+       }
+}
+
+
+
+
+
+SceneGraph::SceneGraph() : VFrameScene()
+{
+       current_camera = 0;
+       affine = 0;
+       overlayer = 0;
+}
+
+SceneGraph::~SceneGraph()
+{
+       nodes.remove_all_objects();
+       cameras.remove_all_objects();
+       delete affine;
+       delete overlayer;
+}
+
+
+SceneNode* SceneGraph::get_node(int number)
+{
+       return nodes.get(number);
+}
+
+void SceneGraph::append(SceneNode *node)
+{
+       node->parent = 0;
+       node->scene = this;
+       nodes.append(node);
+}
+
+void SceneGraph::append_camera(SceneNode *node)
+{
+       node->scene = this;
+       cameras.append(node);
+}
+
+void SceneGraph::render(VFrame *frame, int cpus)
+{
+       const int debug = 0;
+       if(debug) printf("SceneGraph::render %d\n", __LINE__);
+       if(debug) dump();
+       
+       this->cpus = cpus;
+
+       for(int i = 0; i < nodes.size(); i++)
+       {
+               nodes.get(i)->render(frame, 1);
+       }
+}
+
+void SceneGraph::transform_camera(VFrame *frame, 
+       float *x, 
+       float *y, 
+       float *sx, 
+       float *sy, 
+       int flip)
+{
+       if(cameras.size())
+       {
+               SceneCamera *camera = (SceneCamera*)cameras.get(current_camera);
+
+               if(flip)
+               {
+                       *x = frame->get_w() - *x;
+               }
+
+               *x -= camera->at_x;
+               *y -= camera->at_y;
+               *x *= camera->scale;
+               *y *= camera->scale;
+               *sx *= camera->scale;
+               *sy *= camera->scale;
+
+               if(flip)
+               {
+                       *x = frame->get_w() - *x;
+               }
+       }
+}
+
+void SceneGraph::dump()
+{
+       int indent = 2;
+       printf("SceneGraph::dump %d cameras=%d\n", __LINE__, cameras.size());
+       for(int i = 0; i < cameras.size(); i++)
+               cameras.get(i)->dump(indent);
+       printf("SceneGraph::dump %d nodes=%d\n", __LINE__, nodes.size());
+       for(int i = 0; i < nodes.size(); i++)
+               nodes.get(i)->dump(indent);
+}
+
+
+
+
+
+
+
+SceneTransform::SceneTransform() : SceneNode()
+{
+}
+
+SceneTransform::~SceneTransform()
+{
+}
+
+
+
+
+
+SceneLight::SceneLight() : SceneNode()
+{
+}
+
+SceneLight::~SceneLight()
+{
+}
+
+
+
+
+
+
+
+SceneCamera::SceneCamera() : SceneNode()
+{
+       at_x = at_y = at_z = 0;
+       scale = 1;
+}
+
+SceneCamera::~SceneCamera()
+{
+}
+
+void SceneCamera::dump(int indent)
+{
+       PRINT_INDENT
+       printf("SceneCamera::dump %d this=%p\n", __LINE__, this);
+       PRINT_INDENT
+       printf("  at_x=%f at_y=%f at_z=%f scale=%f\n", 
+               at_x,
+               at_y,
+               at_z,
+               scale);
+}
+
+
+
+
+SceneMaterial::SceneMaterial() : SceneNode()
+{
+       r = g = b = a = 0;
+       texture = 0;
+       s = t = 0;
+}
+
+SceneMaterial::~SceneMaterial()
+{
+       delete [] texture;
+}
+
+
+
+
+
+
+
+SceneShape::SceneShape() : SceneNode()
+{
+       pivot_x = pivot_y = pivot_z = 0;
+}
+
+SceneShape::~SceneShape()
+{
+}
+
+
+
+
+
+
+
+
+SceneCylinder::SceneCylinder() : SceneShape()
+{
+}
+
+SceneCylinder::~SceneCylinder()
+{
+}
+
+
+
+
+SceneSphere::SceneSphere() : SceneShape()
+{
+}
+
+
+SceneSphere::~SceneSphere()
+{
+}
+
+
+
+
+SceneBox::SceneBox() : SceneShape()
+{
+}
+
+
+SceneBox::~SceneBox()
+{
+}
+
+
+
+
+
+
+
+
+
+
+
+
+