doom 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Doom
4
- # TextureLoader is responsible for loading and parsing texture data from a WAD file
5
- class TextureLoader
6
- attr_reader :textures, :patch_names
7
-
8
- # Initialize a new TextureLoader with the given WADLoader
9
- # @param wad_loader [WADLoader] the WAD loader to use
10
- def initialize(wad_loader)
11
- @wad_loader = wad_loader
12
- @textures = {}
13
- @patch_names = []
14
- load_patch_names
15
- load_textures
16
- end
17
-
18
- # Load the PNAMES lump which contains patch names
19
- def load_patch_names
20
- pnames_data = @wad_loader.get_lump("PNAMES")
21
- return unless pnames_data
22
-
23
- # First 4 bytes is the number of patch names
24
- num_patches = pnames_data[0..3].unpack("V")[0]
25
-
26
- # Each patch name is 8 bytes
27
- num_patches.times do |i|
28
- offset = 4 + (i * 8)
29
- patch_name = pnames_data[offset..offset + 7].unpack("Z*")[0]
30
- @patch_names << patch_name
31
- end
32
- end
33
-
34
- # Load the TEXTURE1 and TEXTURE2 lumps which contain texture definitions
35
- def load_textures
36
- load_texture_lump("TEXTURE1")
37
- load_texture_lump("TEXTURE2")
38
- end
39
-
40
- # Load a specific texture lump
41
- # @param lump_name [String] the name of the texture lump (TEXTURE1 or TEXTURE2)
42
- def load_texture_lump(lump_name)
43
- texture_data = @wad_loader.get_lump(lump_name)
44
- return unless texture_data
45
-
46
- # First 4 bytes is the number of textures
47
- num_textures = texture_data[0..3].unpack("V")[0]
48
-
49
- # Next num_textures * 4 bytes are offsets to each texture definition
50
- offsets = []
51
- num_textures.times do |i|
52
- offset = 4 + (i * 4)
53
- texture_offset = texture_data[offset..offset + 3].unpack("V")[0]
54
- offsets << texture_offset
55
- end
56
-
57
- # Parse each texture definition
58
- offsets.each do |offset|
59
- parse_texture_definition(texture_data, offset)
60
- end
61
- end
62
-
63
- # Parse a texture definition
64
- # @param texture_data [String] the texture lump data
65
- # @param offset [Integer] the offset to the texture definition
66
- def parse_texture_definition(texture_data, offset)
67
- # Texture definition structure:
68
- # - 8 bytes: texture name
69
- # - 4 bytes: flags (unused)
70
- # - 2 bytes: width
71
- # - 2 bytes: height
72
- # - 4 bytes: column directory (unused)
73
- # - 2 bytes: number of patches
74
- # - patches: array of patch definitions
75
-
76
- texture_name = texture_data[offset..offset + 7].unpack("Z*")[0]
77
- # Skip flags (4 bytes)
78
- width = texture_data[offset + 12..offset + 13].unpack("v")[0]
79
- height = texture_data[offset + 14..offset + 15].unpack("v")[0]
80
- # Skip column directory (4 bytes)
81
- num_patches = texture_data[offset + 20..offset + 21].unpack("v")[0]
82
-
83
- patches = []
84
-
85
- # Parse each patch definition
86
- num_patches.times do |i|
87
- patch_offset = offset + 22 + (i * 10)
88
-
89
- # Patch definition structure:
90
- # - 2 bytes: x offset
91
- # - 2 bytes: y offset
92
- # - 2 bytes: patch number (index into PNAMES)
93
- # - 2 bytes: step dir (unused)
94
- # - 2 bytes: color map (unused)
95
-
96
- x_offset = texture_data[patch_offset..patch_offset + 1].unpack("s<")[0]
97
- y_offset = texture_data[patch_offset + 2..patch_offset + 3].unpack("s<")[0]
98
- patch_num = texture_data[patch_offset + 4..patch_offset + 5].unpack("v")[0]
99
-
100
- patch_name = @patch_names[patch_num] if patch_num < @patch_names.size
101
-
102
- patches << {
103
- x_offset: x_offset,
104
- y_offset: y_offset,
105
- patch_num: patch_num,
106
- patch_name: patch_name
107
- }
108
- end
109
-
110
- @textures[texture_name] = {
111
- name: texture_name,
112
- width: width,
113
- height: height,
114
- patches: patches
115
- }
116
- end
117
-
118
- # Get a specific texture by name
119
- # @param name [String] the name of the texture
120
- # @return [Hash, nil] the texture data or nil if not found
121
- def get_texture(name)
122
- @textures[name]
123
- end
124
-
125
- # List all texture names
126
- # @return [Array<String>] array of texture names
127
- def texture_names
128
- @textures.keys
129
- end
130
-
131
- # Check if a texture exists
132
- # @param name [String] the name of the texture
133
- # @return [Boolean] true if the texture exists
134
- def texture_exists?(name)
135
- @textures.key?(name)
136
- end
137
- end
138
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Doom
4
- # TextureMapper is responsible for mapping textures onto walls
5
- class TextureMapper
6
- attr_reader :texture_loader
7
-
8
- # Initialize a new TextureMapper with the given texture loader
9
- # @param texture_loader [Doom::TextureLoader] the texture loader to use
10
- def initialize(texture_loader)
11
- @texture_loader = texture_loader
12
- @textures = {}
13
- end
14
-
15
- # Load a specific texture
16
- # @param texture_name [String] the name of the texture to load
17
- # @return [Hash, nil] the texture data or nil if not found
18
- def load_texture(texture_name)
19
- return @textures[texture_name] if @textures.key?(texture_name)
20
-
21
- texture_data = @texture_loader.get_texture(texture_name)
22
- return nil unless texture_data
23
-
24
- # In a real implementation, this would convert the texture data
25
- # into a format that can be efficiently rendered
26
- @textures[texture_name] = texture_data
27
- end
28
-
29
- # Map a texture onto a wall
30
- # @param texture_name [String] the name of the texture to map
31
- # @param x [Integer] the x coordinate to start mapping
32
- # @param y [Integer] the y coordinate to start mapping
33
- # @param width [Integer] the width of the wall
34
- # @param height [Integer] the height of the wall
35
- # @param u_offset [Integer] the u offset into the texture
36
- # @param v_offset [Integer] the v offset into the texture
37
- # @param window [Doom::Window] the window to render to
38
- def map_texture(texture_name, x, y, width, height, u_offset, v_offset, window)
39
- texture = load_texture(texture_name)
40
- return unless texture
41
-
42
- # In a real implementation, this would:
43
- # 1. Calculate the texture coordinates for each pixel of the wall
44
- # 2. Sample the texture at those coordinates
45
- # 3. Draw the resulting pixel to the screen
46
-
47
- # For now, we'll just draw a placeholder rectangle
48
- color = Gosu::Color.new(255, 128, 128, 128) # Semi-transparent gray
49
- window.draw_quad(
50
- x, y, color,
51
- x + width, y, color,
52
- x + width, y + height, color,
53
- x, y + height, color
54
- )
55
- end
56
- end
57
- end
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Doom
4
- # WADLoader is responsible for loading and parsing WAD files
5
- class WADLoader
6
- # WAD file header structure:
7
- # - 4 bytes: WAD type (IWAD or PWAD)
8
- # - 4 bytes: number of lumps
9
- # - 4 bytes: directory offset
10
- HEADER_SIZE = 12
11
-
12
- # Directory entry structure:
13
- # - 4 bytes: lump offset
14
- # - 4 bytes: lump size
15
- # - 8 bytes: lump name (null-terminated)
16
- DIRECTORY_ENTRY_SIZE = 16
17
-
18
- attr_reader :wad_type, :lumps, :directory, :filename, :num_lumps
19
-
20
- # Initialize a new WADLoader with the given WAD file
21
- # @param filename [String] path to the WAD file
22
- def initialize(filename)
23
- @filename = filename
24
- @lumps = {}
25
- @directory = []
26
- load_wad
27
- end
28
-
29
- # Load and parse the WAD file
30
- def load_wad
31
- File.open(@filename, "rb") do |file|
32
- read_header(file)
33
- read_directory(file)
34
- load_lumps(file)
35
- end
36
- end
37
-
38
- # Read the WAD file header
39
- # @param file [File] the WAD file
40
- def read_header(file)
41
- header = file.read(HEADER_SIZE)
42
- @wad_type = header[0..3]
43
- @num_lumps = header[4..7].unpack("V")[0]
44
- directory_offset = header[8..11].unpack("V")[0]
45
-
46
- # Validate WAD type
47
- unless ["IWAD", "PWAD"].include?(@wad_type)
48
- raise Error, "Invalid WAD type: #{@wad_type}"
49
- end
50
-
51
- # Seek to the directory
52
- file.seek(directory_offset)
53
- end
54
-
55
- # Read the WAD directory
56
- # @param file [File] the WAD file
57
- def read_directory(file)
58
- # The file position should already be at the directory after read_header
59
- # We'll use the number of lumps from the instance variable
60
-
61
- @num_lumps.times do
62
- entry = file.read(DIRECTORY_ENTRY_SIZE)
63
- lump_offset = entry[0..3].unpack("V")[0]
64
- lump_size = entry[4..7].unpack("V")[0]
65
- lump_name = entry[8..15].unpack("Z*")[0]
66
-
67
- @directory << {
68
- name: lump_name,
69
- offset: lump_offset,
70
- size: lump_size
71
- }
72
- end
73
- end
74
-
75
- # Load all lumps from the WAD file
76
- # @param file [File] the WAD file
77
- def load_lumps(file)
78
- @directory.each do |entry|
79
- next if entry[:size] == 0 # Skip markers
80
-
81
- file.seek(entry[:offset])
82
- @lumps[entry[:name]] = file.read(entry[:size])
83
- end
84
- end
85
-
86
- # Get a specific lump by name
87
- # @param name [String] the name of the lump
88
- # @return [String, nil] the lump data or nil if not found
89
- def get_lump(name)
90
- @lumps[name]
91
- end
92
-
93
- # List all lump names
94
- # @return [Array<String>] array of lump names
95
- def lump_names
96
- @lumps.keys
97
- end
98
-
99
- # Check if a lump exists
100
- # @param name [String] the name of the lump
101
- # @return [Boolean] true if the lump exists
102
- def lump_exists?(name)
103
- @lumps.key?(name)
104
- end
105
- end
106
- end
data/lib/doom/window.rb DELETED
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "gosu"
4
-
5
- module Doom
6
- # Window class for managing the game window
7
- class Window < Gosu::Window
8
- attr_reader :width, :height
9
- attr_accessor :game
10
-
11
- # Initialize a new Window with the given width and height
12
- # @param width [Integer] the width of the window
13
- # @param height [Integer] the height of the window
14
- # @param fullscreen [Boolean] whether the window should be fullscreen
15
- def initialize(width = 640, height = 480, fullscreen = false)
16
- super(width, height, fullscreen)
17
- @width = width
18
- @height = height
19
- self.caption = "Ruby Doom"
20
- end
21
-
22
- # Update the game state
23
- def update
24
- @game.update if @game
25
- end
26
-
27
- # Draw the game
28
- def draw
29
- @game.draw if @game
30
- end
31
-
32
- # Handle button press events
33
- def button_down(id)
34
- if @game
35
- @game.button_down(id)
36
- else
37
- close if id == Gosu::KB_ESCAPE
38
- end
39
- end
40
- end
41
- end