note description: "[ r_main.c Rendering main loop and setup functions, utility functions (BSP, geometry, trigonometry). See tables.c, too ]" license: "[ Copyright (C) 1993-1996 by id Software, Inc. Copyright (C) 2005-2014 Simon Howard Copyright (C) 2021 Ilgiz Mustafin 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ]" class R_MAIN inherit TABLES DOOMDEF_H create make feature i_main: I_MAIN make (a_i_main: like i_main) local i: INTEGER_32 do i_main := a_i_main create viewplayer.make validcount := 1 create scalelightfixed.make_filled (Void, 0, Maxlightscale - 1) create viewangletox.make_filled (0, 0, Fineangles // 2 - 1) from create scalelight.make_filled (create {ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]}.make_empty, 0, Lightlevels - 1) i := 0 until i >= Lightlevels loop scalelight [i] := create {ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]}.make_filled (Void, 0, Maxlightscale - 1) i := i + 1 end from create zlight.make_filled (create {ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]}.make_empty, 0, Lightlevels - 1) i := 0 until i >= Lightlevels loop zlight [i] := create {ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]}.make_filled (Void, 0, Maxlightz - 1) i := i + 1 end end feature viewx: FIXED_T viewy: FIXED_T viewz: FIXED_T feature viewplayer: PLAYER_T viewangle: ANGLE_T viewangleoffset: INTEGER_32 extralight: INTEGER_32 viewsin: FIXED_T viewcos: FIXED_T sscount: INTEGER_32 assign set_sscount set_sscount (a_sscount: like sscount) do sscount := a_sscount end linecount: INTEGER_32 loopcount: INTEGER_32 fixedcolormap: detachable INDEX_IN_ARRAY [LIGHTTABLE_T] -- lighttable_t* scalelightfixed: ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]] -- lighttable_t* [] zlight: ARRAY [ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]] -- ligghttable_t* [][] validcount: INTEGER_32 assign set_validcount -- increment every time a check is made set_validcount (a_validcount: like validcount) do validcount := a_validcount end Fieldofview: INTEGER_32 = 2048 -- Fineangles in the SCREENWIDTH wide window. feature centerx: INTEGER_32 centery: INTEGER_32 centerxfrac: FIXED_T centeryfrac: FIXED_T projection: FIXED_T feature colfunc: detachable PROCEDURE assign set_colfunc set_colfunc (a_colfunc: like colfunc) do colfunc := a_colfunc end basecolfunc: detachable PROCEDURE fuzzcolfunc: detachable PROCEDURE transcolfunc: detachable PROCEDURE spanfunc: detachable PROCEDURE feature detailshift: INTEGER_32 -- 0 = high, 1 = low feature -- Lighting constants. Lightlevels: INTEGER_32 = 16 Lightsegshift: INTEGER_32 = 4 Maxlightscale: INTEGER_32 = 48 Lightscaleshift: INTEGER_32 = 12 Maxlightz: INTEGER_32 = 128 Lightzshift: INTEGER_32 = 20 Numcolormaps: INTEGER_32 = 32 -- Number of diminishing brightness levels. -- There a 0-31, i.e. 32 LUT in the COLORMAP lump. scalelight: ARRAY [ARRAY [detachable INDEX_IN_ARRAY [LIGHTTABLE_T]]] -- lighttable_t* [][] feature Finecosine: ARRAY [FIXED_T] local l_start: INTEGER_32 i: INTEGER_32 once l_start := Fineangles // 4 create Result.make_filled (create {FIXED_T}.from_integer (0), 0, Finesine.count - l_start - 1) from i := 0 until i > Result.upper loop Result [i] := create {FIXED_T}.from_integer (Finesine [i + l_start]) i := i + 1 end ensure instance_free: class end Xtoviewangle: ARRAY [ANGLE_T] -- maps a screen pixel -- to the lowest viewangle that maps back to x ranges -- from clipangle to -clipangle once create Result.make_filled (create {ANGLE_T}.from_natural ({NATURAL_32} 0), 0, {DOOMDEF_H}.screenwidth) end r_pointonsegside (x, y: FIXED_T; line: SEG_T): INTEGER_32 local lx: FIXED_T ly: FIXED_T ldx: FIXED_T ldy: FIXED_T dx: FIXED_T dy: FIXED_T left: FIXED_T right: FIXED_T do lx := line.v1.x ly := line.v1.y ldx := line.v2.x - lx ldy := line.v2.y - ly if ldx = create {FIXED_T}.from_integer (0) then if x <= lx then Result := (ldy > create {FIXED_T}.from_integer (0)).to_integer else Result := (ldy < create {FIXED_T}.from_integer (0)).to_integer end elseif ldy = create {FIXED_T}.from_integer (0) then if y <= ly then Result := (ldx < create {FIXED_T}.from_integer (0)).to_integer else Result := (ldx > create {FIXED_T}.from_integer (0)).to_integer end else dx := (x - lx) dy := (y - ly) if (ldy.bit_xor (ldx).bit_xor (dx).bit_xor (dy) & create {FIXED_T}.from_integer ((2147483648).to_integer_32)) /= create {FIXED_T}.from_integer (0) then if (ldy.bit_xor (dx)) & create {FIXED_T}.from_integer ((2147483648).to_integer_32) /= create {FIXED_T}.from_integer (0) then Result := 1 else Result := 0 end else left := {M_FIXED}.fixedmul (ldy |>> {M_FIXED}.fracbits, dx) right := {M_FIXED}.fixedmul (dy, ldx |>> {M_FIXED}.fracbits) if right < left then Result := 0 else Result := 1 end end end end feature -- R_SetViewSize setsizeneeded: BOOLEAN setblocks: INTEGER_32 setdetail: INTEGER_32 r_setviewsize (blocks: INTEGER_32; detail: INTEGER_32) -- Do not really change anything here, -- because it might be in the middle of a refresh. -- The change will take effect next refresh. do setsizeneeded := True setblocks := blocks setdetail := detail end feature -- precalculated math tables clipangle: ANGLE_T viewangletox: ARRAY [INTEGER_32] -- The viewangletox[viewangle + FINEANGLES/4] lookup -- maps the visible view angles to screen X coordinates, -- flattening the arc to a flat projection plane. -- There will be many angles mapped to the same X. feature r_scalefromglobalangle (visangle: ANGLE_T): FIXED_T -- Returns the texture mapping scale -- for the current line (horizontal span) -- at the given angle. -- rw_distance must be calculated first local scale: FIXED_T anglea: ANGLE_T angleb: ANGLE_T sinea: INTEGER_32 sineb: INTEGER_32 num: FIXED_T den: INTEGER_32 do anglea := Ang90 + (visangle - viewangle) angleb := Ang90 + (visangle - i_main.R_segs.rw_normalangle) sinea := Finesine [anglea |>> Angletofineshift.as_integer_32] sineb := Finesine [angleb |>> Angletofineshift.as_integer_32] num := {M_FIXED}.fixedmul (projection, create {FIXED_T}.from_integer (sineb)) |<< detailshift den := {M_FIXED}.fixedmul (i_main.R_segs.rw_distance, create {FIXED_T}.from_integer (sinea)).to_integer_32 if den > num |>> 16.as_integer_32 then scale := {M_FIXED}.fixeddiv (num, create {FIXED_T}.from_integer (den)) if scale > create {FIXED_T}.from_integer (64 * {M_FIXED}.fracunit) then scale := create {FIXED_T}.from_integer (64 * {M_FIXED}.fracunit) elseif scale < create {FIXED_T}.from_integer (256) then scale := create {FIXED_T}.from_integer (256) end else scale := create {FIXED_T}.from_integer (64 * {M_FIXED}.fracunit) end Result := scale end r_executesetviewsize local cosadj: FIXED_T dy: FIXED_T i, j: INTEGER_32 level: INTEGER_32 startmap: INTEGER_32 do setsizeneeded := False if setblocks = 11 then i_main.R_draw.scaledviewwidth := {DOOMDEF_H}.screenwidth i_main.R_draw.viewheight := {DOOMDEF_H}.screenheight else i_main.R_draw.scaledviewwidth := setblocks * 32 i_main.R_draw.viewheight := (setblocks * 168 // 10).bit_and ((7).bit_not) end detailshift := setdetail i_main.R_draw.viewwidth := i_main.R_draw.scaledviewwidth |>> detailshift centery := i_main.R_draw.viewheight // 2 centerx := i_main.R_draw.viewwidth // 2 centerxfrac := create {FIXED_T}.from_integer (centerx |<< {M_FIXED}.fracbits) centeryfrac := create {FIXED_T}.from_integer (centery |<< {M_FIXED}.fracbits) projection := centerxfrac if detailshift = 0 then colfunc := agent i_main.R_draw.r_drawcolumn basecolfunc := agent i_main.R_draw.r_drawcolumn transcolfunc := agent i_main.R_draw.r_drawtranslatedcolumn spanfunc := agent i_main.R_draw.r_drawspan else colfunc := agent i_main.R_draw.r_drawcolumnlow basecolfunc := agent i_main.R_draw.r_drawcolumnlow fuzzcolfunc := agent i_main.R_draw.r_drawfuzzcolumn transcolfunc := agent i_main.R_draw.r_drawtranslatedcolumn spanfunc := agent i_main.R_draw.r_drawspanlow end i_main.R_draw.r_initbuffer (i_main.R_draw.scaledviewwidth, i_main.R_draw.viewheight) r_inittexturemapping i_main.R_things.pspritescale := create {FIXED_T}.from_integer ({M_FIXED}.fracunit * i_main.R_draw.viewwidth // Screenwidth) i_main.R_things.pspriteiscale := create {FIXED_T}.from_integer ({M_FIXED}.fracunit * Screenwidth // i_main.R_draw.viewwidth) from i := 0 until i >= i_main.R_draw.viewwidth loop i_main.R_things.screenheightarray [i] := i_main.R_draw.viewheight.as_integer_16 i := i + 1 end from i := 0 until i >= i_main.R_draw.viewheight loop dy := create {FIXED_T}.from_integer (((i - i_main.R_draw.viewheight // 2) |<< {M_FIXED}.fracbits) + {M_FIXED}.fracunit // 2) dy := create {FIXED_T}.from_integer (dy.abs) i_main.R_plane.Yslope [i] := {M_FIXED}.fixeddiv (create {FIXED_T}.from_integer ((i_main.R_draw.viewwidth |<< detailshift) // 2 * {M_FIXED}.fracunit), dy) i := i + 1 end from i := 0 until i >= i_main.R_draw.viewwidth loop cosadj := create {FIXED_T}.from_integer (Finecosine [Xtoviewangle [i] |>> Angletofineshift.as_integer_32].abs) i_main.R_plane.Distscale [i] := {M_FIXED}.fixeddiv (create {FIXED_T}.from_integer ({M_FIXED}.fracunit), cosadj) i := i + 1 end from i := 0 until i >= Lightlevels loop startmap := ((Lightlevels - 1 - i) * 2) * Numcolormaps // Lightlevels from j := 0 until j >= Maxlightscale loop level := startmap - j * Screenwidth // (i_main.R_draw.viewwidth |<< detailshift) // Distmap if level < 0 then level := 0 end if level >= Numcolormaps then level := Numcolormaps - 1 end scalelight [i] [j] := create {INDEX_IN_ARRAY [LIGHTTABLE_T]}.make (level * 256, i_main.R_data.colormaps) j := j + 1 end i := i + 1 end end feature r_initpointtoangle do end r_inittables do end r_pointtodist (x, y: FIXED_T): FIXED_T local angle: INTEGER_32 dx: FIXED_T dy: FIXED_T temp: FIXED_T dist: FIXED_T do dx := create {FIXED_T}.from_integer ((x - viewx).abs) dy := create {FIXED_T}.from_integer ((y - viewy).abs) if dy > dx then temp := dx dx := dy dy := temp end angle := (Tantoangle [{M_FIXED}.fixeddiv (dy, dx).to_integer_32 |>> Dbits] + Ang90) |>> Angletofineshift.as_integer_32 dist := {M_FIXED}.fixeddiv (dx, create {FIXED_T}.from_integer (Finesine [angle])) Result := dist end r_inittexturemapping local i: INTEGER_32 x: INTEGER_32 t: INTEGER_32 focallength: FIXED_T do focallength := {M_FIXED}.fixeddiv (centerxfrac, create {FIXED_T}.from_integer ({TABLES}.finetangent [Fineangles // 4 + {R_MAIN}.fieldofview // 2])) from i := 0 until i >= Fineangles // 2 loop if Finetangent [i] > {M_FIXED}.fracunit * 2 then t := -1 elseif Finetangent [i] < - {M_FIXED}.fracunit * 2 then t := i_main.R_draw.viewwidth + 1 else t := {M_FIXED}.fixedmul (create {FIXED_T}.from_integer (Finetangent [i]), focallength).to_integer_32 t := ((centerxfrac - create {FIXED_T}.from_integer (t) + create {FIXED_T}.from_integer ({M_FIXED}.fracunit) - create {FIXED_T}.from_integer (1)) |>> {M_FIXED}.fracbits).to_integer_32 if t < -1 then t := -1 elseif t > i_main.R_draw.viewwidth + 1 then t := i_main.R_draw.viewwidth + 1 end end viewangletox [i] := t i := i + 1 end from x := 0 until x > i_main.R_draw.viewwidth loop from i := 0 until viewangletox [i] <= x loop i := i + 1 end Xtoviewangle [x] := create {ANGLE_T}.from_natural (((i |<< Angletofineshift) - Ang90.as_integer_32).to_natural_32) x := x + 1 end from i := 0 until i >= Fineangles // 2 loop t := {M_FIXED}.fixedmul (create {FIXED_T}.from_integer (Finetangent [i]), focallength).to_integer_32 t := centerx - t if viewangletox [i] = -1 then viewangletox [i] := 0 elseif viewangletox [i] = i_main.R_draw.viewwidth + 1 then viewangletox [i] := i_main.R_draw.viewwidth end i := i + 1 end clipangle := Xtoviewangle [0] end feature -- R_InitLightTables Distmap: INTEGER_32 = 2 r_initlighttables -- Only inits the zlight table, -- because the scalelight table changes with view size local i: INTEGER_32 j: INTEGER_32 level: INTEGER_32 startmap: INTEGER_32 scale: INTEGER_32 do from i := 0 until i >= Lightlevels loop startmap := ((Lightlevels - 1 - i) * 2) * Numcolormaps // Lightlevels from j := 0 until j >= Maxlightz loop scale := {M_FIXED}.fixeddiv (create {FIXED_T}.from_integer (Screenwidth // 2 * {M_FIXED}.fracunit), create {FIXED_T}.from_integer ((j + 1) |<< Lightzshift)).to_integer_32 scale := scale |>> Lightscaleshift level := startmap - scale // Distmap if level < 0 then level := 0 end if level >= Numcolormaps then level := Numcolormaps - 1 end zlight [i] [j] := create {INDEX_IN_ARRAY [LIGHTTABLE_T]}.make (level * 256, i_main.R_data.colormaps) j := j + 1 end i := i + 1 end end feature -- R_Init framecount: INTEGER_32 -- just for profiling purposes r_init do i_main.R_data.r_initdata print ("%NR_InitData") r_initpointtoangle print ("%NR_InitPointToAngle") r_inittables print ("%NR_InitTables") r_setviewsize (i_main.M_menu.screenblocks, i_main.M_menu.detaillevel) i_main.R_plane.r_initplanes print ("%NR_InitPlanes") r_initlighttables print ("%NR_InitLightTables") i_main.R_sky.r_initskymap print ("%NR_InitSkyMap") i_main.R_draw.r_inittranslationtables print ("%NR_InitTranslationsTables") framecount := 0 end feature r_pointtoangle2 (x1, y1, x2, y2: FIXED_T): ANGLE_T do viewx := x1 viewy := y1 Result := r_pointtoangle (x2, y2) end r_pointtoangle (a_x, a_y: FIXED_T): ANGLE_T -- To get a global angle from cartesian coordinates, -- the coordinates are flipped until they are in -- the first octant of the coordinate system, then -- the y (<= x) is scaled and divided by x to get a -- tangent (slope) value which is looked up in the -- tantoangle[] table. local x, y: FIXED_T do x := a_x - viewx y := a_y - viewy if x = create {FIXED_T}.from_integer (0) and y = create {FIXED_T}.from_integer (0) then Result := create {ANGLE_T}.from_natural ({NATURAL_32} 0) else if x >= create {FIXED_T}.from_integer (0) then if y >= create {FIXED_T}.from_integer (0) then if x > y then Result := Tantoangle [slopediv (y.as_natural_32, x.as_natural_32)] else Result := Ang90 - create {ANGLE_T}.from_natural ((1).as_natural_32) - Tantoangle [slopediv (x.as_natural_32, y.as_natural_32)] end else y := - y if x > y then Result := - Tantoangle [slopediv (y.as_natural_32, x.as_natural_32)] else Result := create {ANGLE_T}.from_natural ((Ang270 + Tantoangle [slopediv (x.as_natural_32, y.as_natural_32)]).as_natural_32) end end else x := - x if y >= create {FIXED_T}.from_integer (0) then if x > y then Result := Ang180 - create {ANGLE_T}.from_natural ((1).as_natural_32) - Tantoangle [slopediv (y.as_natural_32, x.as_natural_32)] else Result := Ang90 + Tantoangle [slopediv (x.as_natural_32, y.as_natural_32)] end else y := - y if x > y then Result := Ang180 + Tantoangle [slopediv (y.as_natural_32, x.as_natural_32)] else Result := Ang270 - create {ANGLE_T}.from_natural ((1).as_natural_32) - Tantoangle [slopediv (x.as_natural_32, y.as_natural_32)] end end end end end feature r_renderplayerview (player: PLAYER_T) do r_setupframe (player) i_main.R_bsp.r_clearclipsegs i_main.R_bsp.r_cleardrawsegs i_main.R_plane.r_clearplanes i_main.R_things.r_clearsprites i_main.D_net.netupdate i_main.R_bsp.r_renderbspnode (i_main.P_setup.nodes.count - 1) i_main.D_net.netupdate i_main.R_plane.r_drawplanes i_main.D_net.netupdate i_main.R_things.r_drawmasked i_main.D_net.netupdate end r_setupframe (player: PLAYER_T) local i: INTEGER_32 do viewplayer := player check attached player.mo as mo then viewx := mo.x viewy := mo.y viewangle := mo.angle + create {ANGLE_T}.from_natural (viewangleoffset.to_natural_32) end extralight := player.extralight viewz := player.viewz viewsin := create {FIXED_T}.from_integer (Finesine [viewangle |>> Angletofineshift.as_integer_32]) viewcos := Finecosine [viewangle |>> Angletofineshift.as_integer_32] sscount := 0 if player.fixedcolormap /= 0 then fixedcolormap := create {INDEX_IN_ARRAY [LIGHTTABLE_T]}.make (player.fixedcolormap, i_main.R_data.colormaps) i_main.R_segs.walllights := scalelightfixed from i := 0 until i >= Maxlightscale loop check attached fixedcolormap as fcm then scalelightfixed [i] := fcm end i := i + 1 end else fixedcolormap := Void end framecount := framecount + 1 validcount := validcount + 1 end r_pointonside (x, y: FIXED_T; node: NODE_T): BOOLEAN -- Traverse BSP (sub) tree, -- check point against partition plane. -- Returns side False (front) or True (back) local dx: FIXED_T dy: FIXED_T left: FIXED_T right: FIXED_T do if node.dx = create {FIXED_T}.from_integer (0) then if x <= node.x then Result := node.dy > create {FIXED_T}.from_integer (0) else Result := node.dy < create {FIXED_T}.from_integer (0) end elseif node.dy = create {FIXED_T}.from_integer (0) then if y <= node.y then Result := node.dx < create {FIXED_T}.from_integer (0) else Result := node.dx > create {FIXED_T}.from_integer (0) end else dx := (x - node.x) dy := (y - node.y) if (node.dy.bit_xor (node.dx).bit_xor (dx).bit_xor (dy) & create {FIXED_T}.from_integer (({INTEGER_32} -2147483648))).to_boolean then if (node.dy.bit_xor (dx) & create {FIXED_T}.from_integer (({INTEGER_32} -2147483648))).to_boolean then Result := True else Result := False end else left := {M_FIXED}.fixedmul (node.dy |>> {M_FIXED}.fracbits, dx) right := {M_FIXED}.fixedmul (dy, node.dx |>> {M_FIXED}.fracbits) if right < left then Result := False else Result := True end end end end feature r_pointinsubsector (x, y: FIXED_T): SUBSECTOR_T local node: NODE_T side: INTEGER_32 nodenum: INTEGER_32 do if i_main.P_setup.numnodes = 0 then Result := i_main.P_setup.subsectors [i_main.P_setup.subsectors.lower] else nodenum := i_main.P_setup.numnodes - 1 from until nodenum & {DOOMDATA_H}.nf_subsector /= 0 loop node := i_main.P_setup.nodes [nodenum] side := r_pointonside (x, y, node).to_integer nodenum := node.children [side].to_integer_32 end Result := i_main.P_setup.subsectors [nodenum & {DOOMDATA_H}.nf_subsector.bit_not] end end invariant viewangletox.lower = 0 viewangletox.count = Fineangles // 2 scalelightfixed.lower = 0 and scalelightfixed.count = Maxlightscale scalelight.lower = 0 and scalelight.count = Lightlevels and across scalelight as sc_level all sc_level.item.lower = 0 and sc_level.item.count = Maxlightscale end zlight.lower = 0 and zlight.count = Lightlevels and across zlight as zl_level all zl_level.item.lower = 0 and zl_level.item.count = Maxlightz end end -- class R_MAIN
Generated by ISE EiffelStudio