From e33e19d0587146859d48a134ec9fd94e7b7ba5cd Mon Sep 17 00:00:00 2001 From: "FWoltermann@gmail.com" Date: Thu, 8 Dec 2011 14:53:40 +0000 Subject: Initial upload --- nGenEx/DataLoader.cpp | 1013 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1013 insertions(+) create mode 100644 nGenEx/DataLoader.cpp (limited to 'nGenEx/DataLoader.cpp') diff --git a/nGenEx/DataLoader.cpp b/nGenEx/DataLoader.cpp new file mode 100644 index 0000000..354232b --- /dev/null +++ b/nGenEx/DataLoader.cpp @@ -0,0 +1,1013 @@ +/* Project nGenEx + Destroyer Studios LLC + Copyright © 1997-2004. All Rights Reserved. + + SUBSYSTEM: nGenEx.lib + FILE: DataLoader.cpp + AUTHOR: John DiCamillo + +*/ + +#include "MemDebug.h" +#include "DataLoader.h" +#include "Archive.h" +#include "Color.h" +#include "D3DXImage.h" +#include "Bitmap.h" +#include "Bmp.h" +#include "PCX.h" +#include "Sound.h" +#include "Resource.h" +#include "Video.h" +#include "Wave.h" + +// +------------------------------------------------------------------+ + +static DataLoader* def_loader = 0; + DataLoader* DataLoader::loader = 0; + +static List archives; + +// +--------------------------------------------------------------------+ + +DataLoader::DataLoader() + : datapath(""), video(0), use_file_system(true), enable_media(true) +{ } + +// +--------------------------------------------------------------------+ + +void +DataLoader::UseVideo(Video* v) +{ + video = v; +} + +// +--------------------------------------------------------------------+ + +void +DataLoader::Initialize() +{ + def_loader = new(__FILE__,__LINE__) DataLoader; + loader = def_loader; + + archives.destroy(); +} + +void +DataLoader::Close() +{ + archives.destroy(); + Bitmap::ClearCache(); + + delete def_loader; + def_loader = 0; + loader = 0; +} + +void +DataLoader::Reset() +{ + Close(); +} + +// +--------------------------------------------------------------------+ + +void +DataLoader::UseFileSystem(bool use) +{ + use_file_system = use; +} + +void +DataLoader::EnableMedia(bool enable) +{ + enable_media = enable; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::EnableDatafile(const char* name) +{ + int status = DATAFILE_NOTEXIST; + + FILE* f = fopen(name, "rb"); + if (f) { + ::fclose(f); + + DataArchive* a = new(__FILE__,__LINE__) DataArchive(name); + + if (a && a->NumFiles() >= 1) { + status = DATAFILE_OK; + + bool found = false; + ListIter iter = archives; + while (++iter && !found) { + DataArchive* archive = iter.value(); + if (!strcmp(archive->Name(), name)) { + found = true; + } + } + + if (!found) + archives.append(a); + } + else { + Print(" WARNING: invalid data file '%s'\n", name); + status = DATAFILE_INVALID; + + delete a; + } + + loader = this; + } + else { + Print(" WARNING: could not open datafile '%s'\n", name); + status = DATAFILE_NOTEXIST; + } + + return status; +} + +int +DataLoader::DisableDatafile(const char* name) +{ + ListIter iter = archives; + while (++iter) { + DataArchive* a = iter.value(); + if (!strcmp(a->Name(), name)) { + delete iter.removeItem(); + return DATAFILE_OK; + } + } + + return DATAFILE_NOTEXIST; +} + +// +--------------------------------------------------------------------+ + +void +DataLoader::SetDataPath(const char* path) +{ + if (path) + datapath = path; + else + datapath = ""; +} + +// +--------------------------------------------------------------------+ + +bool +DataLoader::FindFile(const char* name) +{ + // assemble file name: + char filename[1024]; + strcpy(filename, datapath); + strcat(filename, name); + + // first check current directory: + if (use_file_system) { + FILE* f = ::fopen(filename, "rb"); + + if (f) { + ::fclose(f); + return true; + } + } + + // then check datafiles, from last to first: + int narchives = archives.size(); + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + if (a->FindEntry(filename) > -1) { + return true; + } + } + + return false; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::ListFiles(const char* filter, List& list, bool recurse) +{ + list.destroy(); + + ListFileSystem(filter, list, datapath, recurse); + + // then check datafile(s): + int narchives = archives.size(); + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + ListArchiveFiles(a->Name(), filter, list); + } + + return list.size(); +} + +int +DataLoader::ListArchiveFiles(const char* archive_name, const char* filter, List &list) +{ + int pathlen = datapath.length(); + DataArchive* a = 0; + + if (archive_name) { + int narchives = archives.size(); + for (int i = 0; i < narchives && !a; i++) { + a = archives[narchives-1-i]; + + if (stricmp(a->Name(), archive_name)) + a = 0; + } + } + + if (!a) { + ListFileSystem(filter, list, datapath, true); + return list.size(); + } + + if (!strcmp(filter, "*.*")) { + int count = a->NumFiles(); + for (int n = 0; n < count; n++) { + DataEntry* entry = a->GetFile(n); + Text entry_name = entry->name; + entry_name.setSensitive(false); + + if (entry_name.contains(datapath)) { + Text fname = entry_name(pathlen, 1000); + + if (!list.contains(&fname)) + list.append(new Text(fname)); + } + } + } + else { + char data_filter[256]; + ZeroMemory(data_filter, 256); + + const char* pf = filter; + char* pdf = data_filter; + + while (*pf) { + if (*pf != '*') + *pdf++ = *pf; + pf++; + } + + int count = a->NumFiles(); + for (int n = 0; n < count; n++) { + DataEntry* entry = a->GetFile(n); + Text entry_name = entry->name; + entry_name.setSensitive(false); + + if (entry_name.contains(datapath) && entry_name.contains(data_filter)) { + Text fname = entry_name(pathlen, 1000); + + if (!list.contains(&fname)) + list.append(new Text(fname)); + } + } + } + + return list.size(); +} + +// +--------------------------------------------------------------------+ + +void +DataLoader::ListFileSystem(const char* filter, List& list, Text base_path, bool recurse) +{ + if (use_file_system) { + char data_filter[256]; + ZeroMemory(data_filter, 256); + + const char* pf = filter; + char* pdf = data_filter; + + while (*pf) { + if (*pf != '*') + *pdf++ = *pf; + pf++; + } + + int pathlen = base_path.length(); + + // assemble win32 find filter: + char win32_filter[1024]; + strcpy(win32_filter, datapath); + + if (recurse) + strcat(win32_filter, "*.*"); + else + strcat(win32_filter, filter); + + // first check current directory: + WIN32_FIND_DATA data; + HANDLE hFind = FindFirstFile(win32_filter, &data); + + if (hFind != INVALID_HANDLE_VALUE) { + do { + if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { + if (recurse && data.cFileName[0] != '.') { + Text old_datapath = datapath; + + Text newpath = datapath; + newpath += data.cFileName; + newpath += "/"; + datapath = newpath; + + ListFileSystem(filter, list, base_path, recurse); + + datapath = old_datapath; + } + } + else { + if (!strcmp(filter, "*.*") || strstr(data.cFileName, data_filter)) { + Text full_name = datapath; + full_name += data.cFileName; + + list.append(new Text(full_name(pathlen, 1000))); + } + } + } + while (FindNextFile(hFind, &data)); + } + } +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadBuffer(const char* name, BYTE*& buf, bool null_terminate, bool optional) +{ + buf = 0; + + // assemble file name: + char filename[1024]; + strcpy(filename, datapath); + strcat(filename, name); + + if (use_file_system) { + // first check current directory: + FILE* f = ::fopen(filename, "rb"); + + if (f) { + ::fseek(f, 0, SEEK_END); + int len = ftell(f); + ::fseek(f, 0, SEEK_SET); + + if (null_terminate) { + buf = new(__FILE__,__LINE__) BYTE[len+1]; + if (buf) + buf[len] = 0; + } + + else { + buf = new(__FILE__,__LINE__) BYTE[len]; + } + + if (buf) + ::fread(buf, len, 1, f); + + ::fclose(f); + + return len; + } + } + + // then check datafile(s): + int narchives = archives.size(); + + // vox files are usually in their own archive, + // so check there first + if (narchives > 1 && strstr(filename, "Vox")) { + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + if (strstr(a->Name(), "vox")) { + int index = a->FindEntry(filename); + if (index > -1) + return a->ExpandEntry(index, buf, null_terminate); + } + } + } + + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + int index = a->FindEntry(filename); + if (index > -1) + return a->ExpandEntry(index, buf, null_terminate); + } + + if (!optional) + Print("WARNING - DataLoader could not load buffer '%s'\n", filename); + return 0; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadPartialFile(const char* name, BYTE*& buf, int max_load, bool optional) +{ + buf = 0; + + // assemble file name: + char filename[1024]; + strcpy(filename, datapath); + strcat(filename, name); + + // first check current directory: + FILE* f = ::fopen(filename, "rb"); + + if (f) { + ::fseek(f, 0, SEEK_END); + int len = ftell(f); + ::fseek(f, 0, SEEK_SET); + + if (len > max_load) { + len = max_load; + } + + buf = new(__FILE__,__LINE__) BYTE[len]; + + if (buf) + ::fread(buf, len, 1, f); + + ::fclose(f); + + return len; + } + + if (!optional) + Print("WARNING - DataLoader could not load partial file '%s'\n", filename); + return 0; +} + +int +DataLoader::fread(void* buffer, size_t size, size_t count, BYTE*& stream) +{ + CopyMemory(buffer, stream, size*count); + stream += size*count; + + return size*count; +} + +// +--------------------------------------------------------------------+ + +void +DataLoader::ReleaseBuffer(BYTE*& buf) +{ + delete [] buf; + buf = 0; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::CacheBitmap(const char* name, Bitmap*& bitmap, int type, bool optional) +{ + int result = 0; + + // search cache: + bitmap = Bitmap::CheckCache(name); + if (bitmap) return 1; + + // not in cache yet: + bitmap = new(__FILE__,__LINE__) Bitmap; + + if (bitmap) + result = LoadBitmap(name, *bitmap, type, optional); + + if (result && bitmap) + Bitmap::AddToCache(bitmap); + + return result; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadBitmap(const char* name, Bitmap& bitmap, int type, bool optional) +{ + if (!enable_media) + return 0; + + int result = LoadIndexed(name, bitmap, type); + + // check for a matching high color bitmap: + if (result == 1) { + int hi_result = LoadHiColor(name, bitmap, type); + + if (hi_result == 2) + result = 3; + } + + bitmap.SetFilename(name); + + if (!result && !optional) + Print("WARNING - DataLoader could not load bitmap '%s%s'\n", datapath.data(), name); + + return result; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadTexture(const char* name, Bitmap*& bitmap, int type, bool preload_cache, bool optional) +{ + if (!enable_media) + return 0; + + int result = 0; + + // assemble file name: + char filename[256]; + strcpy(filename, datapath); + strcat(filename, name); + + // search cache: + bitmap = Bitmap::CheckCache(filename); + if (bitmap) return 1; + + // not in cache yet: + bitmap = new(__FILE__,__LINE__) Bitmap; + + if (bitmap) { + result = LoadHiColor(name, *bitmap, type); + + if (!result) { + result = LoadIndexed(name, *bitmap, type); + } + + bitmap->SetFilename(filename); + + if (result) { + bitmap->MakeTexture(); + Bitmap::AddToCache(bitmap); + } + else { + delete bitmap; + bitmap = 0; + + if (!optional) + Print("WARNING - DataLoader could not load texture '%s%s'\n", datapath.data(), name); + } + } + else if (!optional) { + Print("WARNING - DataLoader could not allocate texture '%s%s'\n", datapath.data(), name); + } + + return result; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadIndexed(const char* name, Bitmap& bitmap, int type) +{ + if (!enable_media) + return 0; + + int result = 0; + PcxImage pcx; + D3DXImage d3dx; + bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX"); + + // assemble file name: + char filename[256]; + strcpy(filename, datapath); + strcat(filename, name); + + // first try to load from current directory: + bool loaded = false; + + if (use_file_system) { + if (pcx_file) + loaded = pcx.Load(filename) == PCX_OK; + + else + loaded = d3dx.Load(filename); + } + + if (!loaded) { + // then check datafile: + int len = 0; + BYTE* tmp_buf = 0; + + int narchives = archives.size(); + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + int index = a->FindEntry(filename); + if (index > -1) { + len = a->ExpandEntry(index, tmp_buf); + + if (pcx_file) + pcx.LoadBuffer(tmp_buf, len); + + else + d3dx.LoadBuffer(tmp_buf, len); + + ReleaseBuffer(tmp_buf); + break; + } + } + } + + // now copy the image into the bitmap: + if (pcx_file) { + if (pcx.bitmap) { + bitmap.CopyImage(pcx.width, pcx.height, pcx.bitmap, type); + result = 1; + } + + else if (pcx.himap) { + bitmap.CopyHighColorImage(pcx.width, pcx.height, pcx.himap, type); + result = 2; + } + + if (result == 2) + LoadAlpha(name, bitmap, type); + } + + else { + if (d3dx.image) { + bitmap.CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image, type); + result = 2; + } + + if (result == 2) { + LoadAlpha(name, bitmap, type); + } + } + + return result; +} + +int +DataLoader::LoadHiColor(const char* name, Bitmap& bitmap, int type) +{ + if (!enable_media) + return 0; + + int result = 0; + PcxImage pcx; + D3DXImage d3dx; + bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX"); + bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP"); + bool png_file = strstr(name, ".png") || strstr(name, ".PNG"); + + // check for a matching high color bitmap: + char filename[256]; + char name2[256]; + strcpy(name2, name); + + char* dot = strrchr(name2, '.'); + if (dot && pcx_file) + strcpy(dot, "+.pcx"); + else if (dot && bmp_file) + strcpy(dot, "+.bmp"); + else if (dot && png_file) + strcpy(dot, "+.png"); + else + return result; + + strcpy(filename, datapath); + strcat(filename, name2); + + // first try to load from current directory: + bool loaded = false; + + if (use_file_system) { + if (pcx_file) + loaded = pcx.Load(filename) == PCX_OK; + + else + loaded = d3dx.Load(filename); + } + + if (!loaded) { + // then check datafile: + int len = 0; + BYTE* tmp_buf = 0; + + int narchives = archives.size(); + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + int index = a->FindEntry(filename); + if (index > -1) { + len = a->ExpandEntry(index, tmp_buf); + + if (pcx_file) + pcx.LoadBuffer(tmp_buf, len); + else + d3dx.LoadBuffer(tmp_buf, len); + + ReleaseBuffer(tmp_buf); + break; + } + } + } + + // now copy the image into the bitmap: + if (pcx_file && pcx.himap) { + bitmap.CopyHighColorImage(pcx.width, pcx.height, pcx.himap, type); + result = 2; + } + + else if (d3dx.image) { + bitmap.CopyHighColorImage(d3dx.width, d3dx.height, d3dx.image, type); + result = 2; + } + + if (result == 2) + LoadAlpha(name, bitmap, type); + + return result; +} + +int +DataLoader::LoadAlpha(const char* name, Bitmap& bitmap, int type) +{ + if (!enable_media) + return 0; + + PcxImage pcx; + D3DXImage d3dx; + bool pcx_file = strstr(name, ".pcx") || strstr(name, ".PCX"); + bool bmp_file = strstr(name, ".bmp") || strstr(name, ".BMP"); + bool png_file = strstr(name, ".png") || strstr(name, ".PNG"); + bool tga_file = strstr(name, ".tga") || strstr(name, ".TGA"); + + // check for an associated alpha-only (grayscale) bitmap: + char filename[256]; + char name2[256]; + strcpy(name2, name); + char* dot = strrchr(name2, '.'); + if (dot && pcx_file) + strcpy(dot, "@.pcx"); + else if (dot && bmp_file) + strcpy(dot, "@.bmp"); + else if (dot && png_file) + strcpy(dot, "@.png"); + else if (dot && tga_file) + strcpy(dot, "@.tga"); + else + return 0; + + strcpy(filename, datapath); + strcat(filename, name2); + + // first try to load from current directory: + bool loaded = false; + + if (use_file_system) { + if (pcx_file) + loaded = pcx.Load(filename) == PCX_OK; + + else + loaded = d3dx.Load(filename); + } + + if (!loaded) { + // then check datafile: + int len = 0; + BYTE* tmp_buf = 0; + + int narchives = archives.size(); + for (int i = 0; i < narchives; i++) { + DataArchive* a = archives[narchives-1-i]; + int index = a->FindEntry(filename); + if (index > -1) { + len = a->ExpandEntry(index, tmp_buf); + + if (pcx_file) + pcx.LoadBuffer(tmp_buf, len); + else + d3dx.LoadBuffer(tmp_buf, len); + + ReleaseBuffer(tmp_buf); + break; + } + } + } + + // now copy the alpha values into the bitmap: + if (pcx_file && pcx.bitmap) { + bitmap.CopyAlphaImage(pcx.width, pcx.height, pcx.bitmap); + } + else if (pcx_file && pcx.himap) { + bitmap.CopyAlphaRedChannel(pcx.width, pcx.height, pcx.himap); + } + else if (d3dx.image) { + bitmap.CopyAlphaRedChannel(d3dx.width, d3dx.height, d3dx.image); + } + + return 0; +} + +// +--------------------------------------------------------------------+ + +int +DataLoader::LoadSound(const char* name, Sound*& snd, DWORD flags, bool optional) +{ + if (!enable_media) + return 0; + + if (strstr(name, ".ogg")) + return LoadStream(name, snd, optional); + + int result = 0; + + WAVE_HEADER head; + WAVE_FMT fmt; + WAVE_FACT fact; + WAVE_DATA data; + WAVEFORMATEX wfex; + LPBYTE wave; + + LPBYTE buf; + LPBYTE p; + int len; + + ZeroMemory(&head, sizeof(head)); + ZeroMemory(&fmt, sizeof(fmt)); + ZeroMemory(&fact, sizeof(fact)); + ZeroMemory(&data, sizeof(data)); + + len = LoadBuffer(name, buf, false, optional); + + if (len > sizeof(head)) { + CopyMemory(&head, buf, sizeof(head)); + + if (head.RIFF == MAKEFOURCC('R', 'I', 'F', 'F') && + head.WAVE == MAKEFOURCC('W', 'A', 'V', 'E')) { + + p = buf + sizeof(WAVE_HEADER); + + do { + DWORD chunk_id = *((LPDWORD) p); + + switch (chunk_id) { + case MAKEFOURCC('f', 'm', 't', ' '): + CopyMemory(&fmt, p, sizeof(fmt)); + p += fmt.chunk_size + 8; + break; + + case MAKEFOURCC('f', 'a', 'c', 't'): + CopyMemory(&fact, p, sizeof(fact)); + p += fact.chunk_size + 8; + break; + + case MAKEFOURCC('s', 'm', 'p', 'l'): + CopyMemory(&fact, p, sizeof(fact)); + p += fact.chunk_size + 8; + break; + + case MAKEFOURCC('d', 'a', 't', 'a'): + CopyMemory(&data, p, sizeof(data)); + p += 8; + break; + + default: + ReleaseBuffer(buf); + return result; + } + } + while (data.chunk_size == 0); + + wfex.wFormatTag = fmt.wFormatTag; + wfex.nChannels = fmt.nChannels; + wfex.nSamplesPerSec = fmt.nSamplesPerSec; + wfex.nAvgBytesPerSec = fmt.nAvgBytesPerSec; + wfex.nBlockAlign = fmt.nBlockAlign; + wfex.wBitsPerSample = fmt.wBitsPerSample; + wfex.cbSize = 0; + wave = p; + + snd = Sound::Create(flags, &wfex, data.chunk_size, wave); + + if (snd) + result = data.chunk_size; + } + } + + ReleaseBuffer(buf); + return result; +} + +int +DataLoader::LoadStream(const char* name, Sound*& snd, bool optional) +{ + if (!enable_media) + return 0; + + if (!name) + return 0; + + int namelen = strlen(name); + + if (namelen < 5) + return 0; + + if ((name[namelen-3] == 'o' || name[namelen-3] == 'O') && + (name[namelen-2] == 'g' || name[namelen-2] == 'G') && + (name[namelen-1] == 'g' || name[namelen-1] == 'G')) { + + return LoadOggStream(name, snd); + } + + int result = 0; + + WAVE_HEADER head; + WAVE_FMT fmt; + WAVE_FACT fact; + WAVE_DATA data; + WAVEFORMATEX wfex; + + LPBYTE buf; + LPBYTE p; + int len; + + ZeroMemory(&head, sizeof(head)); + ZeroMemory(&fmt, sizeof(fmt)); + ZeroMemory(&fact, sizeof(fact)); + ZeroMemory(&data, sizeof(data)); + + len = LoadPartialFile(name, buf, 4096, optional); + + if (len > sizeof(head)) { + CopyMemory(&head, buf, sizeof(head)); + + if (head.RIFF == MAKEFOURCC('R', 'I', 'F', 'F') && + head.WAVE == MAKEFOURCC('W', 'A', 'V', 'E')) { + + p = buf + sizeof(WAVE_HEADER); + + do { + DWORD chunk_id = *((LPDWORD) p); + + switch (chunk_id) { + case MAKEFOURCC('f', 'm', 't', ' '): + CopyMemory(&fmt, p, sizeof(fmt)); + p += fmt.chunk_size + 8; + break; + + case MAKEFOURCC('f', 'a', 'c', 't'): + CopyMemory(&fact, p, sizeof(fact)); + p += fact.chunk_size + 8; + break; + + case MAKEFOURCC('s', 'm', 'p', 'l'): + CopyMemory(&fact, p, sizeof(fact)); + p += fact.chunk_size + 8; + break; + + case MAKEFOURCC('d', 'a', 't', 'a'): + CopyMemory(&data, p, sizeof(data)); + p += 8; + break; + + default: + ReleaseBuffer(buf); + return result; + } + } + while (data.chunk_size == 0); + + wfex.wFormatTag = fmt.wFormatTag; + wfex.nChannels = fmt.nChannels; + wfex.nSamplesPerSec = fmt.nSamplesPerSec; + wfex.nAvgBytesPerSec = fmt.nAvgBytesPerSec; + wfex.nBlockAlign = fmt.nBlockAlign; + wfex.wBitsPerSample = fmt.wBitsPerSample; + wfex.cbSize = 0; + + snd = Sound::Create(Sound::STREAMED, &wfex); + + if (snd) { + // assemble file name: + char filename[1024]; + strcpy(filename, datapath); + strcat(filename, name); + + snd->StreamFile(filename, p - buf); + + result = data.chunk_size; + } + } + } + + ReleaseBuffer(buf); + return result; +} + +int +DataLoader::LoadOggStream(const char* name, Sound*& snd) +{ + if (!enable_media) + return 0; + + snd = Sound::CreateOggStream(name); + + return snd != 0; +} -- cgit v1.1