static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound) { assert(sound != NULL); if (sound->file_size == 0) return false; int8 *mem = MallocT<int8>(sound->file_size + 2); /* Add two extra bytes so rate conversion can read these * without reading out of its input buffer. */ mem[sound->file_size ] = 0; mem[sound->file_size + 1] = 0; FioSeekToFile(sound->file_slot, sound->file_offset); FioReadBlock(mem, sound->file_size); /* 16-bit PCM WAV files should be signed by default */ if (sound->bits_per_sample == 8) { for (uint i = 0; i != sound->file_size; i++) { mem[i] += -128; // Convert unsigned sound data to signed } } #if TTD_ENDIAN == TTD_BIG_ENDIAN if (sound->bits_per_sample == 16) { uint num_samples = sound->file_size / 2; int16 *samples = (int16 *)mem; for (uint i = 0; i < num_samples; i++) { samples[i] = BSWAP16(samples[i]); } } #endif assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16); assert(sound->channels == 1); assert(sound->file_size != 0 && sound->rate != 0); MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16); return true; }
static void OpenBankFile(const char *filename) { memset(_original_sounds, 0, sizeof(_original_sounds)); /* If there is no sound file (nosound set), don't load anything */ if (filename == NULL) return; FioOpenFile(SOUND_SLOT, filename); size_t pos = FioGetPos(); uint count = FioReadDword(); /* The new format has the highest bit always set */ bool new_format = HasBit(count, 31); ClrBit(count, 31); count /= 8; /* Simple check for the correct number of original sounds. */ if (count != ORIGINAL_SAMPLE_COUNT) { /* Corrupt sample data? Just leave the allocated memory as those tell * there is no sound to play (size = 0 due to calloc). Not allocating * the memory disables valid NewGRFs that replace sounds. */ DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename); return; } FioSeekTo(pos, SEEK_SET); for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { _original_sounds[i].file_slot = SOUND_SLOT; _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos; _original_sounds[i].file_size = FioReadDword(); } for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { SoundEntry *sound = &_original_sounds[i]; char name[255]; FioSeekTo(sound->file_offset, SEEK_SET); /* Check for special case, see else case */ FioReadBlock(name, FioReadByte()); // Read the name of the sound if (new_format || strcmp(name, "Corrupt sound") != 0) { FioSeekTo(12, SEEK_CUR); // Skip past RIFF header /* Read riff tags */ for (;;) { uint32 tag = FioReadDword(); uint32 size = FioReadDword(); if (tag == ' tmf') { FioReadWord(); // wFormatTag sound->channels = FioReadWord(); // wChannels sound->rate = FioReadDword(); // samples per second if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate. FioReadDword(); // avg bytes per second FioReadWord(); // alignment sound->bits_per_sample = FioReadByte(); // bits per sample FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR); } else if (tag == 'atad') { sound->file_size = size; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); break; } else { sound->file_size = 0; break; } } } else { /* * Special case for the jackhammer sound * (name in sample.cat is "Corrupt sound") * It's no RIFF file, but raw PCM data */ sound->channels = 1; sound->rate = 11025; sound->bits_per_sample = 8; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); } } }
static bool LoadPNG(SpriteLoader::Sprite *sprite, const char *filename, uint32 id, volatile bool mask) { png_byte header[8]; png_structp png_ptr; png_infop info_ptr, end_info; uint bit_depth, colour_type; uint i, pixelsize; SpriteLoader::CommonPixel *dst; if (!OpenPNGFile(filename, id, mask)) return mask; // If mask is true, and file not found, continue true anyway, as it isn't a show-stopper /* Check the header */ FioReadBlock(header, 8); if (png_sig_cmp(header, 0, 8) != 0) return false; /* Create the reader */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, png_my_error, png_my_warning); if (png_ptr == NULL) return false; /* Create initial stuff */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return false; } end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); return false; } /* Make sure that upon error, we can clean up graceful */ if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return false; } /* Read the file */ png_set_read_fn(png_ptr, NULL, png_my_read); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); if (!mask) { /* Read the text chunks */ png_textp text_ptr; int num_text = 0; png_get_text(png_ptr, info_ptr, &text_ptr, &num_text); if (num_text == 0) DEBUG(misc, 0, "Warning: PNG Sprite '%s/%d.png' doesn't have x_offs and y_offs; expect graphical problems", filename, id); for (int i = 0; i < num_text; i++) { /* x_offs and y_offs are in the text-chunk of PNG */ if (strcmp("x_offs", text_ptr[i].key) == 0) sprite->x_offs = strtol(text_ptr[i].text, NULL, 0); if (strcmp("y_offs", text_ptr[i].key) == 0) sprite->y_offs = strtol(text_ptr[i].text, NULL, 0); } sprite->height = png_get_image_height(png_ptr, info_ptr); sprite->width = png_get_image_width(png_ptr, info_ptr); sprite->AllocateData(sprite->width * sprite->height); } bit_depth = png_get_bit_depth(png_ptr, info_ptr); colour_type = png_get_color_type(png_ptr, info_ptr); if (mask && (bit_depth != 8 || colour_type != PNG_COLOR_TYPE_PALETTE)) { DEBUG(misc, 0, "Ignoring mask for SpriteID %d as it isn't a 8 bit palette image", id); return true; } if (!mask) { if (bit_depth == 16) png_set_strip_16(png_ptr); if (colour_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); colour_type = PNG_COLOR_TYPE_RGB; } if (colour_type == PNG_COLOR_TYPE_GRAY || colour_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb(png_ptr); colour_type = PNG_COLOR_TYPE_RGB; } if (colour_type == PNG_COLOR_TYPE_RGB) { png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); } pixelsize = sizeof(uint32); } else { pixelsize = sizeof(uint8); } png_bytep row_pointer = AllocaM(png_byte, png_get_image_width(png_ptr, info_ptr) * pixelsize); for (i = 0; i < png_get_image_height(png_ptr, info_ptr); i++) { png_read_row(png_ptr, row_pointer, NULL); dst = sprite->data + i * png_get_image_width(png_ptr, info_ptr); for (uint x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) { if (mask) { if (row_pointer[x * sizeof(uint8)] != 0) { dst[x].r = 0; dst[x].g = 0; dst[x].b = 0; /* Alpha channel is used from the original image (to allow transparency in remap colours) */ dst[x].m = row_pointer[x * sizeof(uint8)]; } } else { dst[x].r = row_pointer[x * sizeof(uint32) + 0]; dst[x].g = row_pointer[x * sizeof(uint32) + 1]; dst[x].b = row_pointer[x * sizeof(uint32) + 2]; dst[x].a = row_pointer[x * sizeof(uint32) + 3]; dst[x].m = 0; } } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); return true; }
static void PNGAPI png_my_read(png_structp png_ptr, png_bytep data, png_size_t length) { FioReadBlock(data, length); }