diff --git a/base/all-all/skytran.lmp b/base/all-all/skytran.lmp new file mode 100644 index 000000000..326707a65 Binary files /dev/null and b/base/all-all/skytran.lmp differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70b25f663..d2930abee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,6 +120,7 @@ set(WOOF_SOURCES r_plane.c r_plane.h r_segs.c r_segs.h r_sky.c r_sky.h + r_skydefs.c r_skydefs.h r_state.h r_swirl.c r_swirl.h r_things.c r_things.h diff --git a/src/p_spec.c b/src/p_spec.c index c6effc8be..be891b009 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2414,6 +2414,8 @@ void P_UpdateSpecials (void) // [crispy] draw fuzz effect independent of rendering frame rate R_SetFuzzPosTic(); + + R_UpdateSky(); } ////////////////////////////////////////////////////////////////////// diff --git a/src/r_draw.h b/src/r_draw.h index 219357f62..9ee009bd5 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -52,6 +52,7 @@ extern boolean fuzzcolumn_mode; void R_SetFuzzColumnMode(void); void R_DrawSkyColumn(void); +void R_DrawSkyColumnMasked(void); // Draw with color translation tables, for player sprite rendering, // Green/Red/Blue/Indigo shirts. diff --git a/src/r_plane.c b/src/r_plane.c index 2666739b7..fe85d3f80 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -39,6 +39,7 @@ #include "doomstat.h" #include "doomtype.h" #include "i_system.h" +#include "m_fixed.h" #include "r_bmaps.h" // [crispy] R_BrightmapForTexName() #include "r_data.h" #include "r_defs.h" @@ -46,11 +47,13 @@ #include "r_main.h" #include "r_plane.h" #include "r_sky.h" +#include "r_skydefs.h" #include "r_state.h" #include "r_swirl.h" // [crispy] R_DistortedFlat() #include "tables.h" #include "v_fmt.h" #include "v_video.h" +#include "w_wad.h" #include "z_zone.h" #define MAXVISPLANES 128 /* must be a power of 2 */ @@ -264,19 +267,19 @@ static visplane_t *new_visplane(unsigned hash) visplane_t *R_DupPlane(const visplane_t *pl, int start, int stop) { - unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); - visplane_t *new_pl = new_visplane(hash); - - new_pl->height = pl->height; - new_pl->picnum = pl->picnum; - new_pl->lightlevel = pl->lightlevel; - new_pl->xoffs = pl->xoffs; // killough 2/28/98 - new_pl->yoffs = pl->yoffs; - new_pl->minx = start; - new_pl->maxx = stop; - memset(new_pl->top, UCHAR_MAX, video.width * sizeof(*new_pl->top)); - - return new_pl; + unsigned hash = visplane_hash(pl->picnum, pl->lightlevel, pl->height); + visplane_t *new_pl = new_visplane(hash); + + new_pl->height = pl->height; + new_pl->picnum = pl->picnum; + new_pl->lightlevel = pl->lightlevel; + new_pl->xoffs = pl->xoffs; // killough 2/28/98 + new_pl->yoffs = pl->yoffs; + new_pl->minx = start; + new_pl->maxx = stop; + memset(new_pl->top, UCHAR_MAX, video.width * sizeof(*new_pl->top)); + + return new_pl; } // @@ -376,152 +379,260 @@ static void R_MakeSpans(int x, unsigned int t1, unsigned int b1, unsigned int t2 spanstart[b2--] = x; } -// New function, by Lee Killough +static void DrawSkyFire(visplane_t *pl, fire_t *fire) +{ + dc_colormap[0] = dc_colormap[1] = fullcolormap; -static void do_draw_plane(visplane_t *pl) + dc_texturemid = -28 * FRACUNIT; + dc_iscale = skyiscale; + dc_texheight = FIRE_HEIGHT; + + for (int x = pl->minx; x <= pl->maxx; x++) + { + dc_x = x; + dc_yl = pl->top[x]; + dc_yh = pl->bottom[x]; + + if (dc_yl != USHRT_MAX && dc_yl <= dc_yh) + { + dc_source = R_GetFireColumn((viewangle + xtoskyangle[x]) + >> ANGLETOSKYSHIFT); + colfunc(); + } + } +} + +static void DrawSkyTex(visplane_t *pl, skytex_t *skytex) { - register int x; - if (pl->minx <= pl->maxx) - { - if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) // sky flat - { - int texture; - angle_t an, flip; - boolean vertically_scrolling = false; - boolean stretch; - - // killough 10/98: allow skies to come from sidedefs. - // Allows scrolling and/or animated skies, as well as - // arbitrary multiple skies per level without having - // to use info lumps. - - an = viewangle; - - if (pl->picnum & PL_SKYFLAT) - { - // Sky Linedef - const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT]; - - // Sky transferred from first sidedef - const side_t *s = *l->sidenum + sides; - - if (s->baserowoffset - s->oldrowoffset) - vertically_scrolling = true; - - // Texture comes from upper texture of reference sidedef - texture = texturetranslation[s->toptexture]; - - // Horizontal offset is turned into an angle offset, - // to allow sky rotation as well as careful positioning. - // However, the offset is scaled very small, so that it - // allows a long-period of sky rotation. - - an += s->textureoffset; - - // Vertical offset allows careful sky positioning. - - dc_texturemid = s->rowoffset - 28*FRACUNIT; - - // We sometimes flip the picture horizontally. - // - // Doom always flipped the picture, so we make it optional, - // to make it easier to use the new feature, while to still - // allow old sky textures to be used. - - flip = l->special==272 ? 0u : ~0u; - } - else // Normal Doom sky, only one allowed per level - { - dc_texturemid = skytexturemid; // Default y-offset - texture = skytexture; // Default texture - flip = 0; // Doom flips it - } - - // Sky is always drawn full bright, i.e. colormaps[0] is used. - // Because of this hack, sky is not affected by INVUL inverse mapping. - // - // killough 7/19/98: fix hack to be more realistic: - - if (STRICTMODE_COMP(comp_skymap) || !(dc_colormap[0] = dc_colormap[1] = fixedcolormap)) - dc_colormap[0] = dc_colormap[1] = fullcolormap; // killough 3/20/98 - - dc_texheight = textureheight[texture]>>FRACBITS; // killough - dc_iscale = skyiscale; - - // [FG] stretch short skies - stretch = (stretchsky && dc_texheight < 200); - if (stretch || !vertically_scrolling) + int texture = R_TextureNumForName(skytex->name); + + dc_colormap[0] = dc_colormap[1] = fullcolormap; + + dc_texturemid = skytex->mid * FRACUNIT; + dc_texheight = textureheight[texture] >> FRACBITS; + dc_iscale = FixedMul(skyiscale, skytex->scaley); + + dc_texturemid += skytex->curry; + + angle_t an = viewangle + FixedToAngle(skytex->currx); + + for (int x = pl->minx; x <= pl->maxx; x++) + { + dc_x = x; + dc_yl = pl->top[x]; + dc_yh = pl->bottom[x]; + + if (dc_yl != USHRT_MAX && dc_yl <= dc_yh) + { + dc_source = R_GetColumnMod2(texture, (an + xtoskyangle[x]) + >> ANGLETOSKYSHIFT); + colfunc(); + } + } +} + +static void DrawSkyDef(visplane_t *pl) +{ + if (sky->type == SkyType_Fire) + { + DrawSkyFire(pl, &sky->fire); + return; + } + + DrawSkyTex(pl, &sky->skytex); + + if (sky->type == SkyType_WithForeground) + { + // Special tranmap to avoid custom render path to render sky + // transparently. See id24 SKYDEFS spec. + tranmap = W_CacheLumpName("SKYTRAN", PU_CACHE); + colfunc = R_DrawTLColumn; + DrawSkyTex(pl, &sky->foreground); + tranmap = main_tranmap; + colfunc = R_DrawColumn; + } +} + +static void do_draw_mbf_sky(visplane_t *pl) +{ + int texture; + angle_t an, flip; + boolean vertically_scrolling = false; + + // killough 10/98: allow skies to come from sidedefs. + // Allows scrolling and/or animated skies, as well as + // arbitrary multiple skies per level without having + // to use info lumps. + + an = viewangle; + + if (pl->picnum & PL_SKYFLAT) + { + // Sky Linedef + const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT]; + + // Sky transferred from first sidedef + const side_t *s = *l->sidenum + sides; + + if (s->baserowoffset - s->oldrowoffset) { - fixed_t diff; + vertically_scrolling = true; + } + + // Texture comes from upper texture of reference sidedef + texture = texturetranslation[s->toptexture]; + + // Horizontal offset is turned into an angle offset, + // to allow sky rotation as well as careful positioning. + // However, the offset is scaled very small, so that it + // allows a long-period of sky rotation. + + an += s->textureoffset; + + // Vertical offset allows careful sky positioning. + + dc_texturemid = s->rowoffset - 28 * FRACUNIT; + + // We sometimes flip the picture horizontally. + // + // Doom always flipped the picture, so we make it optional, + // to make it easier to use the new feature, while to still + // allow old sky textures to be used. + + flip = l->special == 272 ? 0u : ~0u; + } + else // Normal Doom sky, only one allowed per level + { + dc_texturemid = skytexturemid; // Default y-offset + texture = skytexture; // Default texture + flip = 0; // Doom flips it + } + + // Sky is always drawn full bright, i.e. colormaps[0] is used. + // Because of this hack, sky is not affected by INVUL inverse mapping. + // + // killough 7/19/98: fix hack to be more realistic: + + if (STRICTMODE_COMP(comp_skymap) + || !(dc_colormap[0] = dc_colormap[1] = fixedcolormap)) + { + dc_colormap[0] = dc_colormap[1] = fullcolormap; // killough 3/20/98 + } + + dc_texheight = textureheight[texture] >> FRACBITS; // killough + dc_iscale = skyiscale; - if (stretch) - { + // [FG] stretch short skies + boolean stretch = (stretchsky && dc_texheight < 200); + if (stretch || !vertically_scrolling) + { + if (stretch) + { dc_iscale = dc_iscale * dc_texheight / SKYSTRETCH_HEIGHT; dc_texturemid = dc_texturemid * dc_texheight / SKYSTRETCH_HEIGHT; - } + } - // Make sure the fade-to-color effect doesn't happen too early - diff = dc_texturemid - SCREENHEIGHT / 2 * FRACUNIT; - if (diff < 0) - { + // Make sure the fade-to-color effect doesn't happen too early + fixed_t diff = dc_texturemid - SCREENHEIGHT / 2 * FRACUNIT; + if (diff < 0) + { diff += textureheight[texture]; diff %= textureheight[texture]; dc_texturemid = SCREENHEIGHT / 2 * FRACUNIT + diff; - } - dc_skycolor = R_GetSkyColor(texture); - colfunc = R_DrawSkyColumn; } + dc_skycolor = R_GetSkyColor(texture); + colfunc = R_DrawSkyColumn; + } - // killough 10/98: Use sky scrolling offset, and possibly flip picture - for (x = pl->minx; (dc_x = x) <= pl->maxx; x++) - if ((dc_yl = pl->top[x]) != USHRT_MAX && dc_yl <= (dc_yh = pl->bottom[x])) - { - dc_source = R_GetColumnMod2(texture, ((an + xtoskyangle[x])^flip) >> - ANGLETOSKYSHIFT); - colfunc(); - } + // killough 10/98: Use sky scrolling offset, and possibly flip picture + for (int x = pl->minx; x <= pl->maxx; x++) + { + dc_x = x; + dc_yl = pl->top[x]; + dc_yh = pl->bottom[x]; - colfunc = R_DrawColumn; - } - else // regular flat - { - int stop, light; - boolean swirling = (flattranslation[pl->picnum] == -1); - - // [crispy] add support for SMMU swirling flats - if (swirling) - { - ds_source = R_DistortedFlat(firstflat + pl->picnum); - ds_brightmap = R_BrightmapForFlatNum(pl->picnum); - } - else + if (dc_yl != USHRT_MAX && dc_yl <= dc_yh) { - ds_source = V_CacheFlatNum(firstflat + flattranslation[pl->picnum], - PU_STATIC); - ds_brightmap = R_BrightmapForFlatNum(flattranslation[pl->picnum]); + dc_source = R_GetColumnMod2(texture, ((an + xtoskyangle[x]) ^ flip) + >> ANGLETOSKYSHIFT); + colfunc(); } + } + + colfunc = R_DrawColumn; +} + +// New function, by Lee Killough + +static void do_draw_plane(visplane_t *pl) +{ + if (pl->minx > pl->maxx) + { + return; + } - xoffs = pl->xoffs; // killough 2/28/98: Add offsets - yoffs = pl->yoffs; - planeheight = abs(pl->height-viewz); - light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; + // sky flat - if (light >= LIGHTLEVELS) - light = LIGHTLEVELS-1; + if (pl->picnum == skyflatnum && sky) + { + DrawSkyDef(pl); + return; + } - if (light < 0) - light = 0; + if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT) + { + do_draw_mbf_sky(pl); + return; + } - stop = pl->maxx + 1; - planezlight = zlight[light]; - pl->top[pl->minx-1] = pl->top[stop] = USHRT_MAX; + // regular flat - for (x = pl->minx ; x <= stop ; x++) - R_MakeSpans(x,pl->top[x-1],pl->bottom[x-1],pl->top[x],pl->bottom[x]); + int stop, light; + boolean swirling = (flattranslation[pl->picnum] == -1); - if (!swirling) Z_ChangeTag (ds_source, PU_CACHE); - } - } + // [crispy] add support for SMMU swirling flats + if (swirling) + { + ds_source = R_DistortedFlat(firstflat + pl->picnum); + ds_brightmap = R_BrightmapForFlatNum(pl->picnum); + } + else + { + ds_source = V_CacheFlatNum( + firstflat + flattranslation[pl->picnum], PU_STATIC); + ds_brightmap = + R_BrightmapForFlatNum(flattranslation[pl->picnum]); + } + + xoffs = pl->xoffs; // killough 2/28/98: Add offsets + yoffs = pl->yoffs; + planeheight = abs(pl->height - viewz); + light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight; + + if (light >= LIGHTLEVELS) + { + light = LIGHTLEVELS - 1; + } + + if (light < 0) + { + light = 0; + } + + stop = pl->maxx + 1; + planezlight = zlight[light]; + pl->top[pl->minx - 1] = pl->top[stop] = USHRT_MAX; + + for (int x = pl->minx; x <= stop; x++) + { + R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1], pl->top[x], + pl->bottom[x]); + } + + if (!swirling) + { + Z_ChangeTag(ds_source, PU_CACHE); + } } // diff --git a/src/r_sky.c b/src/r_sky.c index 6fcfd538d..832abe8d3 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -22,11 +22,16 @@ //----------------------------------------------------------------------------- #include +#include +#include "doomtype.h" #include "i_video.h" +#include "m_array.h" #include "m_fixed.h" +#include "m_random.h" #include "r_data.h" #include "r_sky.h" +#include "r_skydefs.h" #include "r_state.h" // [FG] textureheight[] #include "w_wad.h" #include "z_zone.h" @@ -42,13 +47,153 @@ int skyflatnum; int skytexture = -1; // [crispy] initialize int skytexturemid; +sky_t *sky = NULL; + +// PSX fire sky, description: https://fabiensanglard.net/doom_fire_psx/ + +static byte fire_indices[FIRE_WIDTH * FIRE_HEIGHT]; + +static byte fire_pixels[FIRE_WIDTH * FIRE_HEIGHT]; + +static void PrepareFirePixels(fire_t *fire) +{ + byte *rover = fire_pixels; + for (int x = 0; x < FIRE_WIDTH; x++) + { + byte *src = fire_indices + x; + for (int y = 0; y < FIRE_HEIGHT; y++) + { + *rover++ = fire->palette[*src]; + src += FIRE_WIDTH; + } + } +} + +static void SpreadFire(void) +{ + for (int x = 0; x < FIRE_WIDTH; ++x) + { + for (int y = 1; y < FIRE_HEIGHT; ++y) + { + int src = y * FIRE_WIDTH + x; + + int index = fire_indices[src]; + + if (!index) + { + fire_indices[src - FIRE_WIDTH] = 0; + } + else + { + int rand_index = M_Random() & 3; + int dst = src - rand_index + 1; + fire_indices[dst - FIRE_WIDTH] = index - (rand_index & 1); + } + } + } +} + +static void SetupFire(fire_t *fire) +{ + memset(fire_indices, 0, FIRE_WIDTH * FIRE_HEIGHT); + + int last = array_size(fire->palette) - 1; + + for (int i = 0; i < FIRE_WIDTH; ++i) + { + fire_indices[(FIRE_HEIGHT - 1) * FIRE_WIDTH + i] = last; + } + + for (int i = 0; i < 64; ++i) + { + SpreadFire(); + } + PrepareFirePixels(fire); +} + +byte *R_GetFireColumn(int col) +{ + while (col < 0) + { + col += FIRE_WIDTH; + } + col %= FIRE_WIDTH; + return &fire_pixels[col * FIRE_HEIGHT]; +} + +static void InitSky(void) +{ + static skydefs_t *skydefs; + + static boolean run_once = true; + if (run_once) + { + skydefs = R_ParseSkyDefs(); + run_once = false; + } + + if (!skydefs) + { + return; + } + + array_foreach(sky, skydefs->skies) + { + if (skytexture == R_CheckTextureNumForName(sky->skytex.name)) + { + if (sky->type == SkyType_Fire) + { + SetupFire(&sky->fire); + } + return; + } + } + + sky = NULL; +} + +void R_UpdateSky(void) +{ + if (!sky) + { + return; + } + + if (sky->type == SkyType_Fire) + { + fire_t *fire = &sky->fire; + + if (fire->tics_left == 0) + { + SpreadFire(); + PrepareFirePixels(fire); + fire->tics_left = fire->updatetime; + } + + fire->tics_left--; + + return; + } + + skytex_t *background = &sky->skytex; + background->currx += background->scrollx; + background->curry += background->scrolly; + + if (sky->type == SkyType_WithForeground) + { + skytex_t *foreground = &sky->foreground; + foreground->currx += foreground->scrollx; + foreground->curry += foreground->scrolly; + } +} + // // R_InitSkyMap // Called whenever the view size changes. // void R_InitSkyMap (void) { - int skyheight; + InitSky(); // [crispy] initialize if (skytexture == -1) @@ -58,7 +203,7 @@ void R_InitSkyMap (void) R_GetSkyColor(skytexture); // [FG] stretch short skies - skyheight = textureheight[skytexture]>>FRACBITS; + int skyheight = textureheight[skytexture] >> FRACBITS; if (stretchsky && skyheight < 200) skytexturemid = -28*FRACUNIT; diff --git a/src/r_sky.h b/src/r_sky.h index 1a483eb4a..142f4f71d 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -21,6 +21,7 @@ #define __R_SKY__ #include "doomtype.h" +#include "r_skydefs.h" // SKY, store the number for name. #define SKYFLATNAME "F_SKY1" @@ -38,11 +39,20 @@ extern boolean linearsky; extern int skytexture; extern int skytexturemid; +extern sky_t *sky; + // Called whenever the view size changes. void R_InitSkyMap(void); byte R_GetSkyColor(int texturenum); +void R_UpdateSky(void); + +#define FIRE_WIDTH 128 +#define FIRE_HEIGHT 256 + +byte *R_GetFireColumn(int col); + #endif //---------------------------------------------------------------------------- diff --git a/src/r_skydefs.c b/src/r_skydefs.c new file mode 100644 index 000000000..1c4154bc4 --- /dev/null +++ b/src/r_skydefs.c @@ -0,0 +1,173 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#include "r_skydefs.h" + +#include "doomdef.h" +#include "doomtype.h" +#include "i_printf.h" +#include "m_array.h" +#include "m_fixed.h" +#include "m_misc.h" +#include "w_wad.h" + +#include "cjson/cJSON.h" + +static boolean ParseFire(cJSON *json, fire_t *out) +{ + cJSON *updatetime = cJSON_GetObjectItemCaseSensitive(json, "updatetime"); + if (!cJSON_IsNumber(updatetime)) + { + return false; + } + out->updatetime = updatetime->valuedouble * TICRATE; + + cJSON *palette = cJSON_GetObjectItemCaseSensitive(json, "palette"); + if (!cJSON_IsArray(palette)) + { + return false; + } + int size = cJSON_GetArraySize(palette); + for (int i = 0; i < size; ++i) + { + cJSON *color = cJSON_GetArrayItem(palette, i); + array_push(out->palette, color->valueint); + } + + return true; +} + +static boolean ParseSkyTex(cJSON *json, skytex_t *out) +{ + cJSON *name = cJSON_GetObjectItemCaseSensitive(json, "name"); + if (!cJSON_IsString(name)) + { + return false; + } + out->name = M_StringDuplicate(name->valuestring); + + cJSON *mid = cJSON_GetObjectItemCaseSensitive(json, "mid"); + cJSON *scrollx = cJSON_GetObjectItemCaseSensitive(json, "scrollx"); + cJSON *scrolly = cJSON_GetObjectItemCaseSensitive(json, "scrolly"); + cJSON *scalex = cJSON_GetObjectItemCaseSensitive(json, "scalex"); + cJSON *scaley = cJSON_GetObjectItemCaseSensitive(json, "scaley"); + if (!cJSON_IsNumber(mid) + || !cJSON_IsNumber(scrollx) || !cJSON_IsNumber(scrolly) + || !cJSON_IsNumber(scalex) || !cJSON_IsNumber(scaley)) + { + return false; + } + out->mid = mid->valuedouble; + const double ticratescale = 1.0 / TICRATE; + out->scrollx = (scrollx->valuedouble * ticratescale) * FRACUNIT; + out->scrolly = (scrolly->valuedouble * ticratescale) * FRACUNIT; + out->scalex = scalex->valuedouble * FRACUNIT; + out->scaley = (1.0 / scaley->valuedouble) * FRACUNIT; + + return true; +} + +static boolean ParseSky(cJSON *json, sky_t *out) +{ + cJSON *type = cJSON_GetObjectItemCaseSensitive(json, "type"); + if (!cJSON_IsNumber(type)) + { + return false; + } + out->type = type->valueint; + + skytex_t background = {0}; + if (!ParseSkyTex(json, &background)) + { + return false; + } + out->skytex = background; + + cJSON *js_fire = cJSON_GetObjectItemCaseSensitive(json, "fire"); + fire_t fire = {0}; + if (!cJSON_IsNull(js_fire)) + { + ParseFire(js_fire, &fire); + } + out->fire = fire; + + cJSON *js_foreground = cJSON_GetObjectItemCaseSensitive(json, "foregroundtex"); + skytex_t foreground = {0}; + if (!cJSON_IsNull(js_foreground)) + { + ParseSkyTex(js_foreground, &foreground); + } + out->foreground = foreground; + + return true; +} + +static boolean ParseFlatMap(cJSON *json, flatmap_t *out) +{ + cJSON *flat = cJSON_GetObjectItemCaseSensitive(json, "flat"); + out->flat = M_StringDuplicate(flat->valuestring); + cJSON *sky = cJSON_GetObjectItemCaseSensitive(json, "sky"); + out->sky = M_StringDuplicate(sky->valuestring); + return true; +} + +skydefs_t *R_ParseSkyDefs(void) +{ + int lumpnum = W_CheckNumForName("SKYDEFS"); + if (lumpnum < 0) + { + return NULL; + } + + cJSON *json = cJSON_Parse(W_CacheLumpNum(lumpnum, PU_CACHE)); + if (json == NULL) + { + I_Printf(VB_ERROR, "JSON: Error parsing SKYDEFS"); + cJSON_Delete(json); + return NULL; + } + + cJSON *data = cJSON_GetObjectItemCaseSensitive(json, "data"); + if (!cJSON_IsObject(data)) + { + cJSON_Delete(json); + return NULL; + } + + skydefs_t *out = calloc(1, sizeof(*out)); + + cJSON *js_skies = cJSON_GetObjectItemCaseSensitive(data, "skies"); + cJSON *js_sky = NULL; + cJSON_ArrayForEach(js_sky, js_skies) + { + sky_t sky = {0}; + if (ParseSky(js_sky, &sky)) + { + array_push(out->skies, sky); + } + } + + cJSON *js_flatmapping = cJSON_GetObjectItemCaseSensitive(data, "flatmapping"); + cJSON *js_flatmap = NULL; + cJSON_ArrayForEach(js_flatmap, js_flatmapping) + { + flatmap_t flatmap = {0}; + if (ParseFlatMap(js_flatmap, &flatmap)) + { + array_push(out->flatmapping, flatmap); + } + } + + cJSON_Delete(json); + return out; +} diff --git a/src/r_skydefs.h b/src/r_skydefs.h new file mode 100644 index 000000000..0f20b3cff --- /dev/null +++ b/src/r_skydefs.h @@ -0,0 +1,68 @@ +// +// Copyright(C) 2024 Roman Fomin +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +#ifndef R_SKYDEFS_H +#define R_SKYDEFS_H + +#include "doomtype.h" +#include "m_fixed.h" + +typedef enum +{ + SkyType_Normal, + SkyType_Fire, + SkyType_WithForeground, +} skytype_t; + +typedef struct fire_s +{ + byte *palette; + int updatetime; + int tics_left; +} fire_t; + +typedef struct +{ + const char *name; + double mid; + fixed_t scrollx; + fixed_t currx; + fixed_t scrolly; + fixed_t curry; + fixed_t scalex; + fixed_t scaley; +} skytex_t; + +typedef struct sky_s +{ + skytype_t type; + skytex_t skytex; + fire_t fire; + skytex_t foreground; +} sky_t; + +typedef struct +{ + const char *flat; + const char *sky; +} flatmap_t; + +typedef struct +{ + sky_t *skies; + flatmap_t *flatmapping; +} skydefs_t; + +skydefs_t *R_ParseSkyDefs(void); + +#endif diff --git a/src/wi_interlvl.c b/src/wi_interlvl.c index 575175cad..f17b4dc6e 100644 --- a/src/wi_interlvl.c +++ b/src/wi_interlvl.c @@ -155,11 +155,7 @@ interlevel_t *WI_ParseInterlevel(const char *lumpname) cJSON *json = cJSON_Parse(W_CacheLumpName(lumpname, PU_CACHE)); if (json == NULL) { - const char *error_ptr = cJSON_GetErrorPtr(); - if (error_ptr != NULL) - { - I_Printf(VB_ERROR, "Error parsing %s", lumpname); - } + I_Printf(VB_ERROR, "Error parsing %s", lumpname); cJSON_Delete(json); return NULL; }