Ejemplo n.º 1
0
	surface& operator=(surface&& s)
	{
		free_surface();
		surface_ = s.surface_;
		s.surface_ = nullptr;
		return *this;
	}
Ejemplo n.º 2
0
void free_ri_surface(struct ris_t *ris)
{
	free_string(ris->filename);
	free_surface(ris->surface);
	
	LL_REMOVE(struct ris_t, &ris0, ris);
}
Ejemplo n.º 3
0
static GstFlowReturn
gst_msdkdec_finish_task (GstMsdkDec * thiz, MsdkDecTask * task)
{
  GstVideoDecoder *decoder = GST_VIDEO_DECODER (thiz);
  GstFlowReturn flow;
  GstVideoCodecFrame *frame;
  MsdkSurface *surface;
  mfxStatus status;
  GList *l;

  if (G_LIKELY (task->sync_point)) {
    status =
        MFXVideoCORE_SyncOperation (gst_msdk_context_get_session
        (thiz->context), task->sync_point, 300000);
    if (status != MFX_ERR_NONE) {
      GST_ERROR_OBJECT (thiz, "failed to do sync operation");
      return GST_FLOW_ERROR;
    }
  }

  if (G_LIKELY (task->sync_point || (task->surface && task->decode_only))) {
    gboolean decode_only = task->decode_only;

    frame = gst_msdkdec_get_oldest_frame (decoder);

    l = g_list_find_custom (thiz->decoded_msdk_surfaces, task->surface,
        _find_msdk_surface);
    if (l) {
      surface = l->data;
    } else {
      GST_ERROR_OBJECT (thiz, "Couldn't find the cached MSDK surface");
      return GST_FLOW_ERROR;
    }

    if (G_LIKELY (frame)) {
      if (G_LIKELY (surface->copy.buffer == NULL)) {
        frame->output_buffer = gst_buffer_ref (surface->buf);
      } else {
        gst_video_frame_copy (&surface->copy, &surface->data);
        frame->output_buffer = gst_buffer_ref (surface->copy.buffer);
      }
    }

    free_surface (thiz, surface);
    task->sync_point = NULL;
    task->surface = NULL;
    task->decode_only = FALSE;

    if (!frame)
      return GST_FLOW_FLUSHING;
    gst_video_codec_frame_unref (frame);

    if (decode_only)
      GST_VIDEO_CODEC_FRAME_SET_DECODE_ONLY (frame);
    flow = gst_video_decoder_finish_frame (decoder, frame);
    return flow;
  }
  return GST_FLOW_OK;
}
Ejemplo n.º 4
0
void set_ri_surface_multiplier(float m)
{
	ris_multiplier = m;
	
	struct ris_t *cris = ris0;
		
	while(cris)
	{
		free_surface(cris->surface);
		
		struct surface_t *temp = read_png_surface(cris->filename->text);
		
		cris->surface = resize(temp, temp->width * ris_multiplier, temp->height * ris_multiplier);
		
		free_surface(temp);		
		
		cris = cris->next;
	}
}
Ejemplo n.º 5
0
void kill_ris()
{
	while(ris0)
	{
		free_string(ris0->filename);
		free_surface(ris0->surface);
		
		LL_REMOVE(struct ris_t, &ris0, ris0);
	}
}
Ejemplo n.º 6
0
static void
release_msdk_surfaces (GstMsdkDec * thiz)
{
  GList *l;
  MsdkSurface *surface;

  for (l = thiz->decoded_msdk_surfaces; l; l = l->next) {
    surface = l->data;
    free_surface (thiz, surface);
  }
}
Ejemplo n.º 7
0
// seg001:0C94
void __pascal far expired() {
	if (!demo_mode) {
		if(offscreen_surface) free_surface(offscreen_surface); // missing in original
		offscreen_surface = NULL;
		clear_screen_and_sounds();
		offscreen_surface = make_offscreen_buffer(&screen_rect);
		load_intro(1, &time_expired, 1);
	}
	start_level = 0;
	start_game();
}
Ejemplo n.º 8
0
struct surface_t *leave_main_lock_and_resize_surface(struct surface_t *in_surface, 
	int width, int height)
{
	struct surface_t *duplicate, *resized;
	
	duplicate = duplicate_surface(in_surface);
	
	leave_main_lock();
	
	resized = resize(duplicate, width, height);
	free_surface(duplicate);
	return resized;
}
Ejemplo n.º 9
0
struct surface_t *leave_main_lock_and_rotate_surface(struct surface_t *in_surface, 
	int scale_width, int scale_height, double theta)
{
	struct surface_t *duplicate, *rotated;
	
	duplicate = duplicate_surface(in_surface);
	
	leave_main_lock();
	
	rotated = rotate_surface(duplicate, scale_width, scale_height, theta);
	free_surface(duplicate);
	return rotated;
}
Ejemplo n.º 10
0
void st::_app::sdl_poll::run() {
    SDL_Surface* image = NULL;
    // Could, should this be a member?  Should I just have a
    // standard loop that I can start up.  I'll refactor this
    // soonish.
    bool quit = false;
    initialize_screen( "Event Test" );
    image = load_image( "x.png" );
    apply_surface(0, 0, image);
    flip();
    // Will need to rework event loop somehow...
    start();
    free_surface( image );
}
Ejemplo n.º 11
0
struct ris_t *load_ri_surface(char *filename)
{
	struct ris_t ris;
		
	ris.filename = new_string_text(filename);
	
	struct surface_t *temp = read_png_surface(filename);
	
	
	ris.surface = resize(temp, temp->width * ris_multiplier, temp->height * ris_multiplier);
	
	free_surface(temp);
	
	LL_ADD(struct ris_t, &ris0, &ris);
		
