note
	description: "[
		r_data.c
		Preparation for data rendering,
		generation of lookups, caching, retrieval by name.
	]"
	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_DATA

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
			create colormaps.make_empty
			create textures.make_empty
			create flattranslation.make_empty
			create texturetranslation.make_empty
			create textureheight.make_empty
			create texturewidthmask.make_empty
		end
	
feature 

	colormaps: ARRAY [LIGHTTABLE_T]

	numtextures: INTEGER_32

	textures: ARRAY [TEXTURE_T]

	firstflat: INTEGER_32

	lastflat: INTEGER_32

	numflats: INTEGER_32

	flattranslation: ARRAY [INTEGER_32]

	texturetranslation: ARRAY [INTEGER_32]

	textureheight: ARRAY [INTEGER_32]

	texturewidthmask: ARRAY [INTEGER_32]

	texturecolumnlump: detachable ARRAY [detachable ARRAY [INTEGER_16]]

	texturecolumnofs: detachable ARRAY [detachable ARRAY [NATURAL_16]]

	texturecomposite: detachable ARRAY [detachable MANAGED_POINTER]

	texturecompositesize: detachable ARRAY [INTEGER_32]

	firstspritelump: INTEGER_32

	lastspritelump: INTEGER_32

	numspritelumps: INTEGER_32

	spritewidth: detachable ARRAY [FIXED_T]

	spriteoffset: detachable ARRAY [FIXED_T]

	spritetopoffset: detachable ARRAY [FIXED_T]
	
