/** * @brief A brand new game has been started */ static void SV_InitGame (void) { /* allow next change after map change or restart */ sv_maxclients->flags |= CVAR_LATCH; /* get any latched variable changes (sv_maxclients, etc) */ Cvar_UpdateLatchedVars(); if (svs.serverMutex) Sys_Error("There is still a server running"); svs.clients = Mem_PoolAllocTypeN(client_t, sv_maxclients->integer, sv_genericPool); svs.serverMutex = SDL_CreateMutex(); /* init network stuff */ if (sv_maxclients->integer > 1) { svs.initialized = SV_Start(nullptr, port->string, &SV_ReadPacket); svs.netDatagramSocket = NET_DatagramSocketNew(nullptr, port->string, &SV_DiscoveryCallback); } else { svs.initialized = SV_Start(nullptr, nullptr, &SV_ReadPacket); } SV_Heartbeat_f(); /* init game */ SV_InitGameProgs(); if (sv_maxclients->integer > 1 && (sv_dedicated->integer || sv_public->integer)) SV_SetMaster_f(); }
/** * @brief Loads brush entities like func_door and func_breakable * @sa CMod_LoadSubmodels */ static void R_ModLoadSubmodels (const lump_t *l) { const dBspModel_t *in; int i, j, count; in = (const dBspModel_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadSubmodels: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspHeader_t* out = Mem_PoolAllocTypeN(mBspHeader_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...submodels: %i\n", count); r_worldmodel->bsp.submodels = out; r_worldmodel->bsp.numsubmodels = count; for (i = 0; i < count; i++, in++, out++) { /* spread the mins / maxs by a pixel */ for (j = 0; j < 3; j++) { out->mins[j] = LittleFloat(in->mins[j]) - 1.0f + (float)shift[j]; out->maxs[j] = LittleFloat(in->maxs[j]) + 1.0f + (float)shift[j]; out->origin[j] = LittleFloat(in->origin[j]) + (float)shift[j]; } out->radius = R_RadiusFromBounds(out->mins, out->maxs); out->headnode = LittleLong(in->headnode); out->firstface = LittleLong(in->firstface); out->numfaces = LittleLong(in->numfaces); } }
void UI_Init (void) { cvar_t* ui_hunkSize = Cvar_Get("ui_hunksize", "3", 0, "UI memory hunk size in megabytes"); #ifdef DEBUG ui_debug = Cvar_Get("debug_ui", "0", CVAR_DEVELOPER, "Prints node names for debugging purposes - valid values are 1 and 2"); #endif /* reset global UI structures */ OBJZERO(ui_global); ui_sounds = Cvar_Get("ui_sounds", "1", CVAR_ARCHIVE, "Activates UI sounds"); #ifdef DEBUG Cmd_AddCommand("debug_uimemory", UI_Memory_f, "Display info about UI memory allocation"); #endif Cmd_AddCommand("ui_restart", UI_Restart_f, "Reload the whole ui"); ui_sysPool = Mem_CreatePool("Client: UI"); ui_dynStringPool = Mem_CreatePool("Client: Dynamic string for UI"); ui_dynPool = Mem_CreatePool("Client: Dynamic memory for UI"); Com_Printf("Allocate %i megabytes for the ui hunk\n", ui_hunkSize->integer); ui_global.adataize = ui_hunkSize->integer * 1024 * 1024; ui_global.adata = Mem_PoolAllocTypeN(byte, ui_global.adataize, ui_sysPool); ui_global.curadata = ui_global.adata; UI_InitData(); UI_InitNodes(); UI_InitWindows(); UI_InitDraw(); UI_InitActions(); }
/** * @brief Load actor skins from a default skin to a a mesh. * @param outMesh Mesh target of skins * @param defaultSkin Default skin of the mesh */ void R_LoadActorSkinsFromModel (mAliasMesh_t *outMesh, image_t * defaultSkin) { int i; assert(outMesh); outMesh->num_skins = r_numActorSkinName; outMesh->skins = Mem_PoolAllocTypeN(mAliasSkin_t, outMesh->num_skins, vid_modelPool); if (defaultSkin == r_noTexture) Com_Printf("R_LoadActorSkinsFromModel: No default skin found for model \"%s\"\n", outMesh->name); for (i = 0; i < outMesh->num_skins; i++) { mAliasSkin_t *modelSkin = &outMesh->skins[i]; if (i == 0) { modelSkin->skin = defaultSkin; } else { const char *skin = R_GetActorSkin(i); modelSkin->skin = R_AliasModelGetSkin(NULL, va("%s_%s", defaultSkin->name, skin)); /** @todo should we add warning here? */ if (modelSkin->skin == r_noTexture) modelSkin->skin = defaultSkin; } Q_strncpyz(modelSkin->name, modelSkin->skin->name, sizeof(outMesh->skins[i].name)); } }
/** * @brief Load the lightmap data */ static void R_ModLoadLighting (const lump_t *l) { /* map has no lightmap */ if (l->filelen == 0) return; r_worldmodel->bsp.lightdata = Mem_PoolAllocTypeN(byte, l->filelen, vid_lightPool); r_worldmodel->bsp.lightquant = *(const byte *) (mod_base + l->fileofs); memcpy(r_worldmodel->bsp.lightdata, mod_base + l->fileofs, l->filelen); }
/** * @sa TR_BuildTracingNode_r * @sa R_RecurseSetParent */ static void R_ModLoadNodes (const lump_t *l) { int i, j, count; const dBspNode_t *in; mBspNode_t *parent = NULL; in = (const dBspNode_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadNodes: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspNode_t* out = Mem_PoolAllocTypeN(mBspNode_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...nodes: %i\n", count); r_worldmodel->bsp.nodes = out; r_worldmodel->bsp.numnodes = count; for (i = 0; i < count; i++, in++, out++) { const int p = LittleLong(in->planenum); /* skip special pathfinding nodes - they have a negative index */ if (p == PLANENUM_LEAF) { /* in case of "special" pathfinding nodes (they don't have a plane) * we have to set this to NULL */ out->plane = NULL; out->contents = CONTENTS_PATHFINDING_NODE; parent = NULL; } else { out->plane = r_worldmodel->bsp.planes + p; /* differentiate from leafs */ out->contents = CONTENTS_NODE; parent = out; } for (j = 0; j < 3; j++) { out->minmaxs[j] = LittleShort(in->mins[j]) + (float)shift[j]; out->minmaxs[3 + j] = LittleShort(in->maxs[j]) + (float)shift[j]; } out->firstsurface = LittleShort(in->firstface); out->numsurfaces = LittleShort(in->numfaces); for (j = 0; j < 2; j++) { const int p2 = LittleLong(in->children[j]); if (p2 > LEAFNODE) { assert(p2 < r_worldmodel->bsp.numnodes); out->children[j] = r_worldmodel->bsp.nodes + p2; } else { assert((LEAFNODE - p2) < r_worldmodel->bsp.numleafs); out->children[j] = (mBspNode_t *) (r_worldmodel->bsp.leafs + (LEAFNODE - p2)); } out->children[j]->parent = parent; } } }
/** * @brief Adds an entry to a new or to an already existing linked list * @sa LIST_AddString * @sa LIST_RemoveEntry * @return Returns a pointer to the data that has been added, wrapped in a linkedList_t * @todo Optimize this to not allocate memory for every entry - but use a hunk */ linkedList_t *LIST_Add (linkedList_t **listDest, void const* data, size_t length) { assert(listDest); assert(data); void* const dataCopy = memcpy(Mem_PoolAllocTypeN(byte, length, com_genericPool), data, length); linkedList_t* const newEntry = LIST_AllocateEntry(dataCopy); LIST_AppendEntry(listDest, newEntry); return newEntry; }
static void R_ModLoadEdges (const lump_t *l) { const dBspEdge_t *in; int i, count; in = (const dBspEdge_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadEdges: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspEdge_t* out = Mem_PoolAllocTypeN(mBspEdge_t, count + 1, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...edges: %i\n", count); r_worldmodel->bsp.edges = out; r_worldmodel->bsp.numedges = count; for (i = 0; i < count; i++, in++, out++) { out->v[0] = (unsigned short) LittleShort(in->v[0]); out->v[1] = (unsigned short) LittleShort(in->v[1]); } }
static void R_ModLoadVertexes (const lump_t *l) { const dBspVertex_t *in; int i, count; in = (const dBspVertex_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadVertexes: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspVertex_t* out = Mem_PoolAllocTypeN(mBspVertex_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...verts: %i\n", count); r_worldmodel->bsp.vertexes = out; r_worldmodel->bsp.numvertexes = count; for (i = 0; i < count; i++, in++, out++) { out->position[0] = LittleFloat(in->point[0]); out->position[1] = LittleFloat(in->point[1]); out->position[2] = LittleFloat(in->point[2]); } }
/** * @sa CMod_LoadPlanes */ static void R_ModLoadPlanes (const lump_t *l) { int i, j; const dBspPlane_t *in; int count; in = (const dBspPlane_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadPlanes: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); cBspPlane_t* out = Mem_PoolAllocTypeN(cBspPlane_t, count * 2, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...planes: %i\n", count); r_worldmodel->bsp.planes = out; r_worldmodel->bsp.numplanes = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) out->normal[j] = LittleFloat(in->normal[j]); out->dist = LittleFloat(in->dist); out->type = LittleLong(in->type); } }
static void R_ModLoadLeafs (const lump_t *l) { const dBspLeaf_t *in; int i, j, count; in = (const dBspLeaf_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadLeafs: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspLeaf_t* out = Mem_PoolAllocTypeN(mBspLeaf_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...leafs: %i\n", count); r_worldmodel->bsp.leafs = out; r_worldmodel->bsp.numleafs = count; for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { out->minmaxs[j] = LittleShort(in->mins[j]) + (float)shift[j]; out->minmaxs[3 + j] = LittleShort(in->maxs[j]) + (float)shift[j]; } out->contents = LittleLong(in->contentFlags); } }
/** * @sa CP_StartMissionMap */ static void R_ModLoadTexinfo (const lump_t *l) { const dBspTexinfo_t *in; int i, j, count; char name[MAX_QPATH]; in = (const dBspTexinfo_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadTexinfo: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspTexInfo_t* out = Mem_PoolAllocTypeN(mBspTexInfo_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...texinfo: %i\n", count); r_worldmodel->bsp.texinfo = out; r_worldmodel->bsp.numtexinfo = count; const char *mapZone = Cvar_GetString("sv_mapzone"); for (i = 0; i < count; i++, in++, out++) { for (j = 0; j < 3; j++) { out->uv[j] = LittleFloat(in->vecs[0][j]); out->vv[j] = LittleFloat(in->vecs[1][j]); } out->u_offset = LittleFloat(in->vecs[0][3]); out->v_offset = LittleFloat(in->vecs[1][3]); out->flags = LittleLong(in->surfaceFlags); /* exchange the textures with the ones that are needed for base assembly */ if (mapZone && strstr(in->texture, "tex_terrain/dummy")) Com_sprintf(name, sizeof(name), "textures/tex_terrain/%s", mapZone); else Com_sprintf(name, sizeof(name), "textures/%s", in->texture); out->image = R_FindImage(name, it_world); } }
/** * @brief Do our own preprocessing to the shader file, before the * GLSL implementation calls it's preprocessor. * * "#if/#endif" pairs, "#unroll", "#endunroll", "#include", "#replace" are handled by our * preprocessor, not the GLSL implementation's preprocessor (except "#include" which may * also be handled by the implementation's preprocessor). "#if" operates off * of the value of a cvar interpreted as a bool. Note the GLSL implementation * preprocessor handles "#ifdef" and "#ifndef", not "#if". * @param[in] name The file name of the shader (e.g. "world_fs.glsl"). * @param[in] inPtr The non-preprocessed shader string. * @param[in,out] out The preprocessed shader string, nullptr if we don't want to write to it. * @param[in,out] remainingOutChars The number of characters left in the out buffer. * @param[in] nested If true, parsing a part of "#if" clause, so "#else" and "#endif" tokens are allowed * @param[in] inElse If true, parsing an "#else" clause and shouldn't expect another "#else" * @return The number of characters added to the buffer pointed to by out. */ static size_t R_PreprocessShaderR (const char* name, const char** inPtr, char* out, long* remainingOutChars, bool nested, bool inElse) { const size_t INITIAL_REMAINING_OUT_CHARS = (size_t)*remainingOutChars; /* Keep looping till we reach the end of the shader string, or a parsing error.*/ while (**inPtr) { if ('#' == **inPtr) { bool endBlockToken; (*inPtr)++; endBlockToken = !strncmp(*inPtr, "endif", 5); if (!strncmp(*inPtr, "else", 4)) { if (inElse) { /* Error in shader! Print a message saying our preprocessor failed parsing.*/ Com_Error(ERR_DROP, "R_PreprocessShaderR: #else without #if: %s", name); } endBlockToken = true; } if (endBlockToken) { if (!nested) { /* Error in shader! Print a message saying our preprocessor failed parsing.*/ Com_Error(ERR_DROP, "R_PreprocessShaderR: Unmatched #endif/#else: %s", name); } /* Whoever called us will have to deal with closing the block */ return (INITIAL_REMAINING_OUT_CHARS - (size_t)*remainingOutChars); } if (!strncmp((*inPtr), "if ", 3)) { /* The line looks like "#if r_postprocess".*/ (*inPtr) += 3; /* Get the corresponding cvar value.*/ float f = Cvar_GetValue(Com_Parse(inPtr)); if (f) { /* Condition is true, recursively preprocess #if block, and skip over #else block, if any */ int size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false); if (out) out += size; if (!strncmp((*inPtr), "else", 4)) {/* Preprocess and skip #else block */ (*inPtr) +=4 ; R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, true); } } else { /* The cvar was false, don't add to out. Lets look and see if we hit a #else, or #endif.*/ R_PreprocessShaderR(name, inPtr, (char*)0, remainingOutChars, true, false); if (!strncmp((*inPtr), "else", 4)) { int size; /* All right, we want to add this to out.*/ (*inPtr) +=4 ; size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true); if (out) out += size; } } /* skip #endif, if any (could also get here by unexpected EOF */ if (!strncmp((*inPtr), "endif", 5)) (*inPtr) +=5 ; } else if (!strncmp((*inPtr), "ifndef", 6) || !strncmp((*inPtr), "ifdef", 5)) { /* leave those for GLSL compiler, but follow #else/#endif nesting */ int size; if (out) { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = '#'; (*remainingOutChars)--; } size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, false); if (out) out += size; if (!strncmp((*inPtr), "else", 4)) { if (out) { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = '#'; (*remainingOutChars)--; } size = R_PreprocessShaderR(name, inPtr, out, remainingOutChars, true, true); if (out) out += size; } if (out) { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = '#'; (*remainingOutChars)--; } } else if (!strncmp((*inPtr), "include", 7)) { char path[MAX_QPATH]; byte* buf = (byte*)0; const char* bufAsChar = (const char*)0; const char** bufAsCharPtr = (const char**)0; (*inPtr) += 8; Com_sprintf(path, sizeof(path), "shaders/%s", Com_Parse(inPtr)); if (FS_LoadFile(path, &buf) == -1) { Com_Printf("Failed to resolve #include: %s.\n", path); continue; } bufAsChar = (const char*)buf; bufAsCharPtr = &bufAsChar; if (out) { out += R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false); } else { R_PreprocessShaderR(name, bufAsCharPtr, out, remainingOutChars, nested, false); } FS_FreeFile(buf); } else if (!strncmp((*inPtr), "unroll", 6)) { /* loop unrolling */ size_t subLength = 0; byte* const buffer = Mem_PoolAllocTypeN(byte, SHADER_BUF_SIZE, vid_imagePool); (*inPtr) += 6; int z = Cvar_GetValue(Com_Parse(inPtr)); while (*(*inPtr)) { if (!strncmp((*inPtr), "#endunroll", 10)) { (*inPtr) += 10; break; } buffer[subLength++] = *(*inPtr)++; if (subLength >= SHADER_BUF_SIZE) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); } if (out) { for (int j = 0; j < z; j++) { for (int l = 0; l < subLength; l++) { if (buffer[l] == '$') { byte insertedLen = (j / 10) + 1; if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", j)) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); out += insertedLen; (*remainingOutChars) -= insertedLen; } else { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = buffer[l]; (*remainingOutChars)--; } } } } Mem_Free(buffer); } else if (!strncmp((*inPtr), "replace", 7)) { int r = 0; (*inPtr) += 8; r = Cvar_GetValue(Com_Parse(inPtr)); if (out) { byte insertedLen = 0; if (!Com_sprintf(out, (size_t)*remainingOutChars, "%d", r)) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); insertedLen = (r / 10) + 1; out += insertedLen; (*remainingOutChars) -= insertedLen; } } else { /* general case is to copy so long as the buffer has room */ if (out) { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = '#'; (*remainingOutChars)--; } } } else { /* general case is to copy so long as the buffer has room */ if (out) { if (*remainingOutChars <= 0) Com_Error(ERR_FATAL, "R_PreprocessShaderR: Overflow in shader loading '%s'", name); *out++ = *(*inPtr); (*remainingOutChars)--; } (*inPtr)++; } } /* Return the number of characters added to the buffer.*/ return (INITIAL_REMAINING_OUT_CHARS - *remainingOutChars); }
/** * Take a screenshot of the frame buffer * @param[in] x * @param[in] y * @param[in] width * @param[in] height * @param[in] filename Force to use a filename. Else NULL to autogen a filename * @param[in] ext Force to use an image format (tga/png/jpg). Else NULL to use value of r_screenshot_format */ void R_ScreenShot (int x, int y, int width, int height, const char *filename, const char *ext) { char checkName[MAX_OSPATH]; int type, shotNum, quality = 100; qFILE f; int rowPack; glGetIntegerv(GL_PACK_ALIGNMENT, &rowPack); glPixelStorei(GL_PACK_ALIGNMENT, 1); /* Find out what format to save in */ if (ext == NULL) ext = r_screenshot_format->string; if (!Q_strcasecmp(ext, "png")) type = SSHOTTYPE_PNG; else if (!Q_strcasecmp(ext, "jpg")) type = SSHOTTYPE_JPG; else type = SSHOTTYPE_TGA_COMP; /* Set necessary values */ switch (type) { case SSHOTTYPE_TGA_COMP: Com_Printf("Taking TGA screenshot...\n"); ext = "tga"; break; case SSHOTTYPE_PNG: Com_Printf("Taking PNG screenshot...\n"); ext = "png"; break; case SSHOTTYPE_JPG: if (Cmd_Argc() == 3) quality = atoi(Cmd_Argv(2)); else quality = r_screenshot_jpeg_quality->integer; if (quality > 100 || quality <= 0) quality = 100; Com_Printf("Taking JPG screenshot (at %i%% quality)...\n", quality); ext = "jpg"; break; } /* Find a file name to save it to */ if (filename) { Com_sprintf(checkName, sizeof(checkName), "scrnshot/%s.%s", filename, ext); } else { for (shotNum = 0; shotNum < 1000; shotNum++) { Com_sprintf(checkName, sizeof(checkName), "scrnshot/ufo%i%i.%s", shotNum / 10, shotNum % 10, ext); if (FS_CheckFile("%s", checkName) == -1) break; } if (shotNum == 1000) { Com_Printf("R_ScreenShot_f: screenshot limit (of 1000) exceeded!\n"); return; } } /* Open it */ FS_OpenFile(checkName, &f, FILE_WRITE); if (!f.f) { Com_Printf("R_ScreenShot_f: Couldn't create file: %s\n", checkName); return; } /* Allocate room for a copy of the framebuffer */ byte* const buffer = Mem_PoolAllocTypeN(byte, width * height * 3, vid_imagePool); if (!buffer) { Com_Printf("R_ScreenShot_f: Could not allocate %i bytes for screenshot!\n", width * height * 3); FS_CloseFile(&f); return; } /* Read the framebuffer into our storage */ glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); R_CheckError(); /* Write */ switch (type) { case SSHOTTYPE_TGA_COMP: R_WriteCompressedTGA(&f, buffer, width, height); break; case SSHOTTYPE_PNG: R_WritePNG(&f, buffer, width, height); break; case SSHOTTYPE_JPG: R_WriteJPG(&f, buffer, width, height, quality); break; } /* Finish */ FS_CloseFile(&f); Mem_Free(buffer); Com_Printf("Wrote %s to %s\n", checkName, FS_Gamedir()); glPixelStorei(GL_PACK_ALIGNMENT, rowPack); }
/** * @brief Consume raw lightmap and deluxemap RGB/XYZ data from the surface samples, * writing processed lightmap and deluxemap RGBA to the specified destinations. * @sa R_BuildDefaultLightmap */ static void R_BuildLightmap (mBspSurface_t *surf, byte *sout, byte *dout, int stride) { unsigned int i, j; byte *lm, *l, *dm; const int smax = (surf->stextents[0] / surf->lightmap_scale) + 1; const int tmax = (surf->stextents[1] / surf->lightmap_scale) + 1; const int size = smax * tmax; stride -= (smax * LIGHTMAP_BLOCK_BYTES); byte* const lightmap = Mem_PoolAllocTypeN(byte, size * LIGHTMAP_BLOCK_BYTES, vid_lightPool); lm = lightmap; byte* const deluxemap = Mem_PoolAllocTypeN(byte, size * DELUXEMAP_BLOCK_BYTES, vid_lightPool); dm = deluxemap; /* convert the raw lightmap samples to floating point and scale them */ for (i = j = 0; i < size; i++, lm += LIGHTMAP_BLOCK_BYTES, dm += DELUXEMAP_BLOCK_BYTES) { lm[0] = surf->samples[j++]; lm[1] = surf->samples[j++]; lm[2] = surf->samples[j++]; /* read in directional samples for deluxe mapping as well */ dm[0] = surf->samples[j++]; dm[1] = surf->samples[j++]; dm[2] = surf->samples[j++]; } /* apply modulate, contrast, resolve average surface color, etc.. */ R_GetAverageSurfaceColor(lightmap, smax, tmax, surf->color, LIGHTMAP_BLOCK_BYTES); if (surf->texinfo->flags & (SURF_BLEND33 | SURF_ALPHATEST)) surf->color[3] = 0.25; else if (surf->texinfo->flags & SURF_BLEND66) surf->color[3] = 0.50; else surf->color[3] = 1.0; /* soften it if it's sufficiently large */ if (r_soften->integer && size > 128) for (i = 0; i < 4; i++) { R_SoftenTexture(lightmap, smax, tmax, LIGHTMAP_BLOCK_BYTES); R_SoftenTexture(deluxemap, smax, tmax, DELUXEMAP_BLOCK_BYTES); } /* the final lightmap is uploaded to the card via the strided lightmap * block, and also cached on the surface for fast point lighting lookups */ surf->lightmap = Mem_PoolAllocTypeN(byte, size * LIGHTMAP_BYTES, vid_lightPool); l = surf->lightmap; lm = lightmap; dm = deluxemap; for (i = 0; i < tmax; i++, sout += stride, dout += stride) { for (j = 0; j < smax; j++) { /* copy the lightmap to the strided block */ sout[0] = lm[0]; sout[1] = lm[1]; sout[2] = lm[2]; sout += LIGHTMAP_BLOCK_BYTES; /* and to the surface, discarding alpha */ l[0] = lm[0]; l[1] = lm[1]; l[2] = lm[2]; l += LIGHTMAP_BYTES; lm += LIGHTMAP_BLOCK_BYTES; /* lastly copy the deluxemap to the strided block */ dout[0] = dm[0]; dout[1] = dm[1]; dout[2] = dm[2]; dout += DELUXEMAP_BLOCK_BYTES; dm += DELUXEMAP_BLOCK_BYTES; } } Mem_Free(lightmap); Mem_Free(deluxemap); }
static void R_ModLoadSurfaces (bool day, const lump_t *l) { const dBspSurface_t *in; int count, surfnum; in = (const dBspSurface_t *) (mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Com_Error(ERR_DROP, "R_ModLoadSurfaces: funny lump size in %s", r_worldmodel->name); count = l->filelen / sizeof(*in); mBspSurface_t* out = Mem_PoolAllocTypeN(mBspSurface_t, count, vid_modelPool); Com_DPrintf(DEBUG_RENDERER, "...faces: %i\n", count); r_worldmodel->bsp.surfaces = out; r_worldmodel->bsp.numsurfaces = count; for (surfnum = 0; surfnum < count; surfnum++, in++, out++) { uint16_t planenum; int16_t side; int ti; int i; out->firstedge = LittleLong(in->firstedge); out->numedges = LittleShort(in->numedges); /* resolve plane */ planenum = LittleShort(in->planenum); out->plane = r_worldmodel->bsp.planes + planenum; /* and sideness */ side = LittleShort(in->side); if (side) { out->flags |= MSURF_PLANEBACK; VectorNegate(out->plane->normal, out->normal); } else { VectorCopy(out->plane->normal, out->normal); } ti = LittleShort(in->texinfo); if (ti < 0 || ti >= r_worldmodel->bsp.numtexinfo) Com_Error(ERR_DROP, "R_ModLoadSurfaces: bad texinfo number"); out->texinfo = r_worldmodel->bsp.texinfo + ti; out->lightmap_scale = (1 << r_worldmodel->bsp.lightquant); /* and size, texcoords, etc */ R_SetSurfaceExtents(out, r_worldmodel); if (!(out->texinfo->flags & SURF_WARP)) out->flags |= MSURF_LIGHTMAP; /* lastly lighting info */ if (day) i = LittleLong(in->lightofs[LIGHTMAP_DAY]); else i = LittleLong(in->lightofs[LIGHTMAP_NIGHT]); if (i == -1) out->samples = NULL; else out->samples = r_worldmodel->bsp.lightdata + i; /* create lightmaps */ R_CreateSurfaceLightmap(out); out->tile = r_numMapTiles - 1; } }
/** * @brief Puts the map data into buffers * @sa R_ModAddMapTile * @note Shift the verts after the texcoords for diffuse and lightmap are loaded * @sa R_ModShiftTile * @todo Don't use the buffers from r_state here - they might overflow * @todo Decrease MAX_GL_ARRAY_LENGTH to 32768 again when this is fixed */ static void R_LoadBspVertexArrays (model_t *mod) { int i, j; int vertOfs, texCoordOfs, tangOfs; float *vecShifted; float soff, toff, s, t; float *point, *sdir, *tdir; vec4_t tangent; vec3_t binormal; mBspSurface_t *surf; mBspVertex_t *vert; int vertexCount, indexCount; vertOfs = texCoordOfs = tangOfs = 0; vertexCount = indexCount = 0; for (i = 0, surf = mod->bsp.surfaces; i < mod->bsp.numsurfaces; i++, surf++) { const int numedges = surf->numedges; vertexCount += numedges; if (numedges > 2) /* no triangles for degenerate polys */ indexCount += (numedges - 2) * 3; } surf = mod->bsp.surfaces; /* allocate the vertex arrays */ mod->bsp.texcoords = Mem_PoolAllocTypeN(GLfloat, vertexCount * 2, vid_modelPool); mod->bsp.lmtexcoords = Mem_PoolAllocTypeN(GLfloat, vertexCount * 2, vid_modelPool); mod->bsp.verts = Mem_PoolAllocTypeN(GLfloat, vertexCount * 3, vid_modelPool); mod->bsp.normals = Mem_PoolAllocTypeN(GLfloat, vertexCount * 3, vid_modelPool); mod->bsp.tangents = Mem_PoolAllocTypeN(GLfloat, vertexCount * 4, vid_modelPool); mod->bsp.indexes = Mem_PoolAllocTypeN(GLint, indexCount, vid_modelPool); /* Will be filled at the end of map loading, after building surface lists */ for (i = 0; i < mod->bsp.numsurfaces; i++, surf++) { surf->index = vertOfs / 3; surf->firstTriangle = -1; /* Mark as "no triangles generated yet" */ for (j = 0; j < surf->numedges; j++) { const float *normal; const int index = mod->bsp.surfedges[surf->firstedge + j]; /* vertex */ if (index > 0) { /* negative indices to differentiate which end of the edge */ const mBspEdge_t *edge = &mod->bsp.edges[index]; vert = &mod->bsp.vertexes[edge->v[0]]; } else { const mBspEdge_t *edge = &mod->bsp.edges[-index]; vert = &mod->bsp.vertexes[edge->v[1]]; } point = vert->position; /* shift it for assembled maps */ vecShifted = &mod->bsp.verts[vertOfs]; /* origin (func_door, func_rotating) bmodels must not have shifted vertices, * they are translated by their entity origin value */ if (surf->isOriginBrushModel) VectorCopy(point, vecShifted); else VectorAdd(point, shift, vecShifted); /* texture directional vectors and offsets */ sdir = surf->texinfo->uv; soff = surf->texinfo->u_offset; tdir = surf->texinfo->vv; toff = surf->texinfo->v_offset; /* texture coordinates */ s = DotProduct(point, sdir) + soff; s /= surf->texinfo->image->width; t = DotProduct(point, tdir) + toff; t /= surf->texinfo->image->height; mod->bsp.texcoords[texCoordOfs + 0] = s; mod->bsp.texcoords[texCoordOfs + 1] = t; if (surf->flags & MSURF_LIGHTMAP) { /* lightmap coordinates */ s = DotProduct(point, sdir) + soff; s -= surf->stmins[0]; s += surf->light_s * surf->lightmap_scale; s += surf->lightmap_scale / 2.0; s /= r_lightmaps.size * surf->lightmap_scale; t = DotProduct(point, tdir) + toff; t -= surf->stmins[1]; t += surf->light_t * surf->lightmap_scale; t += surf->lightmap_scale / 2.0; t /= r_lightmaps.size * surf->lightmap_scale; } mod->bsp.lmtexcoords[texCoordOfs + 0] = s; mod->bsp.lmtexcoords[texCoordOfs + 1] = t; /* normal vectors */ if ((surf->texinfo->flags & SURF_PHONG) && VectorNotEmpty(vert->normal)) normal = vert->normal; /* phong shaded */ else normal = surf->normal; /* per plane */ memcpy(&mod->bsp.normals[vertOfs], normal, sizeof(vec3_t)); /* tangent vector */ TangentVectors(normal, sdir, tdir, tangent, binormal); memcpy(&mod->bsp.tangents[tangOfs], tangent, sizeof(vec4_t)); vertOfs += 3; texCoordOfs += 2; tangOfs += 4; } } R_ReallocateStateArrays(vertOfs / 3); if (qglBindBuffer) { /* and also the vertex buffer objects */ qglGenBuffers(1, &mod->bsp.vertex_buffer); qglBindBuffer(GL_ARRAY_BUFFER, mod->bsp.vertex_buffer); qglBufferData(GL_ARRAY_BUFFER, vertOfs * sizeof(GLfloat), mod->bsp.verts, GL_STATIC_DRAW); qglGenBuffers(1, &mod->bsp.texcoord_buffer); qglBindBuffer(GL_ARRAY_BUFFER, mod->bsp.texcoord_buffer); qglBufferData(GL_ARRAY_BUFFER, texCoordOfs * sizeof(GLfloat), mod->bsp.texcoords, GL_STATIC_DRAW); qglGenBuffers(1, &mod->bsp.lmtexcoord_buffer); qglBindBuffer(GL_ARRAY_BUFFER, mod->bsp.lmtexcoord_buffer); qglBufferData(GL_ARRAY_BUFFER, texCoordOfs * sizeof(GLfloat), mod->bsp.lmtexcoords, GL_STATIC_DRAW); qglGenBuffers(1, &mod->bsp.normal_buffer); qglBindBuffer(GL_ARRAY_BUFFER, mod->bsp.normal_buffer); qglBufferData(GL_ARRAY_BUFFER, vertOfs * sizeof(GLfloat), mod->bsp.normals, GL_STATIC_DRAW); qglGenBuffers(1, &mod->bsp.tangent_buffer); qglBindBuffer(GL_ARRAY_BUFFER, mod->bsp.tangent_buffer); qglBufferData(GL_ARRAY_BUFFER, tangOfs * sizeof(GLfloat), mod->bsp.tangents, GL_STATIC_DRAW); qglBindBuffer(GL_ARRAY_BUFFER, 0); } }
/** * @brief Reads the sequence values from given text-pointer * @sa CL_ParseClientData */ void CL_ParseSequence (const char *name, const char **text) { const char *errhead = "CL_ParseSequence: unexpected end of file (sequence "; sequence_t *sp; const char *token; int i; /* search for sequences with same name */ for (i = 0; i < numSequences; i++) if (Q_streq(name, sequences[i].name)) break; if (i < numSequences) { Com_Printf("CL_ParseSequence: sequence def \"%s\" with same name found, second ignored\n", name); return; } /* initialize the sequence */ if (numSequences >= MAX_SEQUENCES) Com_Error(ERR_FATAL, "Too many sequences"); sp = &sequences[numSequences++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); sp->start = numSeqCmds; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseSequence: sequence def \"%s\" without body ignored\n", name); numSequences--; return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* check for commands */ int i = CL_FindSequenceCommand(token); if (i != -1) { int maxLength = MAX_DATA_LENGTH; char *data; seqCmd_t *sc; /* found a command */ token = Com_EParse(text, errhead, name); if (!*text) return; if (numSeqCmds >= MAX_SEQCMDS) Com_Error(ERR_FATAL, "Too many sequence commands for %s", name); /* init seqCmd */ if (seqCmds == NULL) seqCmds = Mem_PoolAllocTypeN(seqCmd_t, MAX_SEQCMDS, cl_genericPool); sc = &seqCmds[numSeqCmds++]; OBJZERO(*sc); sc->handler = seqCmdFunc[i]; sp->length++; /* copy name */ Q_strncpyz(sc->name, token, sizeof(sc->name)); /* read data */ token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') { // TODO depth is useless IMHO (bayo) int depth = 1; data = &sc->data[0]; while (depth) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s", sc->name); break; } token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') depth++; else if (*token == '}') depth--; if (depth) { Q_strncpyz(data, token, maxLength); data += strlen(token) + 1; maxLength -= (strlen(token) + 1); } } } else if (*token == '(') { linkedList_t *list; Com_UnParseLastToken(); if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "CL_ParseSequence: error while reading list (sequence \"%s\")", name); } data = &sc->data[0]; for (linkedList_t *element = list; element != NULL; element = element->next) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s", sc->name); break; } const char* v = (char*)element->data; Q_strncpyz(data, v, maxLength); data += strlen(v) + 1; maxLength -= (strlen(v) + 1); } LIST_Delete(&list); } else { Com_UnParseLastToken(); } } else { Com_Printf("CL_ParseSequence: unknown command \"%s\" ignored (sequence %s)\n", token, name); Com_EParse(text, errhead, name); } } while (*text); }
/** * @brief Loads the given savegame from an xml File. * @return true on load success false on failures * @param[in] file The Filename to load from (without extension) * @param[out] error On failure an errormessage may be set. */ bool SAV_GameLoad (const char *file, const char **error) { char filename[MAX_OSPATH]; qFILE f; int i, clen; xmlNode_t *topNode, *node; saveFileHeader_t header; Q_strncpyz(filename, file, sizeof(filename)); /* open file */ FS_OpenFile(va("save/%s.%s", filename, SAVEGAME_EXTENSION), &f, FILE_READ); if (!f.f) { Com_Printf("Couldn't open file '%s'\n", filename); *error = "File not found"; return false; } clen = FS_FileLength(&f); byte* const cbuf = Mem_PoolAllocTypeN(byte, clen + 1 /* for '\0' if not compressed */, cp_campaignPool); if (FS_Read(cbuf, clen, &f) != clen) Com_Printf("Warning: Could not read %i bytes from savefile\n", clen); FS_CloseFile(&f); Com_Printf("Loading savegame xml (size %d)\n", clen); memcpy(&header, cbuf, sizeof(header)); /* swap all int values if needed */ header.compressed = LittleLong(header.compressed); header.version = LittleLong(header.version); header.xmlSize = LittleLong(header.xmlSize); /* doing some header verification */ if (!SAV_VerifyHeader(&header)) { /* our header is not valid, we MUST abort loading the game! */ Com_Printf("The Header of the savegame '%s.%s' is corrupted. Loading aborted\n", filename, SAVEGAME_EXTENSION); Mem_Free(cbuf); *error = "Corrupted header"; return false; } Com_Printf("Loading savegame\n" "...version: %i\n" "...game version: %s\n" "...xml Size: %i, compressed? %c\n", header.version, header.gameVersion, header.xmlSize, header.compressed ? 'y' : 'n'); if (header.compressed) { uLongf len = header.xmlSize + 1 /* for '\0' */; byte* const buf = Mem_PoolAllocTypeN(byte, len /* sic, old savegames contain one (garbage) byte more than the header says. */, cp_campaignPool); /* uncompress data, skipping comment header */ const int res = uncompress(buf, &len, cbuf + sizeof(header), clen - sizeof(header)); buf[header.xmlSize] = '\0'; /* Ensure '\0' termination. */ Mem_Free(cbuf); if (res != Z_OK) { Mem_Free(buf); *error = _("Error decompressing data"); Com_Printf("Error decompressing data in '%s'.\n", filename); return false; } topNode = XML_Parse((const char*)buf); if (!topNode) { Mem_Free(buf); Com_Printf("Error: Failure in loading the xml data!\n"); *error = "Corrupted xml data"; return false; } Mem_Free(buf); } else { topNode = XML_Parse((const char*)(cbuf + sizeof(header))); Mem_Free(cbuf); if (!topNode) { Com_Printf("Error: Failure in loading the xml data!\n"); *error = "Corrupted xml data"; return false; } } /* doing a subsystem run */ GAME_ReloadMode(); node = XML_GetNode(topNode, SAVE_ROOTNODE); if (!node) { Com_Printf("Error: Failure in loading the xml data! (savegame node not found)\n"); mxmlDelete(topNode); *error = "Invalid xml data"; return false; } Com_Printf("Load '%s' %d subsystems\n", filename, saveSubsystemsAmount); for (i = 0; i < saveSubsystemsAmount; i++) { Com_Printf("...Running subsystem '%s'\n", saveSubsystems[i].name); if (!saveSubsystems[i].load(node)) { Com_Printf("...subsystem '%s' returned false - savegame could not be loaded\n", saveSubsystems[i].name); *error = va("Could not load subsystem %s", saveSubsystems[i].name); return false; } else Com_Printf("...subsystem '%s' - loaded.\n", saveSubsystems[i].name); } mxmlDelete(node); mxmlDelete(topNode); if (!SAV_GameActionsAfterLoad()) { Com_Printf("Savegame postprocessing returned false - savegame could not be loaded\n"); *error = "Postprocessing failed"; return false; } Com_Printf("File '%s' successfully loaded from %s xml savegame.\n", filename, header.compressed ? "compressed" : ""); cgi->UI_InitStack("geoscape", NULL, true, true); return true; }
/** * @brief This is a savegame function which stores the game in xml-Format. * @param[in] filename The Filename to save to (without extension) * @param[in] comment Description of the savegame * @param[out] error On failure an errormessage may be set. */ static bool SAV_GameSave (const char *filename, const char *comment, char **error) { xmlNode_t *topNode, *node; char savegame[MAX_OSPATH]; int res; int requiredBufferLength; uLongf bufLen; saveFileHeader_t header; char dummy[2]; int i; dateLong_t date; char message[30]; char timeStampBuffer[32]; if (!CP_IsRunning()) { *error = _("No campaign active."); Com_Printf("Error: No campaign active.\n"); return false; } if (!B_AtLeastOneExists()) { *error = _("Nothing to save yet."); Com_Printf("Error: Nothing to save yet.\n"); return false; } Com_MakeTimestamp(timeStampBuffer, sizeof(timeStampBuffer)); Com_sprintf(savegame, sizeof(savegame), "save/%s.%s", filename, SAVEGAME_EXTENSION); topNode = mxmlNewXML("1.0"); node = XML_AddNode(topNode, SAVE_ROOTNODE); /* writing Header */ XML_AddInt(node, SAVE_SAVEVERSION, SAVE_FILE_VERSION); XML_AddString(node, SAVE_COMMENT, comment); XML_AddString(node, SAVE_UFOVERSION, UFO_VERSION); XML_AddString(node, SAVE_REALDATE, timeStampBuffer); CP_DateConvertLong(&ccs.date, &date); Com_sprintf(message, sizeof(message), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day); XML_AddString(node, SAVE_GAMEDATE, message); /* working through all subsystems. perhaps we should redesign it, order is not important anymore */ Com_Printf("Calling subsystems\n"); for (i = 0; i < saveSubsystemsAmount; i++) { if (!saveSubsystems[i].save(node)) Com_Printf("...subsystem '%s' failed to save the data\n", saveSubsystems[i].name); else Com_Printf("...subsystem '%s' - saved\n", saveSubsystems[i].name); } /* calculate the needed buffer size */ OBJZERO(header); header.compressed = LittleLong(save_compressed->integer); header.version = LittleLong(SAVE_FILE_VERSION); header.subsystems = LittleLong(saveSubsystemsAmount); Q_strncpyz(header.name, comment, sizeof(header.name)); Q_strncpyz(header.gameVersion, UFO_VERSION, sizeof(header.gameVersion)); CP_DateConvertLong(&ccs.date, &date); Com_sprintf(header.gameDate, sizeof(header.gameDate), _("%i %s %02i"), date.year, Date_GetMonthName(date.month - 1), date.day); Q_strncpyz(header.realDate, timeStampBuffer, sizeof(header.realDate)); requiredBufferLength = mxmlSaveString(topNode, dummy, 2, MXML_NO_CALLBACK); header.xmlSize = LittleLong(requiredBufferLength); byte* const buf = Mem_PoolAllocTypeN(byte, requiredBufferLength + 1, cp_campaignPool); if (!buf) { mxmlDelete(topNode); *error = _("Could not allocate enough memory to save this game"); Com_Printf("Error: Could not allocate enough memory to save this game\n"); return false; } res = mxmlSaveString(topNode, (char*)buf, requiredBufferLength + 1, MXML_NO_CALLBACK); mxmlDelete(topNode); Com_Printf("XML Written to buffer (%d Bytes)\n", res); if (header.compressed) bufLen = compressBound(requiredBufferLength); else bufLen = requiredBufferLength; byte* const fbuf = Mem_PoolAllocTypeN(byte, bufLen + sizeof(header), cp_campaignPool); memcpy(fbuf, &header, sizeof(header)); if (header.compressed) { res = compress(fbuf + sizeof(header), &bufLen, buf, requiredBufferLength); Mem_Free(buf); if (res != Z_OK) { Mem_Free(fbuf); *error = _("Memory error compressing save-game data - set save_compressed cvar to 0"); Com_Printf("Memory error compressing save-game data (%s) (Error: %i)!\n", comment, res); return false; } } else { memcpy(fbuf + sizeof(header), buf, requiredBufferLength); Mem_Free(buf); } /* last step - write data */ res = FS_WriteFile(fbuf, bufLen + sizeof(header), savegame); Mem_Free(fbuf); return true; }