	return ris0;
}
Ejemplo n.º 12
0
void st::_app::lesson4::run() {
    SDL_Surface* image = NULL;
    // Could, should this be a member?  Should I just have a
    // standard loop that I can start up.  I'll refactor this
    // soonish.
    SDL_Event event;
    bool quit = false;
    initialize_screen( "Event Test" );
    image = load_image( "x.png" );
    apply_surface(0, 0, image);
    flip();
    // Will need to rework event loop somehow...
    while ( quit == false ) {
        while ( SDL_PollEvent(&event) ) {
            if ( event.type == SDL_QUIT ) {
                quit = true;
            }
        }
    }
    free_surface( image );
}
Ejemplo n.º 13
0
void free_scene (struct msscene *ms) {
	struct square *squares;
	struct molecule *head_molecule;
	struct surface *head_srf;
	struct material_table *table;
	struct color_ramp *head_ramp;
	struct object_scheme *scheme;
	struct surface *srf, *next_srf;
	struct color_ramp *rmp, *next_rmp;
	struct molecule *mol, *next_mol;

	head_molecule = ms -> head_molecule;
	head_ramp = ms -> head_ramp;
	table = ms -> table;
	squares = ms -> squares;

	for (mol = head_molecule; mol != NULL; mol = next_mol) {
			next_mol = mol -> next;
			head_srf = mol -> head_surface;
			for (srf = head_srf; srf != NULL; srf = next_srf) {
				next_srf = srf -> next;
				scheme = srf -> scheme;
				if (scheme != NULL) {
					if (scheme -> atom_opacities != NULL)
						free_doubles (scheme -> atom_opacities, 0, ATOM_OPACITIES);
					if (scheme -> atom_colors != NULL)
						free_longs (scheme -> atom_colors, 0, ATOM_COLORS);
					free_object (OBJECT_SCHEME, (short *) (srf -> scheme));
					if (error()) return;
				}
				clear_pqms (srf);
				if (error()) return;
				free_surface (srf);
				if (error()) return;
				free_phn (srf);
				if (error()) return;
				free_object (SURFACE, (short *) srf);
				if (error()) return;
			}
			if (mol -> atom_alphas != NULL)
				free_doubles (mol -> atom_alphas, 0, ATOM_ALPHAS);
			free_object (MOLECULE, (short *) mol);
			if (error()) return;
	}
	for (srf = ms -> this_srf; srf != NULL; srf = next_srf) {
		next_srf = srf -> next;
		clear_pqms (srf);
		if (error()) return;
		free_surface (srf);
		if (error()) return;
		free_phn (srf);
		if (error()) return;
		free_object (SURFACE, (short *) srf);
		if (error()) return;
	}
	for (rmp = head_ramp; rmp != NULL; rmp = next_rmp) {
		next_rmp = rmp -> next;
		free_object (COLOR_RAMP, (short *) rmp);
		if (error()) return;
	}
	free_object (MATERIAL_TABLE, (short *) (ms -> table));
	free_object (MSSCENE, (short *) ms);
}
Ejemplo n.º 14
0
// seg001:09D7
void __pascal far end_sequence() {
	peel_type* peel;
	short bgcolor;
	short color;
	rect_type rect;
	short hof_index;
	short i;
	color = 0;
	bgcolor = 15;
	load_intro(1, &end_sequence_anim, 1);
	clear_screen_and_sounds();
	load_opt_sounds(sound_56_ending_music, sound_56_ending_music); // winning theme
	play_sound_from_buffer(sound_pointers[sound_56_ending_music]); // winning theme
	if(offscreen_surface) free_surface(offscreen_surface); // missing in original
	offscreen_surface = make_offscreen_buffer(&screen_rect);
	load_title_images(0);
	current_target_surface = offscreen_surface;
	draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, 0);
	draw_image_2(3 /*The tyrant Jaffar*/, chtab_title40, 24, 25, get_text_color(15, color_15_brightwhite, 0x800));
	fade_in_2(offscreen_surface, 0x800);
	pop_wait(timer_0, 900);
	start_timer(timer_0, 240);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, 0);
	transition_ltr();
	do_wait(timer_0);
	for (hof_index = 0; hof_index < hof_count; ++hof_index) {
		if (hof[hof_index].min < rem_min ||
			(hof[hof_index].min == rem_min && hof[hof_index].tick < rem_tick)
		) break;
	}
	if (hof_index < MAX_HOF_COUNT && hof_index <= hof_count) {
		fade_out_2(0x1000);
		for (i = 5; hof_index + 1 <= i; --i) {
			hof[i] = hof[i - 1];
		}
		hof[i].name[0] = 0;
		hof[i].min = rem_min;
		hof[i].tick = rem_tick;
		if (hof_count < MAX_HOF_COUNT) {
			++hof_count;
		}
		draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, 0);
		draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 24, blitters_10h_transp);
		show_hof();
		offset4_rect_add(&rect, &hof_rects[hof_index], -4, -1, -40, -1);
		peel = read_peel_from_screen(&rect);
		if (graphics_mode == gmMcgaVga) {
			color = 0xBE;
			bgcolor = 0xB7;
		}
		draw_rect(&rect, bgcolor);
		fade_in_2(offscreen_surface, 0x1800);
		current_target_surface = onscreen_surface_;
		while(input_str(&rect, hof[hof_index].name, 24, "", 0, 4, color, bgcolor) <= 0);
		restore_peel(peel);
		show_hof_text(&hof_rects[hof_index], -1, 0, hof[hof_index].name);
		hof_write();
		pop_wait(timer_0, 120);
		current_target_surface = offscreen_surface;
		draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
		transition_ltr();
	}
	while (check_sound_playing() && !key_test_quit()) idle();
	fade_out_2(0x1000);
	start_level = 0;
	start_game();
}
Ejemplo n.º 15
0
static GstFlowReturn
gst_msdkdec_drain (GstVideoDecoder * decoder)
{
  GstMsdkDec *thiz = GST_MSDKDEC (decoder);
  GstFlowReturn flow;
  GstBuffer *buffer;
  MsdkDecTask *task;
  MsdkSurface *surface = NULL;
  mfxSession session;
  mfxStatus status;
  guint i;

  if (!thiz->initialized)
    return GST_FLOW_OK;
  session = gst_msdk_context_get_session (thiz->context);

  for (;;) {
    task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
    if ((flow = gst_msdkdec_finish_task (thiz, task)) != GST_FLOW_OK) {
      if (flow != GST_FLOW_FLUSHING)
        GST_WARNING_OBJECT (decoder,
            "failed to finish the task %p, but keep draining for the remaining frames",
            task);
    }

    if (!surface) {
      flow = allocate_output_buffer (thiz, &buffer);
      if (flow != GST_FLOW_OK)
        return flow;
      surface = get_surface (thiz, buffer);
      if (!surface)
        return GST_FLOW_ERROR;
    }

    status =
        MFXVideoDECODE_DecodeFrameAsync (session, NULL, surface->surface,
        &task->surface, &task->sync_point);
    if (G_LIKELY (status == MFX_ERR_NONE)) {
      thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;

      if (surface->surface->Data.Locked == 0)
        free_surface (thiz, surface);
      surface = NULL;
    } else if (status == MFX_WRN_VIDEO_PARAM_CHANGED) {
      continue;
    } else if (status == MFX_WRN_DEVICE_BUSY) {
      /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
      g_usleep (1000);

      /* If the current surface is still busy, we should do sync oepration
       * then tries to decode again
       */
      thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
    } else if (status == MFX_ERR_MORE_DATA) {
      break;
    } else if (status == MFX_ERR_MORE_SURFACE) {
      surface = NULL;
      continue;
    } else if (status < MFX_ERR_NONE)
      return GST_FLOW_ERROR;
  }
  if (surface)
    free_surface (thiz, surface);

  for (i = 0; i < thiz->tasks->len; i++) {
    task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
    gst_msdkdec_finish_task (thiz, task);
    thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
  }

  release_msdk_surfaces (thiz);

  return GST_FLOW_OK;
}
Ejemplo n.º 16
0
static GstFlowReturn
gst_msdkdec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
{
  GstMsdkDec *thiz = GST_MSDKDEC (decoder);
  GstMsdkDecClass *klass = GST_MSDKDEC_GET_CLASS (thiz);
  GstFlowReturn flow;
  GstBuffer *buffer, *input_buffer = NULL;
  GstVideoInfo alloc_info;
  MsdkDecTask *task = NULL;
  mfxBitstream bitstream;
  MsdkSurface *surface = NULL;
  mfxSession session;
  mfxStatus status;
  GstMapInfo map_info;
  guint i;
  gsize data_size;
  gboolean hard_reset = FALSE;

  /* configure the subclass in order to fill the CodecID field of
   * mfxVideoParam and also to load the PluginID for some of the
   * codecs which is mandatory to invoke the
   * MFXVideoDECODE_DecodeHeader API.
   *
   * For non packetized formats (currently only vc1), there
   * could be headers received as codec_data which are not available
   * instream and in that case subclass implementation will
   * push it to the internal adapter. We invoke the subclass configure
   * well early to make sure the codec_data received has been correctly
   * pushed to the adapter by the subclasses before doing
   * the DecodeHeader() later on
   */
  if (!thiz->initialized || thiz->do_renego) {
    /* Clear the internal adapter in renegotiation for non-packetized
     * formats */
    if (!thiz->is_packetized)
      gst_adapter_clear (thiz->adapter);

    if (!klass->configure || !klass->configure (thiz)) {
      flow = GST_FLOW_OK;
      goto error;
    }
  }

  /* Current frame-codec could be pushed and released before this
   * function ends -- because msdkdec pushes the oldest frame,
   * according its PTS, and it could be this very same frame-codec
   * among others pending frame-codecs.
   *
   * Instead of copying the input data into the mfxBitstream, let's
   * keep an extra reference to frame-codec's input buffer */
  input_buffer = gst_buffer_ref (frame->input_buffer);
  if (!gst_buffer_map (input_buffer, &map_info, GST_MAP_READ)) {
    gst_buffer_unref (input_buffer);
    return GST_FLOW_ERROR;
  }

  memset (&bitstream, 0, sizeof (bitstream));

  if (thiz->is_packetized) {
    /* Packetized stream: We prefer to have a parser as connected upstream
     * element to the decoder */
    bitstream.Data = map_info.data;
    bitstream.DataLength = map_info.size;
    bitstream.MaxLength = map_info.size;
    bitstream.DataFlag = MFX_BITSTREAM_COMPLETE_FRAME;
  } else {
    /* Non packetized streams: eg: vc1 advanced profile with per buffer bdu */
    gst_adapter_push (thiz->adapter, gst_buffer_ref (input_buffer));
    data_size = gst_adapter_available (thiz->adapter);

    bitstream.Data = (mfxU8 *) gst_adapter_map (thiz->adapter, data_size);
    bitstream.DataLength = (mfxU32) data_size;
    bitstream.MaxLength = bitstream.DataLength;
  }
  GST_INFO_OBJECT (thiz,
      "mfxBitStream=> DataLength:%d DataOffset:%d MaxLength:%d",
      bitstream.DataLength, bitstream.DataOffset, bitstream.MaxLength);

  session = gst_msdk_context_get_session (thiz->context);

  if (!thiz->initialized || thiz->do_renego) {

    /* gstreamer caps will not bring all the necessary parameters
     * required for optimal decode configuration. For eg: the required numbers
     * of surfaces to be allocated can be calculated based on H264 SEI header
     * and this information can't be retrieved from the negotiated caps.
     * So instead of introducing the codecparser dependency to parse the headers
     * inside msdk plugin, we simply use the mfx apis to extract header information */
    status = MFXVideoDECODE_DecodeHeader (session, &bitstream, &thiz->param);
    if (status == MFX_ERR_MORE_DATA) {
      flow = GST_FLOW_OK;
      goto done;
    }

    if (!thiz->initialized)
      hard_reset = TRUE;
    else if (thiz->allocation_caps) {
      gst_video_info_from_caps (&alloc_info, thiz->allocation_caps);

      /* Check whether we need complete reset for dynamic resolution change */
      if (thiz->param.mfx.FrameInfo.Width > GST_VIDEO_INFO_WIDTH (&alloc_info)
          || thiz->param.mfx.FrameInfo.Height >
          GST_VIDEO_INFO_HEIGHT (&alloc_info))
        hard_reset = TRUE;
    }

    /* if subclass requested for the force reset */
    if (thiz->force_reset_on_res_change)
      hard_reset = TRUE;

    /* Config changed dynamically and we are going to do a full reset,
     * this will unref the input frame which has the new configuration.
     * Keep a ref to the input_frame to keep it alive */
    if (thiz->initialized && thiz->do_renego)
      gst_video_codec_frame_ref (frame);

    if (!gst_msdkdec_negotiate (thiz, hard_reset)) {
      GST_ELEMENT_ERROR (thiz, CORE, NEGOTIATION,
          ("Could not negotiate the stream"), (NULL));
      flow = GST_FLOW_ERROR;
      goto error;
    }
  }

  for (;;) {
    task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
    flow = gst_msdkdec_finish_task (thiz, task);
    if (flow != GST_FLOW_OK)
      goto error;
    if (!surface) {
      flow = allocate_output_buffer (thiz, &buffer);
      if (flow != GST_FLOW_OK)
        goto error;
      surface = get_surface (thiz, buffer);
      if (!surface) {
        /* Can't get a surface for some reason, finish tasks to see if
           a surface becomes available. */
        for (i = 0; i < thiz->tasks->len - 1; i++) {
          thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
          task = &g_array_index (thiz->tasks, MsdkDecTask, thiz->next_task);
          flow = gst_msdkdec_finish_task (thiz, task);
          if (flow != GST_FLOW_OK)
            goto error;
          surface = get_surface (thiz, buffer);
          if (surface)
            break;
        }
        if (!surface) {
          GST_ERROR_OBJECT (thiz, "Couldn't get a surface");
          flow = GST_FLOW_ERROR;
          goto error;
        }
      }
    }

    status =
        MFXVideoDECODE_DecodeFrameAsync (session, &bitstream, surface->surface,
        &task->surface, &task->sync_point);

    /* media-sdk requires complete reset since the surface is inadaquate to
     * do further decoding */
    if (status == MFX_ERR_INCOMPATIBLE_VIDEO_PARAM) {
      /* Requires memory re-allocation, do a hard reset */
      if (!gst_msdkdec_negotiate (thiz, TRUE))
        goto error;
      status =
          MFXVideoDECODE_DecodeFrameAsync (session, &bitstream,
          surface->surface, &task->surface, &task->sync_point);
    }

    if (G_LIKELY (status == MFX_ERR_NONE)
        || (status == MFX_WRN_VIDEO_PARAM_CHANGED)) {
      thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;

      if (surface->surface->Data.Locked > 0 || !thiz->use_video_memory)
        surface = NULL;

      if (bitstream.DataLength == 0) {
        flow = GST_FLOW_OK;
        break;
      }
    } else if (status == MFX_ERR_MORE_DATA) {
      if (task->surface) {
        task->decode_only = TRUE;
        thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
      }

      if (surface->surface->Data.Locked > 0)
        surface = NULL;
      flow = GST_VIDEO_DECODER_FLOW_NEED_DATA;
      break;
    } else if (status == MFX_ERR_MORE_SURFACE) {
      surface = NULL;
      continue;
    } else if (status == MFX_WRN_DEVICE_BUSY) {
      /* If device is busy, wait 1ms and retry, as per MSDK's recomendation */
      g_usleep (1000);

      /* If the current surface is still busy, we should do sync oepration
       * then tries to decode again
       */
      thiz->next_task = (thiz->next_task + 1) % thiz->tasks->len;
    } else if (status < MFX_ERR_NONE) {
      GST_ERROR_OBJECT (thiz, "DecodeFrameAsync failed (%s)",
          msdk_status_to_string (status));
      flow = GST_FLOW_ERROR;
      break;
    }
  }

  if (!thiz->is_packetized) {
    /* flush out the data which is already consumed by msdk */
    gst_adapter_flush (thiz->adapter, bitstream.DataOffset);
    flow = GST_FLOW_OK;
  }

done:
  if (surface)
    free_surface (thiz, surface);

  gst_buffer_unmap (input_buffer, &map_info);
  gst_buffer_unref (input_buffer);
  return flow;

error:
  if (input_buffer) {
    gst_buffer_unmap (input_buffer, &map_info);
    gst_buffer_unref (input_buffer);
  }
  gst_video_decoder_drop_frame (decoder, frame);

  return flow;
}
Ejemplo n.º 17
0
	~surface()
	{
		free_surface();
	}
