// filename		- file to search for
// out_name		- output, full path to file
// returns non-zero if file is found
int movie_find(char *filename, char *out_name)
{
	char full_path[MAX_PATH];
	char tmp_name[MAX_PATH];
	int size, offset = 0;
	const int NUM_EXT = 2;
	const char *movie_ext[NUM_EXT] = { ".ogg", ".mve" };

	if (out_name == NULL)
		return MOVIE_NONE;


	memset( full_path, 0, sizeof(full_path) );
	memset( tmp_name, 0, sizeof(tmp_name) );

	// remove extension
	strcpy_s( tmp_name, filename );
	char *p = strrchr(tmp_name, '.');
	if ( p ) *p = 0;

    int rc = cf_find_file_location_ext(tmp_name, NUM_EXT, movie_ext, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0);

	if (rc == MOVIE_NONE)
		return MOVIE_NONE;

	strcpy( out_name, full_path );

	return rc;
}
Example #2
0
int generic_anim_stream(generic_anim *ga, const bool cache)
{
	CFILE *img_cfp = NULL;
	int anim_fps = 0;
	char full_path[MAX_PATH];
	int size = 0, offset = 0;
	const int NUM_TYPES = 3;
	const ubyte type_list[NUM_TYPES] = {BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG};
	const char *ext_list[NUM_TYPES] = {".eff", ".ani", ".png"};
	int rval = -1;
	int bpp;

	ga->type = BM_TYPE_NONE;

	rval = cf_find_file_location_ext(ga->filename, NUM_TYPES, ext_list, CF_TYPE_ANY, sizeof(full_path) - 1, full_path, &size, &offset, 0);

	// could not be found, or is invalid for some reason
	if ( (rval < 0) || (rval >= NUM_TYPES) )
		return -1;

	//make sure we can open it
	img_cfp = cfopen_special(full_path, "rb", size, offset, CF_TYPE_ANY);

	if (img_cfp == NULL) {
		return -1;
	}

	strcat_s(ga->filename, ext_list[rval]);
	ga->type = type_list[rval];
	//seek to the end
	cfseek(img_cfp, 0, CF_SEEK_END);

	cfclose(img_cfp);

	if(ga->type == BM_TYPE_ANI) {
		bpp = ANI_BPP_CHECK;
		if(ga->use_hud_color)
			bpp = 8;
		if (ga->ani.animation == nullptr) {
			ga->ani.animation = anim_load(ga->filename, CF_TYPE_ANY, 0);
		}
		if (ga->ani.instance == nullptr) {
			ga->ani.instance = init_anim_instance(ga->ani.animation, bpp);
		}

	#ifndef NDEBUG
		// for debug of ANI sizes
		strcpy_s(ga->ani.animation->name, ga->filename);
	#endif

		ga->num_frames = ga->ani.animation->total_frames;
		anim_fps = ga->ani.animation->fps;
		ga->height = ga->ani.animation->height;
		ga->width = ga->ani.animation->width;
		ga->buffer = ga->ani.instance->frame;
		ga->bitmap_id = bm_create(bpp, ga->width, ga->height, ga->buffer, (bpp==8)?BMP_AABITMAP:0);
		ga->ani.instance->last_bitmap = -1;

		ga->ani.instance->file_offset = ga->ani.animation->file_offset;
		ga->ani.instance->data = ga->ani.animation->data;

		ga->previous_frame = -1;
	}
	else if (ga->type == BM_TYPE_PNG) {
		if (ga->png.anim == nullptr) {
			try {
				ga->png.anim = new apng::apng_ani(ga->filename, cache);
			}
			catch (const apng::ApngException& e) {
				mprintf(("Failed to load apng: %s\n", e.what() ));
				delete ga->png.anim;
				ga->png.anim = nullptr;
				return -1;
			}
			nprintf(("apng", "apng read OK (%ix%i@%i) duration (%f)\n", ga->png.anim->w, ga->png.anim->h,
					ga->png.anim->bpp, ga->png.anim->anim_time));
		}
		ga->png.anim->goto_start();
		ga->current_frame = 0;
		ga->png.previous_frame_time = 0.0f;
		ga->num_frames = ga->png.anim->nframes;
		ga->height = ga->png.anim->h;
		ga->width = ga->png.anim->w;
		ga->previous_frame = -1;
		ga->buffer = ga->png.anim->frame.data.data();
		ga->bitmap_id = bm_create(ga->png.anim->bpp, ga->width, ga->height, ga->buffer, 0);
	}
	else {
		bpp = 32;
		if(ga->use_hud_color)
			bpp = 8;
		bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0);
		char *p = strrchr( ga->filename, '.' );
		if ( p )
			*p = 0;
		char frame_name[MAX_FILENAME_LEN];
		snprintf(frame_name, MAX_FILENAME_LEN, "%s_0000", ga->filename);
		ga->bitmap_id = bm_load(frame_name);
		if(ga->bitmap_id < 0) {
			mprintf(("Cannot find first frame for eff streaming. eff Filename: %s", ga->filename));
			return -1;
		}
		snprintf(frame_name, MAX_FILENAME_LEN, "%s_0001", ga->filename);
		ga->eff.next_frame = bm_load(frame_name);
		bm_get_info(ga->bitmap_id, &ga->width, &ga->height);
		ga->previous_frame = 0;
	}

	// keyframe info
	if (ga->type == BM_TYPE_ANI) {
		//we only care if there are 2 keyframes - first frame, other frame to jump to for ship/weapons
		//mainhall door anis hav every frame as keyframe, so we don't care
		//other anis only have the first frame
		if(ga->ani.animation->num_keys == 2) {
			int key1 = ga->ani.animation->keys[0].frame_num;
			int key2 = ga->ani.animation->keys[1].frame_num;

			if (key1 < 0 || key1 >= ga->num_frames) key1 = -1;
			if (key2 < 0 || key2 >= ga->num_frames) key2 = -1;

			// some retail anis have their keyframes reversed
			// and some have their keyframes out of bounds
			if (key1 >= 0 && key1 >= key2) {
				ga->keyframe = ga->ani.animation->keys[0].frame_num;
				ga->keyoffset = ga->ani.animation->keys[0].offset;
			}
			else if (key2 >= 0 && key2 >= key1) {
				ga->keyframe = ga->ani.animation->keys[1].frame_num;
				ga->keyoffset = ga->ani.animation->keys[1].offset;
			}
		}
	}

	ga->streaming = 1;

	if (ga->type == BM_TYPE_PNG) {
		ga->total_time = ga->png.anim->anim_time;
	}
	else {
		if (anim_fps == 0) {
			Error(LOCATION, "animation (%s) has invalid fps of zero, fix this!", ga->filename);
		}
		ga->total_time = ga->num_frames / (float) anim_fps;
	}
	ga->done_playing = 0;
	ga->anim_time = 0.0f;

	return 0;
}
// Open
bool WaveFile::Open(char *pszFilename, bool keep_ext)
{
	int rc = -1;
	WORD cbExtra = 0;
	bool fRtn = true;    // assume success
	PCMWAVEFORMAT pcmwf;
	int FileSize, FileOffset;
	char fullpath[MAX_PATH];
	char filename[MAX_FILENAME_LEN];
	const int NUM_EXT = 2;
	const char *audio_ext[NUM_EXT] = { ".ogg", ".wav" };

	m_total_uncompressed_bytes_read = 0;
	m_max_uncompressed_bytes_to_read = AS_HIGHEST_MAX;

	// NOTE: we assume that the extension has already been stripped off if it was supposed to be!!
	strcpy_s( filename, pszFilename );


	// if we are supposed to load the file as passed...
	if (keep_ext) {
		for (int i = 0; i < NUM_EXT; i++) {
			if ( stristr(pszFilename, audio_ext[i]) ) {
				rc = i;
				break;
			}
		}

		// not a supported extension format ... somebody screwed up their tbls :)
		if (rc < 0)
			goto OPEN_ERROR;

		cf_find_file_location(pszFilename, CF_TYPE_ANY, sizeof(fullpath) - 1, fullpath, &FileSize, &FileOffset);
	}
	// ... otherwise we just find the best match
	else {
		rc = cf_find_file_location_ext(filename, NUM_EXT, audio_ext, CF_TYPE_ANY, sizeof(fullpath) - 1, fullpath, &FileSize, &FileOffset);
	}

	if (rc < 0) {
		goto OPEN_ERROR;
	} else {
		// set proper filename for later use (assumes that it doesn't already have an extension)
		strcat_s( filename, audio_ext[rc] );
	}

	m_snd_info.cfp = mmioOpen( fullpath, NULL, MMIO_ALLOCBUF | MMIO_READ );

	if (m_snd_info.cfp == NULL)
		goto OPEN_ERROR;

	m_snd_info.true_offset = FileOffset;
	m_snd_info.size = FileSize;

	// if in a VP then position the stream at the start of the file
	if (FileOffset > 0)
		mmioSeek( m_snd_info.cfp, FileOffset, SEEK_SET );

	// if Ogg Vorbis...
	if (rc == 0) {
		if ( ov_open_callbacks(&m_snd_info, &m_snd_info.vorbis_file, NULL, 0, mmio_callbacks) == 0 ) {
			// got an Ogg Vorbis, so lets read the info in
			ov_info(&m_snd_info.vorbis_file, -1);

			// we only support one logical bitstream
			if ( ov_streams(&m_snd_info.vorbis_file) != 1 ) {
				mprintf(("AUDIOSTR => OGG reading error:  We don't handle bitstream changes!\n"));
				goto OPEN_ERROR;
			}

			m_wave_format = OGG_FORMAT_VORBIS;
			m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
			m_wfmt.nChannels = (WORD) m_snd_info.vorbis_file.vi->channels;
			m_wfmt.nSamplesPerSec = m_snd_info.vorbis_file.vi->rate;

			switch (Ds_sound_quality) {
				case DS_SQ_HIGH:
					m_wfmt.wBitsPerSample = Ds_float_supported ? 32 : 16;
					break;

				case DS_SQ_MEDIUM:
					m_wfmt.wBitsPerSample = 16;
					break;

				default:
					m_wfmt.wBitsPerSample = 8;
					break;
			}

			m_wfmt.cbSize = 0;

			m_wfmt.nBlockAlign = (ushort)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
			m_wfmt.nAvgBytesPerSec = m_wfmt.nSamplesPerSec * m_wfmt.nBlockAlign;

			m_nBlockAlign = m_wfmt.nBlockAlign;
			m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;

			// location of start of file in VP
			m_data_offset = 0;
			m_nDataSize = m_data_bytes_left = ((int)ov_pcm_total(&m_snd_info.vorbis_file, -1) * m_wfmt.nBlockAlign);
		} else {
			mprintf(("AUDIOSTR => OGG reading error: Not a valid Vorbis file!\n"));
		}
	}
	// if Wave...
	else if (rc == 1) {
		bool done = false;

		// Skip the "RIFF" tag and file size (8 bytes)
		// Skip the "WAVE" tag (4 bytes)
		mmioSeek( m_snd_info.cfp, 12+FileOffset, SEEK_SET );

		// Now read RIFF tags until the end of file
		uint tag, size, next_chunk;

		while ( !done ) {
			if ( !audiostr_read_uint(m_snd_info.cfp, &tag) )
				break;

			if ( !audiostr_read_uint(m_snd_info.cfp, &size) )
				break;

			next_chunk = mmioSeek(m_snd_info.cfp, 0, SEEK_CUR );
			next_chunk += size;

			switch (tag)
			{
				case 0x20746d66:		// The 'fmt ' tag
				{
					audiostr_read_word(m_snd_info.cfp, &pcmwf.wf.wFormatTag);
					audiostr_read_word(m_snd_info.cfp, &pcmwf.wf.nChannels);
					audiostr_read_dword(m_snd_info.cfp, &pcmwf.wf.nSamplesPerSec);
					audiostr_read_dword(m_snd_info.cfp, &pcmwf.wf.nAvgBytesPerSec);
					audiostr_read_word(m_snd_info.cfp, &pcmwf.wf.nBlockAlign);
					audiostr_read_word(m_snd_info.cfp, &pcmwf.wBitsPerSample);
			
					if (pcmwf.wf.wFormatTag == WAVE_FORMAT_ADPCM)
						audiostr_read_word(m_snd_info.cfp, &cbExtra);

					// Allocate memory for WAVEFORMATEX structure + extra bytes
					if ( (m_pwfmt_original = (WAVEFORMATEX *) vm_malloc(sizeof(WAVEFORMATEX)+cbExtra)) != NULL ) {
						Assert(m_pwfmt_original != NULL);
						// Copy bytes from temporary format structure
						memcpy (m_pwfmt_original, &pcmwf, sizeof(pcmwf));
						m_pwfmt_original->cbSize = cbExtra;

						// Read those extra bytes, append to WAVEFORMATEX structure
						if (cbExtra != 0)
							mmioRead( m_snd_info.cfp, ((char *)(m_pwfmt_original) + sizeof(WAVEFORMATEX)), cbExtra );
					} else {
						Int3();		// malloc failed
						goto OPEN_ERROR;
					}

					break;
				}

				case 0x61746164:		// the 'data' tag
				{
					m_nDataSize = size;	// This is size of data chunk.  Compressed if ADPCM.
					m_data_bytes_left = size;
					m_data_offset = mmioSeek( m_snd_info.cfp, 0, SEEK_CUR );
					done = true;

					break;
				}

				default:	// unknown, skip it
					break;
			}	// end switch

			mmioSeek( m_snd_info.cfp, next_chunk, SEEK_SET );
		}

		// make sure that we did good
		if ( !done || (m_pwfmt_original == NULL) )
			goto OPEN_ERROR;

  		// At this stage, examine source format, and set up WAVEFORATEX structure for DirectSound.
		// Since DirectSound only supports PCM, force this structure to be PCM compliant.  We will
		// need to convert data on the fly later if our souce is not PCM
		switch (m_pwfmt_original->wFormatTag) {
			case WAVE_FORMAT_PCM:
				m_wave_format = WAVE_FORMAT_PCM;
				m_wfmt.wBitsPerSample = m_pwfmt_original->wBitsPerSample;
				break;

			case WAVE_FORMAT_ADPCM:
				m_wave_format = WAVE_FORMAT_ADPCM;
				m_wfmt.wBitsPerSample = (Ds_sound_quality) ? 16: 8;
				m_bits_per_sample_uncompressed = m_wfmt.wBitsPerSample;
				break;

			case WAVE_FORMAT_IEEE_FLOAT: {
				m_wave_format = WAVE_FORMAT_IEEE_FLOAT;

				switch (Ds_sound_quality) {
					case DS_SQ_HIGH:
						m_wfmt.wBitsPerSample = (Ds_float_supported) ? 32 : 16;
						break;

					case DS_SQ_MEDIUM:
						m_wfmt.wBitsPerSample = 16;
						break;

					default:
						m_wfmt.wBitsPerSample = 8;
						break;
				}

				break;
			}

			default:
				nprintf(("SOUND", "SOUND => Not supporting %d format for playing wave files\n", m_pwfmt_original->wFormatTag));
				goto OPEN_ERROR;
				break;

		} // end switch
            
		// Set up the WAVEFORMATEX structure to have the right PCM characteristics
		m_wfmt.wFormatTag = WAVE_FORMAT_PCM;
		m_wfmt.nChannels = m_pwfmt_original->nChannels;
		m_wfmt.nSamplesPerSec = m_pwfmt_original->nSamplesPerSec;
		m_wfmt.cbSize = 0;
		m_wfmt.nBlockAlign = (ushort)(( m_wfmt.nChannels * m_wfmt.wBitsPerSample ) / 8);
		m_wfmt.nAvgBytesPerSec = m_wfmt.nBlockAlign * m_wfmt.nSamplesPerSec;

		// Init some member data from format chunk
		m_nBlockAlign = m_pwfmt_original->nBlockAlign;
		m_nUncompressedAvgDataRate = m_wfmt.nAvgBytesPerSec;

		Assert( (m_wfmt.nChannels == 1) || (m_wfmt.nChannels == 2) );
	}
	// something unkown???
	else {
		Int3();
	}

	m_al_format = openal_get_format(m_wfmt.wBitsPerSample, m_wfmt.nChannels);

	if (m_al_format != AL_INVALID_VALUE) {	
		// Cue for streaming
		Cue();

		goto OPEN_DONE;
	}

OPEN_ERROR:
	// Handle all errors here
	nprintf(("SOUND","SOUND ==> Could not open wave file %s for streaming\n", filename));

	fRtn = false;

	if (m_snd_info.cfp != NULL) {
		// Close file
		mmioClose( m_snd_info.cfp, 0 );
		m_snd_info.cfp = NULL;
		m_snd_info.true_offset = 0;
		m_snd_info.size = 0;
	}

	if (m_pwfmt_original) {
		vm_free(m_pwfmt_original);
		m_pwfmt_original = NULL;
	}

OPEN_DONE:
	strncpy(m_wFilename, filename, MAX_FILENAME_LEN-1);

	if (fRtn)
		nprintf(("SOUND", "AUDIOSTR => Successfully opened: %s\n", filename));

	return (fRtn);
}