// 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; }
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); }