note description: "[ r_draw.c The actual span/column drawing functios. Here find the main potential for optimization e.g. inline assembly, different algorithms. ]" 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_DRAW inherit DOOMDEF_H create make feature i_main: I_MAIN make (a_i_main: like i_main) do i_main := a_i_main create ylookup.make_filled (create {PIXEL_T_BUFFER}.make (1), 0, Maxheight - 1) end feature Sbarheight: INTEGER_32 = 32 -- status bar height at bottom of screen background_buffer: detachable PIXEL_T_BUFFER feature -- ? Maxwidth: INTEGER_32 = 1120 Maxheight: INTEGER_32 = 832 feature columnofs: ARRAY [INTEGER_32] attribute create Result.make_filled (0, 0, Maxwidth - 1) end ylookup: ARRAY [PIXEL_T_BUFFER] feature r_inittranslationtables -- Creates the translation tables to map -- the green color rmap to gray, brown, red. -- Assumes a given structure of the PLAYPAL. -- Could be read from a lump instead. local i: INTEGER_32 do create translationtables.make_filled (0, 0, 256 * 3 + 255 - 1) from i := 0 until i >= 256 loop check attached translationtables as tt then if i >= 112 and i <= 127 then tt [i] := (96 + (i & 15)).to_natural_16 tt [i + 256] := (64 + (i & 15)).to_natural_16 tt [i + 512] := (32 + (i & 15)).to_natural_16 else tt [i] := i.to_natural_16 tt [i + 256] := i.to_natural_16 tt [i + 512] := i.to_natural_16 end end i := i + 1 end end feature viewwidth: INTEGER_32 assign set_viewwidth set_viewwidth (a_viewwidth: like viewwidth) do viewwidth := a_viewwidth end scaledviewwidth: INTEGER_32 assign set_scaledviewwidth set_scaledviewwidth (a_scaledviewwidth: like scaledviewwidth) do scaledviewwidth := a_scaledviewwidth end viewheight: INTEGER_32 assign set_viewheight set_viewheight (a_viewheight: like viewheight) do viewheight := a_viewheight end viewwindowx: INTEGER_32 viewwindowy: INTEGER_32 feature -- R_DrawColumn dc_colormap: detachable INDEX_IN_ARRAY [LIGHTTABLE_T] assign set_dc_colormap set_dc_colormap (a_dc_colormap: like dc_colormap) do dc_colormap := a_dc_colormap end dc_x: INTEGER_32 assign set_dc_x set_dc_x (a_dc_x: like dc_x) do dc_x := a_dc_x end dc_yl: INTEGER_32 assign set_dc_yl set_dc_yl (a_dc_yl: like dc_yl) do dc_yl := a_dc_yl end dc_yh: INTEGER_32 assign set_dc_yh set_dc_yh (a_dc_yh: like dc_yh) do dc_yh := a_dc_yh end dc_iscale: FIXED_T assign set_dc_iscale set_dc_iscale (a_dc_iscale: like dc_iscale) do dc_iscale := a_dc_iscale end dc_texturemid: FIXED_T assign set_dc_texturemid set_dc_texturemid (a_dc_texturemid: like dc_texturemid) do dc_texturemid := a_dc_texturemid end dc_source: detachable BYTE_SEQUENCE assign set_dc_source -- first pixel in a column (possibly virtual) set_dc_source (a_dc_source: like dc_source) do dc_source := a_dc_source end dccount: INTEGER_32 -- just for profiling r_drawcolumn -- A column is a vertical slice/span from a wall texture that, -- given the DOOM style restrictions on the view orientation, -- will always have constant z depth. -- Thus a special case loop for very fast rendering can be used. -- It has also been used with Wolfenshtein 3D. require rangecheck: dc_x < Screenwidth and dc_yl >= 0 and dc_yh < Screenheight local count: INTEGER_32 dest: PIXEL_T_BUFFER ofs: INTEGER_32 frac: FIXED_T fracstep: FIXED_T val: NATURAL_8 dc_source_val: INTEGER_32 i: INTEGER_32 do count := dc_yh - dc_yl if count >= 0 then dest := ylookup [dc_yl] ofs := columnofs [dc_x] fracstep := dc_iscale frac := dc_texturemid + create {FIXED_T}.from_integer ((dc_yl - i_main.R_main.centery) * fracstep.as_integer_32) from count := count + 1 until count <= 0 loop check attached dc_source as dcs then i := (frac |>> {M_FIXED}.fracbits) & create {FIXED_T}.from_integer (127).as_integer_32 if dcs.valid_index (i) then dc_source_val := dcs [i].to_integer_32 else print ("R_DrawColumn: dc_source read out of bounds [" + i.out + "]%N") dc_source_val := 0 end end check attached dc_colormap as dc_cmap then val := dc_cmap [dc_source_val].to_natural_8 end dest.put (val, ofs) ofs := ofs + Screenwidth frac := frac + fracstep count := count - 1 end end end feature r_fillbackscreen -- Fills the back screen with a pattern -- for variable screen sizes -- Also draws a beveled edge. local src: PIXEL_T_BUFFER dest: PIXEL_T_BUFFER border_patch: MANAGED_POINTER x, y: INTEGER_32 patch: PATCH_T name1: STRING_8 name2: STRING_8 name: STRING_8 do name1 := "FLOOR7_2" name2 := "GRNROCK" if scaledviewwidth = Screenwidth then if background_buffer /= Void then background_buffer := Void end else if background_buffer = Void then create background_buffer.make (Screenwidth * (Screenheight - Sbarheight)) end if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then name := name2 else name := name1 end border_patch := i_main.W_wad.w_cachelumpname (name) create src.share_from_pointer (border_patch.item, border_patch.count) dest := background_buffer check attached dest then from y := 0 until y >= Screenheight - Sbarheight loop from x := 0 until x >= Screenwidth // 64 loop dest.copy_from_count (src + ((y & 63) |<< 6), 64) dest := dest + 64 x := x + 1 end if Screenwidth & 63 /= 0 then dest.copy_from_count (src + ((y & 63) |<< 6), Screenwidth & 63) dest := dest + (Screenwidth & 63) end y := y + 1 end end check attached background_buffer as bb then i_main.V_video.v_usebuffer (bb) end patch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_t")) from x := 0 until x >= scaledviewwidth loop i_main.V_video.v_drawpatch (viewwindowx + x, viewwindowy - 8, patch) x := x + 8 end patch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_b")) from x := 0 until x >= scaledviewwidth loop i_main.V_video.v_drawpatch (viewwindowx + x, viewwindowy + viewheight, patch) x := x + 8 end patch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_l")) from y := 0 until y >= viewheight loop i_main.V_video.v_drawpatch (viewwindowx - 8, viewwindowy + y, patch) y := y + 8 end patch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_r")) from y := 0 until y >= viewheight loop i_main.V_video.v_drawpatch (viewwindowx + scaledviewwidth, viewwindowy + y, patch) y := y + 8 end i_main.V_video.v_drawpatch (viewwindowx - 8, viewwindowy - 8, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_tl"))) i_main.V_video.v_drawpatch (viewwindowx + scaledviewwidth, viewwindowy - 8, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_tr"))) i_main.V_video.v_drawpatch (viewwindowx - 8, viewwindowy + viewheight, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_bl"))) i_main.V_video.v_drawpatch (viewwindowx + scaledviewwidth, viewwindowy + viewheight, create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpname ("brdr_br"))) i_main.V_video.v_restorebuffer end end r_videoerase (ofs: INTEGER_32; count: INTEGER_32) -- Copy a screen buffer -- -- ofs was originally unsigned do if attached background_buffer as bb then (i_main.I_video.i_videobuffer + ofs).copy_from_count (bb + ofs, count) end end r_drawviewborder -- Draws the border around the view -- for different size windows? local top: INTEGER_32 side: INTEGER_32 ofs: INTEGER_32 i: INTEGER_32 do if scaledviewwidth = Screenwidth then else top := ((Screenheight - Sbarheight) - viewheight) // 2 side := (Screenwidth - scaledviewwidth) // 2 r_videoerase (0, top * Screenwidth + side) ofs := (viewheight + top) * Screenwidth - side r_videoerase (ofs, top * Screenwidth + side) ofs := top * Screenwidth + Screenwidth - side side := side |<< 1 from i := 1 until i >= viewheight loop r_videoerase (ofs, side) ofs := ofs + Screenwidth i := i + 1 end i_main.V_video.v_markrect (0, 0, Screenwidth, Screenheight - Sbarheight) end end feature -- R_DrawTranslatedColumn dc_translation: detachable INDEX_IN_ARRAY [NATURAL_16] assign set_dc_translation set_dc_translation (a_dc_translation: like dc_translation) do dc_translation := a_dc_translation end translationtables: detachable ARRAY [NATURAL_16] r_drawtranslatedcolumn -- Used to draw player sprites -- with the green colorramp mapped to others. -- Could be used with different translation -- tables, e.g. the lighter colored version -- of the BaronOfHell, the HellKnight, uses -- identical sprites, kinda brightened up. require rangecheck: dc_x < Screenwidth and dc_yl >= 0 and dc_yh < Screenheight local count: INTEGER_32 dest: PIXEL_T_BUFFER frac: FIXED_T fracstep: FIXED_T do count := dc_yh - dc_yl if count >= 0 then check rangecheck: dc_x < Screenwidth and dc_yl >= 0 and dc_yh < Screenheight end dest := ylookup [dc_yl] + columnofs [dc_x] fracstep := dc_iscale frac := dc_texturemid + create {FIXED_T}.from_integer ((dc_yl - i_main.R_main.centery) * fracstep.as_integer_32) from count := count + 1 until count = 0 loop check attached dc_colormap as dcc and then attached dc_translation as dct and then attached dc_source as dcs then dest.put (dcc [dct [dcs [frac |>> {M_FIXED}.fracbits.as_integer_32].to_integer_32].to_integer_32].to_natural_8, 0) end dest := dest + Screenwidth frac := frac + fracstep count := count - 1 end end end feature -- R_DrawSpan ds_xstep: FIXED_T assign set_ds_xstep set_ds_xstep (a_ds_xstep: like ds_xstep) do ds_xstep := a_ds_xstep end ds_ystep: FIXED_T assign set_ds_ystep set_ds_ystep (a_ds_ystep: like ds_ystep) do ds_ystep := a_ds_ystep end ds_xfrac: FIXED_T assign set_ds_xfrac set_ds_xfrac (a_ds_xfrac: like ds_xfrac) do ds_xfrac := a_ds_xfrac end ds_yfrac: FIXED_T assign set_ds_yfrac set_ds_yfrac (a_ds_yfrac: like ds_yfrac) do ds_yfrac := a_ds_yfrac end ds_colormap: detachable INDEX_IN_ARRAY [LIGHTTABLE_T] assign set_ds_colormap -- lighttable_t* set_ds_colormap (a_ds_colormap: like ds_colormap) do ds_colormap := a_ds_colormap end ds_y: INTEGER_32 assign set_ds_y set_ds_y (a_ds_y: like ds_y) do ds_y := a_ds_y end ds_x1: INTEGER_32 assign set_ds_x1 set_ds_x1 (a_ds_x1: like ds_x1) do ds_x1 := a_ds_x1 end ds_x2: INTEGER_32 assign set_ds_x2 set_ds_x2 (a_ds_x2: like ds_x2) do ds_x2 := a_ds_x2 end ds_source: detachable MANAGED_POINTER_WITH_OFFSET assign set_ds_source set_ds_source (a_ds_source: like ds_source) do ds_source := a_ds_source end r_drawspan -- Draws the actual span require rangecheck: ds_x2 >= ds_x1 and ds_x1 >= 0 and ds_x2 < Screenwidth and ds_y <= Screenheight local xfrac: FIXED_T yfrac: FIXED_T dest: PIXEL_T_BUFFER ofs: INTEGER_32 count: INTEGER_32 spot: INTEGER_32 ds_source_val: INTEGER_32 do xfrac := ds_xfrac yfrac := ds_yfrac dest := ylookup [ds_y] ofs := columnofs [ds_x1] count := ds_x2 - ds_x1 from count := count + 1 until count = 0 loop spot := (((yfrac |>> (16 - 6)) & create {FIXED_T}.from_integer ((63 * 64))) + ((xfrac |>> 16) & create {FIXED_T}.from_integer (63))).to_integer_32 check attached ds_source as src then ds_source_val := src [spot].to_integer_32 end check attached ds_colormap as dsc then dest.put (dsc [ds_source_val].to_natural_8, ofs) ofs := ofs + 1 end xfrac := xfrac + ds_xstep yfrac := yfrac + ds_ystep count := count - 1 end end feature r_drawcolumnlow require rangecheck: dc_x < Screenwidth and dc_yl >= 0 and dc_yh < Screenheight do {NOT_IMPLEMENTED}.not_implemented ("R_DrawColumnLow", True) end r_drawfuzzcolumn require rangecheck: dc_x < Screenwidth and dc_yl >= 0 and dc_yh < Screenheight do {NOT_IMPLEMENTED}.not_implemented ("R_DrawFuzzColumn", True) end r_drawspanlow require rangecheck: ds_x2 >= ds_x1 and ds_x1 >= 0 and ds_x2 < Screenwidth and ds_y <= Screenheight do {NOT_IMPLEMENTED}.not_implemented ("R_DrawSpanLow", True) end feature r_initbuffer (width, height: INTEGER_32) local i: INTEGER_32 ofs: INTEGER_32 left: INTEGER_32 do viewwindowx := (Screenwidth - width) |>> 1 from i := 0 until i >= width loop columnofs [i] := viewwindowx + i i := i + 1 end if width = Screenwidth then viewwindowy := 0 else viewwindowy := (Screenheight - Sbarheight - height) |>> 1 end from i := 0 until i >= height loop ofs := (i + viewwindowy) * Screenwidth left := i_main.I_video.i_videobuffer.p.count - ofs check left > 0 end ylookup [i] := create {PIXEL_T_BUFFER}.share_from_pointer (i_main.I_video.i_videobuffer.p.item + ofs, left) i := i + 1 end end invariant ylookup.lower = 0 ylookup.count = Maxheight end -- class R_DRAW
Generated by ISE EiffelStudio