cryptopunks 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -1,309 +0,0 @@
1
-
2
- module Cryptopunks
3
-
4
- class Metadata
5
- ### todo/fix:
6
- ## move into Punks::Metadata or such
7
- class Sprite
8
- attr_reader :id, :name, :type, :gender, :size, :more_names
9
-
10
-
11
- def initialize( id:,
12
- name:,
13
- type:,
14
- gender:,
15
- size:,
16
- more_names: [] )
17
- @id = id # zero-based index eg. 0,1,2,3, etc.
18
- @name = name
19
- @type = type
20
- @gender = gender
21
- @size = size
22
- @more_names = more_names
23
- end
24
-
25
- ## todo/check - find better names for type attribute/archetypes?
26
- ## use (alternate name/alias) base or face for archetypes? any others?
27
- def attribute?() @type.downcase.start_with?( 'attribute' ); end
28
- def archetype?() @type.downcase.start_with?( 'archetype' ); end
29
-
30
- def small?() @size == 's'; end
31
- def large?() @size == 'l'; end
32
- def universal?() @size == 'u'; end
33
- alias_method :unisize?, :universal? ## add unisize or allsizes or such - why? why not?
34
-
35
- def male?() @gender == 'm'; end
36
- def female?() @gender == 'f'; end
37
- def unisex?() @gender == 'u'; end
38
- end # class Metadata::Sprite
39
- end # class Metadata
40
-
41
-
42
-
43
-
44
- class Generator
45
-
46
- ######
47
- # static helpers - (turn into "true" static self.class methods - why? why not?)
48
- #
49
- def self.normalize_key( str )
50
- ## add & e.g. B&W
51
- str.downcase.gsub(/[ ()&°_-]/, '').strip
52
- end
53
-
54
- def self.normalize_gender( str )
55
- ## e.g. Female => f
56
- ## F => f
57
- ## always return f/m
58
- str.downcase[0]
59
- end
60
-
61
- def self.normalize_size( str )
62
- ## e.g. U or Unisize or Univeral => u
63
- ## S or Small => s
64
- ## L or Large => l
65
- ## always return u/l/s
66
- str.downcase[0]
67
- end
68
-
69
- def self.normalize_name( str )
70
- ## normalize spaces in more names
71
- str.strip.gsub( /[ ]{2,}/, ' ' )
72
- end
73
-
74
- def normalize_key( str ) self.class.normalize_key( str ); end
75
- def normalize_gender( str ) self.class.normalize_gender( str ); end
76
- def normalize_size( str ) self.class.normalize_size( str ); end
77
- def normalize_name( str ) self.class.normalize_name( str ); end
78
-
79
-
80
-
81
-
82
-
83
-
84
- def build_attributes_by_name( recs )
85
- h = {}
86
- recs.each_with_index do |rec|
87
- names = [rec.name] + rec.more_names
88
-
89
- names.each do |name|
90
- key = normalize_key( name )
91
- key << "_(#{rec.gender}+#{rec.size})" if rec.attribute?
92
-
93
- if h[ key ]
94
- puts "!!! ERROR - attribute name is not unique:"
95
- pp rec
96
- puts "duplicate:"
97
- pp h[key]
98
- exit 1
99
- end
100
- h[ key ] = rec
101
- end
102
- end
103
- ## pp h
104
- h
105
- end
106
-
107
-
108
- def build_recs( recs ) ## build and normalize (meta data) records
109
-
110
- ## sort by id
111
- recs = recs.sort do |l,r|
112
- l['id'].to_i( 10 ) <=> r['id'].to_i( 10 ) # use base10 (decimal)
113
- end
114
-
115
- ## assert all recs are in order by id (0 to size)
116
- recs.each_with_index do |rec, exp_id|
117
- id = rec['id'].to_i(10)
118
- if id != exp_id
119
- puts "!! ERROR - meta data record ids out-of-order - expected id #{exp_id}; got #{id}"
120
- exit 1
121
- end
122
- end
123
-
124
- ## convert to "wrapped / immutable" kind-of struct
125
- recs = recs.map do |rec|
126
- id = rec['id'].to_i( 10 )
127
- name = normalize_name( rec['name'] )
128
- gender = normalize_gender( rec['gender'] )
129
- size = normalize_size( rec['size'] )
130
- type = rec['type']
131
-
132
- more_names = (rec['more_names'] || '').split( '|' )
133
- more_names = more_names.map {|str| normalize_name( str ) }
134
-
135
- Metadata::Sprite.new(
136
- id: id,
137
- name: name,
138
- type: type,
139
- gender: gender,
140
- size: size,
141
- more_names: more_names )
142
- end
143
- recs
144
- end # method build_recs
145
-
146
-
147
-
148
-
149
- def initialize( image_path="./spritesheet.png",
150
- meta_path="./spritesheet.csv" )
151
- @sheet = Pixelart::ImageComposite.read( image_path )
152
- recs = CsvHash.read( meta_path )
153
-
154
- @recs = build_recs( recs )
155
-
156
- ## lookup by "case/space-insensitive" name / key
157
- @attributes_by_name = build_attributes_by_name( @recs )
158
- end
159
-
160
-
161
- def spritesheet() @sheet; end
162
- alias_method :sheet, :spritesheet
163
-
164
-
165
- def records() @recs; end
166
- alias_method :meta, :records
167
-
168
-
169
-
170
-
171
- def find_meta( q, gender: nil,
172
- size: nil,
173
- style: nil ) ## note: gender (m/f) required for attributes!!!
174
-
175
- key = normalize_key( q ) ## normalize q(uery) string/symbol
176
-
177
- keys = [] ## note allow lookup by more than one keys
178
- ## e.g. if gender set try f/m first and than try unisex as fallback
179
- if gender
180
- gender = normalize_gender( gender )
181
- ## auto-fill size if not passed in
182
- ## for f(emale) => s(mall)
183
- ## m(ale) => l(arge)
184
- size = if size.nil?
185
- gender == 'f' ? 's' : 'l'
186
- else
187
- normalize_size( size )
188
- end
189
-
190
- ###
191
- # try (auto-add) style-specific version first (fallback to "regular" if not found)
192
- if style
193
- ## for now only support natural series
194
- style_key = if style.downcase.start_with?( 'natural' )
195
- 'natural'
196
- else
197
- puts "!! ERROR - unknown attribute style #{style}; sorry"
198
- exit 1
199
- end
200
-
201
- keys << "#{key}#{style_key}_(#{gender}+#{size})"
202
- ## auto-add (u)niversal size as fallback
203
- keys << "#{key}#{style_key}_(#{gender}+u)" if size == 's' || size == 'l'
204
- ## auto-add u(nisex) as fallback
205
- keys << "#{key}#{style_key}_(u+#{size})" if gender == 'f' || gender == 'm'
206
- end
207
-
208
-
209
- keys << "#{key}_(#{gender}+#{size})"
210
- ## auto-add (u)niversal size as fallback
211
- keys << "#{key}_(#{gender}+u)" if size == 's' || size == 'l'
212
- ## auto-add u(nisex) as fallback
213
- keys << "#{key}_(u+#{size})" if gender == 'f' || gender == 'm'
214
- else
215
- keys << key
216
- end
217
-
218
-
219
- rec = nil
220
- keys.each do |key|
221
- rec = @attributes_by_name[ key ]
222
- if rec
223
- puts " lookup >#{key}< => #{rec.id}: #{rec.name} / #{rec.type} (#{rec.gender}+#{rec.size})"
224
- # pp rec
225
- break
226
- end
227
- end
228
-
229
- if rec.nil?
230
- puts "!! WARN - no lookup found for #{keys.size} key(s) >#{keys.inspect}<"
231
- end
232
-
233
- rec
234
- end
235
-
236
-
237
- def find( q, gender: nil, size: nil, style: nil ) ## gender (m/f) required for attributes!!!
238
- rec = find_meta( q, gender: gender, size: size, style: style )
239
-
240
- ## return image if record found
241
- rec ? @sheet[ rec.id ] : nil
242
- end
243
-
244
-
245
-
246
-
247
- def to_recs( *values, style: nil )
248
- archetype_name = values[0]
249
-
250
- ### todo/fix: check for nil/not found!!!!
251
- ## todo/check/fix: assert meta record returned is archetype NOT attribute!!!!
252
- archetype = find_meta( archetype_name )
253
- if archetype.nil?
254
- puts "!! ERROR - archetype >#{archetype}< not found; sorry"
255
- exit 1
256
- end
257
-
258
- recs = [archetype]
259
-
260
- attribute_names = values[1..-1]
261
- ## note: attribute lookup requires gender from archetype!!!!
262
- attribute_gender = archetype.gender
263
- attribute_size = archetype.size
264
-
265
- attribute_names.each do |attribute_name|
266
- attribute = find_meta( attribute_name,
267
- gender: attribute_gender,
268
- size: attribute_size,
269
- style: style )
270
- if attribute.nil?
271
- puts "!! ERROR - attribute >#{attribute_name}< for (#{attribute_gender}+#{attribute_size}) not found; sorry"
272
- exit 1
273
- end
274
- recs << attribute
275
- end
276
-
277
- recs
278
- end
279
-
280
-
281
-
282
-
283
- def generate_image( *values, style: nil,
284
- background: nil )
285
-
286
- ids = if values[0].is_a?( Integer ) ## assume integer number (indexes)
287
- values
288
- else ## assume strings (names)
289
- to_recs( *values, style: style ).map { |rec| rec.id }
290
- end
291
-
292
-
293
- punk = Pixelart::Image.new( 24, 24 )
294
-
295
- if background ## for now assume background is (simply) color
296
- punk.compose!( Pixelart::Image.new( 24, 24, background ) )
297
- end
298
-
299
- ids.each do |id|
300
- punk.compose!( @sheet[ id ] )
301
- end
302
-
303
- punk
304
- end
305
- alias_method :generate, :generate_image
306
-
307
- end # class Generator
308
-
309
- end # module Cryptopunks