/zoeplat

To get this branch, use:
bzr branch http://9ix.org/bzr/zoeplat
1 by Josh C
zoetrope 1.3.1
1
-- Class: Cached
2
-- This helps you re-use assets in your app instead of creating extraneous
3
-- copies of them. It also hides Love-related calls so that your code is
4
-- more portable.
5
--
6
-- If you're using a class built into Zoetrope, you do not need to use
7
-- this class directly. They take care of setting things up for you
8
-- appropriately. However, if you're rolling your own, you'll want to use
9
-- this to save memory.
10
--
11
-- This class is not meant to be created directly. Instead, call
12
-- methods on Cached directly, e.g. Cached:sound(), Cached:image(), and so on.
13
--
14
-- Extends:
15
--		<Class>
16
17
Cached = Class:extend
18
{
19
	-- Property: defaultGlyphs
20
	-- The default character order of a bitmap font, if none is specified
21
	-- in a <font> call.
22
	defaultGlyphs = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`' ..
23
					'abcdefghijklmnopqrstuvwxyz{|}~',
24
25
	-- private property: library
26
	-- a table to store already-instantiated assets
27
	_library = { image = {}, text = {}, sound = {}, font = {}, binds = {}, },
28
29
	-- Method: image
30
	-- Returns a cached image asset.
31
	--
32
	-- Arguments:
33
	--		path - pathname to image file
34
	--
35
	-- Returns:
36
	--		Love image object
37
38
	image = function (self, path)
39
		assert(type(path) == 'string', 'path must be a string')
40
41
		if not self._library.image[path] then
42
			self._library.image[path] = love.graphics.newImage(path)
43
		end
44
45
		return self._library.image[path]
46
	end,
47
48
	-- Method: text
49
	-- Returns a cached text asset.
50
	--
51
	-- Arguments:
52
	--		path - pathname to text file
53
	--
54
	-- Returns:
55
	--		string
56
57
	text = function (self, path)
58
		assert(type(path) == 'string', 'path must be a string')
59
60
		if not self._library.text[path] then
61
			self._library.text[path] = love.filesystem.read(path)
62
		end
63
64
		return self._library.text[path]
65
	end,
66
67
	-- Method: sound
68
	-- Returns a cached sound asset.
69
	--
70
	-- Arguments:
71
	--		path - pathname to sound file
72
	--		length - either 'short' or 'long'. *It's very important to pass
73
	--				 the correct option here.* A short sound is loaded entirely
74
	--				 into memory, while a long one is streamed from disk. If you
75
	--				 mismatch, you'll either hear a delay in the sound (short sounds
76
	--				 played from disk) or your app will freeze (long sounds played from
77
	--				 memory).
78
	-- 
79
	-- Returns:
80
	--		Either a Love SoundData object (for short sounds) or a
81
	--		Love Decoder object (for long sounds). Either can be used to
82
	--		create a Love Source object.
83
	--
84
	-- See Also:
85
	--		<playSound>, <sound>
86
87
	sound = function (self, path, length)
88
		assert(type(path) == 'string', 'path must be a string')
89
90
		if not self._library.sound[path] then
91
			if length == 'short' then
92
				self._library.sound[path] = love.sound.newSoundData(path)
93
			elseif length == 'long' then
94
				self._library.sound[path] = love.sound.newDecoder(path)
95
			else
96
				error('length must be either "short" or "long"')
97
			end
98
		end
99
100
		return self._library.sound[path]
101
	end,
102
103
	-- Method: font
104
	-- Returns a cached font asset.
105
	--
106
	-- Arguments:
107
	-- Can be:
108
	--		* A single number. This uses Love's default outline font at that point size.
109
	--		* A single string. This uses a bitmap font given by this pathname, and assumes that
110
	--		  the characters come in
111
	--		  <printable ASCII order at https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters>.
112
	--		* A string, then a number. This uses an outline font whose pathname is the first argument,
113
	--		  at the point size given in the second argument.
114
	--		* Two strings. The first is treated as a pathname to a bitmap font, the second
115
	--		  as the character order in the font.
116
	--
117
	-- Returns:
118
	--		Love font object
119
120
	font = function (self, ...)
121
		local arg = {...}
122
		local libKey = arg[1]
123
124
		if #arg > 1 then libKey = libKey .. arg[2] end
125
126
		if not self._library.font[libKey] then
127
			local font, image
128
129
			if #arg == 1 then
130
				if type(arg[1]) == 'number' then
131
					font = love.graphics.newFont(arg[1])
132
				elseif type(arg[1]) == 'string' then
133
					image = Cached:image(arg[1])
134
					font = love.graphics.newImageFont(image, self.defaultGlyphs)
135
				else
136
					error("don't understand single argument: " .. arg[1])
137
				end
138
			elseif #arg == 2 then
139
				if type(arg[2]) == 'number' then
140
					font = love.graphics.newFont(arg[1], arg[2])
141
				elseif type(arg[2]) == 'string' then
142
					image = Cached:image(arg[1])
143
					font = love.graphics.newImageFont(image, arg[2])
144
				else
145
					error("don't understand arguments: " .. arg[1] .. ", " .. arg[2])
146
				end
147
			else
148
				error("too many arguments; should be at most two")
149
			end
150
151
			self._library.font[libKey] = font
152
		end
153
154
		return self._library.font[libKey]
155
	end,
156
157
	-- Function: bind
158
	-- Returns a function that's bound to an object so it can be later called with
159
	-- the correct context. This can be abbreviated as just bind().
160
	--
161
	-- Arguments:
162
	--		obj - object to use as function owner
163
	--		func - either a string name of a property of obj, or a free-standing
164
	--			   function.
165
	--		... - any number of extra arguments 
166
167
	bind = function (self, obj, func, ...)
168
		local arg = {...}
169
170
		if STRICT and type(func) == 'string' then
171
			assert(type(obj[func]) == 'function', 'asked to bind an object to a non-existent method named ' .. func)
172
		end
173
174
		-- look for previous bind
175
		
176
		for key, value in pairs(self._library.binds) do
177
			if key[1] == func and key[2] == obj then
178
				local match = true
179
180
				for i = 1, #arg do
181
					if key[i + 2] ~= arg[i] then
182
						match = false
183
						break
184
					end
185
				end
186
187
				if match then
188
					return value
189
				end
190
			end
191
		end
192
193
		-- have to create a new one
194
		-- note that we have to create a compound key, hence the loop above
195
196
		local result = function()
197
			if type(func) == 'string' then
198
				return obj[func](obj, unpack(arg))
199
			else
200
				return func(obj, unpack(arg))
201
			end
202
		end
203
	
204
		self._library.binds[{func, obj, arg}] = result
205
		return result
206
	end
207
}