static void D_Display(void) { boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; if (dedicated) return; if (nodrawers) return; // for comparative timing/profiling // check for change of screen size (video mode) if (setmodeneeded && !wipe) SCR_SetMode(); // change video mode if (vid.recalc) SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() // change the view size if needed if (setsizeneeded) { R_ExecuteSetViewSize(); forcerefresh = true; // force background redraw } // draw buffered stuff to screen // Used only by linux GGI version I_UpdateNoBlit(); // save the current screen if about to wipe wipe = (gamestate != wipegamestate); if (wipe) { // set for all later wipedefindex = gamestate; // wipe_xxx_toblack if (gamestate == GS_INTERMISSION) { if (intertype == int_spec) // Special Stage wipedefindex = wipe_specinter_toblack; else if (intertype != int_coop) // Multiplayer wipedefindex = wipe_multinter_toblack; } if (rendermode != render_none) { // Fade to black first if (gamestate != GS_LEVEL // fades to black on its own timing, always && wipedefs[wipedefindex] != UINT8_MAX) { F_WipeStartScreen(); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); F_WipeEndScreen(); F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); } F_WipeStartScreen(); } } // do buffered drawing switch (gamestate) { case GS_LEVEL: if (!gametic) break; HU_Erase(); if (automapactive) AM_Drawer(); break; case GS_INTERMISSION: Y_IntermissionDrawer(); HU_Erase(); HU_Drawer(); break; case GS_TIMEATTACK: break; case GS_INTRO: F_IntroDrawer(); if (wipegamestate == (gamestate_t)-1) wipe = true; break; case GS_CUTSCENE: F_CutsceneDrawer(); HU_Erase(); HU_Drawer(); break; case GS_GAMEEND: F_GameEndDrawer(); break; case GS_EVALUATION: F_GameEvaluationDrawer(); HU_Drawer(); break; case GS_CONTINUING: F_ContinueDrawer(); break; case GS_CREDITS: F_CreditDrawer(); HU_Erase(); HU_Drawer(); break; case GS_TITLESCREEN: F_TitleScreenDrawer(); break; case GS_WAITINGPLAYERS: // The clientconnect drawer is independent... case GS_DEDICATEDSERVER: case GS_NULL: break; } // clean up border stuff // see if the border needs to be initially drawn if (gamestate == GS_LEVEL) { // draw the view directly if (!automapactive && !dedicated && cv_renderview.value) { if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { topleft = screens[0] + viewwindowy*vid.width + viewwindowx; objectsdrawn = 0; #ifdef HWRENDER if (rendermode != render_soft) HWR_RenderPlayerView(0, &players[displayplayer]); else #endif if (rendermode != render_none) R_RenderPlayerView(&players[displayplayer]); } // render the second screen if (splitscreen && players[secondarydisplayplayer].mo) { #ifdef HWRENDER if (rendermode != render_soft) HWR_RenderPlayerView(1, &players[secondarydisplayplayer]); else #endif if (rendermode != render_none) { viewwindowy = vid.height / 2; M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0])); topleft = screens[0] + viewwindowy*vid.width + viewwindowx; R_RenderPlayerView(&players[secondarydisplayplayer]); viewwindowy = 0; M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0])); } } // Image postprocessing effect if (postimgtype) V_DoPostProcessor(0, postimgtype, postimgparam); if (postimgtype2) V_DoPostProcessor(1, postimgtype2, postimgparam2); } if (lastdraw) { if (rendermode == render_soft) { VID_BlitLinearScreen(screens[0], screens[1], vid.width*vid.bpp, vid.height, vid.width*vid.bpp, vid.rowbytes); usebuffer = true; } lastdraw = false; } ST_Drawer(); HU_Drawer(); } // change gamma if needed // (GS_LEVEL handles this already due to level-specific palettes) if (forcerefresh && gamestate != GS_LEVEL) V_SetPalette(0); wipegamestate = gamestate; // draw pause pic if (paused && cv_showhud.value && (!menuactive || netgame)) { INT32 py; patch_t *patch; if (automapactive) py = 4; else py = viewwindowy + 4; patch = W_CachePatchName("M_PAUSE", PU_CACHE); V_DrawScaledPatch(viewwindowx + (BASEVIDWIDTH - SHORT(patch->width))/2, py, 0, patch); } // vid size change is now finished if it was on... vid.recalc = 0; // FIXME: draw either console or menu, not the two if (gamestate != GS_TIMEATTACK) CON_Drawer(); M_Drawer(); // menu is drawn even on top of everything // focus lost moved to M_Drawer // // wipe update // if (wipe) { // note: moved up here because NetUpdate does input changes // and input during wipe tends to mess things up wipedefindex += WIPEFINALSHIFT; if (rendermode != render_none) { F_WipeEndScreen(); F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK); } } NetUpdate(); // send out any new accumulation // It's safe to end the game now. if (G_GetExitGameFlag()) { Command_ExitGame_f(); G_ClearExitGameFlag(); } // // normal update // if (!wipe) { if (cv_netstat.value) { char s[50]; Net_GetNetStat(); s[sizeof s - 1] = '\0'; snprintf(s, sizeof s - 1, "get %d b/s", getbps); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-40, V_YELLOWMAP, s); snprintf(s, sizeof s - 1, "send %d b/s", sendbps); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-30, V_YELLOWMAP, s); snprintf(s, sizeof s - 1, "GameMiss %.2f%%", gamelostpercent); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-20, V_YELLOWMAP, s); snprintf(s, sizeof s - 1, "SysMiss %.2f%%", lostpercent); V_DrawRightAlignedString(BASEVIDWIDTH, BASEVIDHEIGHT-ST_HEIGHT-10, V_YELLOWMAP, s); } I_FinishUpdate(); // page flip or blit buffer } }
/** Copies data to the end of a variable size buffer. * * \param buf The buffer. * \param data The data to copy. * \param length The length of the data. * \sa VS_Print */ void VS_Write(vsbuf_t *buf, const void *data, size_t length) { M_Memcpy(VS_GetSpace(buf, length), data, length); }
vector_t *FV_Copy(vector_t *a_o, const vector_t *a_i) { return M_Memcpy(a_o, a_i, sizeof(vector_t)); }
static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) { char *texturesToken; size_t texturesTokenLength; char *endPos; char *patchName = NULL; INT16 patchXPos; INT16 patchYPos; texpatch_t *resultPatch = NULL; lumpnum_t patchLumpNum; // Patch identifier texturesToken = M_GetToken(NULL); if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch name should be"); } texturesTokenLength = strlen(texturesToken); if (texturesTokenLength>8) { I_Error("Error parsing TEXTURES lump: Patch name \"%s\" exceeds 8 characters",texturesToken); } else { if (patchName != NULL) { Z_Free(patchName); } patchName = (char *)Z_Malloc((texturesTokenLength+1)*sizeof(char),PU_STATIC,NULL); M_Memcpy(patchName,texturesToken,texturesTokenLength*sizeof(char)); patchName[texturesTokenLength] = '\0'; } // Comma 1 Z_Free(texturesToken); texturesToken = M_GetToken(NULL); if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after \"%s\"'s patch name should be",patchName); } if (strcmp(texturesToken,",")!=0) { I_Error("Error parsing TEXTURES lump: Expected \",\" after %s's patch name, got \"%s\"",patchName,texturesToken); } // XPos Z_Free(texturesToken); texturesToken = M_GetToken(NULL); if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s x coordinate should be",patchName); } endPos = NULL; #ifndef AVOID_ERRNO errno = 0; #endif patchXPos = strtol(texturesToken,&endPos,10); (void)patchXPos; //unused for now if (endPos == texturesToken // Empty string || *endPos != '\0' // Not end of string #ifndef AVOID_ERRNO || errno == ERANGE // Number out-of-range #endif ) { I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); } // Comma 2 Z_Free(texturesToken); texturesToken = M_GetToken(NULL); if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after patch \"%s\"'s x coordinate should be",patchName); } if (strcmp(texturesToken,",")!=0) { I_Error("Error parsing TEXTURES lump: Expected \",\" after patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); } // YPos Z_Free(texturesToken); texturesToken = M_GetToken(NULL); if (texturesToken == NULL) { I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s y coordinate should be",patchName); } endPos = NULL; #ifndef AVOID_ERRNO errno = 0; #endif patchYPos = strtol(texturesToken,&endPos,10); (void)patchYPos; //unused for now if (endPos == texturesToken // Empty string || *endPos != '\0' // Not end of string #ifndef AVOID_ERRNO || errno == ERANGE // Number out-of-range #endif ) { I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s y coordinate, got \"%s\"",patchName,texturesToken); } Z_Free(texturesToken); if (actuallyLoadPatch == true) { // Check lump exists patchLumpNum = W_GetNumForName(patchName); // If so, allocate memory for texpatch_t and fill 'er up resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL); resultPatch->originx = patchXPos; resultPatch->originy = patchYPos; resultPatch->lump = patchLumpNum & 65535; resultPatch->wad = patchLumpNum>>16; // Clean up a little after ourselves Z_Free(patchName); // Then return it return resultPatch; }
/** Flushes (executes) console commands in the buffer. */ void COM_BufExecute(void) { size_t i; char *ptext; char line[1024] = ""; INT32 quotes; if (com_wait) { com_wait--; return; } while (com_text.cursize) { // find a '\n' or; line break ptext = (char *)com_text.data; quotes = 0; for (i = 0; i < com_text.cursize; i++) { if (ptext[i] == '\"' && !quotes && i > 0 && ptext[i-1] != ' ') // Malformed command break; if (ptext[i] == '\"') quotes++; if (!(quotes & 1) && ptext[i] == ';') break; // don't break if inside a quoted string if (ptext[i] == '\n' || ptext[i] == '\r') break; } M_Memcpy(line, ptext, i); line[i] = 0; // flush the command text from the command buffer, _BEFORE_ // executing, to avoid that 'recursive' aliases overflow the // command text buffer, in that case, new commands are inserted // at the beginning, in place of the actual, so it doesn't // overflow if (i == com_text.cursize) // the last command was just flushed com_text.cursize = 0; else { i++; com_text.cursize -= i; //memcpy(ptext, ptext+i, com_text.cursize); // Use memmove if the memory areas do overlap. memmove(ptext, ptext+i, com_text.cursize); } // execute the command line COM_ExecuteString(line); // delay following commands if a wait was encountered if (com_wait) { com_wait--; break; } } }
// // R_GenerateTexture // // Allocate space for full size texture, either single patch or 'composite' // Build the full textures from patches. // The texture caching system is a little more hungry of memory, but has // been simplified for the sake of highcolor, dynamic ligthing, & speed. // // This is not optimised, but it's supposed to be executed only once // per level, when enough memory is available. // static UINT8 *R_GenerateTexture(size_t texnum) { UINT8 *block; UINT8 *blocktex; texture_t *texture; texpatch_t *patch; patch_t *realpatch; int x, x1, x2, i; size_t blocksize; column_t *patchcol; UINT32 *colofs; I_Assert(texnum <= (size_t)numtextures); texture = textures[texnum]; I_Assert(texture != NULL); // allocate texture column offset lookup // single-patch textures can have holes in them and may be used on // 2sided lines so they need to be kept in 'packed' format // BUT this is wrong for skies and walls with over 255 pixels, // so check if there's holes and if not strip the posts. if (texture->patchcount == 1) { boolean holey = false; patch = texture->patches; realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); // Check the patch for holes. if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) holey = true; colofs = (UINT32 *)realpatch->columnofs; for (x = 0; x < texture->width && !holey; x++) { column_t *col = (column_t *)((UINT8 *)realpatch + LONG(colofs[x])); INT32 topdelta, prevdelta = -1, y = 0; while (col->topdelta != 0xff) { topdelta = col->topdelta; if (topdelta <= prevdelta) topdelta += prevdelta; prevdelta = topdelta; if (topdelta > y) break; y = topdelta + col->length + 1; col = (column_t *)((UINT8 *)col + col->length + 4); } if (y < texture->height) holey = true; // this texture is HOLEy! D: } // If the patch uses transparency, we have to save it this way. if (holey) { texture->holes = true; blocksize = W_LumpLengthPwad(patch->wad, patch->lump); block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function &texturecache[texnum]); M_Memcpy(block, realpatch, blocksize); texturememory += blocksize; // use the patch's column lookup colofs = (UINT32 *)(void *)(block + 8); texturecolumnofs[texnum] = colofs; blocktex = block; for (x = 0; x < texture->width; x++) colofs[x] = LONG(LONG(colofs[x]) + 3); goto done; } // Otherwise, do multipatch format. } // multi-patch textures (or 'composite') texture->holes = false; blocksize = (texture->width * 4) + (texture->width * texture->height); texturememory += blocksize; block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); memset(block, 0xF7, blocksize+1); // Transparency hack // columns lookup table colofs = (UINT32 *)(void *)block; texturecolumnofs[texnum] = colofs; // texture data after the lookup table blocktex = block + (texture->width*4); // Composite the columns together. for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); x1 = patch->originx; x2 = x1 + SHORT(realpatch->width); if (x1 < 0) x = 0; else x = x1; if (x2 > texture->width) x2 = texture->width; for (; x < x2; x++) { patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1])); // generate column ofset lookup colofs[x] = LONG((x * texture->height) + (texture->width*4)); R_DrawColumnInCache(patchcol, block + LONG(colofs[x]), patch->originy, texture->height); } } done: // Now that the texture has been built in column cache, it is purgable from zone memory. Z_ChangeTag(block, PU_CACHE); return blocktex; }
void R_LoadTextures(void) { INT32 i, k, w; UINT16 j; UINT16 texstart, texend, texturesLumpPos; patch_t *patchlump; texpatch_t *patch; texture_t *texture; // Free previous memory before numtextures change. if (numtextures) { for (i = 0; i < numtextures; i++) { Z_Free(textures[i]); Z_Free(texturecache[i]); } Z_Free(texturetranslation); Z_Free(textures); } // Load patches and textures. // Get the number of textures to check. // NOTE: Make SURE the system does not process // the markers. // This system will allocate memory for all duplicate/patched textures even if it never uses them, // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. for (w = 0, numtextures = 0; w < numwadfiles; w++) { texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); if (texturesLumpPos != INT16_MAX) { numtextures += R_CountTexturesInTEXTURESLump((UINT16)w); } // Add all the textures between TX_START and TX_END if (texstart != INT16_MAX && texend != INT16_MAX) { numtextures += (UINT32)(texend - texstart); } // If no textures found by this point, bomb out if (!numtextures && w == (numwadfiles - 1)) { I_Error("No textures detected in any WADs!\n"); } } // Allocate memory and initialize to 0 for all the textures we are initialising. // There are actually 5 buffers allocated in one for convenience. textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); // Allocate texture column offset table. texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); // Allocate texture referencing cache. texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); // Allocate texture width mask table. texturewidthmask = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); // Allocate texture height mask table. textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); // Create translation table for global animation. texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); for (i = 0; i < numtextures; i++) texturetranslation[i] = i; for (i = 0, w = 0; w < numwadfiles; w++) { // Get the lump numbers for the markers in the WAD, if they exist. texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); if (texturesLumpPos != INT16_MAX) R_ParseTEXTURESLump(w,&i); if (texstart == INT16_MAX || texend == INT16_MAX) continue; // Work through each lump between the markers in the WAD. for (j = 0; j < (texend - texstart); i++, j++) { patchlump = W_CacheLumpNumPwad((UINT16)w, texstart + j, PU_CACHE); // Then, check the lump directly to see if it's a texture SOC, // and if it is, load it using dehacked instead. if (strstr((const char *)patchlump, "TEXTURE")) { CONS_Alert(CONS_WARNING, "%s is a Texture SOC.\n", W_CheckNameForNumPwad((UINT16)w,texstart+j)); Z_Unlock(patchlump); DEH_LoadDehackedLumpPwad((UINT16)w, texstart + j); } else { UINT16 patchcount = 1; //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); if (SHORT(patchlump->width) == 64 && SHORT(patchlump->height) == 64) { // 64x64 patch const column_t *column; for (k = 0; k < SHORT(patchlump->width); k++) { // Find use of transparency. column = (const column_t *)((const UINT8 *)patchlump + LONG(patchlump->columnofs[k])); if (column->length != SHORT(patchlump->height)) break; } if (k == SHORT(patchlump->width)) patchcount = 2; // No transparency? 64x128 texture. } texture = textures[i] = Z_Calloc(sizeof(texture_t) + (sizeof(texpatch_t) * patchcount), PU_STATIC, NULL); // Set texture properties. M_Memcpy(texture->name, W_CheckNameForNumPwad((UINT16)w, texstart + j), sizeof(texture->name)); texture->width = SHORT(patchlump->width); texture->height = SHORT(patchlump->height)*patchcount; texture->patchcount = patchcount; texture->holes = false; // Allocate information for the texture's patches. for (k = 0; k < patchcount; k++) { patch = &texture->patches[k]; patch->originx = 0; patch->originy = (INT16)(k*patchlump->height); patch->wad = (UINT16)w; patch->lump = texstart + j; } Z_Unlock(patchlump); k = 1; while (k << 1 <= texture->width) k <<= 1; texturewidthmask[i] = k - 1; textureheight[i] = texture->height << FRACBITS; } } } }
size_t lzf_decompress (const void *const in_data, size_t in_len, void *out_data, size_t out_len) { u8 const *ip = (const u8 *)in_data; u8 *op = (u8 *)out_data; u8 const *const in_end = ip + in_len; u8 *const out_end = op + out_len; do { unsigned int ctrl = *ip++; if (ctrl < (1 << 5)) /* literal run */ { ctrl++; if (op + ctrl > out_end) { SET_ERRNO (E2BIG); return 0; } #if CHECK_INPUT if (ip + ctrl > in_end) { SET_ERRNO (EINVAL); return 0; } #endif #if USE_MEMCPY M_Memcpy (op, ip, ctrl); op += ctrl; ip += ctrl; #else do *op++ = *ip++; while (--ctrl); #endif } else /* back reference */ { unsigned int len = ctrl >> 5; u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; #if CHECK_INPUT if (ip >= in_end) { SET_ERRNO (EINVAL); return 0; } #endif if (len == 7) { len += *ip++; #if CHECK_INPUT if (ip >= in_end) { SET_ERRNO (EINVAL); return 0; } #endif } ref -= *ip++; if (op + len + 2 > out_end) { SET_ERRNO (E2BIG); return 0; } if (ref < (u8 *)out_data) { SET_ERRNO (EINVAL); return 0; } *op++ = *ref++; *op++ = *ref++; do *op++ = *ref++; while (--len); } } while (ip < in_end); return op - (u8 *)out_data; }
// // HGetPacket // Returns false if no packet is waiting // Check Datalength and checksum // boolean HGetPacket(void) { // get a packet from self if (rebound_tail != rebound_head) { M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); doomcom->datalength = reboundsize[rebound_tail]; if (netbuffer->packettype == PT_NODETIMEOUT) doomcom->remotenode = netbuffer->u.textcmd[0]; else doomcom->remotenode = 0; rebound_tail = (rebound_tail+1) % MAXREBOUND; #ifdef DEBUGFILE if (debugfile) DebugPrintpacket("GETLOCAL"); #endif return true; } if (!netgame) return false; while(true) { I_NetGet(); if (doomcom->remotenode == -1) return false; getbytes += packetheaderlength + doomcom->datalength; // for stat if (doomcom->remotenode >= MAXNETNODES) { DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode)); continue; } nodes[doomcom->remotenode].lasttimepacketreceived = I_GetTime(); if (netbuffer->checksum != NetbufferChecksum()) { DEBFILE("Bad packet checksum\n"); if (I_Shun) I_Shun(doomcom->remotenode); Net_CloseConnection(doomcom->remotenode); continue; } #ifdef DEBUGFILE if (debugfile) DebugPrintpacket("GET"); #endif // proceed the ack and ackreturn field if (!Processackpak()) continue; // discarded (duplicated) // a packet with just ackreturn if (netbuffer->packettype == PT_NOTHING) { GotAcks(); continue; } break; } return true; }
// // HSendPacket // boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength) { doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE); if (node == 0) // packet is to go back to us { if ((rebound_head+1) % MAXREBOUND == rebound_tail) { #ifdef PARANOIA CONS_Printf("No more rebound buf\n"); #endif return false; } M_Memcpy(&reboundstore[rebound_head], netbuffer, doomcom->datalength); reboundsize[rebound_head] = doomcom->datalength; rebound_head = (rebound_head+1) % MAXREBOUND; #ifdef DEBUGFILE if (debugfile) { doomcom->remotenode = (INT16)node; DebugPrintpacket("SENDLOCAL"); } #endif return true; } if (!netgame) I_Error("Tried to transmit to another node"); // do this before GetFreeAcknum because this function backup // the current packet doomcom->remotenode = (INT16)node; if (doomcom->datalength <= 0) { DEBFILE("HSendPacket: nothing to send\n"); #ifdef DEBUGFILE if (debugfile) DebugPrintpacket("TRISEND"); #endif return false; } if (node < MAXNETNODES) // can be a broadcast netbuffer->ackreturn = GetAcktosend(node); else netbuffer->ackreturn = 0; if (reliable) { if (I_NetCanSend && !I_NetCanSend()) { if (netbuffer->packettype < PT_CANFAIL) GetFreeAcknum(&netbuffer->ack, true); DEBFILE("HSendPacket: Out of bandwidth\n"); return false; } else if (!GetFreeAcknum(&netbuffer->ack, false)) return false; } else netbuffer->ack = acknum; netbuffer->checksum = NetbufferChecksum(); sendbytes += packetheaderlength + doomcom->datalength; // for stat // simulate internet :) if (true || rand()<(INT32)RAND_MAX/5) { #ifdef DEBUGFILE if (debugfile) DebugPrintpacket("SEND"); #endif I_NetSend(); } #ifdef DEBUGFILE else if (debugfile) DebugPrintpacket("NOTSEND"); #endif return true; }
// send special packet with only ack on it void Net_SendAcks(INT32 node) { netbuffer->packettype = PT_NOTHING; M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND); }
// poly : the convex polygon that encloses all child subsectors static void WalkBSPNode(INT32 bspnum, poly_t *poly, UINT16 *leafnode, fixed_t *bbox) { node_t *bsp; poly_t *backpoly, *frontpoly; fdivline_t fdivline; polyvertex_t *pt; INT32 i; // Found a subsector? if (bspnum & NF_SUBSECTOR) { if (bspnum == -1) { // BP: i think this code is useless and wrong because // - bspnum==-1 happens only when numsubsectors == 0 // - it can't happens in bsp recursive call since bspnum is a INT32 and children is UINT16 // - the BSP is complet !! (there just can have subsector without segs) (i am not sure of this point) // do we have a valid polygon ? if (poly && poly->numpts > 2) { DEBPRINT("Adding a new subsector\n"); if (addsubsector == numsubsectors + NEWSUBSECTORS) I_Error("WalkBSPNode: not enough addsubsectors\n"); else if (addsubsector > 0x7fff) I_Error("WalkBSPNode: addsubsector > 0x7fff\n"); *leafnode = (UINT16)((UINT16)addsubsector | NF_SUBSECTOR); extrasubsectors[addsubsector].planepoly = poly; addsubsector++; } //add subsectors without segs here? //HWR_SubsecPoly(0, NULL); } else { HWR_SubsecPoly(bspnum&(~NF_SUBSECTOR), poly); //Hurdler: implement a loading status if (ls_count-- <= 0) { char s[16]; int x, y; I_OsPolling(); ls_count = numsubsectors/50; CON_Drawer(); sprintf(s, "%d%%", (++ls_percent)<<1); x = BASEVIDWIDTH/2; y = BASEVIDHEIGHT/2; V_DrawFill(0, 0, vid.width, vid.height, 31); // Black background to match fade in effect //V_DrawPatchFill(W_CachePatchName("SRB2BACK",PU_CACHE)); // SRB2 background, ehhh too bright. M_DrawTextBox(x-58, y-8, 13, 1); V_DrawString(x-50, y, V_YELLOWMAP, "Loading..."); V_DrawString(x+50-V_StringWidth(s), y, V_YELLOWMAP, s); // Is this really necessary at this point..? V_DrawCenteredString(BASEVIDWIDTH/2, 40, V_YELLOWMAP, "OPENGL MODE IS INCOMPLETE AND MAY"); V_DrawCenteredString(BASEVIDWIDTH/2, 50, V_YELLOWMAP, "NOT DISPLAY SOME SURFACES."); V_DrawCenteredString(BASEVIDWIDTH/2, 70, V_YELLOWMAP, "USE AT SONIC'S RISK."); I_UpdateNoVsync(); } } M_ClearBox(bbox); poly = extrasubsectors[bspnum&~NF_SUBSECTOR].planepoly; for (i = 0, pt = poly->pts; i < poly->numpts; i++,pt++) M_AddToBox(bbox, FLOAT_TO_FIXED(pt->x), FLOAT_TO_FIXED(pt->y)); return; } bsp = &nodes[bspnum]; SearchDivline(bsp, &fdivline); SplitPoly(&fdivline, poly, &frontpoly, &backpoly); poly = NULL; //debug if (!backpoly) nobackpoly++; // Recursively divide front space. if (frontpoly) { WalkBSPNode(bsp->children[0], frontpoly, &bsp->children[0],bsp->bbox[0]); // copy child bbox M_Memcpy(bbox, bsp->bbox[0], 4*sizeof (fixed_t)); } else I_Error("WalkBSPNode: no front poly?"); // Recursively divide back space. if (backpoly) { // Correct back bbox to include floor/ceiling convex polygon WalkBSPNode(bsp->children[1], backpoly, &bsp->children[1], bsp->bbox[1]); // enlarge bbox with seconde child M_AddToBox(bbox, bsp->bbox[1][BOXLEFT ], bsp->bbox[1][BOXTOP ]); M_AddToBox(bbox, bsp->bbox[1][BOXRIGHT ], bsp->bbox[1][BOXBOTTOM]); } }