Ejemplo n.º 18
0
	void assign_surface_internal(SDL_Surface* surf)
	{
		add_surface_ref(surf); // Needs to be done before assignment to avoid corruption on "a = a;"
		free_surface();
		surface_ = surf;
	}
Ejemplo n.º 19
0
// seg000:17E6
void __pascal far show_title() {
	word textcolor;
	load_opt_sounds(sound_50_story_2_princess, sound_55_story_1_absence); // main theme, story, princess door
	textcolor = get_text_color(15, color_15_white, 0x800);
	dont_reset_time = 0;
	if(offscreen_surface) free_surface(offscreen_surface); // missing in original
	offscreen_surface = make_offscreen_buffer(&screen_rect);
	load_title_images(1);
	current_target_surface = offscreen_surface;
	do_wait(timer_0);

	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	fade_in_2(offscreen_surface, 0x1000); //STUB
	method_1_blit_rect(onscreen_surface_, offscreen_surface, &screen_rect, &screen_rect, blitters_0_no_transp);
	play_sound_from_buffer(sound_pointers[54]); // main theme
	start_timer(timer_0, 0x82);
	draw_image_2(1 /*Broderbund Software presents*/, chtab_title50, 96, 106, blitters_0_no_transp);
	do_wait(timer_0);

	start_timer(timer_0,0xCD);
	method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	do_wait(timer_0);
	
	start_timer(timer_0,0x41);
	method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	draw_image_2(2 /*a game by Jordan Mechner*/, chtab_title50, 96, 122, blitters_0_no_transp);
	do_wait(timer_0);
	
	start_timer(timer_0,0x10E);
	method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	do_wait(timer_0);
	
	start_timer(timer_0,0xEB);
	method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 107, blitters_10h_transp);
	draw_image_2(4 /*Copyright 1990 Jordan Mechner*/, chtab_title50, 48, 184, blitters_0_no_transp);
	do_wait(timer_0);

	method_1_blit_rect(onscreen_surface_, offscreen_surface, &rect_titles, &rect_titles, blitters_0_no_transp);
	draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp);
	draw_image_2(1 /*In the Sultan's absence*/, chtab_title40, 24, 25, textcolor);
	current_target_surface = onscreen_surface_;
	while (check_sound_playing()) {
		idle();
		do_paused();
	}
