void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return; if (nextTag == ID_LIST) { // A list of audio/video chunks int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); size -= 4; // subtract list type // Decode chunks in the list while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { skipChunk(size); return; } Track *track = getTrack(getStreamIndex(nextTag)); if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); Common::SeekableReadStream *chunk = 0; if (size != 0) { chunk = _fileStream->readStream(size); _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != kStreamTypeAudio) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change videoTrack->loadPaletteFromChunk(chunk); } else if (getStreamType(nextTag) == kStreamTypeRawVideo) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); } else { // Otherwise, assume it's a compressed frame videoTrack->decodeFrame(chunk); } } }
void Model3DS::parseMain() { cout << "parseMain" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::EDIT: parseEdit(); break; case chunks::KEYFRAMER: parseKeyframer(); break; default: skipChunk(); } } }
void Model3DS::parseTexmap(Material *material) { cout << "parseTexmap" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::TEXMAP_FILE: { readString(material->texmapFile); cout << material->texmapFile << endl; material->textureRef = numTextures++; break; } default: skipChunk(); } } }
void Model3DS::parseColor(Color &color) { cout << "parseColor" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::COLOR_FLOAT: case chunks::COLOR_FLOATG: fread(&color, sizeof(float), 3, fp); break; case chunks::COLOR_BYTE: case chunks::COLOR_BYTEG: Byte r, g, b; read(r); read(g); read(b); color.r = r/255.0; color.g = g/255.0; color.b = b/255.0; break; default: skipChunk(); } } }
void OgreMeshDeserializer::readGeometry() { std::vector<char> vertexBuffer; std::vector<OgreMeshDeserializer::VertexElement> elements; unsigned int vertexCount = 0; readInts(m_stream, &vertexCount, 1); // Find optional geometry streams if (!m_stream.eof()) { unsigned short streamID = readChunk(m_stream); while (!m_stream.eof() && (streamID == M_GEOMETRY_VERTEX_DECLARATION || streamID == M_GEOMETRY_VERTEX_BUFFER)) { switch (streamID) { case M_GEOMETRY_VERTEX_DECLARATION: elements = readGeometryVertexDeclaration(); break; case M_GEOMETRY_VERTEX_BUFFER: vertexBuffer = readGeometryVertexBuffer(vertexCount); break; default: skipChunk(m_stream); } // Get next stream if (!m_stream.eof()) { streamID = readChunk(m_stream); } } if (!elements.empty()) { for (auto& element : elements) { if (element.vSemantic == VertexElementSemantic::VES_POSITION) { size_t vertexSize = vertexBuffer.size() / vertexCount; for (size_t i = 0; i < vertexCount; ++i) { char* vertexStart = vertexBuffer.data() + (i * vertexSize); char* positionStart = vertexStart + element.offset; if (element.vType == VertexElementType::VET_FLOAT3) { float* positions = reinterpret_cast<float*>(positionStart); m_vertices.push_back(*positions); positions++; m_vertices.push_back(*positions); positions++; m_vertices.push_back(*positions); } } } } } if (!m_stream.eof()) { // Backpedal back to start of non-submesh stream backpedalChunkHeader(m_stream); } } }
void Model3DS::parseObject() { cout << "parseObject" << endl; DWord length = currentChunk.length; Object *object = new Object(textures, currentSelectName++); DWord n = cfg3ds::chunkHeaderSize; n += readString(object->name); cout << "\tname: " << object->name << endl; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::OBJECT_MESH: parseMesh(object); break; default: skipChunk(); } } for (int i=0; i<object->numVertices; ++i) object->normals[i].normalize(); objects.push_back(object); }
void Model3DS::parseMesh(Object *object) { cout << "parseMesh" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::MESH_VERTICES: read(object->numVertices); object->vertices = new Vertex[object->numVertices]; object->normals = new Vector[object->numVertices]; memset(object->normals, 0, sizeof(Vector)*object->numVertices); for (int i=0; i<object->numVertices; ++i) { read(object->vertices[i].x); read(object->vertices[i].y); read(object->vertices[i].z); } break; case chunks::MESH_FACES: parseFaces(object); break; case chunks::MESH_MAPCOORDS: Word numEntries; read(numEntries); object->mapCoords = new MapCoord[numEntries]; for (int i=0; i<numEntries; ++i) { read(object->mapCoords[i].u); read(object->mapCoords[i].v); } break; case chunks::MESH_LOCALCOORDS: read(object->u); read(object->v); read(object->w); read(object->origin); object->u.normalize(); object->v.normalize(); object->w.normalize(); break; default: skipChunk(); } } }
bool AVIDecoder::parseNextChunk() { uint32 tag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return false; debug(3, "Decoding tag %s", tag2str(tag)); switch (tag) { case ID_LIST: handleList(size); break; case ID_AVIH: _header.size = size; _header.microSecondsPerFrame = _fileStream->readUint32LE(); _header.maxBytesPerSecond = _fileStream->readUint32LE(); _header.padding = _fileStream->readUint32LE(); _header.flags = _fileStream->readUint32LE(); _header.totalFrames = _fileStream->readUint32LE(); _header.initialFrames = _fileStream->readUint32LE(); _header.streams = _fileStream->readUint32LE(); _header.bufferSize = _fileStream->readUint32LE(); _header.width = _fileStream->readUint32LE(); _header.height = _fileStream->readUint32LE(); // Ignore 16 bytes of reserved data _fileStream->skip(16); break; case ID_STRH: handleStreamHeader(size); break; case ID_STRD: // Extra stream info, safe to ignore case ID_VEDT: // Unknown, safe to ignore case ID_JUNK: // Alignment bytes, should be ignored case ID_ISFT: // Metadata, safe to ignore case ID_DISP: // Metadata, should be safe to ignore skipChunk(size); break; case ID_IDX1: debug(0, "%d Indices", size / 16); for (uint32 i = 0; i < size / 16; i++) { OldIndex indexEntry; indexEntry.id = _fileStream->readUint32BE(); indexEntry.flags = _fileStream->readUint32LE(); indexEntry.offset = _fileStream->readUint32LE() + _movieListStart - 4; // Adjust to absolute indexEntry.size = _fileStream->readUint32LE(); _indexEntries.push_back(indexEntry); debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags); } break; default: error("Unknown tag \'%s\' found", tag2str(tag)); } return true; }
void StreamTokenizer::nextChunk(SeekableReadStream &stream) { skipChunk(stream); uint32 c = stream.readChar(); if (c == ReadStream::kEOF) return; if (!isIn(c, _chunkEnds)) stream.seek(-1, SeekableReadStream::kOriginCurrent); }
bool AVIDecoder::parseNextChunk() { uint32 tag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return false; debug(6, "Decoding tag %s", tag2str(tag)); switch (tag) { case ID_LIST: handleList(size); break; case ID_AVIH: _header.size = size; _header.microSecondsPerFrame = _fileStream->readUint32LE(); _header.maxBytesPerSecond = _fileStream->readUint32LE(); _header.padding = _fileStream->readUint32LE(); _header.flags = _fileStream->readUint32LE(); _header.totalFrames = _fileStream->readUint32LE(); _header.initialFrames = _fileStream->readUint32LE(); _header.streams = _fileStream->readUint32LE(); _header.bufferSize = _fileStream->readUint32LE(); _header.width = _fileStream->readUint32LE(); _header.height = _fileStream->readUint32LE(); // Ignore 16 bytes of reserved data _fileStream->skip(16); break; case ID_STRH: handleStreamHeader(size); break; case ID_STRD: // Extra stream info, safe to ignore case ID_VEDT: // Unknown, safe to ignore case ID_JUNK: // Alignment bytes, should be ignored case ID_JUNQ: // Same as JUNK, safe to ignore case ID_ISFT: // Metadata, safe to ignore case ID_DISP: // Metadata, should be safe to ignore case ID_DMLH: // OpenDML extension, contains an extra total frames field, safe to ignore skipChunk(size); break; case ID_STRN: // Metadata, safe to ignore readStreamName(size); break; case ID_IDX1: readOldIndex(size); break; default: error("Unknown tag \'%s\' found", tag2str(tag)); } return true; }
static int findChunk(FILE* file, char *tag, int32_t *size) { char curtag[4]; while (1) { if (readHeader(file, curtag, size)) return -1; if (memcmp(curtag, tag, 4) == 0) return 0; if (skipChunk(file, *size)) return -1; } }
void StreamTokenizer::nextChunk(SeekableReadStream &stream) { skipChunk(stream); byte c = stream.readByte(); if (stream.eos() || stream.err()) return; if (!isIn(c, _chunkEnds)) stream.seek(-1, SEEK_CUR); else if (stream.pos() == stream.size()) // This actually the last character, read one more byte to properly set the EOS state stream.readByte(); }
//--------------------------------------------------------------------- void OgreMeshDeserializer::readMesh() { //First value is whether it's skeletally animated m_stream.seekg(sizeof(bool), std::ios_base::cur); // Find all substreams if (!m_stream.eof()) { unsigned short streamID = readChunk(m_stream); while (!m_stream.eof() && (streamID == M_GEOMETRY || streamID == M_SUBMESH || streamID == M_MESH_SKELETON_LINK || streamID == M_MESH_BONE_ASSIGNMENT || streamID == M_MESH_LOD_LEVEL || streamID == M_MESH_BOUNDS || streamID == M_SUBMESH_NAME_TABLE || streamID == M_EDGE_LISTS || streamID == M_POSES || streamID == M_ANIMATIONS || streamID == M_TABLE_EXTREMES)) { switch (streamID) { case M_GEOMETRY: readGeometry(); break; case M_SUBMESH: readSubMesh(); break; case M_MESH_BOUNDS: readBoundsInfo(); break; default: skipChunk(m_stream); } if (!m_stream.eof()) { streamID = readChunk(m_stream); } } if (!m_stream.eof()) { // Backpedal back to start of m_stream backpedalChunkHeader(m_stream); } } }
void LightWaveParser::loadModel(string fname) { in.open(fname.c_str(), ios::in | ios::binary); if (!in.good()) { fprintf(stderr, "Lightwave Parser: Error opening %s\n", fname.c_str()); return ; } string chunkID = readChunkID(in, 4); int size = readIntBE(in); int count = 0; readChunkID(in, 4); // read LWO2 count += 4; while(count < size) { chunkID = readChunkID(in, 4); count += 4; fprintf(stderr, "ID = %s\n", chunkID.c_str()); if(chunkID == "TAGS") { count += parseTags(); } else if(chunkID == "PNTS") { count += parsePoints(); } else if(chunkID == "POLS") { count += parsePolygons(); } else if(chunkID == "PTAG") { parsePTag(); } else if(chunkID == "SURF") { parseSurface(); } else { count += skipChunk(); } } in.close(); calculateNormals(); setupCells(); }
void Model3DS::parseMaterial() { cout << "parseMaterial" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; Material *material = new Material(); while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::MATERIAL_NAME: readString(material->name); break; case chunks::MATERIAL_AMBIENT: parseColor(material->ambient); break; case chunks::MATERIAL_DIFFUSE: parseColor(material->diffuse); break; case chunks::MATERIAL_SPECULAR: parseColor(material->specular); break; case chunks::MATERIAL_TEXMAP: parseTexmap(material); break; default: skipChunk(); } } cout << "\tname: " << material->name << endl; materials.push_back(material); }
void AVIDecoder::readStreamName(uint32 size) { if (!_lastAddedTrack) { skipChunk(size); } else { // Get in the name assert(size > 0 && size < 64); char buffer[64]; _fileStream->read(buffer, size); if (size & 1) _fileStream->skip(1); // Apply it to the most recently read stream assert(_lastAddedTrack); AVIVideoTrack *vidTrack = dynamic_cast<AVIVideoTrack *>(_lastAddedTrack); AVIAudioTrack *audTrack = dynamic_cast<AVIAudioTrack *>(_lastAddedTrack); if (vidTrack) vidTrack->getName() = Common::String(buffer); else if (audTrack) audTrack->getName() = Common::String(buffer); } }
void Model3DS::parseKeyframer() { cout << "parseKeyframer" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::KEYFRAMER_MESHINFO: parseMeshinfo(); break; default: skipChunk(); } } }
static qboolean read_wav_header( int filenum, snd_info_t *info ) { char dump[16]; int fmtlen = 0; // skip the riff wav header trap_FS_Read( dump, 12, filenum ); // Scan for the format chunk if( !( fmtlen = findWavChunk( filenum, "fmt " ) ) ) { Com_Printf( "Error reading wav header: No fmt chunk\n" ); return qfalse; } // Save the parameters FGetLittleShort( filenum ); info->channels = FGetLittleShort( filenum ); info->rate = FGetLittleLong( filenum ); FGetLittleLong( filenum ); FGetLittleShort( filenum ); info->width = FGetLittleShort( filenum ) / 8; // Skip the rest of the format chunk if required if( fmtlen > 16 ) { fmtlen -= 16; skipChunk( filenum, fmtlen ); } // Scan for the data chunk if( !( info->size = findWavChunk( filenum, "data" ) ) ) { Com_Printf( "Error reading wav header: No data chunk\n" ); return qfalse; } info->samples = ( info->size / info->width ) / info->channels; return qtrue; }
// returns the length of the data in the chunk, or 0 if not found static int findWavChunk( int filenum, const char *chunk ) { char name[5]; int len; // This is a bit dangerous... while( qtrue ) { len = readChunkInfo( filenum, name ); // Read failure? if( !len ) return 0; // If this is the right chunk, return if( !strcmp( name, chunk ) ) return len; // Not the right chunk - skip it skipChunk( filenum, len ); } }
void OgreMeshDeserializer::deserialize() { // Determine endianness (must be the first thing we do!) determineEndianness(m_stream); // Check header readFileHeader(m_stream); unsigned short streamID = readChunk(m_stream); while (!m_stream.eof()) { switch (streamID) { case M_MESH: readMesh(); break; default: skipChunk(m_stream); } streamID = readChunk(m_stream); } }
FILE* openWavFile(const char *filename, short *format, long *speed, int *samples, short *channels, short *width) { FILE* file; int16_t blockAlign, bitsPerSample, data16; int32_t bytesPerSec, len, data32; char tag[5]; // open file file = fopen(filename, "rb"); if (!file) return NULL; // automatically close file when we return FileCloser closer(file); // check that it's a valid sound file tag[4] = 0; if (readHeader(file, tag, &len)) return NULL; if (strcmp(tag, "RIFF") != 0) { fprintf(stderr, "File isn't a RIFF file\n"); return NULL; } if ((fread(tag, 1, 4, file) != 4) || strcmp(tag, "WAVE") != 0) { fprintf(stderr, "File isn't a proper WAVE file\n"); return NULL; } if (findChunk(file, "fmt ", &len)) { fprintf(stderr, "Couldn't find format in WAVE\n"); return NULL; } if (len < 16) { fprintf(stderr, "Chunk size not large enough\n"); return NULL; } if (readShort(file, &data16)) { fprintf(stderr, "Couldn't read format\n"); return NULL; } *format = (short)data16; if (readShort(file, &data16)) { fprintf(stderr, "Couldn't read channels\n"); return NULL; } *channels = (short)data16; if (readLong(file, &data32)) { fprintf(stderr, "Couldn't read speed\n"); return NULL; } *speed = (long)data32; if (readLong(file, &bytesPerSec)) { fprintf(stderr, "Couldn't read bytes per second\n"); return NULL; } if (readShort(file, &blockAlign)) { fprintf(stderr, "Couldn't read block alignment\n"); return NULL; } if (readShort(file, &bitsPerSample)) { fprintf(stderr, "Couldn't read bits per sample\n"); return NULL; } if (bitsPerSample==8) *width=1; else if (bitsPerSample==16) *width=2; else if (bitsPerSample==32) *width=4; else return NULL; // go find the data skipChunk(file, len - 16); if (findChunk(file, "data", &len)) { fprintf(stderr, "Failed to find the the data in WAVE\n"); return NULL; } *samples = (int)(len / (int32_t)(*width) / (int32_t)(*channels)); closer.release(); return file; }
void Model3DS::parseEdit() { cout << "parseEdit" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; numTextures = 0; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::EDIT_OBJECT: parseObject(); break; case chunks::EDIT_MATERIAL: parseMaterial(); break; default: skipChunk(); } } textures = new GLuint[numTextures]; glGenTextures(numTextures, textures); for (list<Material *>::iterator it = materials.begin(); it != materials.end(); ++it) { if ((*it)->texmapFile == NULL) continue; char *texmapFileName = new char[strlen(path) + strlen((*it)->texmapFile) + 1]; sprintf(texmapFileName, "%s%s", path, (*it)->texmapFile); sf::Image image; bool result = image.LoadFromFile(texmapFileName); delete [] texmapFileName; if (result == false) { cout << "Can't read texture file!" << endl; (*it)->texmapFile = NULL; continue; } glBindTexture(GL_TEXTURE_2D, textures[(*it)->textureRef]); // select modulate to mix texture with color for shading glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // when texture area is small, bilinear filter the closest mipmap glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // when texture area is large, bilinear filter the original glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // the texture wraps over at the edges (repeat) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.GetWidth(), image.GetHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.GetPixelsPtr()); } }
//--------------------------------------------------------------------- void OgreMeshDeserializer::readSubMesh() { unsigned short streamID; std::string materialName = readString(m_stream); bool useSharedVertices; readBools(m_stream, &useSharedVertices, 1); size_t offset = 0; if (!useSharedVertices) { offset = m_vertices.size() / 3; } unsigned int indexCount = 0; readInts(m_stream, &indexCount, 1); bool idx32bit; readBools(m_stream, &idx32bit, 1); if (indexCount > 0) { if (idx32bit) { std::vector<std::uint32_t> indices; indices.resize(indexCount); readInts(m_stream, indices.data(), indexCount); for (auto& index : indices) { m_indices.emplace_back(index + offset); } } else // 16-bit { std::vector<std::uint16_t> indices; indices.resize(indexCount); readShorts(m_stream, indices.data(), indexCount); for (auto& index : indices) { m_indices.emplace_back(index + offset); } } } { // M_GEOMETRY m_stream (Optional: present only if useSharedVertices = false) if (!useSharedVertices) { streamID = readChunk(m_stream); if (streamID != M_GEOMETRY) { std::runtime_error("Missing geometry data in mesh file"); } readGeometry(); } // Find all bone assignments, submesh operation, and texture aliases (if present) if (!m_stream.eof()) { streamID = readChunk(m_stream); while (!m_stream.eof() && (streamID == M_SUBMESH_BONE_ASSIGNMENT || streamID == M_SUBMESH_OPERATION || streamID == M_SUBMESH_TEXTURE_ALIAS)) { skipChunk(m_stream); if (!m_stream.eof()) { streamID = readChunk(m_stream); } } if (!m_stream.eof()) { // Backpedal back to start of m_stream backpedalChunkHeader(m_stream); } } } }
void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) return; if (nextTag == ID_LIST) { // A list of audio/video chunks int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); size -= 4; // subtract list type // Decode chunks in the list while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { skipChunk(size); return; } Track *track = getTrack(getStreamIndex(nextTag)); if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); Common::SeekableReadStream *chunk = 0; if (size != 0) { chunk = _fileStream->readStream(size); _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != MKTAG16('w', 'b')) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; if (getStreamType(nextTag) == MKTAG16('p', 'c')) { // Palette Change assert(chunk); byte firstEntry = chunk->readByte(); uint16 numEntries = chunk->readByte(); chunk->readUint16LE(); // Reserved // 0 entries means all colors are going to be changed if (numEntries == 0) numEntries = 256; byte *palette = const_cast<byte *>(videoTrack->getPalette()); for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { palette[i * 3] = chunk->readByte(); palette[i * 3 + 1] = chunk->readByte(); palette[i * 3 + 2] = chunk->readByte(); chunk->readByte(); // Flags that don't serve us any purpose } delete chunk; videoTrack->markPaletteDirty(); } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); } else { // Otherwise, assume it's a compressed frame videoTrack->decodeFrame(chunk); } } }
void AVIDecoder::handleNextPacket(TrackStatus &status) { // If there's no more to search, bail out if (status.chunkSearchOffset + 8 >= _movieListEnd) { if (status.track->getTrackType() == Track::kTrackTypeVideo) { // Horrible AVI video has a premature end // Force the frame to be the last frame debug(7, "Forcing end of AVI video"); ((AVIVideoTrack *)status.track)->forceTrackEnd(); } return; } // See if audio needs to be buffered and break out if not if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status)) return; // Seek to where we shall start searching _fileStream->seek(status.chunkSearchOffset); for (;;) { // If there's no more to search, bail out if ((uint32)_fileStream->pos() + 8 >= _movieListEnd) { if (status.track->getTrackType() == Track::kTrackTypeVideo) { // Horrible AVI video has a premature end // Force the frame to be the last frame debug(7, "Forcing end of AVI video"); ((AVIVideoTrack *)status.track)->forceTrackEnd(); } break; } uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (nextTag == ID_LIST) { // A list of audio/video chunks if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); continue; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { skipChunk(size); continue; } // Only accept chunks for this stream uint32 streamIndex = getStreamIndex(nextTag); if (streamIndex != status.index) { skipChunk(size); continue; } Common::SeekableReadStream *chunk = 0; if (size != 0) { chunk = _fileStream->readStream(size); _fileStream->skip(size & 1); } if (status.track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != kStreamTypeAudio) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); ((AVIAudioTrack *)status.track)->queueSound(chunk); // Break out if we have enough audio if (!shouldQueueAudio(status)) break; } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track; if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change videoTrack->loadPaletteFromChunk(chunk); } else { // Otherwise, assume it's a compressed frame videoTrack->decodeFrame(chunk); break; } } } // Start us off in this position next time status.chunkSearchOffset = _fileStream->pos(); }
void Model3DS::parseFaces(Object *object) { cout << "parseFaces" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; n += read(object->numFaces); object->faces = new Face[object->numFaces]; Word faceFlag; for (int i=0; i<object->numFaces; ++i) { n += read(object->faces[i].vertexA); n += read(object->faces[i].vertexB); n += read(object->faces[i].vertexC); n += read(faceFlag); Vector vectorAB = object->vertices[object->faces[i].vertexB] - object->vertices[object->faces[i].vertexA]; Vector vectorBC = object->vertices[object->faces[i].vertexC] - object->vertices[object->faces[i].vertexB]; Vector faceNormal = vectorAB * vectorBC; object->normals[object->faces[i].vertexA] += faceNormal; object->normals[object->faces[i].vertexB] += faceNormal; object->normals[object->faces[i].vertexC] += faceNormal; } VertexList *vertexList; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::FACES_MATERIALS: vertexList = new VertexList(); char *materialName; readString(materialName); // find the material for (list<Material *>::const_iterator it = materials.begin(); it != materials.end(); ++it) { if (strcmp((*it)->name, materialName) == 0) { vertexList->material = *it; break; } } delete [] materialName; if (vertexList->material == NULL) throw runtime_error("Needed material not found in materials list!"); Word numEntries; read(numEntries); vertexList->numVerticesRefs = numEntries * 3; // *3 because there are 3 vertices per face vertexList->verticesRefs = new Word[vertexList->numVerticesRefs]; Word faceRef; for (unsigned int i=0; i<vertexList->numVerticesRefs; i+=3) { read(faceRef); vertexList->verticesRefs[i] = object->faces[faceRef].vertexA; vertexList->verticesRefs[i+1] = object->faces[faceRef].vertexB; vertexList->verticesRefs[i+2] = object->faces[faceRef].vertexC; } object->vertexLists.push_back(vertexList); break; default: skipChunk(); } } }
void Model3DS::parseMeshinfo() { //cout << "parseMeshinfo" << endl; DWord length = currentChunk.length; DWord n = cfg3ds::chunkHeaderSize; Object *object = NULL; while (n < length) { readChunkHeader(); n += currentChunk.length; switch (currentChunk.id) { case chunks::MESHINFO_HIERARCHY: char *name; Word flag1, flag2, hierarchy; object = NULL; readString(name); // if (strcmp(name, "$$$DUMMY") == 0) // break; read(flag1); read(flag2); read(hierarchy); cout << name << " " << static_cast<short int>(hierarchy) << endl; for (list<Object *>::const_iterator it = objects.begin(); it != objects.end(); ++it) { if (strcmp((*it)->name, name) == 0) { object = *it; break; } } if (object == NULL) { delete [] name; break; } if ((static_cast<short int>(hierarchy) <= rootLevel && strcmp(name, "$$$DUMMY") != 0) || previousObject == NULL) { cout << "adding root: " << name << endl; roots.push_back(object); parents.resize(static_cast<short int>(hierarchy)+2); parents[static_cast<short int>(hierarchy)+1] = object; currentParent = object; rootLevel = static_cast<short int>(hierarchy); } else { if (static_cast<short int>(hierarchy) > previousLevel) { currentParent = previousObject; parents.resize(hierarchy+1); parents[hierarchy] = currentParent; } else if (static_cast<short int>(hierarchy) < previousLevel) currentParent = parents[hierarchy]; cout << "adding " << name << " " << object->selectName << " to " << currentParent->name << endl; currentParent->children.push_back(object); } for (int i=0; i<object->numVertices; i+=1) { // cout << object->vertices[i].x << " " << object->vertices[i].y << " " << object->vertices[i].z << endl; } cout << object->u.x << " " << object->v.x << " " << object->w.x << " " << object->origin.x << endl; cout << object->u.y << " " << object->v.y << " " << object->w.y << " " << object->origin.y << endl; cout << object->u.z << " " << object->v.z << " " << object->w.z << " " << object->origin.z << endl; cout << 0.f << " " << 0.f << " " << 0.f << " " << 1.f << endl; previousLevel = static_cast<short int>(hierarchy); previousObject = object; delete [] name; break; case chunks::MESHINFO_PIVOT: if (object == NULL) { skipChunk(); break; } read(object->pivot); cout << "pivot: " << object->pivot.x << " " << object->pivot.y << " " << object->pivot.z << endl; break; case chunks::MESHINFO_POSTRACK: case chunks::MESHINFO_ROTTRACK: case chunks::MESHINFO_SCALETRACK: if (object == NULL) { skipChunk(); break; } Word flag; DWord unknown, keys; read(flag); read(unknown); read(unknown); read(keys); for (unsigned int i=0; i<keys; ++i) { DWord key; Word accelFlag; read(key); read(accelFlag); // Let's assume accelFlag is always 0 and skip to the track specific data switch (currentChunk.id) { case chunks::MESHINFO_POSTRACK: read(object->postrack); cout << "postrack:\t" << object->postrack.x << " " << object->postrack.y << " " << object->postrack.z << endl; break; case chunks::MESHINFO_ROTTRACK: read(object->rottrackAngle); read(object->rottrackAxis); cout << "rottrack:\t" << object->rottrackAxis.x << " " << object->rottrackAxis.y << " " << object->rottrackAxis.z << " " << object->rottrackAngle << endl; break; case chunks::MESHINFO_SCALETRACK: read(object->scaletrackX); read(object->scaletrackY); read(object->scaletrackZ); cout << "scaletrack:\t" << object->scaletrackX << " " << object->scaletrackY << " " << object->scaletrackZ << endl; break; } } break; default: skipChunk(); } } }
bool readSMM0 (FILE *file, const char **errorString, sid_usage_t &usage, const IffHeader &header) { Smm_v0 smm; smm.header = header; { // Read file long pos = ftell (file); bool error = true; for(;;) { size_t ret; uint_least32_t length = 0; uint8_t chunk[4]; // Read a chunk header ret = fread (&chunk, sizeof (chunk), 1, file); // If no chunk header assume end of file if (ret != 1) break; // Check for a chunk we are interested in switch (endian_big32 (chunk)) { case INF0_ID: length = readChunk (file, smm.info); break; case ERR0_ID: length = readChunk (file, smm.error); break; case MD5_ID: length = readChunk (file, smm.md5); break; case TIME_ID: length = readChunk (file, smm.time); break; case BODY_ID: length = readChunk (file, smm.body); break; default: length = skipChunk (file); } if (!length) { error = true; break; } // Move past the chunk pos += (long) length + (sizeof(uint8_t) * 8); fseek (file, pos, SEEK_SET); if (ftell (file) != pos) { error = true; break; } error = false; } // Check for file reader error if (error) { *errorString = txt_reading; return false; } } // Test that all required checks were found if ((smm.info.length == 0) || (smm.error.length == 0) || (smm.body.length == 0)) { *errorString = txt_missing; return false; } // Extract usage information {for (int i = 0; i < 0x100; i++) { int addr = smm.body.usage[i].page << 8; if ((addr == 0) && (i != 0)) break; memcpy (&usage.memory[addr], smm.body.usage[i].flags, sizeof (uint8_t) * 0x100); }} { // File in the load range uint_least16_t load, last; int length; load = endian_big16 (smm.info.startAddr); last = endian_big16 (smm.info.stopAddr); length = (int) (last - load) + 1; if (length < 0) { *errorString = txt_corrupt; return false; } {for (int i = 0; i < length; i++) usage.memory[load + i] |= SID_LOAD_IMAGE; } } usage.flags = endian_big16(smm.error.flags); return true; }
void AVIDecoder::readNextPacket() { if ((uint32)_fileStream->pos() >= _movieListEnd) { // Ugh, reached the end premature. forceVideoEnd(); return; } uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); if (_fileStream->eos()) { // Also premature end. forceVideoEnd(); return; } if (nextTag == ID_LIST) { // A list of audio/video chunks int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) error("Expected 'rec ' LIST"); size -= 4; // subtract list type // Decode chunks in the list while (_fileStream->pos() < startPos + (int32)size) readNextPacket(); return; } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { skipChunk(size); return; } Track *track = getTrack(getStreamIndex(nextTag)); if (!track) error("Cannot get track from tag '%s'", tag2str(nextTag)); Common::SeekableReadStream *chunk = 0; if (size != 0) { chunk = _fileStream->readStream(size); _fileStream->skip(size & 1); } if (track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != kStreamTypeAudio) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change videoTrack->loadPaletteFromChunk(chunk); } else { // Otherwise, assume it's a compressed frame videoTrack->decodeFrame(chunk); } } }