md2 1.0.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.
Files changed (63) hide show
  1. data/.document +5 -0
  2. data/.gitignore +26 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +174 -0
  5. data/Rakefile +51 -0
  6. data/VERSION +1 -0
  7. data/bin/md2_to_json +33 -0
  8. data/ext/md2/extconf.rb +3 -0
  9. data/ext/md2/md2.c +95 -0
  10. data/lib/md2.rb +97 -0
  11. data/lib/md2/command.rb +63 -0
  12. data/lib/md2/errors.rb +13 -0
  13. data/lib/md2/frame.rb +61 -0
  14. data/lib/md2/header.rb +37 -0
  15. data/lib/md2/normals.rb +81 -0
  16. data/lib/md2/triangle.rb +9 -0
  17. data/lib/md2/vertex.rb +33 -0
  18. data/md2.gemspec +117 -0
  19. data/spec/lib/md2/frame_spec.rb +13 -0
  20. data/spec/lib/md2/header_spec.rb +21 -0
  21. data/spec/lib/md2_spec.rb +66 -0
  22. data/spec/spec_helper.rb +40 -0
  23. data/spec/support/crafty/Crafty.BMP +0 -0
  24. data/spec/support/crafty/Crafty.pcx +0 -0
  25. data/spec/support/crafty/Crafty.txt +113 -0
  26. data/spec/support/crafty/Weapon.md2 +0 -0
  27. data/spec/support/crafty/Weapon.pcx +0 -0
  28. data/spec/support/crafty/crafty.md2 +0 -0
  29. data/spec/support/laalaa/laalaa.md2 +0 -0
  30. data/spec/support/laalaa/laalaa24.BMP +0 -0
  31. data/spec/support/laalaa/laalaa8.BMP +0 -0
  32. data/spec/support/ogro/Ogro.txt +132 -0
  33. data/spec/support/ogro/Ogrobase.pcx +0 -0
  34. data/spec/support/ogro/Weapon.md2 +0 -0
  35. data/spec/support/ogro/Weapon.pcx +0 -0
  36. data/spec/support/ogro/ogro.md2 +0 -0
  37. data/spec/support/ogro/ogro.png +0 -0
  38. data/spec/support/pilot/CC_attribution_licence.txt +68 -0
  39. data/spec/support/pilot/GNU_licence.txt +340 -0
  40. data/spec/support/pilot/Readme.txt +30 -0
  41. data/spec/support/pilot/body.md2 +0 -0
  42. data/spec/support/pilot/body.obj +9331 -0
  43. data/spec/support/pilot/head.md2 +0 -0
  44. data/spec/support/pilot/head.obj +6145 -0
  45. data/spec/support/pilot/pilot.md2 +0 -0
  46. data/spec/support/pilot/pilot_body.3ds +0 -0
  47. data/spec/support/pilot/pilot_body.jpg +0 -0
  48. data/spec/support/pilot/pilot_body.obj +2264 -0
  49. data/spec/support/pilot/pilot_head.3ds +0 -0
  50. data/spec/support/pilot/pilot_head.jpg +0 -0
  51. data/spec/support/pilot/pilot_head.obj +1970 -0
  52. data/spec/support/pknight/pknight.BMP +0 -0
  53. data/spec/support/pknight/pknight.PCX +0 -0
  54. data/spec/support/pknight/pknight.md2 +0 -0
  55. data/spec/support/pknight/pknight_weapon.PCX +0 -0
  56. data/spec/support/pknight/pknight_weapon.bmp +0 -0
  57. data/spec/support/pknight/pknight_weapon.md2 +0 -0
  58. data/spec/support/sodf8/Abarlith.pcx +0 -0
  59. data/spec/support/sodf8/SFOD8.txt +108 -0
  60. data/spec/support/sodf8/Weapon.PCX +0 -0
  61. data/spec/support/sodf8/Weapon.md2 +0 -0
  62. data/spec/support/sodf8/sodf8.md2 +0 -0
  63. metadata +167 -0