//	method_1_blit_rect(onscreen_surface_, offscreen_surface, &screen_rect, &screen_rect, blitters_0_no_transp);
	play_sound_from_buffer(sound_pointers[sound_55_story_1_absence]); // story 1: In the absence
	transition_ltr();
	pop_wait(timer_0, 0x258);
	fade_out_2(0x800);
	release_title_images();
	
	load_intro(0, &pv_scene, 0);
	
	load_title_images(1);
	current_target_surface = offscreen_surface;
	draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp);
	draw_image_2(2 /*Marry Jaffar*/, chtab_title40, 24, 25, textcolor);
	fade_in_2(offscreen_surface, 0x800);
	draw_image_2(0 /*main title image*/, chtab_title50, 0, 0, blitters_0_no_transp);
	draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 107, blitters_10h_transp);
	draw_image_2(4 /*Copyright 1990 Jordan Mechner*/, chtab_title50, 48, 184, blitters_0_no_transp);
	while (check_sound_playing()) {
		idle();
		do_paused();
	}
	transition_ltr();
	pop_wait(timer_0, 0x78);
	draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp);
	draw_image_2(4 /*credits*/, chtab_title40, 24, 26, textcolor);
	transition_ltr();
	pop_wait(timer_0, 0x168);
	if (hof_count) {
		draw_image_2(0 /*story frame*/, chtab_title40, 0, 0, blitters_0_no_transp);
		draw_image_2(3 /*Prince Of Persia*/, chtab_title50, 24, 24, blitters_10h_transp);
		show_hof();
		transition_ltr();
		pop_wait(timer_0, 0xF0);
	}
	current_target_surface = onscreen_surface_;
	while (check_sound_playing()) {
		idle();
		do_paused();
	}
	fade_out_2(0x1800);
	free_surface(offscreen_surface);
	offscreen_surface = NULL; // added
	release_title_images();
	init_game(0);
}
Ejemplo n.º 20
0
int NLLoc
(

        // calling parameters
        char *pid_main, // CUSTOM_ETH only: snap id
        char *fn_control_main, // NLLoc control file: full path and name (set to NULL if *param_line_array not NULL)
        char **param_line_array, // array of NLLoc control file lines (set to NULL if fn_control_main not NULL)
        int n_param_lines, // number of elements (parameter lines) in array param_line_array (use 0 if fn_control_main not NULL)
        char **obs_line_array, // array of observations file lines (set to NULL if obs file name is read from NLLoc control file)
        int n_obs_lines, // number of elements (obs file lines) in array obs_line_array (set to 0 if obs file name is read from NLLoc control file)
        int return_locations, // if = 1, return Locations with basic information (HypoDesc* phypo, ArrivalDesc* parrivals, int narrivals, GridDesc* pgrid
        int return_oct_tree_grid, // if = 1 and LOCSEARCH OCT used, includes location probabily density oct-tree structure in Locations (Tree3D* poctTree)
        int return_scatter_sample, // if = 1, includes location location scatter sample data in Locations (float* pscatterSample)

        // returned parameters
        LocNode **ploc_list_head // pointer to pointer to head of list of LocNodes containing Location's for located events (see phaseloclist.h), *ploc_list_head must be initialized to NULL on first call to NLLoc()

        ) {

    int istat, n;
    int i_end_of_input, iLocated;
    int narr, ngrid, nObsFile;
    int numArrivalsIgnore, numSArrivalsLocation;
    int numArrivalsReject;
    int maxArrExceeded = 0;
    int n_file_root_count = 1;
    char fn_root_out[FILENAME_MAX], fname[FILENAME_MAX], fn_root_out_last[FILENAME_MAX];
    char sys_command[MAXLINE_LONG];
    char *chr;
    FILE *fp_obs = NULL, *fpio;

    char *ppath;

    int return_value = EXIT_NORMAL;


    /* set program name */
    strcpy(prog_name, PNAME);


    // DD
    nll_mode = MODE_ABSOLUTE;

    /* set constants */

    SetConstants();
    NumLocGrids = 0;
    NumEvents = NumEventsLocated = NumLocationsCompleted = 0;
    NumCompDesc = 0;
    NumLocAlias = 0;
    NumLocExclude = 0;
    NumTimeDelays = 0;
    NumPhaseID = 0;
    DistStaGridMax = 0.0;
    MinNumArrLoc = 0;
    MinNumSArrLoc = 0;
    MaxNumArrLoc = MAX_NUM_ARRIVALS;
    FixOriginTimeFlag = 0;
    Scatter.npts = -1;
    for (n = 0; n < MAX_NUM_MAG_METHODS; n++)
        Magnitude[n].type = MAG_UNDEF;
    NumMagnitudeMethods = 0;
    ApplyCrustElevCorrFlag = 0;
    MinDistCrustElevCorr = 2.0; // deg
    ApplyElevCorrFlag = 0;
    NumTimeDelaySurface = 0;
    topo_surface_index = -1;
    iRejectDuplicateArrivals = 1;
    strcpy(fn_root_out_last, "");
    ;

    // Arrival prior weighting  (NLL_FORMAT_VER_2)
    iUseArrivalPriorWeights = 1;

    // station distance weighting
    iSetStationDistributionWeights = 0;
    stationDistributionWeightCutoff = -1;

    // GridMemLib
    MaxNum3DGridMemory = -1;
    GridMemList = NULL;
    GridMemListSize = 0;
    GridMemListNumElements = 0;

    // otime limits
    OtimeLimitList = NULL;
    NumOtimeLimit = 0;

    // GLOBAL
    NumSources = 0;
    NumStations = 0;

    // Gauss2
    iUseGauss2 = 0;


    // output
    iSaveNLLocEvent = iSaveNLLocSum = iSaveHypo71Event = iSaveHypo71Sum
            = iSaveHypoEllEvent = iSaveHypoEllSum
            = iSaveHypoInvSum = iSaveHypoInvY2KArc
            = iSaveAlberto4Sum = iSaveNLLocOctree = iSaveNone = 0;

    /* open control file */

    if (fn_control_main != NULL) {
        strcpy(fn_control, fn_control_main);
        if ((fp_control = fopen(fn_control, "r")) == NULL) {
            nll_puterr("FATAL ERROR: opening control file.");
            return_value = EXIT_ERROR_FILEIO;
            goto cleanup_return;
        } else {
            NumFilesOpen++;
        }
    } else {
        fp_control = NULL;
    }


#ifdef CUSTOM_ETH
    /* SH 02/27/2004
    added snap_pid   */
    strcpy(snap_pid, pid_main);
    /* SH 02AUG2004 not needed any more
    // AJL 20040527 added snap param file
    if (argc > 3)
    strcpy(snap_param_file, argv[3]);
    else
    strcpy(snap_param_file, "snap_param.txt");
     */
#endif


    /* read NLLoc control statements from control file */

    if ((istat = ReadNLLoc_Input(fp_control, param_line_array, n_param_lines)) < 0) {
        nll_puterr("FATAL ERROR: reading control file.");
        return_value = EXIT_ERROR_FILEIO;
        goto cleanup_return;
    }
    if (fp_control != NULL) {
        fclose(fp_control);
        NumFilesOpen--;
    }


    /* read observation lines into memory stream (must read control file first) */

    char *bp_memory_stream = NULL;
    if (n_obs_lines > 0) {
#ifdef _GNU_SOURCE
        size_t memory_stream_size;
        FILE *fp_memory_stream = NULL;
        // read lines into memory memory stream
        fp_memory_stream = open_memstream(&bp_memory_stream, &memory_stream_size);
        if (fp_memory_stream == NULL) {
            nll_puterr("FATAL ERROR: Cannot pass observations file lines as string array to NLLoc function: GNU C library extensions needed to support memory streams (function open_memstream).");
            return_value = EXIT_ERROR_MEMORY;
            goto cleanup_return;
        }
        for (n = 0; n < n_obs_lines; n++) {
            fprintf(fp_memory_stream, "%s", obs_line_array[n]);
            /*DEBUG*///printf("%s", obs_line_array[n]);
        }
        fclose(fp_memory_stream);
        //
        fp_obs = fmemopen(bp_memory_stream, memory_stream_size, "r");

        NumObsFiles = 1;
#else
        nll_puterr("FATAL ERROR: Cannot pass observations file lines as string array to NLLoc function: GNU C library extensions needed to support memory streams (function open_memstream(); see compiler define _GNU_SOURCE).");
        return_value = EXIT_ERROR_MEMORY;
        goto cleanup_return;
#endif
    }



    // get path to output files
    strcpy(f_outpath, fn_path_output);
    if ((ppath = strrchr(f_outpath, '/')) != NULL
            || (ppath = strrchr(f_outpath, '\\')) != NULL)
        *(ppath + 1) = '\0';
    else
        strcpy(f_outpath, "");


    // copy control file to output directory

    if (!iSaveNone && fp_control != NULL) {
        chr = strrchr(fn_control, '/');
        if (chr != NULL)
            strcpy(fname, chr + 1);
        else
            strcpy(fname, fn_control);
        sprintf(sys_command, "cp -p %s %s_%s", fn_control, fn_path_output, fname);
        system(sys_command);
        sprintf(sys_command, "cp -p %s %slast.in", fn_control, f_outpath);
        system(sys_command);
        //printf("sys_command: %s\n", sys_command);
    }


    /* convert source location coordinates  */
    istat = ConvertSourceLoc(0, Source, NumSources, 1, 1);


    /* initialize random number generator */

    SRAND_FUNC(RandomNumSeed);
    if (message_flag >= 4)
        test_rand_int();


    /* open summary output file */

    if (!iSaveNone) {
        if ((istat = OpenSummaryFiles(fn_path_output, "grid")) < 0) {
            nll_puterr("FATAL ERROR: opening hypocenter summary files.");
            return_value = EXIT_ERROR_FILEIO;
            goto cleanup_return;
        }
    }

    // 20101005 AJL
    // open velocity files if needed
    fp_model_grid_P = fp_model_hdr_P = NULL;
    fp_model_grid_S = fp_model_hdr_S = NULL;
    if (LocMethod == METH_OT_STACK) {
        sprintf(fname, "%s.%s", fn_loc_grids, "P.mod");
        if ((istat = OpenGrid3dFile(fname, &fp_model_grid_P, &fp_model_hdr_P,
                &model_grid_P, " ", NULL, iSwapBytesOnInput)) < 0) {
            sprintf(MsgStr, "WARNING: LocMethod == OT_STACK, but cannot open velocity model file %s.*", fname);
            nll_putmsg(1, MsgStr);
        } else {
            sprintf(MsgStr, "INFO: LocMethod == OT_STACK, sucessfully opened velocity model file %s.*", fname);
            nll_putmsg(1, MsgStr);

        }
        sprintf(fname, "%s.%s", fn_loc_grids, "S.mod");
        if ((istat = OpenGrid3dFile(fname, &fp_model_grid_S, &fp_model_hdr_S,
                &model_grid_S, " ", NULL, iSwapBytesOnInput)) < 0) {
            sprintf(MsgStr, "WARNING: LocMethod == OT_STACK, but cannot open velocity model file %s.*", fname);
            nll_putmsg(1, MsgStr);
        } else {
            sprintf(MsgStr, "INFO: LocMethod == OT_STACK, sucessfully opened velocity model file %s.*", fname);
            nll_putmsg(1, MsgStr);

        }
    }


    /* perform location for each observation file */

    for (nObsFile = 0; nObsFile < NumObsFiles; nObsFile++) {

        i_end_of_input = 0;

        nll_putmsg(2, "");
        sprintf(MsgStr, "... Reading observation file %s",
                fn_loc_obs[nObsFile]);
        nll_putmsg(1, MsgStr);

        // check if observations are read from file(s)
        if ((n_obs_lines <= 0)) {
            /* open observation file */
            if ((fp_obs = fopen(fn_loc_obs[nObsFile], "r")) == NULL) {
                nll_puterr2("ERROR: opening observations file",
                        fn_loc_obs[nObsFile]);
                continue;
            } else {
                NumFilesOpen++;
            }
            /* extract info from filename */
            if ((istat = ExtractFilenameInfo(fn_loc_obs[nObsFile], ftype_obs)) < 0)
                nll_puterr("WARNING: error extractng information from filename.");
        }


        /* read arrivals and locate event for each  */
        /*		event (set of observations) in file */

        NumArrivals = 0;
        while (1) {

            iLocated = 0;

            if (i_end_of_input)
                break;

            if (NumArrivals != OBS_FILE_SKIP_INPUT_LINE) {
                nll_putmsg(2, "");
                sprintf(MsgStr,
                        "Reading next set of observations (Files open: Tot:%d Buf:%d Hdr:%d  Alloc: %d) ...",
                        NumFilesOpen, NumGridBufFilesOpen, NumGridHdrFilesOpen, NumAllocations);
                nll_putmsg(1, MsgStr);
            }


            /* read next set of observations */

            NumArrivalsLocation = 0;
            if ((NumArrivals = GetObservations(fp_obs,
                    ftype_obs, fn_loc_grids, Arrival,
                    &i_end_of_input, &numArrivalsIgnore,
                    &numArrivalsReject,
                    MaxNumArrLoc, &Hypocenter,
                    &maxArrExceeded, &numSArrivalsLocation, 0)) == 0)
                break;

            if (NumArrivals < 0)
                goto cleanup;


            /* set number of arrivals to be used in location */

            NumArrivalsLocation = NumArrivals - numArrivalsIgnore;
            NumArrivalsRead = NumArrivals + numArrivalsReject;

            nll_putmsg(2, "");
            // AJL 20040720 SetOutName(Arrival + 0, fn_path_output, fn_root_out, fn_root_out_last, 1);
            SetOutName(Arrival + 0, fn_path_output, fn_root_out, fn_root_out_last, iSaveDecSec, &n_file_root_count);
            //strcpy(fn_root_out_last, fn_root_out); /* save filename */
            sprintf(MsgStr,
                    "... %d observations read, %d will be used for location (%s).",
                    NumArrivalsRead, NumArrivalsLocation, fn_root_out);
            nll_putmsg(1, MsgStr);


            /* sort to get rejected arrivals at end of arrivals array */

            if ((istat = SortArrivalsIgnore(Arrival, NumArrivalsRead)) < 0) {
                nll_puterr("ERROR: sorting arrivals by ignore flag.");
                goto cleanup;
            }


            /* check for minimum number of arrivals */

            if (NumArrivalsLocation < MinNumArrLoc) {
                sprintf(MsgStr,
                        "WARNING: too few observations to locate (%d available, %d needed), skipping event.", NumArrivalsLocation, MinNumArrLoc);
                nll_putmsg(1, MsgStr);
                sprintf(MsgStr,
                        "INFO: %d observations needed (specified in control file entry LOCMETH).",
                        MinNumArrLoc);
                nll_putmsg(2, MsgStr);
                goto cleanup;
            }


            /* check for minimum number of S arrivals */

            if (numSArrivalsLocation < MinNumSArrLoc) {
                sprintf(MsgStr,
                        "WARNING: too few S observations to locate (%d available, %d needed), skipping event.", numSArrivalsLocation, MinNumSArrLoc);
                nll_putmsg(1, MsgStr);
                sprintf(MsgStr,
                        "INFO: %d S observations needed (specified in control file entry LOCMETH).",
                        MinNumSArrLoc);
                nll_putmsg(2, MsgStr);
                goto cleanup;
            }


            /* process arrivals */

            /* add stations to station list */

            // station distribution weighting
            if (iSetStationDistributionWeights || iSaveNLLocSum || octtreeParams.use_stations_density) {
                //printf(">>>>>>>>>>> NumStations %d, NumArrivals %d, numArrivalsReject %d\n", NumStations, NumArrivals, numArrivalsReject);
                NumStations = addToStationList(StationList, NumStations, Arrival, NumArrivalsRead);
                if (iSetStationDistributionWeights)
                    setStationDistributionWeights(StationList, NumStations, Arrival, NumArrivals);

            }

            /* sort to get location arrivals in time order */

            if ((istat = SortArrivalsIgnore(Arrival, NumArrivals)) < 0) {
                nll_puterr("ERROR: sorting arrivals by ignore flag.");
                goto cleanup;
            }
            if ((istat = SortArrivalsTime(Arrival, NumArrivalsLocation)) < 0) {
                nll_puterr("ERROR: sorting arrivals by time.");
                goto cleanup;
            }


            /* construct weight matrix (TV82, eq. 10-9; MEN92, eq. 12) */

            if ((istat = ConstWeightMatrix(NumArrivalsLocation, Arrival, &Gauss)) < 0) {
                nll_puterr("ERROR: constructing weight matrix - NLLoc requires non-zero observation or modelisation errors.");
                /* close time grid files and continue */
                goto cleanup;
            }


            /* calculate weighted mean of obs arrival times   */
            /*	(TV82, eq. A-38) */

            CalcCenteredTimesObs(NumArrivalsLocation, Arrival, &Gauss, &Hypocenter);


            /* preform location for each grid */

            sprintf(MsgStr,
                    "Locating... (Files open: Tot:%d Buf:%d Hdr:%d  Alloc: %d  3DMem: %d) ...",
                    NumFilesOpen, NumGridBufFilesOpen, NumGridHdrFilesOpen, NumAllocations, Num3DGridReadToMemory);
            nll_putmsg(1, MsgStr);

            for (ngrid = 0; ngrid < NumLocGrids; ngrid++) {
                if ((istat = Locate(ngrid, fn_loc_obs[nObsFile], fn_root_out, numArrivalsReject, return_locations, return_oct_tree_grid, return_scatter_sample, ploc_list_head)) < 0) {
                    if (istat == GRID_NOT_INSIDE)
                        break;
                    else {
                        nll_puterr("ERROR: location failed.");
                        goto cleanup;
                    }
                }
            }

            NumEventsLocated++;
            if (istat == 0 && ngrid == NumLocGrids)
                NumLocationsCompleted++;
            iLocated = 1;

cleanup:
            ;

            NumEvents++;
            //n_file_root_count++;

            /* release grid buffer or sheet storage */

            // 20130413 AJL - bug? fix, release memory for all arrivals read
            //for (narr = 0; narr < NumArrivalsLocation; narr++) {
            for (narr = 0; narr < NumArrivals; narr++) {
                //printf("DEBUG: FREE: narr %d Arrival[narr].n_time_grid %d\n", narr, Arrival[narr].n_time_grid);
                if (Arrival[narr].n_time_grid < 0) { // check has opened time grid
                    DestroyGridArray(&(Arrival[narr].sheetdesc));
                    FreeGrid(&(Arrival[narr].sheetdesc));
                    NLL_DestroyGridArray(&(Arrival[narr].gdesc));
                    NLL_FreeGrid(&(Arrival[narr].gdesc));
                }
            }
            //  20141219 AJL - bug fix, should be outside events/obs loop!
            //NLL_FreeGridMemory();

            /* close time grid files (opened in function GetObservations) */

            // 20130413 AJL - bug? fix, release memory for all arrivals read
            //for (narr = 0; narr < NumArrivalsLocation; narr++) {
            for (narr = 0; narr < NumArrivals; narr++) {
                CloseGrid3dFile(&(Arrival[narr].fpgrid), &(Arrival[narr].fphdr));
            }

            if (iLocated) {
                nll_putmsg(2, "");
                sprintf(MsgStr,
                        "Finished event location, output files: %s.* <%s.grid0.loc.hyp>",
                        fn_root_out, fn_root_out);
                nll_putmsg(0, MsgStr);
            } else
                nll_putmsg(2, "");

            // 201101013 AJL - Bug fix - this cleanup was done in NLLocLib.c->clean_memory() which puts the cleanup incorrectly inside the Locate loop
            CleanWeightMatrix();

        } /* next event */

        nll_putmsg(2, "");
        sprintf(MsgStr, "...end of observation file detected.");
        nll_putmsg(1, MsgStr);

        if ((n_obs_lines <= 0)) { // observations are read from file(s)
            fclose(fp_obs);
            NumFilesOpen--;
        } else { // observation lines are read from memory stream (20101110 AJL)
            // AJL 20101110 - Bug fix for function version
            fclose(fp_obs);
        }

    } /* next observation file */

    nll_putmsg(2, "");
    sprintf(MsgStr,
            "No more observation files.  %d events read,  %d events located,  %d locations completed.",
            NumEvents, NumEventsLocated, NumLocationsCompleted);
    nll_putmsg(0, MsgStr);
    nll_putmsg(2, "");


    /* write cumulative arrival statistics */
    if (!iSaveNone) {
        for (ngrid = 0; ngrid < NumLocGrids; ngrid++) {
            if (LocGridSave[ngrid]) {
                sprintf(fname, "%s.sum.grid%d.loc.stat", fn_path_output, ngrid);
                if ((fpio = fopen(fname, "w")) == NULL) {
                    nll_puterr2(
                            "ERROR: opening cumulative phase statistics output file", fname);
                    return_value = EXIT_ERROR_FILEIO;
                    goto cleanup_return;
                } else {
                    NumFilesOpen++;
                }
                WriteStaStatTable(ngrid, fpio,
                        RMS_Max, NRdgs_Min, Gap_Max,
                        P_ResidualMax, S_ResidualMax, Ell_Len3_Max, Hypo_Depth_Min, Hypo_Depth_Max, Hypo_Dist_Max, WRITE_RESIDUALS);
                WriteStaStatTable(ngrid, fpio,
                        RMS_Max, NRdgs_Min, Gap_Max,
                        P_ResidualMax, S_ResidualMax, Ell_Len3_Max, Hypo_Depth_Min, Hypo_Depth_Max, Hypo_Dist_Max, WRITE_RES_DELAYS);
                WriteStaStatTable(ngrid, fpio,
                        RMS_Max, NRdgs_Min, Gap_Max,
                        P_ResidualMax, S_ResidualMax, Ell_Len3_Max, Hypo_Depth_Min, Hypo_Depth_Max, Hypo_Dist_Max, WRITE_PDF_RESIDUALS);
                WriteStaStatTable(ngrid, fpio,
                        RMS_Max, NRdgs_Min, Gap_Max,
                        P_ResidualMax, S_ResidualMax, Ell_Len3_Max, Hypo_Depth_Min, Hypo_Depth_Max, Hypo_Dist_Max, WRITE_PDF_DELAYS);
                fclose(fpio);
                // save to last
                sprintf(sys_command, "cp %s %slast.stat", fname, f_outpath);
                system(sys_command);
                // write delays only
                sprintf(fname, "%s.sum.grid%d.loc.stat_totcorr", fn_path_output, ngrid);
                if ((fpio = fopen(fname, "w")) == NULL) {
                    nll_puterr2(
                            "ERROR: opening total phase corrections output file", fname);
                    return_value = EXIT_ERROR_FILEIO;
                    goto cleanup_return;
                } else {
                    NumFilesOpen++;
                }
                WriteStaStatTable(ngrid, fpio,
                        RMS_Max, NRdgs_Min, Gap_Max,
                        P_ResidualMax, S_ResidualMax, Ell_Len3_Max, Hypo_Depth_Min, Hypo_Depth_Max, Hypo_Dist_Max, WRITE_RES_DELAYS);
                fclose(fpio);
                // save to last
                sprintf(sys_command, "cp %s %slast.stat_totcorr", fname, f_outpath);
                system(sys_command);
            }
        }
    }

    /* write station list */
    if (!iSaveNone) {
        for (ngrid = 0; ngrid < NumLocGrids; ngrid++)
            if (LocGridSave[ngrid]) {
                sprintf(fname, "%s.sum.grid%d.loc.stations", fn_path_output, ngrid);
                if ((fpio = fopen(fname, "w")) == NULL) {
                    nll_puterr2(
                            "ERROR: opening cumulative phase statistics output file", fname);
                    return_value = EXIT_ERROR_FILEIO;
                    goto cleanup_return;
                } else {
                    NumFilesOpen++;
                }
                WriteStationList(fpio, StationList, NumStations);
                fclose(fpio);
                // save to last
                sprintf(sys_command, "cp %s %slast.stations", fname, f_outpath);
                system(sys_command);
            }
    }


    // clean up before leaving NLLoc function
cleanup_return:

    //  20141219 AJL - bug? fix, moved here from inside events/obs loop!
    NLL_FreeGridMemory();

    if (!iSaveNone)
        CloseSummaryFiles();

    if (fp_model_grid_P != NULL) {
        CloseGrid3dFile(&fp_model_grid_P, &fp_model_hdr_P);
    }
    if (fp_model_grid_S != NULL) {
        CloseGrid3dFile(&fp_model_grid_S, &fp_model_hdr_S);
    }

    // AEH/AJL 20080709
    if (Arrival != NULL) {
        free(Arrival);
        Arrival = NULL;
    }

    // AJL 20101110 - Bug fix for function version
    for (ngrid = 0; ngrid < NumLocGrids; ngrid++) {
        // 20100607 AJL added to prevent valgrind error of not-freed blocks
        FreeStaStatTable(ngrid);
    }

    // AJL 20100929 - Bug fix for function version
    // free any allocated surface data
    if (topo_surface_index >= 0) {
        free_surface(topo_surface);
    }
    for (n = 0; n < NumTimeDelaySurface; n++) {
        free_surface(model_surface + n);
    }


    if (bp_memory_stream != NULL) {
        free(bp_memory_stream);
        bp_memory_stream = NULL;
    }


    return (return_value);

}