feature 

	r_inittextures
			-- Initializes the texture list
			-- with the textures from the world map.
		local
			i: INTEGER_32
			j: INTEGER_32
			maptex1: TEXTUREX
			maptex2: TEXTUREX
			names: PNAMES
			patchlookup: ARRAY [INTEGER_32]
		do
			create names.from_pointer (i_main.W_wad.w_cachelumpname ("PNAMES"))
			create patchlookup.make_filled (0, 0, names.names.count - 1)
			from
				i := 0
			until
				i > names.names.upper
			loop
				patchlookup [i] := i_main.W_wad.w_checknumforname (names.names [i])
				i := i + 1
			variant
					names.names.upper - i + 1
			end
			create maptex1.from_pointer (i_main.W_wad.w_cachelumpname ("TEXTURE1"))
			numtextures := maptex1.textures.count
			if i_main.W_wad.w_checknumforname ("TEXTURE2") /= -1 then
				create maptex2.from_pointer (i_main.W_wad.w_cachelumpname ("TEXTURE2"))
				numtextures := numtextures + maptex2.textures.count
			end
			create textures.make_filled (create {TEXTURE_T}.make, 0, numtextures - 1)
			create texturewidthmask.make_filled (0, 0, numtextures - 1)
			create textureheight.make_filled (0, 0, numtextures - 1)
			create texturecolumnlump.make_filled (Void, 0, numtextures - 1)
			create texturecomposite.make_filled (Void, 0, numtextures - 1)
			create texturecompositesize.make_filled (0, 0, numtextures - 1)
			create texturecolumnofs.make_filled (Void, 0, numtextures - 1)
			from
				i := 0
			until
				i >= maptex1.textures.count
			loop
				textures [i] := create {TEXTURE_T}.make_from_maptexture_t (maptex1.textures [i], patchlookup)
				i := i + 1
			end
			if attached maptex2 as m2 then
				from
					j := 0
				until
					j >= m2.textures.count
				loop
					textures [i] := create {TEXTURE_T}.make_from_maptexture_t (m2.textures [j], patchlookup)
					i := i + 1
					j := j + 1
				end
			end
			from
				i := textures.lower
			until
				i > textures.upper
			loop
				check
						attached texturecolumnlump as tcl
				then
					tcl [i] := create {ARRAY [INTEGER_16]}.make_filled (0, 0, textures [i].width - 1.to_integer_32)
				end
				check
						attached texturecolumnofs as tco
				then
					tco [i] := create {ARRAY [NATURAL_16]}.make_filled (0, 0, textures [i].width - 1.to_integer_32)
				end
				from
					j := 1
				until
					j * 2 > textures [i].width.to_integer_32
				loop
					j := j |<< 1
				end
				texturewidthmask [i] := j - 1
				textureheight [i] := textures [i].height.to_integer_32 |<< {M_FIXED}.fracbits
				i := i + 1
			end
			from
				i := 0
			until
				i >= numtextures
			loop
				r_generatelookup (i)
				i := i + 1
			end
			create texturetranslation.make_filled (0, 0, numtextures + 1)
			from
				i := 0
			until
				i >= numtextures
			loop
				texturetranslation [i] := i
				i := i + 1
			end
		ensure
				not texturetranslation.is_empty
				not texturewidthmask.is_empty
		end

	r_generatelookup (texnum: INTEGER_32)
		local
			texture: TEXTURE_T
			patchcount: ARRAY [INTEGER_32]
			patch: INTEGER_32
			realpatch: PATCH_T
			x: INTEGER_32
			x1: INTEGER_32
			x2: INTEGER_32
			i: INTEGER_32
			collump: ARRAY [INTEGER_16]
			colofs: ARRAY [NATURAL_16]
		do
			texture := textures [texnum]
			check
					attached texturecomposite as tc
			then
				tc [texnum] := Void
			end
			check
					attached texturecompositesize as tcs
			then
				tcs [texnum] := 0
			end
			check
					attached texturecolumnlump as tcl
			then
				collump := tcl [texnum]
			end
			check
					attached texturecolumnofs as tcofs
			then
				check
						attached tcofs [texnum] as tcofs_texnum
				then
					colofs := tcofs [texnum]
				end
			end
			create patchcount.make_filled (0, 0, texture.width - 1.to_integer_32)
			from
				i := 0
				patch := 0
			until
				i >= texture.patches.count
			loop
				realpatch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpnum (texture.patches [patch].patch))
				x1 := texture.patches [patch].originx
				x2 := x1 + realpatch.width.to_integer_32
				if x1 < 0 then
					x := 0
				else
					x := x1
				end
				if x2 > texture.width.to_integer_32 then
					x2 := texture.width.to_integer_32
				end
				from
				until
					x >= x2
				loop
					patchcount [x] := patchcount [x] + 1
					check
							attached collump as cl
					then
						collump [x] := texture.patches [patch].patch.to_integer_16
					end
					check
							attached colofs
					then
						colofs [x] := (realpatch.columnofs [x - x1] + 3).to_natural_16
					end
					x := x + 1
				end
				i := i + 1
				patch := patch + 1
			end
			from
				x := 0
			until
				x >= texture.width.to_integer_32
			loop
				if patchcount [x] = 0 then
					print ("R_GenerateLookup: column without a patch (" + texture.name + ")%N")
					x := texture.width.to_integer_32
				elseif patchcount [x] > 1 then
					check
							attached collump as cl
					then
						cl [x] := -1
					end
					check
							attached texturecompositesize as tcs
					then
						check
								attached colofs
						then
							colofs [x] := tcs [texnum].to_natural_16
						end
						if tcs [texnum] > 65536 - texture.height.to_integer_32 then
							{I_MAIN}.i_error ("R_GenerateLookup: texture " + texnum.out + " is > 64k")
						end
						tcs [texnum] := tcs [texnum] + texture.height.to_integer_32
					end
				end
				x := x + 1
			end
		end

	r_initflats
		local
			i: INTEGER_32
		do
			firstflat := i_main.W_wad.w_getnumforname ("F_START") + 1
			lastflat := i_main.W_wad.w_getnumforname ("F_END") - 1
			numflats := lastflat - firstflat + 1
			create flattranslation.make_filled (0, 0, numflats + 1)
			from
				i := 0
			until
				i >= numflats
			loop
				flattranslation [i] := i
				i := i + 1
			end
		end

	r_initspritelumps
			-- Finds the width and hoffset of all sprites in the wad,
			-- so the sprite does not need to be cached completely
			-- just for having the header info ready during rendering.
		local
			i: INTEGER_32
			patch: PATCH_T
		do
			print ("R_InitSpriteLumps%N")
			firstspritelump := i_main.W_wad.w_getnumforname ("S_START") + 1
			lastspritelump := i_main.W_wad.w_getnumforname ("S_END") - 1
			numspritelumps := lastspritelump - firstspritelump + 1
			create spritewidth.make_filled (create {FIXED_T}.from_integer (0), 0, numspritelumps - 1)
			create spriteoffset.make_filled (create {FIXED_T}.from_integer (0), 0, numspritelumps - 1)
			create spritetopoffset.make_filled (create {FIXED_T}.from_integer (0), 0, numspritelumps - 1)
			from
				i := 0
			until
				i >= numspritelumps
			loop
				patch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpnum (firstspritelump + i))
				check
						attached spritewidth as sw and then attached spriteoffset as so and then attached spritetopoffset as st
				then
					sw [i] := create {FIXED_T}.from_integer (patch.width.to_integer_32 |<< {M_FIXED}.fracbits)
					so [i] := create {FIXED_T}.from_integer (patch.leftoffset.to_integer_32 |<< {M_FIXED}.fracbits)
					st [i] := create {FIXED_T}.from_integer (patch.topoffset.to_integer_32 |<< {M_FIXED}.fracbits)
				end
				i := i + 1
			end
		end

	r_initcolormaps
		local
			i: INTEGER_32
			lump, length: INTEGER_32
			p: MANAGED_POINTER
		do
			lump := i_main.W_wad.w_getnumforname ("COLORMAP")
			length := i_main.W_wad.w_lumplength (lump)
			create colormaps.make_filled (create {LIGHTTABLE_T}.from_natural_8 ({NATURAL_8} 0), 0, length - 1)
			p := i_main.W_wad.w_readlump (lump)
			from
				i := 0
			until
				i > colormaps.upper
			loop
				colormaps [i] := create {LIGHTTABLE_T}.from_natural_8 (p.read_natural_8_le (i))
				i := i + 1
			end
		end

	r_initdata
		do
			r_inittextures
			print ("%NInitTextures")
			r_initflats
			print ("%NInitFlats")
			r_initspritelumps
			print ("%NInitSprites")
			r_initcolormaps
			print ("%NInitColormaps")
		end

	r_texturenumforname (name: STRING_8): INTEGER_32
			-- Calls R_CheckTextureForName,
			-- aborts with error message
		do
			Result := r_checktexturenumforname (name)
			if Result = -1 then
				{I_MAIN}.i_error ("R_TextureNumForName: " + name + " not found%N")
			end
		end

	r_checktexturenumforname (name: STRING_8): INTEGER_32
			-- Check whether texture is available.
			-- Filter out NoTexture indicator.
		do
			if name.starts_with ("-") then
				Result := 0
			else
				from
					Result := 0
				until
					Result >= numtextures or else textures [Result].name.as_upper ~ name.as_upper
				loop
					Result := Result + 1
				end
				if Result >= numtextures then
					Result := -1
				end
			end
		end

	r_flatnumforname (name: STRING_8): INTEGER_32
			-- Retrieval, get a flat number for a flat name.
		do
			Result := i_main.W_wad.w_checknumforname (name)
			if Result = -1 then
				{I_MAIN}.i_error ("R_FlatNumForName: " + name + " not found%N")
			end
			Result := Result - firstflat
		end

	r_precachelevel
		do
			{NOT_IMPLEMENTED}.not_implemented ("R_PrecacheLevel", False)
		end

	r_getcolumn (tex, a_col: INTEGER_32): MANAGED_POINTER_WITH_OFFSET
		local
			lump: INTEGER_32
			ofs: INTEGER_32
			col: INTEGER_32
		do
			col := a_col
			col := col & texturewidthmask [tex]
			check
					attached texturecolumnlump as tcl
			then
				check
						attached tcl [tex] as tcl_tex
				then
					check
							attached tcl_tex [col] as tcl_tex_col
					then
						lump := tcl_tex_col.to_integer_32
					end
				end
			end
			check
					attached texturecolumnofs as tcofs
			then
				check
						attached tcofs [tex] as tcofs_tex
				then
					ofs := tcofs_tex [col].to_integer_32
				end
			end
			if lump > 0 then
				create Result.make (i_main.W_wad.w_cachelumpnum (lump), ofs)
			else
				check
						attached texturecomposite as tc_ar
				then
					if tc_ar [tex] = Void then
						r_generatecomposite (tex)
					end
					check
							attached tc_ar [tex] as tc
					then
						create Result.make (tc, ofs)
					end
				end
			end
		end

	r_generatecomposite (texnum: INTEGER_32)
			-- Using the texture definition,
			-- the composite texture is created from the patches,
			-- and each column is cached
		local
			block: MANAGED_POINTER
			texture: TEXTURE_T
			patch: INTEGER_32
			realpatch: PATCH_T
			x: INTEGER_32
			x1: INTEGER_32
			x2: INTEGER_32
			i: INTEGER_32
			collump: ARRAY [INTEGER_16]
			colofs: ARRAY [NATURAL_16]
		do
			texture := textures [texnum]
			check
					attached texturecompositesize as tcs
			then
				check
						attached texturecomposite as tc
				then
					block := create {MANAGED_POINTER}.make (tcs [texnum])
					tc [texnum] := block
				end
			end
			check
					attached texturecolumnlump as tcl
			then
				collump := tcl [texnum]
			end
			check
					attached texturecolumnofs as tcofs
			then
				check
						attached tcofs [texnum] as tcofs_texnum
				then
					colofs := tcofs_texnum
				end
			end
			from
				i := 0
				patch := 0
			until
				i >= texture.patches.count
			loop
				realpatch := create {PATCH_T}.from_pointer (i_main.W_wad.w_cachelumpnum (texture.patches [patch].patch))
				x1 := texture.patches [patch].originx
				x2 := x1 + realpatch.width.to_integer_32
				if x1 < 0 then
					x := 0
				else
					x := x1
				end
				if x2 > texture.width.to_integer_32 then
					x2 := texture.width.to_integer_32
				end
				from
				until
					x >= x2
				loop
					check
							attached collump
					then
						if collump [x] >= 0 then
						else
							r_drawcolumnincache (realpatch, x - x1, block, colofs [x].to_integer_32, texture.patches [patch].originy, texture.height.to_integer_32)
						end
					end
					x := x + 1
				end
				i := i + 1
				patch := patch + 1
			end
		end

	r_drawcolumnincache (real_patch: PATCH_T; col_num: INTEGER_32; cache: MANAGED_POINTER; cache_ofs: INTEGER_32; originy: INTEGER_32; cacheheight: INTEGER_32)
		local
			count: INTEGER_32
			position: INTEGER_32
			source: ARRAY [NATURAL_8]
			column: COLUMN_T
			post_num: INTEGER_32
		do
			from
				column := real_patch.columns [col_num + 1]
				post_num := 1
			until
				post_num > column.posts.upper
			loop
				source := column.posts [post_num].body
				count := column.posts [post_num].length.to_integer_32
				position := originy + column.posts [post_num].topdelta.to_integer_32
				if position < 0 then
					count := count + position
					position := 0
				end
				if position + count > cacheheight then
					count := cacheheight - position
				end
				if count > 0 then
					cache.put_array (source.subarray (0, count - 1), cache_ofs + position)
				end
				post_num := post_num + 1
			end
		end
	
end -- class R_DATA

Generated by ISE EiffelStudio