@@ -0,0 +1,63 @@
1
+ # This class is instantiated from the C extension. You shouldn't have to instantiate it directly.
2
+ #
3
+ # GL Commands are an optimization technique employed by MD2 files to improve render time. The
4
+ # MD2 file contains a span of bytes equal to the MD2::Header#gl_command_count. Those bytes in
5
+ # turn have the following format:
6
+ #
7
+ # 1. How many bytes follow for a single GL command. This is an integer, so the data need to be
8
+ # cast into an integer in order to be processed.
9
+ #
10
+ # This byte also indicates the render method for this GL command: if it's positive,
11
+ # this is a triangle strip; if it's negative, a triangle fan. If zero, this byte
12
+ # represents the end of the command list. Terminating bytes are silently omitted
13
+ # by this Ruby library.
14
+ # 2. The horizontal texture coordinate. This is a float, so the data needs to be cast into a
15
+ # float to be processed.
16
+ # 3. The vertical texture coordinate. This is a float, so the data needs to be cast into a
17
+ # float to be processed.
18
+ # 4. The vertex index to be rendered. This is an integer, so the data needs to be cast into
19
+ # an integer to be processed.
20
+ #
21
+ # As the data are cast into the necessary types, the boundaries of any given command structure
22
+ # must be adjusted to match. I was not able to find a way to do this using pure Ruby, so the
23
+ # bulk of the above algorithm is implemented in this gem's C extension.
24
+ #
25
+ # This class is only instantiated after the fact, with the data already deserialized.
26
+ #
27
+ class MD2::Command
28
+ # A data structure containing a single #texture_s, #texture_t and #vertex_index.
29
+ class Segment
30
+ attr_reader :texture_s, :texture_t, :vertex_index
31
+ def initialize(s, t, index)
32
+ @texture_s, @texture_t, @vertex_index = s, t, index
33
+ end
34
+ end
35
+
36
+ # The type of command. This is equal to either :triangle_strip or :triangle_fan.
37
+ attr_reader :type
38
+
39
+ # an array of segments, each an instance of MD2::Command::Segment. Segments contain the vertex and texture data
40
+ # for this command.
41
+ attr_reader :segments
42
+
43
+ # Arguments are expected to be a single array with the following content:
44
+ # [ (:triangle_strip|:triangle_fan), *elements ]
45
+ #
46
+ # The remainder of the elements are expected to appear in this order:
47
+ # (s_coord, t_coord, vert_index)
48
+ #
49
+ # So, the elements are expected to be in groups of 3: the s and t texture coordinates (which are Floats),
50
+ # and the vertex index (which is a Fixnum).
51
+ #
52
+ # The array of args is expected to be a single, flat array -- the data should not be nested
53
+ # into other arrays.
54
+ #
55
+ def initialize(args)
56
+ @type = args.shift
57
+ @segments = []
58
+
59
+ 0.step(args.length-1, 3) do |index|
60
+ @segments << MD2::Command::Segment.new(args[index], args[index+1], args[index+2])
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ module MD2::Errors
2
+ # Not raised directly: this is a superclass for all other MD2 errors.
3
+ class Error < ::StandardError
4
+ end
5
+
6
+ # Raised when the specified file is invalid: for instance, when it is not an MD2 file.
7
+ class InvalidFile < Error
8
+ end
9
+
10
+ # Raised when the file format version specified in the header is not what was expected.
11
+ class InvalidVersion < Error
12
+ end
13
+ end
@@ -0,0 +1,61 @@
1
+ class MD2::Frame
2
+ # Float[3] containing X, Y, Z scale values
3
+ attr_reader :scale
4
+
5
+ # Float[3] containing X, Y, Z translations
6
+ attr_reader :translation
7
+
8
+ # The name of this frame (string)
9
+ attr_reader :name
10
+
11
+ # The vertices for this frame.
12
+ attr_reader :vertices
13
+
14
+ # The indices of the normal vectors.
15
+ attr_reader :normal_indices
16
+
17
+ def reduce
18
+ {
19
+ :name => name,
20
+ :translation => @translation,
21
+ :scale => @scale,
22
+ :vertices => packed_vertices,
23
+ :normal_indices => normal_indices.flatten
24
+ }
25
+ end
26
+
27
+ def initialize(frame_data)
28
+ @scale = []
29
+ @translation = []
30
+ @vertices = []
31
+ @normal_indices = []
32
+
33
+ # 3 floats (scale), 3 floats (transl), 16 bytes (name), and variable num of unsigned chars (vertices)
34
+ frame_data = frame_data.unpack("f3f3a16C*")
35
+ 3.times { @scale << frame_data.shift }
36
+ 3.times { @translation << frame_data.shift }
37
+ @name = frame_data.shift.strip
38
+ while !frame_data.empty?
39
+ packed_vertex = MD2::Vertex.new(frame_data.shift, frame_data.shift, frame_data.shift)
40
+ @vertices << unpack_vertex_data(packed_vertex)
41
+ @normal_indices << frame_data.shift
42
+ end
43
+ end
44
+
45
+ private
46
+ def packed_vertices
47
+ vertices.collect do |vert|
48
+ [ ((vert[0] - @translation[0]) / @scale[0]).to_i,
49
+ ((vert[1] - @translation[1]) / @scale[1]).to_i,
50
+ ((vert[2] - @translation[2]) / @scale[2]).to_i ]
51
+ end.flatten
52
+ end
53
+
54
+ def unpack_vertex_data(packed_vertex)
55
+ 3.times do |i|
56
+ packed_vertex[i] = (packed_vertex[i] * @scale[i]) + @translation[i]
57
+ end
58
+
59
+ packed_vertex
60
+ end
61
+ end
@@ -0,0 +1,37 @@
1
+ class MD2::Header
2
+ # The length of an MD2 header is fixed.
3
+ LENGTH = 68
4
+
5
+ # The magic number that all MD2 headers start with. This is equal to "IDP2" in bytes.
6
+ MD2_IDENT = ((?2.ord<<24) + (?P.ord<<16) + (?D.ord<<8) + ?I.ord) # we use #ord because of Ruby 1.9
7
+
8
+ # The MD2 file format version. This is always 8.
9
+ MD2_VERSION = 8
10
+
11
+ attr_reader :skin_width, :skin_height, :frame_size, :skin_count, :vertex_count,
12
+ :texture_coord_count, :triangle_count, :gl_command_count, :frame_count,
13
+ :skin_name_offset, :texture_coord_offset, :triangle_offset, :frame_data_offset,
14
+ :gl_command_offset, :eof_offset
15
+
16
+ def initialize(file)
17
+ header = file.sysread(LENGTH).unpack("i17")
18
+ raise MD2::Errors::InvalidFile, "Header identifier did not match" unless header.shift == MD2_IDENT
19
+ raise MD2::Errors::InvalidVersion, "File format version mismatch" unless header.shift == MD2_VERSION
20
+
21
+ @skin_width = header.shift
22
+ @skin_height = header.shift
23
+ @frame_size = header.shift
24
+ @skin_count = header.shift
25
+ @vertex_count = header.shift
26
+ @texture_coord_count = header.shift
27
+ @triangle_count = header.shift
28
+ @gl_command_count = header.shift
29
+ @frame_count = header.shift
30
+ @skin_name_offset = header.shift
31
+ @texture_coord_offset = header.shift
32
+ @triangle_offset = header.shift
33
+ @frame_data_offset = header.shift
34
+ @gl_command_offset = header.shift
35
+ @eof_offset = header.shift
36
+ end
37
+ end
@@ -0,0 +1,81 @@
1
+ class MD2
2
+ # For your convenience: NORMALS is an array of arrays which contain X, Y and Z float values.
3
+ #
4
+ # This is the same for every MD2 file, and is referenced by the normal indices within the model data.
5
+ #
6
+ # You can get this data with simply:
7
+ #
8
+ # MD2::Normals[index]
9
+ #
10
+ # or you can use its longer variant:
11
+ #
12
+ # MD2::Normals::NORMALS[index].
13
+ #
14
+ class Normals
15
+ class << self
16
+ delegate :[], :[]=, :to => :_normals
17
+
18
+ def _normals #:nodoc:
19
+ MD2::Normals::NORMALS
20
+ end
21
+ end
22
+
23
+
24
+ NORMALS = [
25
+ [-0.525731, 0.000000, 0.850651], [-0.442863, 0.238856, 0.864188], [-0.295242, 0.000000, 0.955423],
26
+ [-0.309017, 0.500000, 0.809017], [-0.162460, 0.262866, 0.951056], [ 0.000000, 0.000000, 1.000000],
27
+ [ 0.000000, 0.850651, 0.525731], [-0.147621, 0.716567, 0.681718], [ 0.147621, 0.716567, 0.681718],
28
+ [ 0.000000, 0.525731, 0.850651], [ 0.309017, 0.500000, 0.809017], [ 0.525731, 0.000000, 0.850651],
29
+ [ 0.295242, 0.000000, 0.955423], [ 0.442863, 0.238856, 0.864188], [ 0.162460, 0.262866, 0.951056],
30
+ [-0.681718, 0.147621, 0.716567], [-0.809017, 0.309017, 0.500000], [-0.587785, 0.425325, 0.688191],
31
+ [-0.850651, 0.525731, 0.000000], [-0.864188, 0.442863, 0.238856], [-0.716567, 0.681718, 0.147621],
32
+ [-0.688191, 0.587785, 0.425325], [-0.500000, 0.809017, 0.309017], [-0.238856, 0.864188, 0.442863],
33
+ [-0.425325, 0.688191, 0.587785], [-0.716567, 0.681718, -0.147621], [-0.500000, 0.809017, -0.309017],
34
+ [-0.525731, 0.850651, 0.000000], [ 0.000000, 0.850651, -0.525731], [-0.238856, 0.864188, -0.442863],
35
+ [ 0.000000, 0.955423, -0.295242], [-0.262866, 0.951056, -0.162460], [ 0.000000, 1.000000, 0.000000],
36
+ [ 0.000000, 0.955423, 0.295242], [-0.262866, 0.951056, 0.162460], [ 0.238856, 0.864188, 0.442863],
37
+ [ 0.262866, 0.951056, 0.162460], [ 0.500000, 0.809017, 0.309017], [ 0.238856, 0.864188, -0.442863],
38
+ [ 0.262866, 0.951056, -0.162460], [ 0.500000, 0.809017, -0.309017], [ 0.850651, 0.525731, 0.000000],
39
+ [ 0.716567, 0.681718, 0.147621], [ 0.716567, 0.681718, -0.147621], [ 0.525731, 0.850651, 0.000000],
40
+ [ 0.425325, 0.688191, 0.587785], [ 0.864188, 0.442863, 0.238856], [ 0.688191, 0.587785, 0.425325],
41
+ [ 0.809017, 0.309017, 0.500000], [ 0.681718, 0.147621, 0.716567], [ 0.587785, 0.425325, 0.688191],
42
+ [ 0.955423, 0.295242, 0.000000], [ 1.000000, 0.000000, 0.000000], [ 0.951056, 0.162460, 0.262866],
43
+ [ 0.850651, -0.525731, 0.000000], [ 0.955423, -0.295242, 0.000000], [ 0.864188, -0.442863, 0.238856],
44
+ [ 0.951056, -0.162460, 0.262866], [ 0.809017, -0.309017, 0.500000], [ 0.681718, -0.147621, 0.716567],
45
+ [ 0.850651, 0.000000, 0.525731], [ 0.864188, 0.442863, -0.238856], [ 0.809017, 0.309017, -0.500000],
46
+ [ 0.951056, 0.162460, -0.262866], [ 0.525731, 0.000000, -0.850651], [ 0.681718, 0.147621, -0.716567],
47
+ [ 0.681718, -0.147621, -0.716567], [ 0.850651, 0.000000, -0.525731], [ 0.809017, -0.309017, -0.500000],
48
+ [ 0.864188, -0.442863, -0.238856], [ 0.951056, -0.162460, -0.262866], [ 0.147621, 0.716567, -0.681718],
49
+ [ 0.309017, 0.500000, -0.809017], [ 0.425325, 0.688191, -0.587785], [ 0.442863, 0.238856, -0.864188],
50
+ [ 0.587785, 0.425325, -0.688191], [ 0.688191, 0.587785, -0.425325], [-0.147621, 0.716567, -0.681718],
51
+ [-0.309017, 0.500000, -0.809017], [ 0.000000, 0.525731, -0.850651], [-0.525731, 0.000000, -0.850651],
52
+ [-0.442863, 0.238856, -0.864188], [-0.295242, 0.000000, -0.955423], [-0.162460, 0.262866, -0.951056],
53
+ [ 0.000000, 0.000000, -1.000000], [ 0.295242, 0.000000, -0.955423], [ 0.162460, 0.262866, -0.951056],
54
+ [-0.442863, -0.238856, -0.864188], [-0.309017, -0.500000, -0.809017], [-0.162460, -0.262866, -0.951056],
55
+ [ 0.000000, -0.850651, -0.525731], [-0.147621, -0.716567, -0.681718], [ 0.147621, -0.716567, -0.681718],
56
+ [ 0.000000, -0.525731, -0.850651], [ 0.309017, -0.500000, -0.809017], [ 0.442863, -0.238856, -0.864188],
57
+ [ 0.162460, -0.262866, -0.951056], [ 0.238856, -0.864188, -0.442863], [ 0.500000, -0.809017, -0.309017],
58
+ [ 0.425325, -0.688191, -0.587785], [ 0.716567, -0.681718, -0.147621], [ 0.688191, -0.587785, -0.425325],
59
+ [ 0.587785, -0.425325, -0.688191], [ 0.000000, -0.955423, -0.295242], [ 0.000000, -1.000000, 0.000000],
60
+ [ 0.262866, -0.951056, -0.162460], [ 0.000000, -0.850651, 0.525731], [ 0.000000, -0.955423, 0.295242],
61
+ [ 0.238856, -0.864188, 0.442863], [ 0.262866, -0.951056, 0.162460], [ 0.500000, -0.809017, 0.309017],
62
+ [ 0.716567, -0.681718, 0.147621], [ 0.525731, -0.850651, 0.000000], [-0.238856, -0.864188, -0.442863],
63
+ [-0.500000, -0.809017, -0.309017], [-0.262866, -0.951056, -0.162460], [-0.850651, -0.525731, 0.000000],
64
+ [-0.716567, -0.681718, -0.147621], [-0.716567, -0.681718, 0.147621], [-0.525731, -0.850651, 0.000000],
65
+ [-0.500000, -0.809017, 0.309017], [-0.238856, -0.864188, 0.442863], [-0.262866, -0.951056, 0.162460],
66
+ [-0.864188, -0.442863, 0.238856], [-0.809017, -0.309017, 0.500000], [-0.688191, -0.587785, 0.425325],
67
+ [-0.681718, -0.147621, 0.716567], [-0.442863, -0.238856, 0.864188], [-0.587785, -0.425325, 0.688191],
68
+ [-0.309017, -0.500000, 0.809017], [-0.147621, -0.716567, 0.681718], [-0.425325, -0.688191, 0.587785],
69
+ [-0.162460, -0.262866, 0.951056], [ 0.442863, -0.238856, 0.864188], [ 0.162460, -0.262866, 0.951056],
70
+ [ 0.309017, -0.500000, 0.809017], [ 0.147621, -0.716567, 0.681718], [ 0.000000, -0.525731, 0.850651],
71
+ [ 0.425325, -0.688191, 0.587785], [ 0.587785, -0.425325, 0.688191], [ 0.688191, -0.587785, 0.425325],
72
+ [-0.955423, 0.295242, 0.000000], [-0.951056, 0.162460, 0.262866], [-1.000000, 0.000000, 0.000000],
73
+ [-0.850651, 0.000000, 0.525731], [-0.955423, -0.295242, 0.000000], [-0.951056, -0.162460, 0.262866],
74
+ [-0.864188, 0.442863, -0.238856], [-0.951056, 0.162460, -0.262866], [-0.809017, 0.309017, -0.500000],
75
+ [-0.864188, -0.442863, -0.238856], [-0.951056, -0.162460, -0.262866], [-0.809017, -0.309017, -0.500000],
76
+ [-0.681718, 0.147621, -0.716567], [-0.681718, -0.147621, -0.716567], [-0.850651, 0.000000, -0.525731],
77
+ [-0.688191, 0.587785, -0.425325], [-0.587785, 0.425325, -0.688191], [-0.425325, 0.688191, -0.587785],
78
+ [-0.425325, -0.688191, -0.587785], [-0.587785, -0.425325, -0.688191], [-0.688191, -0.587785, -0.425325]
79
+ ].collect { |c| c.freeze }.freeze
80
+ end
81
+ end
@@ -0,0 +1,9 @@
1
+ class MD2::Triangle
2
+ attr_reader :vertex_indices, :texcoord_indices
3
+
4
+ def initialize(data)
5
+ data = data.unpack("s6")
6
+ @vertex_indices = [data[0], data[1], data[2]]
7
+ @texcoord_indices = [data[3], data[4], data[5]]
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ class MD2::Vertex < Array
2
+ def initialize(x, y, z)
3
+ super()
4
+ raise ArgumentError, "x is nil" if x.nil?
5
+ raise ArgumentError, "y is nil" if y.nil?
6
+ raise ArgumentError, "z is nil" if z.nil?
7
+ self << x << y << z
8
+ end
9
+
10
+ def x
11
+ self[0]
12
+ end
13
+
14
+ def y
15
+ self[1]
16
+ end
17
+
18
+ def z
19
+ self[2]
20
+ end
21
+
22
+ def x=(x)
23
+ self[0] = x
24
+ end
25
+
26
+ def y=(y)
27
+ self[1] = y
28
+ end
29
+
30
+ def z=(z)
31
+ self[2] = z
32
+ end
33
+ end
@@ -0,0 +1,117 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{md2}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Colin MacKenzie IV"]
12
+ s.date = %q{2010-10-28}
13
+ s.default_executable = %q{md2_to_json}
14
+ s.description = %q{A Ruby library for loading MD2 3D model files.}
15
+ s.email = %q{sinisterchipmunk@gmail.com}
16
+ s.executables = ["md2_to_json"]
17
+ s.extensions = ["ext/md2/extconf.rb"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".gitignore",
25
+ "LICENSE",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "bin/md2_to_json",
30
+ "ext/md2/extconf.rb",
31
+ "ext/md2/md2.c",
32
+ "lib/md2.rb",
33
+ "lib/md2/command.rb",
34
+ "lib/md2/errors.rb",
35
+ "lib/md2/frame.rb",
36
+ "lib/md2/header.rb",
37
+ "lib/md2/normals.rb",
38
+ "lib/md2/triangle.rb",
39
+ "lib/md2/vertex.rb",
40
+ "md2.gemspec",
41
+ "spec/lib/md2/frame_spec.rb",
42
+ "spec/lib/md2/header_spec.rb",
43
+ "spec/lib/md2_spec.rb",
44
+ "spec/spec_helper.rb",
45
+ "spec/support/crafty/Crafty.BMP",
46
+ "spec/support/crafty/Crafty.pcx",
47
+ "spec/support/crafty/Crafty.txt",
48
+ "spec/support/crafty/Weapon.md2",
49
+ "spec/support/crafty/Weapon.pcx",
50
+ "spec/support/crafty/crafty.md2",
51
+ "spec/support/laalaa/laalaa.md2",
52
+ "spec/support/laalaa/laalaa24.BMP",
53
+ "spec/support/laalaa/laalaa8.BMP",
54
+ "spec/support/ogro/Ogro.txt",
55
+ "spec/support/ogro/Ogrobase.pcx",
56
+ "spec/support/ogro/Weapon.md2",
57
+ "spec/support/ogro/Weapon.pcx",
58
+ "spec/support/ogro/ogro.md2",
59
+ "spec/support/ogro/ogro.png",
60
+ "spec/support/pilot/CC_attribution_licence.txt",
61
+ "spec/support/pilot/GNU_licence.txt",
62
+ "spec/support/pilot/Readme.txt",
63
+ "spec/support/pilot/body.md2",
64
+ "spec/support/pilot/body.obj",
65
+ "spec/support/pilot/head.md2",
66
+ "spec/support/pilot/head.obj",
67
+ "spec/support/pilot/pilot.md2",
68
+ "spec/support/pilot/pilot_body.3ds",
69
+ "spec/support/pilot/pilot_body.jpg",
70
+ "spec/support/pilot/pilot_body.obj",
71
+ "spec/support/pilot/pilot_head.3ds",
72
+ "spec/support/pilot/pilot_head.jpg",
73
+ "spec/support/pilot/pilot_head.obj",
74
+ "spec/support/pknight/pknight.BMP",
75
+ "spec/support/pknight/pknight.PCX",
76
+ "spec/support/pknight/pknight.md2",
77
+ "spec/support/pknight/pknight_weapon.PCX",
78
+ "spec/support/pknight/pknight_weapon.bmp",
79
+ "spec/support/pknight/pknight_weapon.md2",
80
+ "spec/support/sodf8/Abarlith.pcx",
81
+ "spec/support/sodf8/SFOD8.txt",
82
+ "spec/support/sodf8/Weapon.PCX",
83
+ "spec/support/sodf8/Weapon.md2",
84
+ "spec/support/sodf8/sodf8.md2"
85
+ ]
86
+ s.homepage = %q{http://thoughtsincomputation.com}
87
+ s.rdoc_options = ["--charset=UTF-8"]
88
+ s.require_paths = ["lib"]
89
+ s.rubygems_version = %q{1.3.6}
90
+ s.summary = %q{A Ruby library for loading MD2 3D model files.}
91
+ s.test_files = [
92
+ "spec/lib/md2/frame_spec.rb",
93
+ "spec/lib/md2/header_spec.rb",
94
+ "spec/lib/md2_spec.rb",
95
+ "spec/spec_helper.rb"
96
+ ]
97
+
98
+ if s.respond_to? :specification_version then
99
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
100
+ s.specification_version = 3
101
+
102
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
103
+ s.add_runtime_dependency(%q<sizes>, [">= 1.0"])
104
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.5"])
105
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
106
+ else
107
+ s.add_dependency(%q<sizes>, [">= 1.0"])
108
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
109
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
110
+ end
111
+ else
112
+ s.add_dependency(%q<sizes>, [">= 1.0"])
113
+ s.add_dependency(%q<activesupport>, [">= 2.3.5"])
114
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
115
+ end
116
+ end
117
+
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe MD2 do
4
+ subject { MD2.new(md2_file("pilot")) }
5
+
6
+ it "should have frames.first.vertices.size == header.vertex_count" do
7
+ subject.frames.first.vertices.size.should == subject.header.vertex_count
8
+ end
9
+
10
+ it "should not contain null characters" do
11
+ subject.frames.first.name.should_not =~ /#{Regexp::escape ?\0.chr}/
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe MD2::Header do
4
+ context "with invalid content" do
5
+ subject { MD2::Header.new(mock_io("this is invalid "*10)) }
6
+
7
+ it "should raise MD2::Errors::InvalidFile" do
8
+ proc { subject }.should raise_error(MD2::Errors::InvalidFile)
9
+ end
10
+ end
11
+
12
+ context "with valid ID" do
13
+ context "and invalid version" do
14
+ subject { MD2::Header.new(mock_io("IDP2" + ("this is invalid"*10))) }
15
+
16
+ it "should raise MD2::Errors::InvalidVersion" do
17
+ proc { subject }.should raise_error(MD2::Errors::InvalidVersion)
18
+ end
19
+ end
20
+ end
21
+ end