void* WAV_MemoryLoad(const byte* data, size_t datalength, int* bits, int* rate, int* samples) { const byte* end = data + datalength; byte* sampledata = NULL; chunk_hdr_t riff_chunk; wav_format_t wave_format; LOG_AS("WAV_MemoryLoad"); if(!WAV_CheckFormat((const char*)data)) { LOG_RES_WARNING("Not WAV format data"); return NULL; } // Read the RIFF header. data += sizeof(riff_hdr_t); data += 4; // "WAVE" already verified above #ifdef _DEBUG assert(sizeof(wave_format) == 16); assert(sizeof(riff_chunk) == 8); #endif // Start readin' the chunks, baby! while(data < end) { // Read next chunk header. WReadAndAdvance(data, &riff_chunk, sizeof(riff_chunk)); // Correct endianness. riff_chunk.len = DD_ULONG(riff_chunk.len); // What have we got here? if(!strncmp(riff_chunk.id, "fmt ", 4)) { // Read format chunk. WReadAndAdvance(data, &wave_format, sizeof(wave_format)); // Correct endianness. wave_format.wFormatTag = DD_USHORT(wave_format.wFormatTag ); wave_format.wChannels = DD_USHORT(wave_format.wChannels ); wave_format.dwSamplesPerSec = DD_ULONG (wave_format.dwSamplesPerSec ); wave_format.dwAvgBytesPerSec = DD_ULONG (wave_format.dwAvgBytesPerSec); wave_format.wBlockAlign = DD_USHORT(wave_format.wBlockAlign ); wave_format.wBitsPerSample = DD_USHORT(wave_format.wBitsPerSample ); assert(wave_format.wFormatTag == WAVE_FORMAT_PCM); // linear PCM // Check that it's a format we know how to read. if(wave_format.wFormatTag != WAVE_FORMAT_PCM) { LOG_RES_WARNING("Unsupported format (%i)") << wave_format.wFormatTag; return NULL; } if(wave_format.wChannels != 1) { LOG_RES_WARNING("Too many channels (only mono supported)"); return NULL; } // Read the extra format information. //WReadAndAdvance(&data, &wave_format2, sizeof(*wave_format2)); /*if(wave_format->wBitsPerSample == 0) { // We'll have to guess... *bits = 8*wave_format->dwAvgBytesPerSec/ wave_format->dwSamplesPerSec; } else { */ if(wave_format.wBitsPerSample != 8 && wave_format.wBitsPerSample != 16) { LOG_RES_WARNING("Must have 8 or 16 bits per sample"); return NULL; } // Now we know some information about the sample. *bits = wave_format.wBitsPerSample; *rate = wave_format.dwSamplesPerSec; } else if(!strncmp(riff_chunk.id, "data", 4)) { if(!wave_format.wFormatTag) { LOG_RES_WARNING("Malformed WAV data"); return NULL; } // Read data chunk. *samples = riff_chunk.len / wave_format.wBlockAlign; // Allocate the sample buffer. sampledata = (byte *) Z_Malloc(riff_chunk.len, PU_APPSTATIC, 0); memcpy(sampledata, data, riff_chunk.len); #ifdef __BIG_ENDIAN__ // Correct endianness. /*if(wave_format->wBitsPerSample == 16) { ushort* sample = sampledata; for(; sample < ((short*)sampledata) + *samples; ++sample) *sample = DD_USHORT(*sample); }*/ #endif // We're satisfied with this! Let's get out of here. break; } else { // Unknown chunk, just skip it. data += riff_chunk.len; } } return sampledata; }
void NetUpdate(void) { static int lastmadetic; if (isExtraDDisplay) return; if (server) { // Receive network packets size_t recvlen; packet_header_t *packet = Z_Malloc(10000, PU_STATIC, NULL); while ((recvlen = I_GetPacket(packet, 10000))) { switch(packet->type) { case PKT_TICS: { byte *p = (void*)(packet+1); int tics = *p++; unsigned long ptic = doom_ntohl(packet->tic); if (ptic > (unsigned)remotetic) { // Missed some packet_set(packet, PKT_RETRANS, remotetic); *(byte*)(packet+1) = consoleplayer; I_SendPacket(packet, sizeof(*packet)+1); } else { if (ptic + tics <= (unsigned)remotetic) break; // Will not improve things remotetic = ptic; while (tics--) { int players = *p++; while (players--) { int n = *p++; RawToTic(&netcmds[n][remotetic%BACKUPTICS], p); p += sizeof(ticcmd_t); } remotetic++; } } } break; case PKT_RETRANS: // Resend request remotesend = doom_ntohl(packet->tic); break; case PKT_DOWN: // Server downed { int j; for (j=0; j<MAXPLAYERS; j++) if (j != consoleplayer) playeringame[j] = false; server = false; doom_printf("Server is down\nAll other players are no longer in the game\n"); jni_info_msg("Server is down\nAll other players are no longer in the game!", TT_LONG_DELAY | TT_COLOR_RED); } break; case PKT_EXTRA: // Misc stuff case PKT_QUIT: // Player quit // Queue packet to be processed when its tic time is reached queuedpacket = Z_Realloc(queuedpacket, ++numqueuedpackets * sizeof *queuedpacket, PU_STATIC, NULL); queuedpacket[numqueuedpackets-1] = Z_Malloc(recvlen, PU_STATIC, NULL); memcpy(queuedpacket[numqueuedpackets-1], packet, recvlen); break; case PKT_BACKOFF: /* cph 2003-09-18 - * The server sends this when we have got ahead of the other clients. We should * stall the input side on this client, to allow other clients to catch up. */ lastmadetic++; break; default: // Other packet, unrecognised or redundant break; } } Z_Free(packet); } { // Build new ticcmds int newtics = I_GetTime() - lastmadetic; newtics = (newtics > 0 ? newtics : 0); lastmadetic += newtics; if (ffmap) newtics++; while (newtics--) { I_StartTic(); if (maketic - gametic > BACKUPTICS/2) break; G_BuildTiccmd(&localcmds[maketic%BACKUPTICS]); maketic++; } if (server && maketic > remotesend) { // Send the tics to the server int sendtics; remotesend -= xtratics; if (remotesend < 0) remotesend = 0; sendtics = maketic - remotesend; { size_t pkt_size = sizeof(packet_header_t) + 2 + sendtics * sizeof(ticcmd_t); packet_header_t *packet = Z_Malloc(pkt_size, PU_STATIC, NULL); packet_set(packet, PKT_TICC, maketic - sendtics); *(byte*)(packet+1) = sendtics; *(((byte*)(packet+1))+1) = consoleplayer; { void *tic = ((byte*)(packet+1)) +2; while (sendtics--) { TicToRaw(tic, &localcmds[remotesend++%BACKUPTICS]); tic = (byte *)tic + sizeof(ticcmd_t); } } I_SendPacket(packet, pkt_size); Z_Free(packet); } } } }
bool LoadTGAPalletteImage ( const char *name, byte **pic, int *width, int *height) { int columns, rows, numPixels; byte *buf_p; byte *buffer; TargaHeader targa_header; byte *dataStart; *pic = NULL; // // load the file // ri->FS_ReadFile ( ( char * ) name, (void **)&buffer); if (!buffer) { return false; } buf_p = buffer; targa_header.id_length = *buf_p++; targa_header.colormap_type = *buf_p++; targa_header.image_type = *buf_p++; targa_header.colormap_index = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.colormap_length = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.colormap_size = *buf_p++; targa_header.x_origin = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.y_origin = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.width = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.height = LittleShort ( *(short *)buf_p ); buf_p += 2; targa_header.pixel_size = *buf_p++; targa_header.attributes = *buf_p++; if (targa_header.image_type!=1 ) { Com_Error (ERR_DROP, "LoadTGAPalletteImage: Only type 1 (uncompressed pallettised) TGA images supported\n"); } if ( targa_header.colormap_type == 0 ) { Com_Error( ERR_DROP, "LoadTGAPalletteImage: colormaps ONLY supported\n" ); } columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; if (width) *width = columns; if (height) *height = rows; *pic = (unsigned char *) Z_Malloc (numPixels, TAG_TEMP_WORKSPACE, qfalse ); if (targa_header.id_length != 0) { buf_p += targa_header.id_length; // skip TARGA image comment } dataStart = buf_p + (targa_header.colormap_length * (targa_header.colormap_size / 4)); memcpy(*pic, dataStart, numPixels); ri->FS_FreeFile (buffer); return true; }
int EV_DoDoor ( line_t* line, vldoor_e type ) { int secnum,rtn; sector_t* sec; vldoor_t* door; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { sec = §ors[secnum]; if (sec->specialdata) continue; // new door thinker rtn = 1; door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor; door->sector = sec; door->type = type; door->topwait = VDOORWAIT; door->speed = VDOORSPEED; switch(type) { case vld_blazeClose: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; door->speed = VDOORSPEED * 4; S_StartSound(&door->sector->soundorg, sfx_bdcls); break; case vld_close: door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_close30ThenOpen: door->topheight = sec->ceilingheight; door->direction = -1; S_StartSound(&door->sector->soundorg, sfx_dorcls); break; case vld_blazeRaise: case vld_blazeOpen: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; door->speed = VDOORSPEED * 4; if (door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, sfx_bdopn); break; case vld_normal: case vld_open: door->direction = 1; door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; if (door->topheight != sec->ceilingheight) S_StartSound(&door->sector->soundorg, sfx_doropn); break; default: break; } } return rtn; }
static void ExpandSoundData_SDL(byte *data, int samplerate, uint32_t length, Mix_Chunk *destination) { SDL_AudioCVT convertor; uint32_t expanded_length; // Calculate the length of the expanded version of the sample. expanded_length = (uint32_t)(((uint64_t)length * mixer_freq) / samplerate); // Double up twice: 8 -> 16 bit and mono -> stereo expanded_length *= 4; destination->alen = expanded_length; destination->abuf = (Uint8 *)Z_Malloc(expanded_length, PU_STATIC, (void **)&destination->abuf); // If we can, use the standard / optimized SDL conversion routines. if (samplerate <= mixer_freq && ConvertibleRatio(samplerate, mixer_freq) && SDL_BuildAudioCVT(&convertor, AUDIO_U8, 1, samplerate, mixer_format, mixer_channels, mixer_freq)) { convertor.buf = destination->abuf; convertor.len = length; memcpy(convertor.buf, data, length); SDL_ConvertAudio(&convertor); } else { Sint16 *expanded = (Sint16 *)destination->abuf; int expanded_length; int expand_ratio; int i; // Generic expansion if conversion does not work: // // SDL's audio conversion only works for rate conversions that are // powers of 2; if the two formats are not in a direct power of 2 // ratio, do this naive conversion instead. // number of samples in the converted sound expanded_length = ((uint64_t)length * mixer_freq) / samplerate; expand_ratio = (length << 8) / expanded_length; for (i = 0; i < expanded_length; ++i) { Sint16 sample; int src; src = (i * expand_ratio) >> 8; sample = data[src] | (data[src] << 8); sample -= 32768; // expand 8->16 bits, mono->stereo expanded[i * 2] = expanded[i * 2 + 1] = sample; } { float rc, dt, alpha; // Low-pass filter for cutoff frequency f: // // For sampling rate r, dt = 1 / r // rc = 1 / 2*pi*f // alpha = dt / (rc + dt) // Filter to the half sample rate of the original sound effect // (maximum frequency, by nyquist) dt = 1.0f / mixer_freq; rc = 1.0f / (float)(2 * M_PI * samplerate); alpha = dt / (rc + dt); // Both channels are processed in parallel, hence [i - 2]: for (i = 2; i < expanded_length * 2; ++i) { expanded[i] = (Sint16)(alpha * expanded[i] + (1 - alpha) * expanded[i - 2]); } } } }
/** * @brief Change sv_maxclients and move real clients slots when a demo is playing or stopped */ void SV_DemoChangeMaxClients(void) { int oldMaxClients, oldDemoClients; int i, j, k; client_t *oldClients = NULL; int count; //qboolean firstTime = svs.clients == NULL; // == Checking the prerequisites // Note: we check here that we have enough slots to fit all clients, and that it doesn't overflow the MAX_CLIENTS the engine can support. Also, we save the oldMaxClients and oldDemoClients values. // -- Get the highest client number in use count = 0; for (i = 0 ; i < sv_maxclients->integer ; i++) { if (svs.clients[i].state >= CS_CONNECTED) { if (i > count) { count = i; } } } count++; // -- Save the previous oldMaxClients and oldDemoClients values, and update // Save the previous sv_maxclients value before updating it oldMaxClients = sv_maxclients->integer; // update the cvars Cvar_Get("sv_maxclients", "8", 0); Cvar_Get("sv_democlients", "0", 0); // unnecessary now that sv_democlients is not latched anymore? // Save the previous sv_democlients (since it's updated instantly, we cannot get it directly), we use a trick by computing the difference between the new and previous sv_maxclients (the difference should indeed be the exact value of sv_democlients) oldDemoClients = (oldMaxClients - sv_maxclients->integer); if (oldDemoClients < 0) // if the difference is negative, this means that before it was set to 0 (because the newer sv_maxclients is greater than the old) { oldDemoClients = 0; } // -- Check limits // never go below the highest client number in use (make sure we have enough room for all players) SV_BoundMaxClients(count); // -- Change check: if still the same, we just quit, there's nothing to do if (sv_maxclients->integer == oldMaxClients) { return; } // == Memorizing clients // Note: we save in a temporary variables the clients, because after we will wipe completely the svs.clients struct // copy the clients to hunk memory oldClients = Hunk_AllocateTempMemory((sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // we allocate just enough memory for the real clients (not counting in the democlients) // For all previous clients slots, we copy the entire client into a temporary var for (i = 0, j = 0, k = sv_privateClients->integer ; i < oldMaxClients ; i++) // for all the previously connected clients, we copy them to a temporary var { // If there is a real client in this slot if (svs.clients[i].state >= CS_CONNECTED) { // if the client is in a privateClient reserved slot, we move him on the reserved slots if (i >= oldDemoClients && i < oldDemoClients + sv_privateClients->integer) { oldClients[j++] = svs.clients[i]; // else the client is not a privateClient, and we move him to the first available slot after the privateClients slots } else { oldClients[k++] = svs.clients[i]; } } } // Fill in the remaining clients slots with empty clients (else the engine crash when copying into memory svs.clients) for (i = j; i < sv_privateClients->integer; i++) // Fill the privateClients empty slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } for (i = k; i < (sv_maxclients->integer - sv_democlients->integer); i++) // Fill the other normal clients slots { Com_Memset(&oldClients[i], 0, sizeof(client_t)); } // free old clients arrays Z_Free(svs.clients); // == Allocating the new svs.clients and moving the saved clients over from the temporary var // allocate new svs.clients svs.clients = Z_Malloc(sv_maxclients->integer * sizeof(client_t)); Com_Memset(svs.clients, 0, sv_maxclients->integer * sizeof(client_t)); // copy the clients over (and move them depending on sv_democlients: if >0, move them upwards, if == 0, move them to their original slots) Com_Memcpy(svs.clients + sv_democlients->integer, oldClients, (sv_maxclients->integer - sv_democlients->integer) * sizeof(client_t)); // free the old clients on the hunk Hunk_FreeTempMemory(oldClients); // == Allocating snapshot entities // allocate new snapshot entities if (com_dedicated->integer) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; } // == Server-side demos management // set demostate to none if it was just waiting to set maxclients and move real clients slots if (sv.demoState == DS_WAITINGSTOP) { sv.demoState = DS_NONE; Cvar_SetValue("sv_demoState", DS_NONE); } }
{ int groupid = groupcount; pgroup_t *group; if(from->groupid != R_NOGROUP) return from->groupid; if(groupcount == grouplimit) { grouplimit = grouplimit ? (grouplimit << 1) : 8; groups = erealloc(pgroup_t **, groups, sizeof(pgroup_t **) * grouplimit); } groupcount++; group = groups[groupid] = (pgroup_t *)(Z_Malloc(sizeof(pgroup_t), PU_LEVEL, 0)); group->seclist = NULL; group->listsize = 0; P_GatherSectors(from, groupid); return groupid; } // // P_GatherSectors // // The function will run through the sector's lines list, and add // attached sectors to the group's sector list. As each sector is added the // currently forming group's id is assigned to that sector. This will continue // until every attached sector has been added to the list, thus defining a
// // 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; } } } }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); Hunk_Clear(); // clear out those shaders, images and Models R_InitImages(); R_InitShaders(); R_ModelInit(); // create a heap for Ghoul2 to use for game side model vertex transforms used in collision detection if (!G2VertSpaceServer) { static const int MiniHeapSize=128 * 1024; // maxsize of ghoul2 miniheap G2VertSpaceServer = new CMiniHeap(MiniHeapSize); } if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); } // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); // wipe the entire per-level structure for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); } } memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; G2API_SetTime(sv.time,G2T_SV_TIME); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); } // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info svs.nextHeartbeatTime = -9999999; Hunk_SetMark(); Com_Printf ("-----------------------------------\n"); }
// // EV_VerticalDoor : open a door manually, no tag value // void EV_VerticalDoor(line_t *line, mobj_t *thing) { player_t *player; int secnum; sector_t *sec; vldoor_t *door; int side; side = 0; // only front sides can be used // Check for locks player = thing->player; switch (line->special) { case 26: // Blue Lock case 32: if(!player) return; if(!player->cards[it_bluecard] && !player->cards[it_blueskull]) { P_SetMessage(player, PD_BLUEK); S_StartSound(sfx_oof, player->plr->mo); return; } break; case 27: // Yellow Lock case 34: if(!player) return; if(!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) { P_SetMessage(player, PD_YELLOWK); S_StartSound(sfx_oof, player->plr->mo); return; } break; case 28: // Red Lock case 33: if(!player) return; if(!player->cards[it_redcard] && !player->cards[it_redskull]) { P_SetMessage(player, PD_REDK); S_StartSound(sfx_oof, player->plr->mo); return; } break; } // if the sector has an active thinker, use it sec = sides[line->sidenum[side ^ 1]].sector; secnum = sec - sectors; if(sec->specialdata) { door = sec->specialdata; switch (line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: case 117: if(door->direction == -1) door->direction = 1; // go back up else { if(!thing->player) return; // JDC: bad guys never close doors door->direction = -1; // start going down immediately } return; } } // for proper sound switch (line->special) { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN S_SectorSound(sec, sfx_bdopn); break; case 1: // NORMAL DOOR SOUND case 31: S_SectorSound(sec, sfx_doropn); break; default: // LOCKED DOOR SOUND S_SectorSound(sec, sfx_doropn); break; } // new door thinker door = Z_Malloc(sizeof(*door), PU_LEVSPEC, 0); P_AddThinker(&door->thinker); sec->specialdata = door; door->thinker.function = T_VerticalDoor; door->sector = sec; door->direction = 1; door->speed = VDOORSPEED; door->topwait = VDOORWAIT; switch (line->special) { case 1: case 26: case 27: case 28: door->type = normal; break; case 31: case 32: case 33: case 34: door->type = open; line->special = 0; break; case 117: // blazing door raise door->type = blazeRaise; door->speed = VDOORSPEED * 4; break; case 118: // blazing door open door->type = blazeOpen; line->special = 0; door->speed = VDOORSPEED * 4; break; } // find the top and bottom of the movement range door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4 * FRACUNIT; }
// // Do Platforms // "amount" is only used for SOME platforms. // int EV_DoPlat(line_t *line, plattype_e type, int amount) { plat_t *plat; int secnum; int rtn; sector_t *sec; secnum = -1; rtn = 0; // Activate all <type> plats that are in_stasis switch(type) { case perpetualRaise: P_ActivateInStasis(line->tag); break; default: break; } while ((secnum = P_FindSectorFromLineTag(line, secnum)) >= 0) { sec = §ors[secnum]; if (sec->floordata) continue; // Find lowest & highest floors around sector rtn = 1; plat = Z_Malloc(sizeof(*plat), PU_LEVSPEC, (void *)0); P_AddThinker(&plat->thinker); plat->type = type; plat->sector = sec; plat->sector->floordata = plat; plat->thinker.function.acp1 = (actionf_p1)T_PlatRaise; plat->crush = false; plat->tag = line->tag; switch(type) { case raiseToNearestAndChange: plat->speed = PLATSPEED / 2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = P_FindNextHighestFloor(sec, sec->floorheight); plat->wait = 0; plat->status = up; // NO MORE DAMAGE, IF APPLICABLE sec->special = 0; S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov); break; case raiseAndChange: plat->speed = PLATSPEED / 2; sec->floorpic = sides[line->sidenum[0]].sector->floorpic; plat->high = sec->floorheight + amount * FRACUNIT; plat->wait = 0; plat->status = up; S_StartSound((mobj_t *)&sec->soundorg, sfx_stnmov); break; case downWaitUpStay: plat->speed = PLATSPEED * 4; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = 35 * PLATWAIT; plat->status = down; S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); break; case blazeDWUS: plat->speed = PLATSPEED * 8; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = sec->floorheight; plat->wait = 35 * PLATWAIT; plat->status = down; S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); break; case perpetualRaise: plat->speed = PLATSPEED; plat->low = P_FindLowestFloorSurrounding(sec); if (plat->low > sec->floorheight) plat->low = sec->floorheight; plat->high = P_FindHighestFloorSurrounding(sec); if (plat->high < sec->floorheight) plat->high = sec->floorheight; plat->wait = 35 * PLATWAIT; plat->status = P_Random() & 1; S_StartSound((mobj_t *)&sec->soundorg, sfx_pstart); break; } P_AddActivePlat(plat); } return rtn; }
//--------------------------------------------------------------------------- static void createTextureCompositePatch(int id) { rpatch_t *composite_patch; texture_t *texture; texpatch_t *texpatch; int patchNum; const patch_t *oldPatch; const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; int i, x, y; int oy, count; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; int edgeSlope; count_t *countsInColumn; #ifdef RANGECHECK if (id >= numtextures) I_Error("createTextureCompositePatch: %i >= numtextures", id); #endif composite_patch = &texture_composites[id]; texture = textures[id]; composite_patch->width = texture->width; composite_patch->height = texture->height; composite_patch->widthmask = texture->widthmask; composite_patch->leftoffset = 0; composite_patch->topoffset = 0; composite_patch->isNotTileable = 0; // work out how much memory we need to allocate for this patch's data pixelDataSize = (composite_patch->width * composite_patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * composite_patch->width; // count the number of posts in each column countsInColumn = (count_t *)calloc(sizeof(count_t), composite_patch->width); numPostsTotal = 0; for (i=0; i<texture->patchcount; i++) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); for (x=0; x<SHORT(oldPatch->width); x++) { int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; countsInColumn[tx].patches++; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); while (oldColumn->topdelta != 0xff) { countsInColumn[tx].posts++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } W_UnlockLumpNum(patchNum); } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; composite_patch->data = (unsigned char*)Z_Malloc(dataSize, PU_STATIC, (void **)&composite_patch->data); memset(composite_patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array composite_patch->pixels = composite_patch->data; composite_patch->columns = (rcolumn_t*)((unsigned char*)composite_patch->pixels + pixelDataSize); composite_patch->posts = (rpost_t*)((unsigned char*)composite_patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)composite_patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)composite_patch->data) == dataSize); memset(composite_patch->pixels, 0xff, (composite_patch->width*composite_patch->height)); numPostsUsedSoFar = 0; for (x=0; x<texture->width; x++) { // setup the column's data composite_patch->columns[x].pixels = composite_patch->pixels + (x*composite_patch->height); composite_patch->columns[x].numPosts = countsInColumn[x].posts; composite_patch->columns[x].posts = composite_patch->posts + numPostsUsedSoFar; numPostsUsedSoFar += countsInColumn[x].posts; } // fill in the pixels, posts, and columns for (i=0; i<texture->patchcount; i++) { texpatch = &texture->patches[i]; patchNum = texpatch->patch; oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); for (x=0; x<SHORT(oldPatch->width); x++) { int tx = texpatch->originx + x; if (tx < 0) continue; if (tx >= composite_patch->width) break; oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); { // tiling int prevColumnIndex = x-1; int nextColumnIndex = x+1; while (prevColumnIndex < 0) prevColumnIndex += SHORT(oldPatch->width); while (nextColumnIndex >= SHORT(oldPatch->width)) nextColumnIndex -= SHORT(oldPatch->width); oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); } while (oldColumn->topdelta != 0xff) { rpost_t *post = &composite_patch->columns[tx].posts[countsInColumn[tx].posts_used]; oldColumnPixelData = (const byte *)oldColumn + 3; oy = texpatch->originy; count = oldColumn->length; // the original renderer had several bugs which we reproduce here if (countsInColumn[tx].patches > 1) { // when there are multiple patches, then we need to handle the // column differently if (i == 0) { // draw first patch at original position, it will be partly // overdrawn below for (y=0; y<count; y++) { int ty = oy + oldColumn->topdelta + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } } // do the buggy clipping if (oy < 0) { count += oy; oy = 0; } } else { // with a single patch only negative y origins are wrong oy = 0; } // set up the post's data post->topdelta = oldColumn->topdelta + oy; post->length = count; if ((post->topdelta + post->length) > composite_patch->height) { if ((post->topdelta) > composite_patch->height) post->length = 0; else post->length = composite_patch->height - post->topdelta; } if (post->topdelta < 0) { post->topdelta = 0; if ((post->topdelta + post->length) <= 0) post->length = 0; else post->length -= post->topdelta; } post->slope = 0; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_TOP_UP; else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_TOP_DOWN; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+count); if (edgeSlope == 1) post->slope |= RDRAW_EDGESLOPE_BOT_UP; else if (edgeSlope == -1) post->slope |= RDRAW_EDGESLOPE_BOT_DOWN; // fill in the post's pixels for (y=0; y<count; y++) { int ty = oy + oldColumn->topdelta + y; if (ty < 0) continue; if (ty >= composite_patch->height) break; composite_patch->pixels[tx * composite_patch->height + ty] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); countsInColumn[tx].posts_used++; assert(countsInColumn[tx].posts_used <= countsInColumn[tx].posts); } } W_UnlockLumpNum(patchNum); } for (x=0; x<texture->width; x++) { rcolumn_t *column; if (countsInColumn[x].patches <= 1) continue; // cleanup posts on multipatch columns column = &composite_patch->columns[x]; i = 0; while (i<(column->numPosts-1)) { rpost_t *post1 = &column->posts[i]; rpost_t *post2 = &column->posts[i+1]; int length; if ((post2->topdelta - post1->topdelta) < 0) switchPosts(post1, post2); if ((post1->topdelta + post1->length) >= post2->topdelta) { length = (post1->length + post2->length) - ((post1->topdelta + post1->length) - post2->topdelta); if (post1->length < length) { post1->slope = post2->slope; post1->length = length; } removePostFromColumn(column, i+1); i = 0; continue; } i++; } } if (1 || composite_patch->isNotTileable) { const rcolumn_t *column, *prevColumn; // copy the patch image down and to the right where there are // holes to eliminate the black halo from bilinear filtering for (x=0; x<composite_patch->width; x++) { //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); column = R_GetPatchColumnClamped(composite_patch, x); prevColumn = R_GetPatchColumnClamped(composite_patch, x-1); if (column->pixels[0] == 0xff) { // force the first pixel (which is a hole), to use // the color from the next solid spot in the column for (y=0; y<composite_patch->height; y++) { if (column->pixels[y] != 0xff) { column->pixels[0] = column->pixels[y]; break; } } } // copy from above or to the left for (y=1; y<composite_patch->height; y++) { //if (getIsSolidAtSpot(oldColumn, y)) continue; if (column->pixels[y] != 0xff) continue; // this pixel is a hole if (x && prevColumn->pixels[y-1] != 0xff) { // copy the color from the left column->pixels[y] = prevColumn->pixels[y]; } else { // copy the color from above column->pixels[y] = column->pixels[y-1]; } } } // verify that the patch truly is non-rectangular since // this determines tiling later on } free(countsInColumn); }
//--------------------------------------------------------------------------- static void createPatch(int id) { rpatch_t *patch; const int patchNum = id; const patch_t *oldPatch = (const patch_t*)W_CacheLumpNum(patchNum); const column_t *oldColumn, *oldPrevColumn, *oldNextColumn; int x, y; int pixelDataSize; int columnsDataSize; int postsDataSize; int dataSize; int *numPostsInColumn; int numPostsTotal; const unsigned char *oldColumnPixelData; int numPostsUsedSoFar; int edgeSlope; #ifdef RANGECHECK if (id >= numlumps) I_Error("createPatch: %i >= numlumps", id); #endif patch = &patches[id]; // proff - 2003-02-16 What about endianess? patch->width = SHORT(oldPatch->width); patch->widthmask = 0; patch->height = SHORT(oldPatch->height); patch->leftoffset = SHORT(oldPatch->leftoffset); patch->topoffset = SHORT(oldPatch->topoffset); patch->isNotTileable = getPatchIsNotTileable(oldPatch); // work out how much memory we need to allocate for this patch's data pixelDataSize = (patch->width * patch->height + 4) & ~3; columnsDataSize = sizeof(rcolumn_t) * patch->width; // count the number of posts in each column numPostsInColumn = (int*)malloc(sizeof(int) * patch->width); numPostsTotal = 0; for (x=0; x<patch->width; x++) { oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); numPostsInColumn[x] = 0; while (oldColumn->topdelta != 0xff) { numPostsInColumn[x]++; numPostsTotal++; oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); } } postsDataSize = numPostsTotal * sizeof(rpost_t); // allocate our data chunk dataSize = pixelDataSize + columnsDataSize + postsDataSize; patch->data = (unsigned char*)Z_Malloc(dataSize, PU_CACHE, (void **)&patch->data); memset(patch->data, 0, dataSize); // set out pixel, column, and post pointers into our data array patch->pixels = patch->data; patch->columns = (rcolumn_t*)((unsigned char*)patch->pixels + pixelDataSize); patch->posts = (rpost_t*)((unsigned char*)patch->columns + columnsDataSize); // sanity check that we've got all the memory allocated we need assert((((byte*)patch->posts + numPostsTotal*sizeof(rpost_t)) - (byte*)patch->data) == dataSize); memset(patch->pixels, 0xff, (patch->width*patch->height)); // fill in the pixels, posts, and columns numPostsUsedSoFar = 0; for (x=0; x<patch->width; x++) { oldColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x])); if (patch->isNotTileable) { // non-tiling if (x == 0) oldPrevColumn = 0; else oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x-1])); if (x == patch->width-1) oldNextColumn = 0; else oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[x+1])); } else { // tiling int prevColumnIndex = x-1; int nextColumnIndex = x+1; while (prevColumnIndex < 0) prevColumnIndex += patch->width; while (nextColumnIndex >= patch->width) nextColumnIndex -= patch->width; oldPrevColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[prevColumnIndex])); oldNextColumn = (const column_t *)((const byte *)oldPatch + LONG(oldPatch->columnofs[nextColumnIndex])); } // setup the column's data patch->columns[x].pixels = patch->pixels + (x*patch->height) + 0; patch->columns[x].numPosts = numPostsInColumn[x]; patch->columns[x].posts = patch->posts + numPostsUsedSoFar; while (oldColumn->topdelta != 0xff) { // set up the post's data patch->posts[numPostsUsedSoFar].topdelta = oldColumn->topdelta; patch->posts[numPostsUsedSoFar].length = oldColumn->length; patch->posts[numPostsUsedSoFar].slope = 0; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_TOP_DOWN; edgeSlope = getColumnEdgeSlope(oldPrevColumn, oldNextColumn, oldColumn->topdelta+oldColumn->length); if (edgeSlope == 1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_UP; else if (edgeSlope == -1) patch->posts[numPostsUsedSoFar].slope |= RDRAW_EDGESLOPE_BOT_DOWN; // fill in the post's pixels oldColumnPixelData = (const byte *)oldColumn + 3; for (y=0; y<oldColumn->length; y++) { patch->pixels[x * patch->height + oldColumn->topdelta + y] = oldColumnPixelData[y]; } oldColumn = (const column_t *)((const byte *)oldColumn + oldColumn->length + 4); numPostsUsedSoFar++; } } if (1 || patch->isNotTileable) { const rcolumn_t *column, *prevColumn; // copy the patch image down and to the right where there are // holes to eliminate the black halo from bilinear filtering for (x=0; x<patch->width; x++) { //oldColumn = (const column_t *)((const byte *)oldPatch + oldPatch->columnofs[x]); column = R_GetPatchColumnClamped(patch, x); prevColumn = R_GetPatchColumnClamped(patch, x-1); if (column->pixels[0] == 0xff) { // force the first pixel (which is a hole), to use // the color from the next solid spot in the column for (y=0; y<patch->height; y++) { if (column->pixels[y] != 0xff) { column->pixels[0] = column->pixels[y]; break; } } } // copy from above or to the left for (y=1; y<patch->height; y++) { //if (getIsSolidAtSpot(oldColumn, y)) continue; if (column->pixels[y] != 0xff) continue; // this pixel is a hole if (x && prevColumn->pixels[y-1] != 0xff) { // copy the color from the left column->pixels[y] = prevColumn->pixels[y]; } else { // copy the color from above column->pixels[y] = column->pixels[y-1]; } } } // verify that the patch truly is non-rectangular since // this determines tiling later on } W_UnlockLumpNum(patchNum); free(numPostsInColumn); }
/* ----------------------------------------------------------------------------- Function: LoadOggInfo -Load ogg file. Parameters: filename -[in] Name of wav file to load. wav -[out] wav data. info -[out] wav sound info. Returns: True if file loaded, otherwise false. Notes: Caller is responsible for freeing wav data by calling Z_Free. ----------------------------------------------------------------------------- */ PUBLIC _boolean LoadOggInfo( const char *filename, W8 **wav, soundInfo_t *info ) { W8 *data; int size; int dummy; char *newFilename; int len; OggVorbis_File vorbisFile; vorbis_info vorbisInfo; ov_callbacks vorbisCallbacks = {ovc_read, ovc_seek, ovc_close, ovc_tell}; int ret; newFilename = strdup( filename ); len = strlen( newFilename ); if ( len < 5 || strcmp( newFilename + len - 4, ".wav" ) ) { free( newFilename ); return false; } newFilename[ len - 3 ] = 'o'; newFilename[ len - 2 ] = 'g'; newFilename[ len - 1 ] = 'g'; fh = FS_OpenFile( newFilename, 0 ); if( ! fh ) { free( newFilename ); return false; } if( (ret = ov_open_callbacks( fh, &vorbisFile, NULL, 0, vorbisCallbacks )) < 0 ) { free( newFilename ); return false; } vorbisInfo = *ov_info( &vorbisFile, -1 ); if( vorbisInfo.channels != 1 && vorbisInfo.channels != 2 ) { Com_Printf( "Only mono and stereo OGG files supported (%s)\n", newFilename ); free( newFilename ); return false; } info->channels = vorbisInfo.channels; info->sample_rate = vorbisInfo.rate; info->sample_size = 2; #define BUFFER_SIZE ( 128 * 1024 ) data = (W8 *)malloc( BUFFER_SIZE ); size = 0; while( size < BUFFER_SIZE ) { int read = 0; read = ov_read( &vorbisFile, (char *)data + size, BUFFER_SIZE - size, &dummy ); if( read == 0 ) { break; } if( read <= 0 ) { Com_Printf( "Only mono and stereo OGG files supported (%s)\n", newFilename ); free( newFilename ); return false; } size += read; } info->samples = size / ( info->channels * info->sample_size ); // Com_Printf("Loaded %s: channels=%d, sample_rate=%d, sample_size=%d, samples=%d. \n", newFilename, info->channels, info->sample_rate, info->sample_size, info->samples ); free( newFilename ); *wav = (W8 *)Z_Malloc( size ); memcpy(*wav, data, size ); free( data ); FS_CloseFile( fh ); return true; }
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; }
/* ================== SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client Fill up msg with data ================== */ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) { int curindex; int rate; int blockspersnap; int idPack, missionPack; char errorMessage[1024]; if (!*cl->downloadName) return; // Nothing being downloaded if (!cl->download) { // We open the file here Com_Printf( "clientDownload: %d : begining \"%s\"\n", cl - svs.clients, cl->downloadName ); missionPack = FS_idPak(cl->downloadName, "missionpack"); idPack = missionPack || FS_idPak(cl->downloadName, "base"); if ( !sv_allowDownload->integer || idPack || ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { // cannot auto-download file if (idPack) { Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", cl - svs.clients, cl->downloadName); if (missionPack) { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n" "The Team Arena mission pack can be found in your local game store.", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); } } else if ( !sv_allowDownload->integer ) { Com_Printf("clientDownload: %d : \"%s\" download disabled", cl - svs.clients, cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "You will need to get this file elsewhere before you " "can connect to this pure server.\n", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "Set autodownload to No in your settings and you might be " "able to connect if you do have the file.\n", cl->downloadName); } } else { Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", cl - svs.clients, cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName); } MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, 0 ); // client is expecting block zero MSG_WriteLong( msg, -1 ); // illegal file size MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; return; } // Init cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; cl->downloadCount = 0; cl->downloadEOF = qfalse; } // Perform any reads that we need to while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW && cl->downloadSize != cl->downloadCount) { curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) cl->downloadBlocks[curindex] = (unsigned char *)Z_Malloc( MAX_DOWNLOAD_BLKSIZE, TAG_DOWNLOAD, qtrue ); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); if (cl->downloadBlockSize[curindex] < 0) { // EOF right now cl->downloadCount = cl->downloadSize; break; } cl->downloadCount += cl->downloadBlockSize[curindex]; // Load in next block cl->downloadCurrentBlock++; } // Check to see if we have eof condition and add the EOF block if (cl->downloadCount == cl->downloadSize && !cl->downloadEOF && cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) { cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0; cl->downloadCurrentBlock++; cl->downloadEOF = qtrue; // We have added the EOF block } // Loop up to window size times based on how many blocks we can fit in the // client snapMsec and rate // based on the rate, how many bytes can we fit in the snapMsec time of the client // normal rate / snapshotMsec calculation rate = cl->rate; if ( sv_maxRate->integer ) { if ( sv_maxRate->integer < 1000 ) { Cvar_Set( "sv_MaxRate", "1000" ); } if ( sv_maxRate->integer < rate ) { rate = sv_maxRate->integer; } } if (!rate) { blockspersnap = 1; } else { blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / MAX_DOWNLOAD_BLKSIZE; } if (blockspersnap < 0) blockspersnap = 1; while (blockspersnap--) { // Write out the next section of the file, if we have already reached our window, // automatically start retransmitting if (cl->downloadClientBlock == cl->downloadCurrentBlock) return; // Nothing to transmit if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { // We have transmitted the complete window, should we start resending? //FIXME: This uses a hardcoded one second timeout for lost blocks //the timeout should be based on client rate somehow if (svs.time - cl->downloadSendTime > 1000) cl->downloadXmitBlock = cl->downloadClientBlock; else return; } // Send current block curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, cl->downloadXmitBlock ); // block zero is special, contains file size if ( cl->downloadXmitBlock == 0 ) MSG_WriteLong( msg, cl->downloadSize ); MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); // Write the block if ( cl->downloadBlockSize[curindex] ) { MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); } Com_DPrintf( "clientDownload: %d : writing block %d\n", cl - svs.clients, cl->downloadXmitBlock ); // Move on to the next block // It will get sent with next snap shot. The rate will keep us in line. cl->downloadXmitBlock++; cl->downloadSendTime = svs.time; } }
/* ============== S_LoadSound ============== */ sfxcache_t *S_LoadSound (sfx_t *s) { char namebuffer[MAX_QPATH]; byte *data; wavinfo_t info; int len; float stepscale; sfxcache_t *sc; int size; char *name; if (s->name[0] == '*') return NULL; // see if still in memory sc = s->cache; if (sc) return sc; //Com_Printf ("S_LoadSound: %x\n", (int)stackbuf); // load it in if (s->truename) name = s->truename; else name = s->name; if (name[0] == '#') strcpy(namebuffer, &name[1]); else Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name); // Com_Printf ("loading %s\n",namebuffer); size = FS_LoadFile (namebuffer, (void **)&data); if (!data) { Com_DPrintf ("Couldn't load %s\n", namebuffer); return NULL; } info = GetWavinfo (s->name, data, size); if (info.channels != 1) { Com_Printf ("%s is a stereo sample\n",s->name); FS_FreeFile (data); return NULL; } stepscale = (float)info.rate / dma.speed; len = info.samples / stepscale; len = len * info.width * info.channels; sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t)); if (!sc) { FS_FreeFile (data); return NULL; } sc->length = info.samples; sc->loopstart = info.loopstart; sc->speed = info.rate; sc->width = info.width; sc->stereo = info.channels; ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); FS_FreeFile (data); return sc; }
// // Special Stuff that can not be categorized // int EV_DoDonut(line_t* line) { sector_t* s1; sector_t* s2; sector_t* s3; int secnum; int rtn; int i; floormove_t* floor; secnum = -1; rtn = 0; while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0) { s1 = §ors[secnum]; // ALREADY MOVING? IF SO, KEEP GOING... if (s1->specialdata) continue; rtn = 1; s2 = getNextSector(s1->lines[0],s1); for (i = 0;i < s2->linecount;i++) { // if ((!s2->lines[i]->flags & ML_TWOSIDED) || if (((!s2->lines[i]->flags) & ML_TWOSIDED) || (s2->lines[i]->backsector == s1)) { continue; } s3 = s2->lines[i]->backsector; // Spawn rising slime floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s2->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = donutRaise; floor->crush = false; floor->direction = 1; floor->sector = s2; floor->speed = FLOORSPEED / 2; floor->texture = s3->floorpic; floor->newspecial = 0; floor->floordestheight = s3->floorheight; // Spawn lowering donut-hole floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0); P_AddThinker (&floor->thinker); s1->specialdata = floor; floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor; floor->type = lowerFloor; floor->crush = false; floor->direction = -1; floor->sector = s1; floor->speed = FLOORSPEED / 2; floor->floordestheight = s3->floorheight; break; } } return rtn; }
// JPG decompression now subroutinised so I can call it from the savegame stuff... // // (note, the param "byte* pJPGData" should be a malloc of 4K more than the JPG data because the decompressor will read // up to 4K beyond what's actually presented during decompression). // // This will Z_Malloc the output data buffer that gets fed back into "pic", so Z_Free it yourself later. // void Decompress_JPG( const char *filename, byte *pJPGData, unsigned char **pic, int *width, int *height ) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ unsigned char *out; byte *bbuf; /* Step 1: allocate and initialize JPEG decompression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, pJPGData); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; if (cinfo.output_components!=4 && cinfo.output_components!=1 ) { VID_Printf(PRINT_WARNING, "JPG %s is unsupported color depth (%d)\n", filename, cinfo.output_components); } out = (byte *)Z_Malloc(cinfo.output_width*cinfo.output_height*4, TAG_TEMP_JPG, qfalse ); *pic = out; *width = cinfo.output_width; *height = cinfo.output_height; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ bbuf = ((out+(row_stride*cinfo.output_scanline))); buffer = &bbuf; (void) jpeg_read_scanlines(&cinfo, buffer, 1); } // if we've just loaded a greyscale, then adjust it from 8-bit to 32bit by stretch-copying it over itself... // (this also does the alpha stuff as well) // if (cinfo.output_components == 1) { byte *pbDest = (*pic + (cinfo.output_width * cinfo.output_height * 4))-1; byte *pbSrc = (*pic + (cinfo.output_width * cinfo.output_height ))-1; int iPixels = cinfo.output_width * cinfo.output_height; for (int i=0; i<iPixels; i++) { byte b = *pbSrc--; *pbDest-- = 255; *pbDest-- = b; *pbDest-- = b; *pbDest-- = b; } } else {// clear all the alphas to 255 int i, j; byte *buf; buf = *pic; j = cinfo.output_width * cinfo.output_height * 4; for ( i = 3 ; i < j ; i+=4 ) { buf[i] = 255; } } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ }
// a file has been loaded in memory, see if we want to keep it as MP3, else as normal WAV... // // return = qtrue if keeping as MP3 // // (note: the reason I pass in the unpacked size rather than working it out here is simply because I already have it) // qboolean MP3Stream_InitFromFile( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, int iMP3UnPackedSize, qboolean bStereoDesired /* = qfalse */ ) { // first, make a decision based on size here as to whether or not it's worth it because of MP3 buffer space // making small files much bigger (and therefore best left as WAV)... // if (cv_MP3overhead && ( //iSrcDatalen + sizeof(MP3STREAM) + FUZZY_AMOUNT < iMP3UnPackedSize iSrcDatalen + cv_MP3overhead->integer < iMP3UnPackedSize ) ) { // ok, let's keep it as MP3 then... // float fMaxVol = 128; // seems to be a reasonable typical default for maxvol (for lip synch). Naturally there's no #define I can use instead... MP3_ReadSpecialTagInfo(pbSrcData, iSrcDatalen, NULL, NULL, &fMaxVol ); // try and read a read maxvol from MP3 header // fill in some sfx_t fields... // // Q_strncpyz( sfx->name, psSrcDataFilename, sizeof(sfx->name) ); sfx->eSoundCompressionMethod = ct_MP3; sfx->fVolRange = fMaxVol; //sfx->width = 2; sfx->iSoundLengthInSamples = ((iMP3UnPackedSize / 2/*sfx->width*/) / (44100 / dma.speed)) / (bStereoDesired?2:1); // // alloc mem for data and store it (raw MP3 in this case)... // sfx->pSoundData = (short *) SND_malloc( iSrcDatalen, sfx ); memcpy( sfx->pSoundData, pbSrcData, iSrcDatalen ); // now init the low-level MP3 stuff... // MP3STREAM SFX_MP3Stream = {0}; // important to init to all zeroes! char *psError = C_MP3Stream_DecodeInit( &SFX_MP3Stream, /*sfx->data*/ /*sfx->soundData*/ pbSrcData, iSrcDatalen, dma.speed,//(s_khz->value == 44)?44100:(s_khz->value == 22)?22050:11025, 2/*sfx->width*/ * 8, bStereoDesired ); SFX_MP3Stream.pbSourceData = (byte *) sfx->pSoundData; if (psError) { // This should never happen, since any errors or problems with the MP3 file would have stopped us getting // to this whole function, but just in case... // Com_Printf(va(S_COLOR_YELLOW"File \"%s\": %s\n",psSrcDataFilename,psError)); // This will leave iSrcDatalen bytes on the hunk stack (since you can't dealloc that), but MP3 files are // usually small, and like I say, it should never happen. // // Strictly speaking, I should do a Z_Malloc above, then I could do a Z_Free if failed, else do a Hunk_Alloc // to copy the Z_Malloc data into, then Z_Free, but for something that shouldn't happen it seemed bad to // penalise the rest of the game with extra alloc demands. // return qfalse; } // success ( ...on a plate). // // make a copy of the filled-in stream struct and attach to the sfx_t struct... // sfx->pMP3StreamHeader = (MP3STREAM *) Z_Malloc( sizeof(MP3STREAM), TAG_SND_MP3STREAMHDR, qfalse ); memcpy( sfx->pMP3StreamHeader, &SFX_MP3Stream, sizeof(MP3STREAM) ); // return qtrue; } return qfalse; }
// returns a Z_Malloc'd piece of mem that you should free up yourself // byte *Compress_JPG(int *pOutputSize, int quality, int image_width, int image_height, byte *image_buffer, qboolean bInvertDuringCompression) { /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; /* More stuff */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ byte *out = // (unsigned char *)ri.Hunk_AllocateTempMemory(image_width*image_height*4); (unsigned char *)Z_Malloc(image_width*image_height*4, TAG_TEMP_JPG, qfalse); jpegDest(&cinfo, out, image_width*image_height*4); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 4; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = image_width * 4; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ if (bInvertDuringCompression) { row_pointer[0] = & image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride]; } else { row_pointer[0] = & image_buffer[ cinfo.next_scanline * row_stride]; } jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); /* And we're done! */ *pOutputSize = hackSize; return out; }
// // EV_VerticalDoor : open a door manually, no tag value // void EV_VerticalDoor ( line_t* line, mobj_t* thing ) { player_t* player; sector_t* sec; vldoor_t* door; int side; side = 0; // only front sides can be used // Check for locks player = thing->player; switch(line->special) { case 26: // Blue Lock case 32: if ( !player ) return; if (!player->cards[it_bluecard] && !player->cards[it_blueskull]) { player->message = DEH_String(PD_BLUEK); S_StartSound(NULL,sfx_oof); return; } break; case 27: // Yellow Lock case 34: if ( !player ) return; if (!player->cards[it_yellowcard] && !player->cards[it_yellowskull]) { player->message = DEH_String(PD_YELLOWK); S_StartSound(NULL,sfx_oof); return; } break; case 28: // Red Lock case 33: if ( !player ) return; if (!player->cards[it_redcard] && !player->cards[it_redskull]) { player->message = DEH_String(PD_REDK); S_StartSound(NULL,sfx_oof); return; } break; } // if the sector has an active thinker, use it if (line->sidenum[side^1] == -1) { I_Error("EV_VerticalDoor: DR special type on 1-sided linedef"); } sec = sides[ line->sidenum[side^1]] .sector; if (sec->specialdata) { door = sec->specialdata; switch(line->special) { case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s case 26: case 27: case 28: case 117: if (door->direction == -1) door->direction = 1; // go back up else { if (!thing->player) return; // JDC: bad guys never close doors // When is a door not a door? // In Vanilla, door->direction is set, even though // "specialdata" might not actually point at a door. if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor) { door->direction = -1; // start going down immediately } else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise) { // Erm, this is a plat, not a door. // This notably causes a problem in ep1-0500.lmp where // a plat and a door are cross-referenced; the door // doesn't open on 64-bit. // The direction field in vldoor_t corresponds to the wait // field in plat_t. Let's set that to -1 instead. plat_t *plat; plat = (plat_t *) door; plat->wait = -1; } else { // This isn't a door OR a plat. Now we're in trouble. fprintf(stderr, "EV_VerticalDoor: Tried to close " "something that wasn't a door.\n"); // Try closing it anyway. At least it will work on 32-bit // machines. door->direction = -1; } } return; } } // for proper sound switch(line->special) { case 117: // BLAZING DOOR RAISE case 118: // BLAZING DOOR OPEN S_StartSound(&sec->soundorg,sfx_bdopn); break; case 1: // NORMAL DOOR SOUND case 31: S_StartSound(&sec->soundorg,sfx_doropn); break; default: // LOCKED DOOR SOUND S_StartSound(&sec->soundorg,sfx_doropn); break; } // new door thinker door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0); P_AddThinker (&door->thinker); sec->specialdata = door; door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor; door->sector = sec; door->direction = 1; door->speed = VDOORSPEED; door->topwait = VDOORWAIT; switch(line->special) { case 1: case 26: case 27: case 28: door->type = vld_normal; break; case 31: case 32: case 33: case 34: door->type = vld_open; line->special = 0; break; case 117: // blazing door raise door->type = vld_blazeRaise; door->speed = VDOORSPEED*4; break; case 118: // blazing door open door->type = vld_blazeOpen; line->special = 0; door->speed = VDOORSPEED*4; break; } // find the top and bottom of the movement range door->topheight = P_FindLowestCeilingSurrounding(sec); door->topheight -= 4*FRACUNIT; }
/* ============== SV_InitGame A brand new game has been started ============== */ void SV_InitGame (void) { int i; edict_t *ent; char idmaster[32]; if (svs.initialized) { // cause any connected clients to reconnect SV_Shutdown ("Server restarted\n", true); } else { // make sure the client is down CL_Drop (); SCR_BeginLoadingPlaque (); } // get any latched variable changes (maxclients, etc) Cvar_GetLatchedVars (); svs.initialized = true; if (Cvar_VariableValue ("coop") && Cvar_VariableValue ("deathmatch")) { Com_Printf("Deathmatch and Coop both set, disabling Coop\n"); Cvar_FullSet ("coop", "0", CVAR_SERVERINFO | CVAR_LATCH); } // dedicated servers are can't be single player and are usually DM // so unless they explicity set coop, force it to deathmatch if (dedicated->value) { if (!Cvar_VariableValue ("coop")) Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); } // init clients if (Cvar_VariableValue ("deathmatch")) { if (maxclients->value <= 1) Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH); else if (maxclients->value > MAX_CLIENTS) Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH); } else if (Cvar_VariableValue ("coop")) { if (maxclients->value <= 1 || maxclients->value > 4) Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); } else // non-deathmatch, non-coop is one player { Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); } svs.spawncount = rand(); svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value); svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64; svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities); // init network stuff NET_Config ( (maxclients->value > 1) ); // heartbeats will always be sent to the id master svs.last_heartbeat = -99999; // send immediately Com_sprintf(idmaster, sizeof(idmaster), "192.246.40.37:%i", PORT_MASTER); NET_StringToAdr (idmaster, &master_adr[0]); // init game SV_InitGameProgs (); for (i=0 ; i<maxclients->value ; i++) { ent = EDICT_NUM(i+1); ent->s.number = i+1; svs.clients[i].edict = ent; memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); } }
boolean D_NetGetWad(const char* name) { #if defined(HAVE_WAIT_H) size_t psize = sizeof(packet_header_t) + strlen(name) + 500; packet_header_t *packet; boolean done = false; if (!server || strchr(name, '/')) return false; // If it contains path info, reject do { // Send WAD request to remote packet = Z_Malloc(psize, PU_STATIC, NULL); packet_set(packet, PKT_WAD, 0); *(byte*)(packet+1) = consoleplayer; strcpy(1+(byte*)(packet+1), name); I_SendPacket(packet, sizeof(packet_header_t) + strlen(name) + 2); I_uSleep(10000); } while (!I_GetPacket(packet, psize) || (packet->type != PKT_WAD)); Z_Free(packet); if (!strcasecmp((void*)(packet+1), name)) { pid_t pid; int rv; byte *p = (byte*)(packet+1) + strlen(name) + 1; /* Automatic wad file retrieval using wget (supports http and ftp, using URLs) * Unix systems have all these commands handy, this kind of thing is easy * Any windo$e port will have some awkward work replacing these. */ /* cph - caution here. This is data from an untrusted source. * Don't pass it via a shell. */ if ((pid = fork()) == -1) perror("fork"); else if (!pid) { /* Child chains to wget, does the download */ execlp("wget", "wget", p, NULL); } /* This is the parent, i.e. main LxDoom process */ wait(&rv); if (!(done = !access(name, R_OK))) { if (!strcmp(p+strlen(p)-4, ".zip")) { p = strrchr(p, '/')+1; if ((pid = fork()) == -1) perror("fork"); else if (!pid) { /* Child executes decompressor */ execlp("unzip", "unzip", p, name, NULL); } /* Parent waits for the file */ wait(&rv); done = !!access(name, R_OK); } /* Add more decompression protocols here as desired */ } Z_Free(buffer); } return done; #else /* HAVE_WAIT_H */ return false; #endif }
// // R_GenerateComposite // Using the texture definition, // the composite texture is created from the patches, // and each column is cached. // void R_GenerateComposite (int texnum) { byte* block; texture_t* texture; texpatch_t* patch; patch_t* realpatch; int x; int x1; int x2; int i; column_t* patchcol; short* collump; unsigned short* colofs; texture = textures[texnum]; block = Z_Malloc (texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; // Composite the columns together. patch = texture->patches; for (i=0 , patch = texture->patches; i<texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNum (patch->patch, 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++) { // Column does not have multiple patches? if (collump[x] >= 0) continue; patchcol = (column_t *)((byte *)realpatch + LONG(realpatch->columnofs[x-x1])); R_DrawColumnInCache (patchcol, block + colofs[x], patch->originy, texture->height); } } // Now that the texture has been built in column cache, // it is purgable from zone memory. Z_ChangeTag (block, PU_CACHE); }
void D_InitNetGame (void) { int i; int numplayers = 1; i = M_CheckParm("-net"); if (i && i < myargc-1) i++; if (!(netgame = server = !!i)) { playeringame[consoleplayer = 0] = true; // e6y // for play, recording or playback using "single-player coop" mode. // Equivalent to using prboom_server with -N 1 netgame = M_CheckParm("-solo-net"); } else { // Get game info from server packet_header_t *packet = Z_Malloc(1000, PU_STATIC, NULL); struct setup_packet_s *sinfo = (void*)(packet+1); struct { packet_header_t head; short pn; } PACKEDATTR initpacket; I_InitNetwork(); udp_socket = I_Socket(0); I_ConnectToServer(myargv[i]); do { do { // Send init packet initpacket.pn = doom_htons(wanted_player_number); packet_set(&initpacket.head, PKT_INIT, 0); I_SendPacket(&initpacket.head, sizeof(initpacket)); I_WaitForPacket(5000); } while (!I_GetPacket(packet, 1000)); if (packet->type == PKT_DOWN) I_Error("Server aborted the game"); } while (packet->type != PKT_SETUP); // Once we have been accepted by the server, we should tell it when we leave atexit(D_QuitNetGame); // Get info from the setup packet consoleplayer = sinfo->yourplayer; compatibility_level = sinfo->complevel; G_Compatibility(); startskill = sinfo->skill; deathmatch = sinfo->deathmatch; startmap = sinfo->level; startepisode = sinfo->episode; ticdup = sinfo->ticdup; xtratics = sinfo->extratic; G_ReadOptions(sinfo->game_options); lprintf(LO_INFO, "\tjoined game as player %d/%d; %d WADs specified\n", consoleplayer+1, numplayers = sinfo->players, sinfo->numwads); { char *p = sinfo->wadnames; int i = sinfo->numwads; while (i--) { #ifdef USE_ANDROID char tmp[80]; strcpy(tmp, doomWADDir); strcat(tmp, "/"); strcat(tmp, p); D_AddFile(tmp, source_net); #else D_AddFile(p, source_net); #endif p += strlen(p) + 1; } } Z_Free(packet); } localcmds = netcmds[displayplayer = consoleplayer]; for (i=0; i<numplayers; i++) playeringame[i] = true; for (; i<MAXPLAYERS; i++) playeringame[i] = false; if (!playeringame[consoleplayer]) I_Error("D_InitNetGame: consoleplayer not in game"); }
// // R_InitTextures // Initializes the texture list // with the textures from the world map. // void R_InitTextures (void) { maptexture_t* mtexture; texture_t* texture; mappatch_t* mpatch; texpatch_t* patch; int i; int j; int* maptex; int* maptex2; int* maptex1; char name[9]; char* names; char* name_p; int* patchlookup; int totalwidth; int nummappatches; int offset; int maxoff; int maxoff2; int numtextures1; int numtextures2; int* directory; int temp1; int temp2; int temp3; // Load the patch names from pnames.lmp. name[8] = 0; names = W_CacheLumpName ("PNAMES", PU_STATIC); nummappatches = LONG ( *((int *)names) ); name_p = names+4; patchlookup = alloca (nummappatches*sizeof(*patchlookup)); for (i=0 ; i<nummappatches ; i++) { strncpy (name,name_p+i*8, 8); patchlookup[i] = W_CheckNumForName (name); } Z_Free (names); // Load the map texture definitions from textures.lmp. // The data is contained in one or two lumps, // TEXTURE1 for shareware, plus TEXTURE2 for commercial. maptex = maptex1 = W_CacheLumpName ("TEXTURE1", PU_STATIC); numtextures1 = LONG(*maptex); maxoff = W_LumpLength (W_GetNumForName ("TEXTURE1")); directory = maptex+1; if (W_CheckNumForName ("TEXTURE2") != -1) { maptex2 = W_CacheLumpName ("TEXTURE2", PU_STATIC); numtextures2 = LONG(*maptex2); maxoff2 = W_LumpLength (W_GetNumForName ("TEXTURE2")); } else { maptex2 = NULL; numtextures2 = 0; maxoff2 = 0; } numtextures = numtextures1 + numtextures2; textures = Z_Malloc (numtextures*4, PU_STATIC, 0); texturecolumnlump = Z_Malloc (numtextures*4, PU_STATIC, 0); texturecolumnofs = Z_Malloc (numtextures*4, PU_STATIC, 0); texturecomposite = Z_Malloc (numtextures*4, PU_STATIC, 0); texturecompositesize = Z_Malloc (numtextures*4, PU_STATIC, 0); texturewidthmask = Z_Malloc (numtextures*4, PU_STATIC, 0); textureheight = Z_Malloc (numtextures*4, PU_STATIC, 0); totalwidth = 0; // Really complex printing shit... temp1 = W_GetNumForName ("S_START"); // P_??????? temp2 = W_GetNumForName ("S_END") - 1; temp3 = ((temp2-temp1+63)/64) + ((numtextures+63)/64); printf("["); for (i = 0; i < temp3; i++) printf(" "); printf(" ]"); for (i = 0; i < temp3; i++) printf("\x8"); printf("\x8\x8\x8\x8\x8\x8\x8\x8\x8\x8"); for (i=0 ; i<numtextures ; i++, directory++) { if (!(i&63)) printf ("."); if (i == numtextures1) { // Start looking in second texture file. maptex = maptex2; maxoff = maxoff2; directory = maptex+1; } offset = LONG(*directory); if (offset > maxoff) I_Error ("R_InitTextures: bad texture directory"); mtexture = (maptexture_t *) ( (byte *)maptex + offset); texture = textures[i] = Z_Malloc (sizeof(texture_t) + sizeof(texpatch_t)*(SHORT(mtexture->patchcount)-1), PU_STATIC, 0); texture->width = SHORT(mtexture->width); texture->height = SHORT(mtexture->height); texture->patchcount = SHORT(mtexture->patchcount); memcpy (texture->name, mtexture->name, sizeof(texture->name)); mpatch = &mtexture->patches[0]; patch = &texture->patches[0]; for (j=0 ; j<texture->patchcount ; j++, mpatch++, patch++) { patch->originx = SHORT(mpatch->originx); patch->originy = SHORT(mpatch->originy); patch->patch = patchlookup[SHORT(mpatch->patch)]; if (patch->patch == -1) { I_Error ("R_InitTextures: Missing patch in texture %s", texture->name); } } texturecolumnlump[i] = Z_Malloc (texture->width*2, PU_STATIC,0); texturecolumnofs[i] = Z_Malloc (texture->width*2, PU_STATIC,0); j = 1; while (j*2 <= texture->width) j<<=1; texturewidthmask[i] = j-1; textureheight[i] = texture->height<<FRACBITS; totalwidth += texture->width; } Z_Free (maptex1); if (maptex2) Z_Free (maptex2); // Precalculate whatever possible. for (i=0 ; i<numtextures ; i++) R_GenerateLookup (i); // Create translation table for global animation. texturetranslation = Z_Malloc ((numtextures+1)*4, PU_STATIC, 0); for (i=0 ; i<numtextures ; i++) texturetranslation[i] = i; }
void LoadTGA ( const char *name, byte **pic, int *width, int *height) { char sErrorString[1024]; bool bFormatErrors = false; // these don't need to be declared or initialised until later, but the compiler whines that 'goto' skips them. // byte *pRGBA = NULL; byte *pOut = NULL; byte *pIn = NULL; *pic = NULL; #define TGA_FORMAT_ERROR(blah) {sprintf(sErrorString,blah); bFormatErrors = true; goto TGADone;} //#define TGA_FORMAT_ERROR(blah) Com_Error( ERR_DROP, blah ); // // load the file // byte *pTempLoadedBuffer = 0; ri->FS_ReadFile ( ( char * ) name, (void **)&pTempLoadedBuffer); if (!pTempLoadedBuffer) { return; } TGAHeader_t *pHeader = (TGAHeader_t *) pTempLoadedBuffer; if (pHeader->byColourmapType!=0) { TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" ); } if (pHeader->byImageType != 2 && pHeader->byImageType != 3 && pHeader->byImageType != 10) { TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RLE-RGB) images supported\n"); } if (pHeader->w1stColourMapEntry != 0) { TGA_FORMAT_ERROR("LoadTGA: colourmaps not supported\n" ); } if (pHeader->wColourMapLength !=0 && pHeader->wColourMapLength != 256) { TGA_FORMAT_ERROR("LoadTGA: ColourMapLength must be either 0 or 256\n" ); } if (pHeader->byColourMapEntrySize != 0 && pHeader->byColourMapEntrySize != 24) { TGA_FORMAT_ERROR("LoadTGA: ColourMapEntrySize must be either 0 or 24\n" ); } if ( ( pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) && (pHeader->byImagePlanes != 8 && pHeader->byImageType != 3)) { TGA_FORMAT_ERROR("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); } if ((pHeader->byScanLineOrder&0x30)!=0x00 && (pHeader->byScanLineOrder&0x30)!=0x10 && (pHeader->byScanLineOrder&0x30)!=0x20 && (pHeader->byScanLineOrder&0x30)!=0x30 ) { TGA_FORMAT_ERROR("LoadTGA: ScanLineOrder must be either 0x00,0x10,0x20, or 0x30\n"); } // these last checks are so i can use ID's RLE-code. I don't dare fiddle with it or it'll probably break... // if ( pHeader->byImageType == 10) { if ((pHeader->byScanLineOrder & 0x30) != 0x00) { TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be in bottom-to-top format\n"); } if (pHeader->byImagePlanes != 24 && pHeader->byImagePlanes != 32) // probably won't happen, but avoids compressed greyscales? { TGA_FORMAT_ERROR("LoadTGA: RLE-RGB Images (type 10) must be 24 or 32 bit\n"); } } // now read the actual bitmap in... // // Image descriptor bytes // bits 0-3 = # attr bits (alpha chan) // bits 4-5 = pixel order/dir // bits 6-7 scan line interleave (00b=none,01b=2way interleave,10b=4way) // int iYStart,iXStart,iYStep,iXStep; switch(pHeader->byScanLineOrder & 0x30) { default: // default case stops the compiler complaining about using uninitialised vars case 0x00: // left to right, bottom to top iXStart = 0; iXStep = 1; iYStart = pHeader->wImageHeight-1; iYStep = -1; break; case 0x10: // right to left, bottom to top iXStart = pHeader->wImageWidth-1; iXStep = -1; iYStart = pHeader->wImageHeight-1; iYStep = -1; break; case 0x20: // left to right, top to bottom iXStart = 0; iXStep = 1; iYStart = 0; iYStep = 1; break; case 0x30: // right to left, top to bottom iXStart = pHeader->wImageWidth-1; iXStep = -1; iYStart = 0; iYStep = 1; break; } // feed back the results... // if (width) *width = pHeader->wImageWidth; if (height) *height = pHeader->wImageHeight; pRGBA = (byte *) Z_Malloc (pHeader->wImageWidth * pHeader->wImageHeight * 4, TAG_TEMP_WORKSPACE, qfalse); *pic = pRGBA; pOut = pRGBA; pIn = pTempLoadedBuffer + sizeof(*pHeader); // I don't know if this ID-thing here is right, since comments that I've seen are at the end of the file, // with a zero in this field. However, may as well... // if (pHeader->byIDFieldLength != 0) pIn += pHeader->byIDFieldLength; // skip TARGA image comment byte red,green,blue,alpha; if ( pHeader->byImageType == 2 || pHeader->byImageType == 3 ) // RGB or greyscale { for (int y=iYStart, iYCount=0; iYCount<pHeader->wImageHeight; y+=iYStep, iYCount++) { pOut = pRGBA + y * pHeader->wImageWidth *4; for (int x=iXStart, iXCount=0; iXCount<pHeader->wImageWidth; x+=iXStep, iXCount++) { switch (pHeader->byImagePlanes) { case 8: blue = *pIn++; green = blue; red = blue; *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = 255; break; case 24: blue = *pIn++; green = *pIn++; red = *pIn++; *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = 255; break; case 32: blue = *pIn++; green = *pIn++; red = *pIn++; alpha = *pIn++; *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = alpha; break; default: assert(0); // if we ever hit this, someone deleted a header check higher up TGA_FORMAT_ERROR("LoadTGA: Image can only have 8, 24 or 32 planes for RGB/greyscale\n"); break; } } } } else if (pHeader->byImageType == 10) // RLE-RGB { // I've no idea if this stuff works, I normally reject RLE targas, but this is from ID's code // so maybe I should try and support it... // byte packetHeader, packetSize, j; for (int y = pHeader->wImageHeight-1; y >= 0; y--) { pOut = pRGBA + y * pHeader->wImageWidth *4; for (int x=0; x<pHeader->wImageWidth;) { packetHeader = *pIn++; packetSize = 1 + (packetHeader & 0x7f); if (packetHeader & 0x80) // run-length packet { switch (pHeader->byImagePlanes) { case 24: blue = *pIn++; green = *pIn++; red = *pIn++; alpha = 255; break; case 32: blue = *pIn++; green = *pIn++; red = *pIn++; alpha = *pIn++; break; default: assert(0); // if we ever hit this, someone deleted a header check higher up TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n"); break; } for (j=0; j<packetSize; j++) { *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = alpha; x++; if (x == pHeader->wImageWidth) // run spans across rows { x = 0; if (y > 0) y--; else goto breakOut; pOut = pRGBA + y * pHeader->wImageWidth * 4; } } } else { // non run-length packet for (j=0; j<packetSize; j++) { switch (pHeader->byImagePlanes) { case 24: blue = *pIn++; green = *pIn++; red = *pIn++; *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = 255; break; case 32: blue = *pIn++; green = *pIn++; red = *pIn++; alpha = *pIn++; *pOut++ = red; *pOut++ = green; *pOut++ = blue; *pOut++ = alpha; break; default: assert(0); // if we ever hit this, someone deleted a header check higher up TGA_FORMAT_ERROR("LoadTGA: RLE-RGB can only have 24 or 32 planes\n"); break; } x++; if (x == pHeader->wImageWidth) // pixel packet run spans across rows { x = 0; if (y > 0) y--; else goto breakOut; pOut = pRGBA + y * pHeader->wImageWidth * 4; } } } } breakOut:; } } TGADone: ri->FS_FreeFile (pTempLoadedBuffer); if (bFormatErrors) { Com_Error( ERR_DROP, "%s( File: \"%s\" )\n",sErrorString,name); } }
void *Z_MemDup(void const *ptr, size_t size) { void *copy = Z_Malloc(size, PU_APPSTATIC, 0); memcpy(copy, ptr, size); return copy; }