port Map icon packet from srb2classic #198
No files matched your search
+283
-17
@@ -16,6 +16,8 @@
|
||||
#include <unistd.h> //for unlink
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "i_time.h"
|
||||
#include "i_net.h"
|
||||
#include "i_system.h"
|
||||
@@ -87,6 +89,17 @@ boolean serverrunning = false;
|
||||
INT32 serverplayer = 0;
|
||||
char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
|
||||
|
||||
#define MAP_ICON_REQUEST_FREQUENCY 8
|
||||
|
||||
static UINT8 map_icon_index; // amount of fragments we have retrieved
|
||||
static UINT8 map_icon_needed; // amount of fragments we need to get the full data set
|
||||
static INT32 map_icon_read; // amount of bytes we have read
|
||||
static UINT32 map_icon_missing; // bitmask of fragments we haven't received yet
|
||||
static tic_t map_icon_last_request; // last time we sent an icon request, to avoid flood
|
||||
static int map_icon_request_count; // current count of icon requests sent
|
||||
static UINT8 *map_icon_data;
|
||||
static patch_t *map_icon;
|
||||
|
||||
plrinfo playerinfo[MAXPLAYERS];
|
||||
SINT8 joinnode = 0; // used for CL_VIEWSERVER
|
||||
|
||||
@@ -1211,6 +1224,10 @@ static inline void CL_DrawConnectionStatus(void)
|
||||
if (!menuactive) // menu already draws its own fade
|
||||
V_DrawFadeScreen(0xFF00, 16); // force default
|
||||
|
||||
// reset the counter for mapicon
|
||||
if (cl_mode != CL_VIEWSERVER)
|
||||
map_icon_request_count = 0;
|
||||
|
||||
if (cl_mode != CL_DOWNLOADFILES && cl_mode != CL_LOADFILES && cl_mode != CL_CHECKFILES && cl_mode != CL_VIEWSERVER
|
||||
#ifdef HAVE_CURL
|
||||
&& cl_mode != CL_DOWNLOADHTTPFILES
|
||||
@@ -1337,9 +1354,42 @@ static inline void CL_DrawConnectionStatus(void)
|
||||
|
||||
V_DrawThinString(12 + 80, 18, V_ALLOWLOWERCASE, va("%s", serverlist[joinnode].info.servername));
|
||||
|
||||
const char *map = va("%sP", serverlist[joinnode].info.mapname);
|
||||
patch_t *current_map = W_LumpExists(map) ? W_CachePatchName(map, PU_CACHE) : W_CachePatchName("BLANKLVL", PU_CACHE);
|
||||
V_DrawSmallScaledPatch(10, 18, 0, current_map);
|
||||
if (map_icon == NULL)
|
||||
{
|
||||
const char *map = va("%sP", serverlist[joinnode].info.mapname);
|
||||
patch_t *current_map = W_LumpExists(map) ? W_CachePatchName(map, PU_CACHE) : NULL;
|
||||
|
||||
// check first if we may have the map icon loaded already
|
||||
if (current_map != NULL)
|
||||
V_DrawSmallScaledPatch(10, 18, 0, current_map);
|
||||
else if (map_icon_data != NULL && map_icon_request_count <= 5)
|
||||
{
|
||||
if (I_GetTime() - map_icon_last_request > MAP_ICON_REQUEST_FREQUENCY)
|
||||
{
|
||||
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
|
||||
netbuffer->packettype = PT_NEEDMAPICON;
|
||||
|
||||
// failed to retrieve map icon, request it again
|
||||
HSendPacket(servernode, false, 0, 0);
|
||||
map_icon_last_request = I_GetTime();
|
||||
map_icon_request_count++;
|
||||
}
|
||||
|
||||
V_DrawFill(10, 18, MAP_ICON_WIDTH / 2, MAP_ICON_HEIGHT / 2, 31);
|
||||
char dots[4] = "...";
|
||||
if ((I_GetTime() & 0xf) < 4)
|
||||
dots[0] = '\0';
|
||||
else if ((I_GetTime() & 0xf) < 8)
|
||||
dots[1] = '\0';
|
||||
else if ((I_GetTime() & 0xf) < 12)
|
||||
dots[2] = '\0';
|
||||
V_DrawString(10 + MAP_ICON_WIDTH / 4 - V_StringWidth("...", 0) / 2, 18 + MAP_ICON_HEIGHT / 4 - 3, 0, dots);
|
||||
}
|
||||
else
|
||||
V_DrawSmallScaledPatch(10, 18, 0, W_CachePatchName("BLANKLVL", PU_CACHE));
|
||||
}
|
||||
else
|
||||
V_DrawSmallScaledPatch(10, 18, 0, map_icon);
|
||||
|
||||
if (serverlist[joinnode].info.iszone)
|
||||
V_DrawThinString(12 + 80, 38, V_ALLOWLOWERCASE, va("%s Zone", serverlist[joinnode].info.maptitle));
|
||||
@@ -1705,6 +1755,83 @@ static void SV_SendPlayerInfo(INT32 node)
|
||||
HSendPacket(node, false, 0, sizeof(plrinfo) * MSCOMPAT_MAXPLAYERS);
|
||||
}
|
||||
|
||||
static void SV_SendMapIcon(INT32 node)
|
||||
{
|
||||
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
|
||||
|
||||
const char *map = va("%sP", G_BuildMapName(gamemap));
|
||||
if (!W_LumpExists(map) || (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU))
|
||||
{
|
||||
// send an empty icon to tell the client there is no map icon
|
||||
netbuffer->packettype = PT_MAPICON;
|
||||
UINT8 *icondata = netbuffer->u.mapicondata;
|
||||
WRITEUINT8(icondata, 0x80);
|
||||
HSendPacket(node, false, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
patch_t *current_map = W_CachePatchName(map, PU_CACHE);
|
||||
if (current_map->width != MAP_ICON_WIDTH || current_map->height != MAP_ICON_HEIGHT)
|
||||
{
|
||||
// we only support 160x100 for now
|
||||
netbuffer->packettype = PT_MAPICON;
|
||||
UINT8 *icondata = netbuffer->u.mapicondata;
|
||||
WRITEUINT8(icondata, 0x80);
|
||||
HSendPacket(node, false, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
UINT8 *data = Z_Malloc(2 * current_map->width * current_map->height, PU_STATIC, NULL);
|
||||
UINT8 *pixeldata = data + current_map->width * current_map->height;
|
||||
|
||||
R_PatchToPixels(current_map, pixeldata);
|
||||
|
||||
z_stream stream;
|
||||
stream.zalloc = NULL;
|
||||
stream.zfree = NULL;
|
||||
stream.opaque = NULL;
|
||||
if (deflateInit(&stream, Z_DEFAULT_COMPRESSION) != Z_OK)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Cannot compress map icon, not enough memory\n");
|
||||
Z_Free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
stream.next_in = pixeldata;
|
||||
stream.avail_in = current_map->width * current_map->height;
|
||||
stream.next_out = data;
|
||||
stream.avail_out = current_map->width * current_map->height;
|
||||
if (deflate(&stream, Z_FINISH) != Z_STREAM_END)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Cannot compress map icon, error occured during compression\n");
|
||||
deflateEnd(&stream);
|
||||
Z_Free(data);
|
||||
return;
|
||||
}
|
||||
size_t count = stream.total_out;
|
||||
deflateEnd(&stream);
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
for (size_t i = 0; i < count; i += MAXPACKETLENGTH-BASEPACKETSIZE-1)
|
||||
{
|
||||
size_t size = min(MAXPACKETLENGTH-BASEPACKETSIZE-1, count-i);
|
||||
|
||||
UINT8 *icondata = netbuffer->u.mapicondata;
|
||||
netbuffer->packettype = PT_MAPICON;
|
||||
|
||||
if (count-i <= MAXPACKETLENGTH-BASEPACKETSIZE-1)
|
||||
WRITEUINT8(icondata, 0x80 | index);
|
||||
else
|
||||
WRITEUINT8(icondata, index);
|
||||
index++;
|
||||
|
||||
WRITEMEM(icondata, &data[i], size);
|
||||
HSendPacket(node, false, 0, size + 1);
|
||||
}
|
||||
Z_Free(data);
|
||||
}
|
||||
|
||||
/** Sends a PT_SERVERCFG packet
|
||||
*
|
||||
* \param node The destination
|
||||
@@ -2687,9 +2814,26 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
|
||||
if (cl_mode == CL_VIEWSERVER)
|
||||
{
|
||||
if (key == KEY_ENTER || key == KEY_JOY1)
|
||||
{
|
||||
cl_mode = CL_CHECKFILES;
|
||||
if (map_icon != NULL)
|
||||
Patch_Free(map_icon);
|
||||
map_icon = NULL;
|
||||
if (map_icon_data != NULL)
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
}
|
||||
else if (key == KEY_ESCAPE || key == KEY_JOY1+1)
|
||||
{
|
||||
cl_mode = CL_ABORTED;
|
||||
if (map_icon != NULL)
|
||||
Patch_Free(map_icon);
|
||||
map_icon = NULL;
|
||||
if (map_icon_data != NULL)
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
map_icon_request_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Only ESC and non-keyboard keys abort connection
|
||||
@@ -2805,6 +2949,17 @@ static void CL_ConnectToServer(void)
|
||||
serverlist[i].info.version, serverlist[i].info.subversion);
|
||||
}
|
||||
SL_ClearServerList(servernode);
|
||||
|
||||
if (map_icon_data != NULL)
|
||||
Z_Free(map_icon_data);
|
||||
if (map_icon != NULL)
|
||||
Patch_Free(map_icon);
|
||||
map_icon_data = Z_Malloc(MAP_ICON_WIDTH * MAP_ICON_HEIGHT, PU_CACHE, NULL);
|
||||
map_icon_index = 0;
|
||||
map_icon_needed = 0xff;
|
||||
map_icon_read = 0;
|
||||
map_icon_missing = 0xffffffff;
|
||||
map_icon_last_request = I_GetTime();
|
||||
#endif
|
||||
|
||||
do
|
||||
@@ -4690,7 +4845,7 @@ static void HandleConnect(SINT8 node)
|
||||
connectedplayers++;
|
||||
|
||||
#ifdef SATURNJOIN
|
||||
const boolean issaturn = (((doomcom->datalength-BASEPACKETSIZE) == sizeof(clientconfig_pak)) && netbuffer->u.clientcfg.issaturn == ISSATURN); // Check the packet lenght to skip potential garbo data!
|
||||
const boolean issaturn = (((doomcom->datalength) == sizeof(clientconfig_pak)) && netbuffer->u.clientcfg.issaturn == ISSATURN); // Check the packet lenght to skip potential garbo data!
|
||||
#endif
|
||||
|
||||
if (bannednode && bannednode[node].banid != SIZE_MAX)
|
||||
@@ -4860,17 +5015,6 @@ static void HandleTimeout(SINT8 node)
|
||||
M_StartMessage(M_GetText("Server Timeout\n\nPress Esc\n"), NULL, MM_NOTHING);
|
||||
}
|
||||
|
||||
// Helper function for packets that should only be sent by the server
|
||||
// If it is NOT from the server, bail out and close the connection!
|
||||
static boolean ServerOnly(SINT8 node)
|
||||
{
|
||||
if (node == servernode)
|
||||
return false;
|
||||
|
||||
Net_CloseConnection(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NONET
|
||||
/** Called when a PT_SERVERINFO packet is received
|
||||
*
|
||||
@@ -4910,6 +5054,115 @@ static void HandlePlayerInfo(void)
|
||||
playerinfo[i] = netbuffer->u.playerinfo[i];
|
||||
}
|
||||
|
||||
// Helper function for packets that should only be sent by the server
|
||||
// If it is NOT from the server, bail out and close the connection!
|
||||
static boolean ServerOnly(SINT8 node)
|
||||
{
|
||||
if (node == servernode)
|
||||
return false;
|
||||
|
||||
Net_CloseConnection(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PT_MapIcon(void)
|
||||
{
|
||||
if (map_icon_data == NULL)
|
||||
return;
|
||||
|
||||
if (ServerOnly(doomcom->remotenode))
|
||||
return;
|
||||
|
||||
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
|
||||
|
||||
UINT8 *icondata = netbuffer->u.mapicondata;
|
||||
|
||||
map_icon_last_request = I_GetTime();
|
||||
map_icon_request_count = 0;
|
||||
|
||||
UINT8 index = READUINT8(icondata);
|
||||
if (index & 0x80)
|
||||
map_icon_needed = (index & 0x7f) + 1;
|
||||
index &= 0x7f;
|
||||
|
||||
// check if we already got this fragment
|
||||
if (map_icon_missing & ((UINT32)1 << index))
|
||||
{
|
||||
map_icon_missing &= ~((UINT32)1 << index);
|
||||
INT32 offset = index * (MAXPACKETLENGTH-BASEPACKETSIZE-1);
|
||||
if (offset + doomcom->datalength-1 > MAP_ICON_WIDTH * MAP_ICON_HEIGHT)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Excess amount of data for map icon (expected %d, got %d)\n", MAP_ICON_WIDTH * MAP_ICON_HEIGHT, offset + doomcom->datalength-1);
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
READMEM(icondata, &map_icon_data[offset], doomcom->datalength-1);
|
||||
map_icon_read += doomcom->datalength-1;
|
||||
map_icon_index++;
|
||||
}
|
||||
|
||||
if (map_icon_index >= map_icon_needed)
|
||||
{
|
||||
if (map_icon_read == 0)
|
||||
{
|
||||
// map has no icon
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
UINT8 *data = Z_Malloc(MAP_ICON_WIDTH * MAP_ICON_HEIGHT, PU_STATIC, NULL);
|
||||
z_stream stream;
|
||||
stream.zalloc = NULL;
|
||||
stream.zfree = NULL;
|
||||
stream.opaque = NULL;
|
||||
stream.next_in = map_icon_data;
|
||||
stream.avail_in = map_icon_read;
|
||||
if (inflateInit(&stream) != Z_OK)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Cannot decompress map icon, not enough memory\n");
|
||||
Z_Free(data);
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
return;
|
||||
}
|
||||
stream.next_out = data;
|
||||
stream.avail_out = MAP_ICON_WIDTH * MAP_ICON_HEIGHT;
|
||||
if (inflate(&stream, Z_FINISH) != Z_STREAM_END)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Failed to decompress map icon, map icon is invalid or corrupted\n");
|
||||
deflateEnd(&stream);
|
||||
Z_Free(data);
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
return;
|
||||
}
|
||||
inflateEnd(&stream);
|
||||
Z_Free(map_icon_data);
|
||||
map_icon_data = NULL;
|
||||
|
||||
if (stream.total_out > MAP_ICON_WIDTH * MAP_ICON_HEIGHT)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Excess amount of data for map icon (expected %d, got %ld)\n", MAP_ICON_WIDTH * MAP_ICON_HEIGHT, stream.total_out);
|
||||
Z_Free(data);
|
||||
return;
|
||||
}
|
||||
else if (stream.total_out < MAP_ICON_WIDTH * MAP_ICON_HEIGHT)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Insufficient amount of data for map icon (expected %d, got %ld)\n", MAP_ICON_WIDTH * MAP_ICON_HEIGHT, stream.total_out);
|
||||
Z_Free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
//map_icon = Patch_CreateFromData(MAP_ICON_WIDTH, MAP_ICON_HEIGHT, data);
|
||||
map_icon = (patch_t *)R_PixelsToPatch(data, MAP_ICON_WIDTH, MAP_ICON_HEIGHT, 0, 0, NULL);
|
||||
|
||||
Z_Free(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void PT_TellFilesNeeded(SINT8 node)
|
||||
{
|
||||
if (server && serverrunning)
|
||||
@@ -4958,11 +5211,18 @@ static void PT_AskInfo(SINT8 node)
|
||||
doomdata_t *netbuffer = DOOMCOM_DATA(doomcom);
|
||||
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
|
||||
SV_SendPlayerInfo(node); // Send extra info
|
||||
//SV_SendMapIcon(node); // idk i dont think we need this here
|
||||
}
|
||||
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
static void PT_NeedMapIcon(SINT8 node)
|
||||
{
|
||||
SV_SendMapIcon(node);
|
||||
Net_CloseConnection(node);
|
||||
}
|
||||
|
||||
// Negative response of client join request
|
||||
static void PT_ServerRefuse(SINT8 node)
|
||||
{
|
||||
@@ -5223,6 +5483,12 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
||||
case PT_PLAYERINFO:
|
||||
HandlePlayerInfo();
|
||||
break;
|
||||
case PT_MAPICON:
|
||||
PT_MapIcon();
|
||||
break;
|
||||
case PT_NEEDMAPICON:
|
||||
PT_NeedMapIcon(node);
|
||||
break;
|
||||
case PT_SERVERTICS:
|
||||
// Do not remove my own server (we have just get a out of order packet)
|
||||
if (node == servernode)
|
||||
@@ -5511,10 +5777,10 @@ static void PT_TextCmd(INT32 netconsole, SINT8 node)
|
||||
|
||||
// ignore if the textcmd size var is actually larger than it should be
|
||||
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
|
||||
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
|
||||
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-1)
|
||||
{
|
||||
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
|
||||
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
|
||||
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-1),
|
||||
node, netconsole));
|
||||
Net_UnAcknowledgePacket(node);
|
||||
return;
|
||||
|
||||
+3
-1
@@ -120,6 +120,8 @@ typedef enum
|
||||
PT_ISSATURN, // Saturn specific identifier packet
|
||||
#endif
|
||||
|
||||
PT_MAPICON, // Send map image icon (gamespy).
|
||||
PT_NEEDMAPICON, // Request missed map icon (gamespy).
|
||||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
@@ -513,6 +515,7 @@ typedef struct
|
||||
INT32 filesneedednum; // 4 bytes
|
||||
filesneededconfig_pak filesneededcfg; // ??? bytes
|
||||
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
|
||||
UINT8 mapicondata[0];
|
||||
} u; // This is needed to pack diff packet types data together
|
||||
} ATTRPACK doomdata_t;
|
||||
|
||||
@@ -564,7 +567,6 @@ typedef enum
|
||||
KR_TIMEOUT, //Connection Timeout
|
||||
KR_BAN, //Banned by server
|
||||
KR_LEAVE, //Quit the game
|
||||
|
||||
} kickreason_t;
|
||||
|
||||
/* the max number of name changes in some time period */
|
||||
|
||||
@@ -1201,6 +1201,7 @@ boolean HGetPacket(void)
|
||||
GotAcks();
|
||||
continue;
|
||||
}
|
||||
doomcom->datalength -= BASEPACKETSIZE;
|
||||
break;
|
||||
}
|
||||
#endif // ifndef NONET
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT
|
||||
|
||||
#define MAP_ICON_WIDTH 160
|
||||
#define MAP_ICON_HEIGHT 100
|
||||
|
||||
//
|
||||
// ClipWallSegment
|
||||
// Clips the given range of columns
|
||||
|
||||
+159
@@ -451,6 +451,124 @@ void *Patch_CreateGL(patch_t *patch)
|
||||
}
|
||||
#endif // HWRENDER
|
||||
|
||||
//
|
||||
// R_MaskedFlatToPatch
|
||||
//
|
||||
// Convert raw pixels to a patch.
|
||||
//
|
||||
void *R_PixelsToPatch(UINT8 *raw, INT16 width, INT16 height, INT16 leftoffset, INT16 topoffset, size_t *destsize)
|
||||
{
|
||||
INT16 x, y;
|
||||
UINT8 *img;
|
||||
UINT8 *imgptr = imgbuf;
|
||||
UINT8 *colpointers, *startofspan;
|
||||
size_t size = 0;
|
||||
|
||||
if (!raw)
|
||||
return NULL;
|
||||
|
||||
// Write image size and offset
|
||||
WRITEINT16(imgptr, width);
|
||||
WRITEINT16(imgptr, height);
|
||||
WRITEINT16(imgptr, leftoffset);
|
||||
WRITEINT16(imgptr, topoffset);
|
||||
|
||||
// Leave placeholder to column pointers
|
||||
colpointers = imgptr;
|
||||
imgptr += width*4;
|
||||
|
||||
// Write columns
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
int lastStartY = 0;
|
||||
int spanSize = 0;
|
||||
startofspan = NULL;
|
||||
|
||||
// Write column pointer
|
||||
WRITEINT32(colpointers, imgptr - imgbuf);
|
||||
|
||||
// Write pixels
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
UINT8 pixel = raw[((y * width) + x)];
|
||||
UINT8 opaque = (pixel != 0xf7); // If not 247 (0xf7), we have a pixel
|
||||
|
||||
// End span if we have a transparent pixel
|
||||
if (!opaque)
|
||||
{
|
||||
if (startofspan)
|
||||
WRITEUINT8(imgptr, 0);
|
||||
startofspan = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start new column if we need to
|
||||
if (!startofspan || spanSize == 255)
|
||||
{
|
||||
int writeY = y;
|
||||
|
||||
// If we reached the span size limit, finish the previous span
|
||||
if (startofspan)
|
||||
WRITEUINT8(imgptr, 0);
|
||||
|
||||
if (y > 254)
|
||||
{
|
||||
// Make sure we're aligned to 254
|
||||
if (lastStartY < 254)
|
||||
{
|
||||
WRITEUINT8(imgptr, 254);
|
||||
WRITEUINT8(imgptr, 0);
|
||||
imgptr += 2;
|
||||
lastStartY = 254;
|
||||
}
|
||||
|
||||
// Write stopgap empty spans if needed
|
||||
writeY = y - lastStartY;
|
||||
|
||||
while (writeY > 254)
|
||||
{
|
||||
WRITEUINT8(imgptr, 254);
|
||||
WRITEUINT8(imgptr, 0);
|
||||
imgptr += 2;
|
||||
writeY -= 254;
|
||||
}
|
||||
}
|
||||
|
||||
startofspan = imgptr;
|
||||
WRITEUINT8(imgptr, writeY);
|
||||
imgptr += 2;
|
||||
spanSize = 0;
|
||||
|
||||
lastStartY = y;
|
||||
}
|
||||
|
||||
// Write the pixel
|
||||
WRITEUINT8(imgptr, pixel);
|
||||
spanSize++;
|
||||
startofspan[1] = spanSize;
|
||||
}
|
||||
|
||||
if (startofspan)
|
||||
WRITEUINT8(imgptr, 0);
|
||||
|
||||
WRITEUINT8(imgptr, 0xFF);
|
||||
}
|
||||
|
||||
size = imgptr-imgbuf;
|
||||
img = Z_Malloc(size, PU_STATIC, NULL);
|
||||
memcpy(img, imgbuf, size);
|
||||
|
||||
if (destsize != NULL)
|
||||
*destsize = size;
|
||||
|
||||
patch_t *converted = Patch_Create((softwarepatch_t *)img, size, NULL);
|
||||
#ifdef HWRENDER
|
||||
Patch_CreateGL(converted);
|
||||
#endif
|
||||
Z_Free(img);
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
//
|
||||
// R_MaskedFlatToPatch
|
||||
@@ -615,3 +733,44 @@ UINT16 R_GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip)
|
||||
|
||||
return 0xFF00;
|
||||
}
|
||||
|
||||
void R_PatchToPixels(patch_t *patch, UINT8 *dst)
|
||||
{
|
||||
const INT16 width = patch->width;
|
||||
|
||||
// init out destination to cyan so we can easily check for it when we convert it back to a patch
|
||||
memset(dst, 0xf7, (width * patch->height)); // should this be here or should this be taken care of before passing it?
|
||||
|
||||
for (INT32 x = 0; x < width; ++x)
|
||||
{
|
||||
INT32 y = 0;
|
||||
INT32 prevdelta = -1;
|
||||
|
||||
column_t *column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[x]));
|
||||
|
||||
while (column->topdelta != 0xff)
|
||||
{
|
||||
INT32 topdelta = column->topdelta;
|
||||
|
||||
if (topdelta <= prevdelta)
|
||||
topdelta += prevdelta;
|
||||
|
||||
prevdelta = topdelta;
|
||||
|
||||
for (; y-topdelta < column->length; ++y)
|
||||
{
|
||||
UINT8 pixel = 0;
|
||||
|
||||
if (y >= topdelta)
|
||||
{
|
||||
UINT8 *source = (UINT8*)(column) + 3;
|
||||
pixel = source[y-topdelta];
|
||||
}
|
||||
|
||||
dst[(y*width) + x] = pixel;
|
||||
}
|
||||
|
||||
column = (column_t *)((UINT8 *)column + column->length + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
-62
@@ -1,62 +1,64 @@
|
||||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos.
|
||||
// Copyright (C) 2019 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file r_patch.h
|
||||
/// \brief Patch generation.
|
||||
|
||||
#ifndef __R_PATCH__
|
||||
#define __R_PATCH__
|
||||
|
||||
#include "r_defs.h"
|
||||
|
||||
// Structs
|
||||
typedef enum
|
||||
{
|
||||
ROTAXIS_X, // Roll (the default)
|
||||
ROTAXIS_Y, // Pitch
|
||||
ROTAXIS_Z // Yaw
|
||||
} rotaxis_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
INT32 x, y;
|
||||
rotaxis_t rotaxis;
|
||||
} spriteframepivot_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
spriteframepivot_t pivot[64];
|
||||
boolean available;
|
||||
} spriteinfo_t;
|
||||
|
||||
// Patch functions
|
||||
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest);
|
||||
void Patch_Free(patch_t *patch);
|
||||
|
||||
#define Patch_FreeTag(tagnum) Patch_FreeTags(tagnum, tagnum)
|
||||
void Patch_FreeTags(INT32 lowtag, INT32 hightag);
|
||||
|
||||
#ifdef HWRENDER
|
||||
void *Patch_AllocateHardwarePatch(patch_t *patch);
|
||||
void *Patch_CreateGL(patch_t *patch);
|
||||
#endif
|
||||
|
||||
// Conversions between patches / flats / textures...
|
||||
boolean R_CheckIfPatch(lumpnum_t lump);
|
||||
|
||||
// SpriteInfo
|
||||
extern spriteinfo_t spriteinfo[NUMSPRITES];
|
||||
void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
|
||||
void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum);
|
||||
|
||||
void *R_MaskedFlatToPatch(UINT16 *raw, INT16 width, INT16 height, INT16 leftoffset, INT16 topoffset, size_t *destsize);
|
||||
UINT16 R_GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip);
|
||||
|
||||
#endif // __R_PATCH__
|
||||
// SONIC ROBO BLAST 2
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos.
|
||||
// Copyright (C) 2019 by Sonic Team Junior.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file r_patch.h
|
||||
/// \brief Patch generation.
|
||||
|
||||
#ifndef __R_PATCH__
|
||||
#define __R_PATCH__
|
||||
|
||||
#include "r_defs.h"
|
||||
|
||||
// Structs
|
||||
typedef enum
|
||||
{
|
||||
ROTAXIS_X, // Roll (the default)
|
||||
ROTAXIS_Y, // Pitch
|
||||
ROTAXIS_Z // Yaw
|
||||
} rotaxis_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
INT32 x, y;
|
||||
rotaxis_t rotaxis;
|
||||
} spriteframepivot_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
spriteframepivot_t pivot[64];
|
||||
boolean available;
|
||||
} spriteinfo_t;
|
||||
|
||||
// Patch functions
|
||||
patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest);
|
||||
void Patch_Free(patch_t *patch);
|
||||
|
||||
#define Patch_FreeTag(tagnum) Patch_FreeTags(tagnum, tagnum)
|
||||
void Patch_FreeTags(INT32 lowtag, INT32 hightag);
|
||||
|
||||
#ifdef HWRENDER
|
||||
void *Patch_AllocateHardwarePatch(patch_t *patch);
|
||||
void *Patch_CreateGL(patch_t *patch);
|
||||
#endif
|
||||
|
||||
// Conversions between patches / flats / textures...
|
||||
boolean R_CheckIfPatch(lumpnum_t lump);
|
||||
|
||||
// SpriteInfo
|
||||
extern spriteinfo_t spriteinfo[NUMSPRITES];
|
||||
void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
|
||||
void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum);
|
||||
|
||||
void *R_MaskedFlatToPatch(UINT16 *raw, INT16 width, INT16 height, INT16 leftoffset, INT16 topoffset, size_t *destsize);
|
||||
void *R_PixelsToPatch(UINT8 *raw, INT16 width, INT16 height, INT16 leftoffset, INT16 topoffset, size_t *destsize);
|
||||
UINT16 R_GetPatchPixel(patch_t *patch, INT32 x, INT32 y, boolean flip);
|
||||
void R_PatchToPixels(patch_t *patch, UINT8 *dst); // Important: dst must have enough space for patch->width*patch->height pixels!
|
||||
|
||||
#endif // __R_PATCH__
|
||||
Reference in new issue
Block a user