/** * @brief Init menu cvar for one savegame slot given by actual index. * @param[in] idx the savegame slot to retrieve gamecomment for * @sa SAV_GameReadGameComments_f */ static void SAV_GameReadGameComment (const int idx) { char filename[MAX_OSPATH]; cgi->GetRelativeSavePath(filename, sizeof(filename)); Q_strcat(filename, sizeof(filename), "slot%i.%s", idx, SAVEGAME_EXTENSION); ScopedFile f; cgi->FS_OpenFile(filename, &f, FILE_READ); if (!f) { cgi->UI_ExecuteConfunc("update_game_info %i \"\" \"\" \"\" \"\"", idx); return; } saveFileHeader_t header; if (cgi->FS_Read(&header, sizeof(header), &f) != sizeof(header)) Com_Printf("Warning: Savefile header may be corrupted\n"); header.compressed = LittleLong(header.compressed); header.version = LittleLong(header.version); header.xmlSize = LittleLong(header.xmlSize); header.subsystems = LittleLong(header.subsystems); const char* basename = Com_SkipPath(filename); if (!SAV_VerifyHeader(&header)) { Com_Printf("Savegame header for slot%d is corrupted!\n", idx); return; } cgi->UI_ExecuteConfunc("update_game_info %i \"%s\" \"%s\" \"%s\" \"%s\"", idx, header.name, header.gameDate, header.realDate, basename); }
/** * @brief Generates material files in case the settings can be guessed from map file */ static void GenerateMaterialFile (const char* filename, int mipTexIndex, side_t* s) { bool terrainByTexture = false; char fileBase[MAX_OSPATH], materialPath[MAX_OSPATH]; if (!config.generateMaterialFile) return; /* we already have a material definition for this texture */ if (textureref[mipTexIndex].materialMarked) return; assert(filename); Com_StripExtension(filename, fileBase, sizeof(fileBase)); Com_sprintf(materialPath, sizeof(materialPath), "materials/%s.mat", Com_SkipPath(fileBase)); ScopedFile f; FS_OpenFile(materialPath, &f, FILE_APPEND); if (!f) { Com_Printf("Could not open material file '%s' for writing\n", materialPath); config.generateMaterialFile = false; return; } if (strstr(textureref[mipTexIndex].name, "dirt") || strstr(textureref[mipTexIndex].name, "rock") || strstr(textureref[mipTexIndex].name, "grass")) { terrainByTexture = true; } if ((s->contentFlags & CONTENTS_TERRAIN) || terrainByTexture) { FS_Printf(&f, "{\n\tmaterial %s\n\t{\n\t\ttexture <fillme>\n\t\tterrain 0 64\n\t\tlightmap\n\t}\n}\n", textureref[mipTexIndex].name); textureref[mipTexIndex].materialMarked = true; materialsCnt++; } /* envmap for water surfaces */ if ((s->contentFlags & CONTENTS_WATER) || strstr(textureref[mipTexIndex].name, "glass") || strstr(textureref[mipTexIndex].name, "window")) { FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 2.0\n\t{\n\t\tenvmap 0\n\t}\n}\n", textureref[mipTexIndex].name); textureref[mipTexIndex].materialMarked = true; materialsCnt++; } if (strstr(textureref[mipTexIndex].name, "wood")) { FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 0.2\n}\n", textureref[mipTexIndex].name); textureref[mipTexIndex].materialMarked = true; materialsCnt++; } if (strstr(textureref[mipTexIndex].name, "wall")) { FS_Printf(&f, "{\n\tmaterial %s\n\tspecular 0.6\n\tbump 2.0\n}\n", textureref[mipTexIndex].name); textureref[mipTexIndex].materialMarked = true; materialsCnt++; } }
/** * @brief Export the day and night lightmap and direction data for the given map. * @note The bsp file must already be loaded. * @param bspFileName The path of the loaded bsp file. */ void ExportLightmaps (const char* bspFileName) { char path[MAX_QPATH], lightmapName[MAX_QPATH]; const char* fileName = Com_SkipPath(bspFileName); Com_FilePath(bspFileName, path, sizeof(path)); Com_StripExtension(fileName, lightmapName, sizeof(lightmapName)); /* note it */ Com_Printf("--- ExportLightmaps ---\n"); BuildFaceExtents(); ExportLightmap(path, lightmapName, true); ExportLightmap(path, lightmapName, false); }
/** * @brief The contract is that the directory name is equal to the base of the ump filename */ static const char* GetUMPName (const char* mapFilename) { static char name[MAX_QPATH]; const char* filename = Com_SkipPath(mapFilename); /* if we are in no subdir, we don't have any ump */ if (filename == nullptr) return nullptr; const char* mapsDir = "maps/"; const int lMaps = strlen(mapsDir); const int l = strlen(filename); const int targetLength = strlen(mapFilename) - lMaps - l; if (targetLength <= 0) return nullptr; Q_strncpyz(name, mapFilename + lMaps, targetLength); Com_Printf("...ump: '%s%s.ump'\n", mapsDir, name); return name; }
/** * @brief Sets the music cvar to a random track */ static void M_RandomTrack_f (void) { if (!s_env.initialized || !music.playing) return; const int musicTrackCount = FS_BuildFileList("music/*.ogg"); if (musicTrackCount) { int randomID = rand() % musicTrackCount; Com_DPrintf(DEBUG_SOUND, "M_RandomTrack_f: random track id: %i/%i\n", randomID, musicTrackCount); const char* filename; while ((filename = FS_NextFileFromFileList("music/*.ogg")) != nullptr) { if (!randomID) { const char* musicTrack = Com_SkipPath(filename); Com_Printf("..playing next music track: '%s'\n", musicTrack); Cvar_Set("snd_music", "%s", musicTrack); } randomID--; } FS_NextFileFromFileList(nullptr); } else { Com_DPrintf(DEBUG_SOUND, "M_RandomTrack_f: No music found!\n"); } }
/** * @brief Load material definitions for each map that has one * @param[in] map the base name of the map to load the material for */ void R_LoadMaterials (const char *map) { char path[MAX_QPATH]; byte *fileBuffer; const char *buffer; bool inmaterial; image_t *image; material_t *m; materialStage_t *ss; /* clear previously loaded materials */ R_ImageClearMaterials(); if (map[0] == '+' || map[0] == '-') map++; else if (map[0] == '-') return; /* load the materials file for parsing */ Com_sprintf(path, sizeof(path), "materials/%s.mat", Com_SkipPath(map)); if (FS_LoadFile(path, &fileBuffer) < 1) { Com_DPrintf(DEBUG_RENDERER, "Couldn't load %s\n", path); return; } else { Com_Printf("load material file: '%s'\n", path); if (!r_materials->integer) Com_Printf("...ignore materials (r_materials is deactivated)\n"); } buffer = (const char *)fileBuffer; inmaterial = false; image = nullptr; m = nullptr; while (true) { const char *c = Com_Parse(&buffer); if (c[0] == '\0') break; if (*c == '{' && !inmaterial) { inmaterial = true; continue; } if (Q_streq(c, "material")) { c = Com_Parse(&buffer); image = R_GetImage(va("textures/%s", c)); if (image == nullptr) Com_DPrintf(DEBUG_RENDERER, "R_LoadMaterials: skip texture: %s - not used in the map\n", c); continue; } if (!image) continue; m = &image->material; if (Q_streq(c, "normalmap")){ c = Com_Parse(&buffer); image->normalmap = R_FindImage(va("textures/%s", c), it_normalmap); if (image->normalmap == r_noTexture){ Com_Printf("R_LoadMaterials: Failed to resolve normalmap: %s\n", c); image->normalmap = nullptr; } } if (Q_streq(c, "glowmap")){ c = Com_Parse(&buffer); image->glowmap = R_FindImage(va("textures/%s", c), it_glowmap); if (image->glowmap == r_noTexture){ Com_Printf("R_LoadMaterials: Failed to resolve glowmap: %s\n", c); image->glowmap = nullptr; } } if (Q_streq(c, "bump")) { m->bump = atof(Com_Parse(&buffer)); if (m->bump < 0.0) { Com_Printf("R_LoadMaterials: Invalid bump value for %s\n", image->name); m->bump = defaultMaterial.bump; } } if (Q_streq(c, "parallax")) { m->parallax = atof(Com_Parse(&buffer)); if (m->parallax < 0.0) { Com_Printf("R_LoadMaterials: Invalid parallax value for %s\n", image->name); m->parallax = defaultMaterial.parallax; } } if (Q_streq(c, "hardness")) { m->hardness = atof(Com_Parse(&buffer)); if (m->hardness < 0.0) { Com_Printf("R_LoadMaterials: Invalid hardness value for %s\n", image->name); m->hardness = defaultMaterial.hardness; } } if (Q_streq(c, "specular")) { m->specular = atof(Com_Parse(&buffer)); if (m->specular < 0.0) { Com_Printf("R_LoadMaterials: Invalid specular value for %s\n", image->name); m->specular = defaultMaterial.specular; } } if (Q_streq(c, "glowscale")) { m->glowscale = atof(Com_Parse(&buffer)); if (m->glowscale < 0.0) { Com_Printf("R_LoadMaterials: Invalid glowscale value for %s\n", image->name); m->glowscale = defaultMaterial.glowscale; } } if (*c == '{' && inmaterial) { materialStage_t* const s = Mem_PoolAllocType(materialStage_t, vid_imagePool); s->glowscale = defaultMaterial.glowscale; if (R_ParseStage(s, &buffer) == -1) { Mem_Free(s); continue; } /* load animation frame images */ if (s->flags & STAGE_ANIM) { if (R_LoadAnimImages(s) == -1) { Mem_Free(s); continue; } } /* append the stage to the chain */ if (!m->stages) m->stages = s; else { ss = m->stages; while (ss->next) ss = ss->next; ss->next = s; } m->flags |= s->flags; m->num_stages++; continue; } if (*c == '}' && inmaterial) { Com_DPrintf(DEBUG_RENDERER, "Parsed material %s with %d stages\n", image->name, m->num_stages); inmaterial = false; image = nullptr; /* multiply stage glowscale values by material glowscale */ ss = m->stages; while (ss) { ss->glowscale *= m->glowscale; ss = ss->next; } } } FS_FreeFile(fileBuffer); R_CreateMaterialData(); }