Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filescene.C
diff --git a/cinelerra-5.0/cinelerra/filescene.C b/cinelerra-5.0/cinelerra/filescene.C
deleted file mode 100644 (file)
index ace2c08..0000000
+++ /dev/null
@@ -1,1920 +0,0 @@
-/*
- * 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 "asset.h"
-#include "bcsignals.h"
-#include "clip.h"
-#include "file.h"
-#include "filescene.h"
-#include "filesystem.h"
-#include "format.inc"
-#include "libmjpeg.h"
-#include "scenegraph.h"
-
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-
-extern "C"
-{
-#include <uuid.h>
-}
-
-
-// Paths relative to the exe path
-#define FESTIVAL_PATH "/festival"
-#define FESTIVAL_LIB_PATH "/lib/"
-#define ASSET_PATH "/models/"
-#define FREAD_SIZE 0x10000
-#define WAVHEADER 44
-#define FESTIVAL_SAMPLERATE 16000
-#define PAUSE_SAMPLES FESTIVAL_SAMPLERATE
-// Amount to truncate if ...
-#define ADVANCE_SAMPLES FESTIVAL_SAMPLERATE
-
-// Maximum characters in a line of dialog is limited by festival
-#define MAX_CHARS 65536
-
-#define STRIP_LINE(string) \
-/* Strip linefeeds */ \
-       while(len > 0 && (string[len - 1] == '\n' || \
-               string[len - 1] == ' ')) \
-       { \
-               string[len - 1] = 0; \
-               len--; \
-       } \
- \
-/* Strip comments */ \
-       for(i = 0; i < len; i++) \
-       { \
-               if(string[i] == '#') \
-               { \
-                       string[i] = 0; \
-                       i = len; \
-               } \
-       }
-
-
-
-
-#define STRING_PARAMETER(title, need_char, dst) \
-if(!strncmp(command, title, strlen(title))) \
-{ \
-/* advance to argument */ \
-       i += strlen(title); \
-       while(string[i] != 0 && string[i] == ' ') \
-               i++; \
- \
-       if(current_char || !need_char) \
-       { \
-/* printf("STRING_PARAMETER %s %s %p\n", title, string + i, dst); */ \
-               strcpy(dst, string + i); \
-       } \
-       else \
-       { \
-               printf("FileScene::read_script %d Line %d: %s but no current character\n",  \
-                       __LINE__, \
-                       current_line, \
-                       title); \
-       } \
- \
-       i = len; \
-}
-
-static int read_parameter(char *string,
-       int *i,
-       const char *title, 
-       char *dst_string, 
-       float *dst_float0, 
-       float *dst_float1, 
-       float *dst_float2)
-{
-       char *command = string + *i;
-       char *arg_text[3];
-
-       if(!strncmp(command, title, strlen(title)))
-       {
-               *i += strlen(title);
-
-               for(int j = 0; j < 4; j++)
-               {
-/* skip to start of argument */
-                       while(string[*i] != 0 && string[*i] == ' ')
-                               (*i)++;
-
-                       if(string[*i] != 0)
-                       {
-                               arg_text[j] = string + *i;
-                               while(string[*i] != 0 && string[*i] != ' ')
-                                       (*i)++;
-                       }
-                       else
-                       {
-                               arg_text[j] = 0;
-                       }
-               }
-
-// printf("read_parameter %d %s %s %s %s\n", 
-// __LINE__, 
-// title, 
-// arg_text[0], 
-// arg_text[1], 
-// arg_text[2]);
-
-               if(arg_text[0])
-               {
-                       if(dst_string)
-                       {
-                               char *ptr1 = dst_string;
-                               char *ptr2 = arg_text[0];
-                               while(*ptr2 != 0 && *ptr2 != ' ')
-                                       *ptr1++ = *ptr2++;
-                               *ptr1 = 0;
-                       }
-                       else
-                       if(dst_float0)
-                       {
-                               *dst_float0 = atof(arg_text[0]);
-                       }
-               }
-
-               if(arg_text[1])
-               {
-                       if(dst_float1)
-                       {
-                               *dst_float1 = atof(arg_text[1]);
-                       }
-               }
-
-               if(arg_text[2])
-               {
-                       if(dst_float2)
-                       {
-                               *dst_float2 = atof(arg_text[2]);
-                       }
-               }
-
-               return 1;
-       }
-
-       return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-FileScene::FileScene(Asset *asset, File *file)
- : FileBase(asset, file)
-{
-       reset_parameters();
-       get_exe_path(exe_path);
-}
-
-
-FileScene::~FileScene()
-{
-       close_file();
-}
-
-
-
-int FileScene::open_file(int rd, int wr)
-{
-// Load the script to get character count
-       read_script();
-       
-
-
-// Set asset format
-       asset->format = FILE_SCENE;
-       asset->video_data = 1;
-// Should be set in the scene file
-       asset->layers = 1;
-       asset->width = 1280;
-       asset->height = 720;
-// Dictated by character animations
-       asset->frame_rate = (double)30000 / 1001;
-// Some arbitrary default length.
-// Hard to calculate without rendering it.
-       asset->video_length = -1;
-
-
-
-       asset->audio_data = 1;
-// The speech synthesizer outputs different samplerates depending on the speaker.
-// The heroine voices are all 16khz
-       asset->sample_rate = FESTIVAL_SAMPLERATE;
-// Mono voice placement for now
-// Maybe a different track for each voice in the future or 3D positioning
-       asset->channels = script->total_characters();
-       asset->audio_length = -1;
-
-
-       return 0;
-}
-
-int FileScene::close_file()
-{
-       delete script;
-       delete [] audio_temp;
-//     delete overlayer;
-//     delete affine;
-       FileBase::close_file();
-       return 0;
-}
-
-
-int FileScene::check_sig(Asset *asset, char *test)
-{
-       if(!strncmp(test, "TEXT2MOVIE", 10)) return 1;
-
-       return 0;
-}
-
-
-
-int FileScene::set_video_position(int64_t x)
-{
-       return 0;
-}
-
-
-int FileScene::set_audio_position(int64_t x)
-{
-       return 0;
-}
-
-
-int FileScene::read_frame(VFrame *frame)
-{
-// Everything is timed based on speech, so render the audio for this frame.
-       const int debug = 0;
-       
-       
-       frame->clear_frame();
-       int64_t audio_position1 = (int64_t)(file->current_frame * 
-               asset->sample_rate /
-               asset->frame_rate);
-       int64_t audio_position2 = (int64_t)(audio_position1 + 
-               asset->sample_rate /
-               asset->frame_rate);
-
-       if(debug) printf("FileScene::read_frame %d frame=" _LD
-               " frame_rate=%f sample_rate=%d audio_position1=" _LD
-               " audio_position2=" _LD "\n", __LINE__,
-               file->current_frame, asset->frame_rate,
-               asset->sample_rate, audio_position1,
-               audio_position2);
-
-       render_chunks(audio_position1, 
-               audio_position2 - audio_position1,
-               1);
-       if(!script) return 1;
-       if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-
-//     script->dump();
-
-
-// Determine lip position from amplitude
-       double accum = 0;
-       for(int i = 0; i < audio_position2 - audio_position1; i++)
-       {
-               double sample_float = fabs((double)audio_temp[i] / 32768);
-               if(sample_float > accum) accum = sample_float;
-       }
-       if(debug) printf("FileScene::read_frame %d accum=%f\n", __LINE__, accum);
-
-// Reset cameras
-       for(int i = 0; i < script->total_characters(); i++)
-       {
-               SceneChar *character = script->get_character(i);
-               character->current_camera = SceneChar::CAMERA_WIDE;
-               character->is_speeking = 0;
-               character->max = 0;
-       }
-
-// Now determine most recent character which is speaking from the sample times.
-       int64_t current_sample = 0;
-       SceneChar *speeking_character = 0;
-// Sample relative to start of chunk
-       int64_t chunk_sample = 0;
-       for(int i = 0; 
-               i < script->total_chunks() && current_sample < audio_position2; 
-               i++)
-       {
-               SceneChunk *chunk = script->get_chunk(i);
-               int samples = chunk->audio_size / 2;
-
-
-               if(audio_position1 >= current_sample && 
-                       audio_position1 < current_sample + samples)
-               {
-                       speeking_character = chunk->character;
-                       speeking_character->max = chunk->max;
-                       chunk->character->is_speeking = 1;
-                       chunk_sample = audio_position1 - current_sample;
-//                     break;
-               }
-               else
-               if(!chunk->character->is_speeking)
-               {
-                       chunk->character->increment_camera();
-               }
-
-               current_sample += chunk->advance_samples;
-       }
-
-
-
-       if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-       
-// Render the scene.
-// Store component placement in a scene graph.
-       SceneGraph scene;
-       //SceneNode *speeking_node = 0;
-
-// Scale for the entire scene
-       SceneCamera *camera = new SceneCamera;
-       scene.append_camera(camera);
-       camera->at_x = 0;
-       camera->at_y = 0;
-
-// Render background
-       if(script->background[0])
-       {
-               script->render_background(&scene);
-       }
-
-       if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-
-// Render characters
-       for(int i = 0; i < script->total_characters(); i++)
-       {
-               SceneChar *character = script->get_character(i);
-
-               character->read_model();
-
-// Nodes for the character
-               SceneNode *character_node = new SceneNode(character->name);
-               scene.append(character_node);
-               character_node->sx = character_node->sy = character->scale;
-
-               SceneNode *head_node = new SceneNode("head");
-
-               SceneNode *body_node = new SceneNode("body");
-
-// Render in the order listed in the file
-               if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-               for(int j = 0; j < 2; j++)
-               {
-                       if(debug) printf("FileScene::read_frame %d j=%d head_order=%d body_order=%d\n", 
-                               __LINE__, 
-                               j,
-                               character->head_order,
-                               character->body_order);
-                       if(j == character->head_order) character_node->append(head_node);
-                       else
-                       if(j == character->body_order) character_node->append(body_node);
-               }
-
-               SceneNode *eye_node = 0;
-               if(character->eyes.size())
-               {
-                       eye_node = new SceneNode("eyes");
-                       head_node->append(eye_node);
-               }
-
-               SceneNode *mouth_node = new SceneNode("mouth");
-               head_node->append(mouth_node);
-
-// Logical character placement
-               switch(script->total_characters())
-               {
-                       case 1:
-                               if(speeking_character == character &&
-                                       speeking_character->current_camera == SceneChar::CAMERA_CU)
-                               {
-                                       camera->at_x = asset->width / 4;
-                               }
-
-                               character_node->x = (int)(asset->width / 2 - 
-                                       character->w * character->scale / 2);
-                               character_node->y = (int)(asset->height - 
-                                       character->h * character->scale);
-                               break;
-
-                       case 2:
-                               if(i == 0)
-                               {
-                                       character_node->x = 0;
-                                       character_node->y = (int)(asset->height - 
-                                               character->h * character->scale);
-
-                                       if(speeking_character == character &&
-                                               speeking_character->current_camera == SceneChar::CAMERA_CU)
-                                       {
-                                               camera->at_y = character_node->y;
-                                               camera->at_x = character_node->x + 
-                                                       (character->head->x + character->head->image->get_w() / 2) * character->scale - 
-                                                       asset->width / 4;
-                                               CLAMP(camera->at_x, 0, asset->width / 2);
-                                               CLAMP(camera->at_y, 0, asset->height);
-//printf("FileScene::read_frame %d camera->at_x=%f camera->at_y=%f\n", __LINE__, camera->at_x, camera->at_y);
-                                       }
-
-                                       if(character->faces_left)
-                                       {
-                                               character_node->flip = 1;
-                                               character_node->x = asset->width - 
-                                                       character->w * character->scale;
-                                       }
-                               }
-                               else
-                               {
-
-                                       character_node->x = (int)(asset->width - 
-                                               character->w * character->scale);
-                                       character_node->y = (int)(asset->height - 
-                                               character->h * character->scale);
-
-                                       if(speeking_character == character &&
-                                               speeking_character->current_camera == SceneChar::CAMERA_CU)
-                                       {
-                                               camera->at_x = character_node->x + 
-                                                       character->head->x * character->scale - 
-                                                       asset->width / 4;
-                                               CLAMP(camera->at_x, 0, asset->width / 2);
-                                       }
-
-                                       if(!character->faces_left) 
-                                       {
-                                               character_node->flip = 1;
-                                               character_node->x = 0;
-                                       }
-                               }
-                               break;
-
-                       case 3:
-                               if(i == 0)
-                               {
-                                       character_node->x = 0;
-                                       character_node->y = (int)(asset->height - 
-                                               character->h * character->scale);
-                                       if(character->faces_left)
-                                       {
-                                               character_node->flip = 1;
-                                       }
-                               }
-                               else
-                               if(i == 1)
-                               {
-                                       if(speeking_character == character &&
-                                               speeking_character->current_camera == SceneChar::CAMERA_CU)
-                                       {
-                                               camera->at_x = asset->width / 4;
-                                       }
-                                       character_node->x = (int)(asset->width / 2 - 
-                                               character->w * character->scale / 2);
-                                       character_node->y = (int)(asset->height - 
-                                               character->h * character->scale);
-                                       if(character->faces_left)
-                                       {
-                                               character_node->flip = 1;
-                                       }
-                               }
-                               else
-                               {
-                                       if(speeking_character == character &&
-                                               speeking_character->current_camera == SceneChar::CAMERA_CU)
-                                       {
-                                               camera->at_x = asset->width / 2;
-                                       }
-                                       character_node->x = (int)(asset->width - 
-                                               character->w * character->scale);
-                                       character_node->y = (int)(asset->height - 
-                                               character->h * character->scale);
-                                       if(!character->faces_left)
-                                       {
-                                               character_node->flip = 1;
-                                               character_node->x = 0;
-                                       }
-                               }
-                               break;
-               }
-
-// Clamp the head
-               if(character_node->y < 0) character_node->y = 0;
-
-// Add remaining parts
-               body_node->copy_ref(character->body);
-               head_node->copy_ref(character->head);
-
-// Speeker head rotation
-               if(speeking_character == character)
-               {
-                       //speeking_node = character_node;
-               
-                       int head_time = (chunk_sample / asset->sample_rate / 2) % 2;
-
-                       if(head_time > 0)
-                       {
-                               double temp;
-                               double anim_position = modf((double)chunk_sample / asset->sample_rate / 2, &temp);
-                               double anim_length = 0.1;
-// printf("FileScene::read_frame %d %d %f\n", 
-// __LINE__, 
-// head_time,
-// anim_position);
-
-                               if(anim_position < anim_length)
-                                       head_node->ry = -5 * anim_position / anim_length;
-                               else
-                               if(anim_position > 1.0 - anim_length)
-                                       head_node->ry = -5 * (1.0 - anim_position) / anim_length;
-                               else
-                                       head_node->ry = -5;
-                       }
-               }
-
-//head_node->ry = -5;
-
-// Eyes
-               double intpart;
-               if(character->eyes.size())
-               {
-                       if(modf((file->current_frame / asset->frame_rate + script->get_char_number(character)) / 5, &intpart) <= 
-                               0.1 / 5 &&
-                               file->current_frame / asset->frame_rate > 1)
-                       {
-                               eye_node->copy_ref(character->eyes.get(0));
-                       }
-                       else
-                               eye_node->copy_ref(character->eyes.get(1));
-               }
-
-// Compute the mouth image
-               int fraction = 0;
-               if(character->is_speeking && character->max > 0)
-               {
-                       fraction = (int)(accum * character->mouths.size() / character->max);
-                       if(fraction >= character->mouths.size())
-                               fraction = character->mouths.size() - 1;
-               }
-
-               mouth_node->copy_ref(character->mouths.get(fraction));
-
-
-// camera->scale = 2;
-// camera->at_x = asset->width / 2;
-// camera->at_y = 0;
-
-// Compute camera
-               if(speeking_character == character &&
-                       speeking_character->current_camera == SceneChar::CAMERA_CU)
-               {
-// If closeup, increase scene scale
-                       camera->scale = 2;
-               }
-       }
-
-
-
-
-       if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-
-
-
-// Render scene graph
-       scene.render(frame, file->cpus);
-               
-               
-               
-       if(debug) printf("FileScene::read_frame %d\n", __LINE__);
-
-
-       return 0;
-}
-
-
-int FileScene::read_samples(double *buffer, int64_t len)
-{
-// Speech rendering
-// Everything is timed based on speech, so we have to do this for video, too.
-       render_chunks(file->current_sample, len, 0);
-
-//     script->dump();
-
-
-// Convert temp to output
-       for(int i = 0; i < len; i++)
-       {
-               buffer[i] = (double)audio_temp[i] / 32768;
-       }
-
-       return 0;
-}
-
-
-int64_t FileScene::get_memory_usage()
-{
-//PRINT_TRACE
-       int total = 0x100000;
-       if(script)
-       {
-               total += script->get_memory_usage();
-               
-       }
-//PRINT_TRACE
-       return total;
-}
-
-
-
-int FileScene::get_best_colormodel(Asset *asset, int driver)
-{
-       return 0;
-}
-
-
-int FileScene::colormodel_supported(int colormodel)
-{
-       return BC_RGBA8888;
-}
-
-
-int FileScene::can_copy_from(Asset *asset, int64_t position)
-{
-       return 0;
-}
-
-
-int FileScene::reset_parameters_derived()
-{
-       script = 0;
-       audio_temp = 0;
-       temp_allocated = 0;
-//     overlayer = 0;
-//     affine = 0;
-       return 0;
-}
-
-
-
-void FileScene::render_chunks(int64_t start_position, 
-       int64_t len, 
-       int all_channels)
-{
-       int64_t end_position = start_position + len;
-       const int debug = 0;
-
-
-       if(debug) printf("FileScene::render_chunks %d start_position="
-               _LD " len=" _LD "\n", __LINE__, start_position, len);
-
-// Update script
-       read_script();
-
-       if(!script) return;
-
-       if(debug) PRINT_TRACE
-
-// Reallocate temp buffer
-       if(len > temp_allocated)
-       {
-               delete [] audio_temp;
-               audio_temp = new int16_t[len];
-               temp_allocated = len;
-       }
-       bzero(audio_temp, sizeof(int16_t) * len);
-
-       if(debug) PRINT_TRACE
-
-
-
-
-// Find start_position in script output.
-// Must know length of every chunk before end of buffer
-       int64_t current_sample = 0;
-       for(int i = 0; i < script->total_chunks() &&
-               current_sample < end_position; i++)
-       {
-               SceneChunk *chunk = script->get_chunk(i);
-               chunk->used = 0;
-               if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
-
-// If extent of audio output hasn't been calculated, render it
-               if(!chunk->audio_size)
-               {
-                       if(debug) printf("FileScene::render_chunks %d i=%d\n", __LINE__, i);
-                       chunk->render();
-               }
-
-// Dialog chunk is inside output buffer
-               if(current_sample + chunk->audio_size / 2 > start_position &&
-                       current_sample < end_position)
-               {
-                       if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
-
-// If no audio output exists, render it
-                       if(!chunk->audio)
-                       {
-                               if(debug) printf("FileScene::render_chunks %d rerendering audio\n", __LINE__);
-                               chunk->render();
-                       }
-
-                       if(debug) printf("FileScene::render_chunks %d: Using \"%s\" samples=%d\n",
-                               __LINE__,
-                               chunk->text,
-                               chunk->audio_size / 2);
-                       if(debug) printf("FileScene::render_chunks %d: start_position="
-                                       _LD " current_sample=" _LD "\n", __LINE__,
-                                       start_position, current_sample);
-
-// Memcpy it.
-// TODO: allow characters to talk simultaneously
-                       int64_t src_offset = start_position - current_sample;
-                       int64_t dst_offset = 0;
-                       int64_t src_len = chunk->audio_size / 2 - src_offset;
-
-                       if(debug) printf("FileScene::render_chunks %d: src_offset="
-                               _LD " dst_offset=" _LD " src_len=" _LD "\n", __LINE__,
-                               src_offset, dst_offset, src_len);
-
-                       if(src_offset < 0)
-                       {
-                               dst_offset -= src_offset;
-                               src_len += src_offset;
-                               src_offset = 0;
-                       }
-
-                       if(dst_offset + src_len > len)
-                       {
-                               src_len = len - dst_offset;
-                       }
-
-                       if(debug) printf("FileScene::render_chunks %d: src_offset="
-                               _LD " dst_offset=" _LD " src_len=" _LD "\n", __LINE__,
-                               src_offset, dst_offset, src_len);
-
-// Transfer if right channel
-                       if(all_channels || 
-                               file->current_channel == script->get_char_number(chunk->character))
-                       {
-                               for(int j = 0; j < src_len; j++)
-                               {
-                                       audio_temp[dst_offset + j] = 
-                                               chunk->audio[(src_offset + j) * 2] | 
-                                               (chunk->audio[(src_offset + j) * 2 + 1] << 8);
-                               }
-                       }
-
-                       if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
-                       chunk->used = 1;
-               }
-
-               current_sample += chunk->advance_samples;
-       }
-
-// Erase unused dialog chunks
-       if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
-       for(int i = 0; i < script->total_chunks(); i++)
-       {
-               SceneChunk *chunk = script->get_chunk(i);
-               if(!chunk->used && chunk->audio)
-               {
-                       if(debug) printf("FileScene::render_chunks %d erasing unused audio\n", __LINE__);
-                       delete [] chunk->audio;
-                       chunk->audio = 0;
-                       chunk->audio_allocated = 0;
-               }
-       }
-       if(debug) printf("FileScene::render_chunks %d\n", __LINE__);
-       
-       
-}
-
-
-
-int FileScene::read_script()
-{
-       const int debug = 0;
-       struct stat ostat;
-       if(stat(asset->path, &ostat))
-       {
-               printf("FileScene::read_script %d: %s\n", __LINE__, strerror(errno));
-               return 1;
-       }
-
-// Test timestamp
-       if(script)
-       {
-               if(ostat.st_mtime == script->timestamp)
-               {
-                       if(debug) printf("FileScene::read_script %d: script unchanged\n", __LINE__);
-                       return 0;
-               }
-       }
-
-
-// Read new script
-       delete script;
-       script = 0;
-       if(!script) script = new SceneTokens(this, file->cpus);
-       script->timestamp = ostat.st_mtime;
-
-       script->read_script(asset->path);
-
-       return 1;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-SceneChar::SceneChar(SceneTokens *script)
-{
-       this->script = script;
-       name[0] = 0;
-       voice[0] = 0;
-       body = 0;
-       head = 0;
-       body_order = 0;
-       head_order = 1;
-       sprintf(model, "heroine01");
-       current_camera = CAMERA_WIDE;
-       faces_left = 0;
-       scale = 1;
-       max = 0;
-       is_speeking = 0;
-}
-
-SceneChar::~SceneChar()
-{
-       mouths.remove_all_objects();
-       eyes.remove_all_objects();
-       delete body;
-       delete head;
-}
-
-
-void SceneChar::increment_camera()
-{
-       current_camera++;
-       if(current_camera >= CAMERA_TOTAL) 
-               current_camera = 0;
-}
-
-
-int SceneChar::read_model()
-{
-// Read descriptor file
-       const int debug = 0;
-       int current_line = 0;
-       float x, y;
-       int i;
-       int current_order = 0;
-       char path[BCTEXTLEN];
-
-// Already read it
-       if(body) return 0;
-
-       script->convert_path(path, model);
-       FILE *fd = fopen(path, "r");
-       
-
-// Read assets
-       if(fd)
-       {
-// Read 1 line
-               char string[BCTEXTLEN];
-               char string2[BCTEXTLEN];
-
-               while(!feof(fd))
-               {
-                       char *result = fgets(string, BCTEXTLEN, fd);
-                       
-                       if(result)
-                       {
-                               int len = strlen(string);
-
-                               STRIP_LINE(string);
-
-                               if(debug) printf("SceneChar::read_model %d: %s\n", 
-                                       __LINE__, 
-                                       string);
-                       
-                               for(i = 0; i < len; i++)
-                               {
-                                       if(isalnum(string[i]))
-                                       {
-                                               string2[0] = 0;
-                                               
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "width:", 
-                                                       0, 
-                                                       &w, 
-                                                       0, 
-                                                       0))
-                                               {
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "height:", 
-                                                       0, 
-                                                       &h, 
-                                                       0, 
-                                                       0))
-                                               {
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "body:", 
-                                                       string2, 
-                                                       0, 
-                                                       &x, 
-                                                       &y))
-                                               {
-// Load image
-                                                       body = new SceneNode(script->load_image(string2), 1, x, y);
-                                                       body_order = current_order++;
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "head:", 
-                                                       string2, 
-                                                       0, 
-                                                       &x, 
-                                                       &y))
-                                               {
-// Load image
-                                                       head = new SceneNode(script->load_image(string2), 1, x, y);
-                                                       head_order = current_order++;
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "mouth:", 
-                                                       string2, 
-                                                       0, 
-                                                       &x, 
-                                                       &y))
-                                               {
-// Load image
-                                                       SceneNode *mouth;
-                                                       mouths.append(mouth = new SceneNode(script->load_image(string2), 1, x, y));
-// Make coordinates relative to head
-                                                       if(head)
-                                                       {
-                                                               mouth->x -= head->x;
-                                                               mouth->y -= head->y;
-                                                       }
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "eyes:", 
-                                                       string2, 
-                                                       0, 
-                                                       &x, 
-                                                       &y))
-                                               {
-// Load image
-                                                       SceneNode *eye;
-                                                       eyes.append(eye = new SceneNode(script->load_image(string2), 1, x, y));
-// Make coordinates relative to head
-                                                       if(head)
-                                                       {
-                                                               eye->x -= head->x;
-                                                               eye->y -= head->y;
-                                                       }
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "faces_left", 
-                                                       0, 
-                                                       0, 
-                                                       0, 
-                                                       0))
-                                               {
-                                                       faces_left = 1;
-                                               }
-                                               else
-                                               if(read_parameter(string,
-                                                       &i,
-                                                       "scale:", 
-                                                       0, 
-                                                       &scale, 
-                                                       0, 
-                                                       0))
-                                               {
-                                               }
-                                               
-                                               i = len;
-                                       }
-                               }
-                       }
-                       
-                       current_line++;
-               }
-               
-               fclose(fd);
-               if(debug) dump();
-               return 0;
-       }
-       
-       printf("SceneChar::read_model %d: %s %s\n", __LINE__, path, strerror(errno));
-       return 1;
-}
-
-int SceneChar::get_memory_usage()
-{
-       int total = 0;
-       if(body) total += body->get_memory_usage();
-       if(head) total += head->get_memory_usage();
-       for(int i = 0; i < mouths.size(); i++)
-               total += mouths.get(i)->get_memory_usage();
-       return total;
-}
-
-void SceneChar::dump()
-{
-       printf("SceneChar::dump %d: %p name=%s voice=%s model=%s body=%p eyes=%d mouths=%d\n", 
-               __LINE__, 
-               this,
-               name, 
-               voice, 
-               model,
-               body,
-               eyes.size(),
-               mouths.size());
-       printf("SceneChar::dump %d: w=%f h=%f\n", __LINE__, w, h);
-
-
-       for(int i = 0; i < mouths.size(); i++)
-       {
-               SceneNode *node = mouths.get(i);
-               printf("    mouth=%p x=%f y=%f\n", node, node->x, node->y);
-       }
-
-       for(int i = 0; i < eyes.size(); i++)
-       {
-               SceneNode *node = eyes.get(i);
-               printf("    eyes=%p x=%f y=%f\n", node, node->x, node->y);
-       }
-}
-
-
-
-
-
-
-
-
-
-// Dialog from a single character
-SceneChunk::SceneChunk(SceneTokens *script)
-{
-       text = 0;
-       character = 0;
-       audio = 0;
-       audio_size = 0;
-       audio_allocated = 0;
-       advance_samples = 0;
-       used = 0;
-       max = 0;
-       command = NO_COMMAND;
-       this->script = script;
-}
-
-SceneChunk::~SceneChunk()
-{
-       delete [] text;
-       delete [] audio;
-}
-
-void SceneChunk::dump()
-{
-       printf("SceneChunk::dump %d: character=%s command=%d text=%s\n", 
-               __LINE__, 
-               character->name,
-               command,
-               text);
-       printf("SceneChunk::dump %d: audio=%p audio_size=%d advance_samples=%d\n",
-               __LINE__,
-               audio,
-               audio_size,
-               advance_samples);
-}
-
-int SceneChunk::get_memory_usage()
-{
-       return audio_allocated;
-}
-
-
-void SceneChunk::append_text(char *new_text)
-{
-       char string[BCTEXTLEN];
-
-// Replace "
-// Convert ' to \'
-       char *ptr = string;
-       int len = strlen(new_text);
-       for(int i = 0; i < len; i++)
-       {
-//             if(new_text[i] == '"')
-//                     *ptr++ = ' ';
-//             else
-//             if(new_text[i] == '\'')
-//             {
-//                     *ptr++ = '\\';
-//                     *ptr++ = '\'';
-//                     *ptr++ = '\'';
-//             }
-//             else
-                       *ptr++ = new_text[i];
-       }
-       *ptr++ = 0;
-       
-       int len2 = strlen(string);
-       if(text)
-       {
-               int len1 = strlen(text);
-               int len3 = 1;
-               int need_space = 0;
-
-//             if(len1 > 0 && isalnum(text[len1 - 1]))
-               if(len1 > 0 && text[len1 - 1] != ' ')
-               {
-                       need_space = 1;
-                       len3++;
-               }
-
-               text = (char*)realloc(text, len1 + len2 + len3);
-
-// Append space
-               if(need_space)
-               {
-                       text[len1] = ' ';
-                       text[len1 + 1] = 0;
-               }
-       }
-       else
-       {
-               text = new char[len2 + 1];
-               text[0] = 0;
-       }
-
-       strcat(text, string);
-}
-
-
-
-
-void SceneChunk::render()
-{
-       const int debug = 0;
-       int len = 0;
-       char command_line[BCTEXTLEN];
-       char string2[MAX_CHARS];
-       char script_path[BCTEXTLEN];
-       
-       //int total_args = 0;
-       if(text) len = strlen(text);
-       char *text_end = text + len;
-       char *text_ptr = text;
-
-       audio_size = 0;
-
-       if(!character)
-       {
-               printf("SceneChunk::render %d: no character defined.\n", __LINE__);
-       }
-       
-       if(len > MAX_CHARS)
-       {
-               printf("SceneChunk::render %d: text '%s' exceeds festival's maximum line length of %d chars.\n",
-                       __LINE__,
-                       text,
-                       MAX_CHARS);
-       }
-
-// Process command
-       switch(command)
-       {
-               case SceneChunk::PAUSE_COMMAND:
-                       audio_allocated = PAUSE_SAMPLES * 2;
-                       audio_size = PAUSE_SAMPLES * 2;
-                       advance_samples = PAUSE_SAMPLES;
-                       audio = (unsigned char*)realloc(audio, audio_allocated);
-                       bzero(audio, audio_size);
-                       max = 0;
-                       break;
-       }
-
-       while(text && text_ptr < text_end)
-       {
-// Copy at most MAX_CHARS of data into string2
-               char *ptr = string2;
-               for(int i = 0; i < MAX_CHARS && text_ptr < text_end; i++)
-               {
-                       *ptr++ = *text_ptr++;
-               }
-               *ptr++ = 0;
-
-
-// Rewind to white space if still more text
-               if(text_ptr < text_end)
-               {
-                       ptr--;
-                       text_ptr--;
-                       while(*text_ptr != ' ' && 
-                               *text_ptr != '\n' && 
-                               text_ptr > text)
-                       {
-                               text_ptr--;
-                               ptr--;
-                       }
-
-
-// Truncate string2 at white space
-                       *ptr = 0;
-// If no white space, abort.
-                       if(text_ptr <= text)
-                       {
-                               break;
-                       }
-
-               }
-
-               uuid_t temp_id;
-               sprintf(script_path, "/tmp/cinelerra.");
-               uuid_generate(temp_id);
-               uuid_unparse(temp_id, script_path + strlen(script_path));
-               FILE *script_fd = fopen(script_path, "w");
-
-               sprintf(command_line, "%s%s --libdir %s%s -b %s", 
-                       script->file->exe_path,
-                       FESTIVAL_PATH,
-                       script->file->exe_path,
-                       FESTIVAL_LIB_PATH,
-                       script_path);
-
-// Create script.
-// The maximum text length is limited with the command line
-
-               fprintf(script_fd, 
-                       "(voice_%s)\n"
-                       "(set! text (Utterance Text \"%s\"))\n"
-                       "(utt.synth text)"
-                       "(utt.save.wave text \"-\")",
-                       character->voice,
-                       string2);
-               fclose(script_fd);
-
-
-               if(debug)
-               {
-                       printf("SceneChunk::render %d %s\n", 
-                               __LINE__,
-                               command_line);
-                       
-                       FILE *script_fd = fopen(script_path, "r");
-                       while(!feof(script_fd))
-                               fputc(fgetc(script_fd), stdout);
-                       printf("\n");
-                       fclose(script_fd);
-               }
-
-// popen only does half duplex
-               FILE *fd = popen(command_line, "r");
-
-// Capture output
-               if(fd)
-               {
-                       int audio_start = audio_size;
-
-               
-                       if(debug) printf("SceneChunk::render %d\n", 
-                               __LINE__);
-                       while(!feof(fd))
-                       {
-                               if(debug) printf("SceneChunk::render %d\n", 
-                                       __LINE__);
-                               if(audio_size + FREAD_SIZE > audio_allocated)
-                               {
-                                       audio_allocated += FREAD_SIZE;
-                                       audio = (unsigned char*)realloc(audio, audio_allocated);
-                               }
-
-
-                               if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d\n", 
-                                       __LINE__,
-                                       audio,
-                                       audio_size);
-
-                               int bytes_read = fread(audio + audio_size, 1, FREAD_SIZE, fd);
-                               if(debug) printf("SceneChunk::render %d bytes_read=%d\n", 
-                                       __LINE__,
-                                       bytes_read);
-                               audio_size += bytes_read;
-                               if(bytes_read < FREAD_SIZE)
-                               {
-                                       break;
-                               }
-                       }
-
-
-                       pclose(fd);
-
-                       if(debug) printf("SceneChunk::render %d audio=%p audio_size=%d audio_allocated=%d\n", 
-                               __LINE__,
-                               audio,
-                               audio_size,
-                               audio_allocated);
-
-// Strip WAV header
-
-                       if(audio_size - audio_start > WAVHEADER)
-                       {
-// for(int i = 0; i < 128; i++)
-// {
-// printf("%c ", audio[audio_start + i]);
-// if(!((i + 1) % 16)) printf("\n");
-// }
-// printf("\n");
-// Find header after error messages
-                               int header_size = WAVHEADER;
-                               for(int i = audio_start; i < audio_start + audio_size - 4; i++)
-                               {
-                                       if(audio[i] == 'R' &&
-                                               audio[i + 1] == 'I' &&
-                                               audio[i + 2] == 'F' &&
-                                               audio[i + 3] == 'F')
-                                       {
-                                               header_size += i - audio_start;
-                                               break;
-                                       }
-                               }
-
-                               memcpy(audio + audio_start, 
-                                       audio + audio_start + header_size, 
-                                       audio_size - audio_start - header_size);
-                               audio_size -= header_size;
-                               if(debug) printf("SceneChunk::render %d: audio_size=%d\n",
-                                       __LINE__,
-                                       audio_size);
-                       }
-                       
-                       advance_samples = audio_size / 2;
-               }
-               else
-               {
-                       printf("SceneChunk::render %d: Couldn't run %s: %s\n",
-                               __LINE__,
-                               command_line,
-                               strerror(errno));
-               }
-
-               remove(script_path);
-               if(debug) printf("SceneChunk::render %d max=%f\n", 
-                       __LINE__,
-                       max);
-       }
-
-
-       if(text)
-       {
-
-// Truncate if ...
-               text_ptr = text + len - 1;
-               while(text_ptr > text && 
-                       (*text_ptr == ' ' ||
-                       *text_ptr == '\n'))
-                       text_ptr--;
-               if(text_ptr > text + 3 &&
-                       *(text_ptr - 0) == '.' &&
-                       *(text_ptr - 1) == '.' &&
-                       *(text_ptr - 2) == '.')
-               {
-                       advance_samples -= ADVANCE_SAMPLES;
-                       if(advance_samples < 0) advance_samples = 0;
-               }
-
-// Calculate loudest part
-               max = 0;
-               for(int i = 0; i < audio_size; i += 2)
-               {
-                       int16_t sample = audio[i] |
-                               (audio[i + 1] << 8);
-                       double sample_float = fabs((double)sample / 32768);
-                       if(sample_float > max) max = sample_float;
-               }
-       }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-SceneTokens::SceneTokens(FileScene *file, int cpus)
-{
-       background[0] = 0;
-       background_image = 0;
-       timestamp = 0;
-       this->cpus = cpus;
-       this->file = file;
-//     overlayer = 0;
-}
-
-SceneTokens::~SceneTokens()
-{
-       chunks.remove_all_objects();
-       characters.remove_all_objects();
-       delete background_image;
-//     delete overlayer;
-}
-
-SceneChar* SceneTokens::get_character(char *name)
-{
-       const int debug = 0;
-       if(debug) printf("SceneTokens::get_character %d %d\n",
-               __LINE__,
-               characters.size());
-
-       for(int i = 0; i < characters.size(); i++)
-       {
-               if(!strcmp(characters.get(i)->name, name)) return characters.get(i);
-       }
-       if(debug) printf("SceneTokens::get_character %d %d\n",
-               __LINE__,
-               characters.size());
-       
-       SceneChar *result = new SceneChar(this);
-       if(debug) printf("SceneTokens::get_character %d %d this=%p\n",
-               __LINE__,
-               characters.size(),
-               &characters);
-
-       characters.append(result);
-       if(debug) printf("SceneTokens::get_character %d %d\n",
-               __LINE__,
-               characters.size());
-
-       strcpy(result->name, name);
-       if(debug) printf("SceneTokens::get_character %d %d\n",
-               __LINE__,
-               characters.size());
-
-       if(debug) printf("SceneTokens::get_character %d %d\n",
-               __LINE__,
-               characters.size());
-
-       return result;
-}
-
-SceneChar* SceneTokens::get_character(int number)
-{
-       return characters.get(number);
-}
-
-int SceneTokens::get_char_number(SceneChar *ptr)
-{
-       for(int i = 0; i < characters.size(); i++)
-               if(ptr == characters.get(i)) return i;
-       return 0;
-}
-
-SceneChunk* SceneTokens::new_chunk()
-{
-       SceneChunk *result = new SceneChunk(this);
-       chunks.append(result);
-       return result;
-}
-
-int SceneTokens::total_chunks()
-{
-       return chunks.size();
-}
-
-int SceneTokens::total_characters()
-{
-       return characters.size();
-}
-
-SceneChunk* SceneTokens::get_chunk(int number)
-{
-       return chunks.get(number);
-}
-
-int SceneTokens::read_script(char *path)
-{
-       const int debug = 0;
-
-       strcpy(this->path, path);
-
-       FILE *fd = fopen(path, "r");
-       if(fd)
-       {
-// Read 1 line
-               char string[BCTEXTLEN];
-// Current character name
-               char char_name[BCTEXTLEN];
-               SceneChar *current_char = 0;
-               char_name[0] = 0;
-               SceneChunk *current_chunk = 0;
-               int current_line = 0;
-               int i;
-
-               while(!feof(fd))
-               {
-                       char *result = fgets(string, BCTEXTLEN, fd);
-                       current_line++;
-
-                       if(result)
-                       {
-                               int len = strlen(string);
-                               STRIP_LINE(string)
-
-                               if(debug) printf("SceneTokens::read_script %d: %s\n", 
-                                       __LINE__, 
-                                       string);
-
-// Skip the file ID & empty lines
-                               if(string[0] == 0 ||
-                                       !strncmp(string, "TEXT2MOVIE", 10))
-                                       continue;
-
-                               int got_it = 0;
-                               for(i = 0; i < len; i++)
-                               {
-                                       if(isalnum(string[i]))
-                                       {
-                                               got_it = 1;
-                                               i = len;
-                                       }
-                               }
-
-                               if(!got_it) continue;
-
-// A line all in caps is a character name
-                               got_it = 1;
-                               for(i = 0; i < len; i++)
-                               {
-                                       if(islower(string[i]))
-                                       {
-                                               got_it = 0;
-                                               i = len;
-                                       }
-                               }
-
-                               if(got_it)
-                               {
-                                       strcpy(char_name, string);
-
-                                       if(debug) printf("SceneTokens::read_script %d: char_name=%s\n", 
-                                               __LINE__, 
-                                               char_name);
-
-                                       current_char = get_character(char_name);
-
-                                       if(debug) printf("SceneTokens::read_script %d current_char=%p\n", 
-                                               __LINE__, 
-                                               current_char);
-
-// Reset the current chunk pointer
-                                       current_chunk = 0;
-                                       i = len;
-                               }
-                               else
-                                       i = 0;
-
-// Certain words are commands
-                               for(; i < len; i++)
-                               {
-                                       if(string[i] == '[' || isalnum(string[i]))
-                                       {
-                                               char *command = string + i;
-
-                                               STRING_PARAMETER("voice:", 1, current_char->voice)
-                                               else
-                                               STRING_PARAMETER("model:", 1, current_char->model)
-                                               else
-                                               STRING_PARAMETER("background:", 0, background)
-                                               else
-// Default is dialogue
-                                               {
-                                                       if(!current_char)
-                                                       {
-                                                               printf("SceneTokens::read_script %d Line %d: dialogue text but no current character\n", 
-                                                                       __LINE__,
-                                                                       current_line);
-                                                       }
-                                                       else
-                                                       {
-                                                               if(!current_chunk)
-                                                               {
-                                                                       current_chunk = new_chunk();
-                                                                       current_chunk->character = current_char;
-                                                               }
-
-// Append dialogue to current chunk
-                                                               current_chunk->append_text(string + i);
-                                                       }
-                                                       
-                                                       i = len;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               
-               
-               
-               fclose(fd);
-
-               if(debug) printf("SceneTokens::read_script %d total_chunks=%d\n", 
-                       __LINE__,
-                       total_chunks());
-// Parse commands in dialogue
-               for(i = 0; i < total_chunks(); i++)
-               {
-                       SceneChunk *chunk = get_chunk(i);
-                       if(chunk->text)
-                       {
-                               char *ptr = chunk->text;
-                               char *end = chunk->text + strlen(chunk->text);
-                               int got_text = 0;
-                               if(debug) printf("SceneTokens::read_script %d %s\n", __LINE__, chunk->text);
-                               while(ptr < end)
-                               {
-// Start of command
-                                       if(*ptr == '[')
-                                       {
-                                               if(debug) printf("SceneTokens::read_script %d [\n", __LINE__);
-// Split chunk
-                                               if(got_text)
-                                               {
-                                                       SceneChunk *new_chunk = new SceneChunk(this);
-                                                       new_chunk->character = chunk->character;
-                                                       chunks.insert(new_chunk, i + 1);
-                                                       
-// Move text from start of command to new chunk.
-                                                       new_chunk->append_text(ptr);
-// Truncate current chunk
-                                                       *ptr = 0;
-// Advance to next chunk
-                                                       ptr = new_chunk->text;
-                                                       end = new_chunk->text + strlen(new_chunk->text);
-                                                       chunk = new_chunk;
-                                                       i++;
-                                               }
-                                               if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
-
-// Read command
-                                               while(ptr < end && 
-                                                       (*ptr == '[' || *ptr == ' ' || *ptr == '\n')) 
-                                                       ptr++;
-
-                                               if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
-
-                                               char *ptr2 = string;
-                                               char *string_end = string + BCTEXTLEN;
-                                               while(*ptr != ']' && 
-                                                       *ptr != ' ' &&
-                                                       *ptr != '\n' &&
-                                                       ptr < end && 
-                                                       ptr2 < string_end - 1)
-                                               {
-                                                       *ptr2++ = *ptr++;
-                                               }
-                                               *ptr2 = 0;
-                                               if(debug) printf("SceneTokens::read_script %d command=%s\n", __LINE__, string);
-
-// Convert command to code
-                                               if(!strcasecmp(string, "pause"))
-                                               {
-                                                       chunk->command = SceneChunk::PAUSE_COMMAND;
-                                               }
-                                               else
-                                               {
-// TODO: line numbers
-                                                       printf("SceneTokens::read_script %d: Unknown command '%s'\n", 
-                                                               __LINE__, 
-                                                               string);
-                                               }
-                                               if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
-
-// Search for more text
-                                               while(ptr < end && 
-                                                       (*ptr == ']' || *ptr == ' ' || *ptr == '\n')) 
-                                                       ptr++;
-
-// Create new chunk for rest of text
-                                               if(ptr < end)
-                                               {
-                                                       SceneChunk *new_chunk = new SceneChunk(this);
-                                                       new_chunk->character = chunk->character;
-                                                       chunks.insert(new_chunk, i + 1);
-// Move text from end of command to new chunk.
-                                                       new_chunk->append_text(ptr);
-// Parse next chunk in next iteration
-                                                       ptr = end;
-//                                                     i++;
-                                               }
-                                               if(debug) printf("SceneTokens::read_script %d\n", __LINE__);
-
-// Truncate current chunk
-                                               chunk->text[0] = 0;
-                                       }
-                                       else
-// Got non whitespace
-                                       if(*ptr != ' ' &&
-                                               *ptr != '\n')
-                                       {
-                                               got_text = 1;
-                                       }
-
-                                       ptr++;
-                               }
-                       }
-               }
-               
-               
-               if(debug) dump();
-               return 0;
-       }
-
-       printf("SceneTokens::read_script %d: %s %s\n", __LINE__, path, strerror(errno));
-       return 1;
-}
-
-void SceneTokens::convert_path(char *dst, char *src)
-{
-// Absolute path in src
-       if(src[0] == '/')
-       {
-               strcpy(dst, src);
-       }
-       else
-// Relative path
-       {
-// Try directory of script
-               FileSystem fs;
-               fs.extract_dir(dst, path);
-               strcat(dst, src);
-               
-               struct stat ostat;
-               if(stat(dst, &ostat))
-               {
-// Try cinelerra directory
-                       get_exe_path(dst);
-                       strcat(dst, ASSET_PATH);
-                       strcat(dst, src);
-//printf("SceneTokens::convert_path %d %s\n", __LINE__, dst);
-               }
-       }
-}
-
-VFrame* SceneTokens::load_image(char *path)
-{
-       VFrame *result = 0;
-       char complete_path[BCTEXTLEN];
-       convert_path(complete_path, path);
-
-       int64_t size = FileSystem::get_size(complete_path);
-       if(!size)
-       {
-               printf("SceneTokens::load_image %d: Couldn't open %s\n",
-                       __LINE__,
-                       complete_path);
-               return 0;
-       }
-
-       unsigned char *data = new unsigned char[size + 4];
-       FILE *fd = fopen(complete_path, "r");
-       (void)fread(data + 4, 1, size, fd);
-       data[0] = (size >> 24) & 0xff;
-       data[1] = (size >> 16) & 0xff;
-       data[2] = (size >> 8) & 0xff;
-       data[3] = size & 0xff;
-       result = new VFramePng(data, 1.);
-       delete [] data;
-
-
-       if(!BC_CModels::has_alpha(result->get_color_model()) )
-               printf("SceneTokens::load_image %d: image %s has no alpha channel\n", 
-                       __LINE__,
-                       path);
-       return result;
-}
-
-void SceneTokens::render_background(SceneGraph *scene)
-{
-// Decompress background image
-       if(!background_image)
-       {
-               background_image = load_image(background);
-       }
-       
-       if(background_image)
-       {
-               SceneNode *node = new SceneNode("background");
-               scene->append(node);
-               node->image = background_image;
-               node->x = 0;
-               node->y = 0;
-               node->sx = 1;
-               node->sy = 1;
-       }
-}
-
-int SceneTokens::get_memory_usage()
-{
-       int total = 0;
-       if(background_image) total += background_image->get_memory_usage();
-       for(int i = 0; i < total_chunks(); i++)
-       {
-               total += get_chunk(i)->get_memory_usage();
-       }
-       for(int i = 0; i < total_characters(); i++)
-       {
-               total += get_character(i)->get_memory_usage();
-       }
-       return total;
-}
-
-
-void SceneTokens::dump()
-{
-       printf("SceneTokens::dump %d background=%s\n", __LINE__, background);
-       for(int i = 0; i < characters.size(); i++)
-       {
-               characters.get(i)->dump();
-       }
-
-       
-       for(int i = 0; i < chunks.size(); i++)
-       {
-               chunks.get(i)->dump();
-       }
-}
-
-
-
-