Browse Source

LoaderTR2 loads Moveables and Entities

Thomas Buck 9 years ago
parent
commit
00706b69ab
11 changed files with 312 additions and 29 deletions
  1. 3
    0
      ChangeLog.md
  2. 2
    0
      include/Entity.h
  3. 1
    0
      include/Game.h
  4. 11
    0
      include/SkeletalModel.h
  5. 2
    2
      src/Console.cpp
  6. 15
    0
      src/Entity.cpp
  7. 14
    1
      src/Game.cpp
  8. 40
    0
      src/SkeletalModel.cpp
  9. 3
    3
      src/TextureManager.cpp
  10. 4
    4
      src/commands/Command.cpp
  11. 217
    19
      src/loader/LoaderTR2.cpp

+ 3
- 0
ChangeLog.md View File

@@ -2,6 +2,9 @@
2 2
 
3 3
 ## OpenRaider (0.1.3) xythobuz <xythobuz@xythobuz.de>
4 4
 
5
+    [ 20141206 ]
6
+    * LoaderTR2 now tries to load Moveables and Entities
7
+
5 8
     [ 20141203 ]
6 9
     * Renamed Vector3d to Vec3, small cleanup
7 10
     * Added preliminary math unit test

+ 2
- 0
include/Entity.h View File

@@ -21,6 +21,8 @@ class Entity {
21 21
         MoveTypeSwim       = 3
22 22
     } MoveType;
23 23
 
24
+    Entity(float p[3], float a[3], int id, long r, unsigned int model);
25
+
24 26
     Entity(TombRaider& tr, unsigned int index, unsigned int i, unsigned int model);
25 27
 
26 28
     bool operator<(Entity& o);

+ 1
- 0
include/Game.h View File

@@ -33,6 +33,7 @@ class Game {
33 33
     void handleMouseMotion(int xrel, int yrel, int xabs, int yabs);
34 34
 
35 35
     Entity& getLara();
36
+    void setLara(long lara);
36 37
 
37 38
   private:
38 39
 

+ 11
- 0
include/SkeletalModel.h View File

@@ -15,6 +15,8 @@
15 15
 
16 16
 class BoneTag {
17 17
   public:
18
+    BoneTag(int m, float o[3], float r[3], char f);
19
+
18 20
     BoneTag(TombRaider& tr, unsigned int index, unsigned int j, unsigned int* l,
19 21
             unsigned int frame_offset);
20 22
     void display();
@@ -32,6 +34,8 @@ class BoneTag {
32 34
 
33 35
 class BoneFrame {
34 36
   public:
37
+    BoneFrame(float p[3]);
38
+
35 39
     BoneFrame(TombRaider& tr, unsigned int index, unsigned int frame_offset);
36 40
     ~BoneFrame();
37 41
 
@@ -39,6 +43,7 @@ class BoneFrame {
39 43
 
40 44
     unsigned long size();
41 45
     BoneTag& get(unsigned long i);
46
+    void add(BoneTag* t);
42 47
 
43 48
   private:
44 49
     float pos[3];
@@ -47,12 +52,15 @@ class BoneFrame {
47 52
 
48 53
 class AnimationFrame {
49 54
   public:
55
+    AnimationFrame(char r);
56
+
50 57
     AnimationFrame(TombRaider& tr, unsigned int index, int a, unsigned int* frame_offset,
51 58
                    int frame_step);
52 59
     ~AnimationFrame();
53 60
 
54 61
     unsigned long size();
55 62
     BoneFrame& get(unsigned long i);
63
+    void add(BoneFrame* f);
56 64
 
57 65
   private:
58 66
     char rate;
@@ -61,6 +69,8 @@ class AnimationFrame {
61 69
 
62 70
 class SkeletalModel {
63 71
   public:
72
+    SkeletalModel(int i);
73
+
64 74
     SkeletalModel(TombRaider& tr, unsigned int index, int objectId);
65 75
     ~SkeletalModel();
66 76
     void display(unsigned long aframe, unsigned long bframe);
@@ -71,6 +81,7 @@ class SkeletalModel {
71 81
 
72 82
     unsigned long size();
73 83
     AnimationFrame& get(unsigned long i);
84
+    void add(AnimationFrame* f);
74 85
 
75 86
   private:
76 87
     int id;

+ 2
- 2
src/Console.cpp View File

@@ -87,8 +87,8 @@ void Console::display() {
87 87
 
88 88
         if (ImGui::InputText("Command", buffer, bufferLength,
89 89
                              ImGuiInputTextFlags_EnterReturnsTrue
90
-                              | ImGuiInputTextFlags_CallbackCompletion
91
-                              | ImGuiInputTextFlags_CallbackHistory,
90
+                             | ImGuiInputTextFlags_CallbackCompletion
91
+                             | ImGuiInputTextFlags_CallbackHistory,
92 92
                              &Console::callback)) {
93 93
             getLog() << "> " << buffer << Log::endl;
94 94
             if (strlen(buffer) > 0) {

+ 15
- 0
src/Entity.cpp View File

@@ -15,6 +15,21 @@
15 15
 
16 16
 #include "games/TombRaider1.h"
17 17
 
18
+Entity::Entity(float p[3], float a[3], int id, long r, unsigned int model) {
19
+    for (int i = 0; i < 3; i++) {
20
+        pos[i] = p[i];
21
+        angles[i] = a[i];
22
+    }
23
+    objectId = id;
24
+    moveType = MoveTypeWalk;
25
+    room = r;
26
+    skeletalModel = model;
27
+    boneFrame = 0;
28
+    animationFrame = 0;
29
+    idleAnimation = 0;
30
+    state = 0;
31
+}
32
+
18 33
 Entity::Entity(TombRaider& tr, unsigned int index, unsigned int i, unsigned int model) {
19 34
     tr2_moveable_t* moveable = tr.Moveable();
20 35
     tr2_item_t* item = tr.Item();

+ 14
- 1
src/Game.cpp View File

@@ -82,6 +82,13 @@ int Game::loadLevel(const char* level) {
82 82
             destroy();
83 83
         } else {
84 84
             SoundManager::prepareSources();
85
+
86
+            if (mLara == -1) {
87
+                getLog() << "Can't find Lara entity in level?!" << Log::endl;
88
+            } else {
89
+                //mLoaded = true;
90
+                //getRender().setMode(Render::modeVertexLight);
91
+            }
85 92
         }
86 93
     }
87 94
 
@@ -117,7 +124,7 @@ int Game::loadLevel(const char* level) {
117 124
         if (mLara == -1) {
118 125
             //! \todo Cutscene support
119 126
             getLog() << "Can't find Lara entity in level pak!" << Log::endl;
120
-            destroy();
127
+            //destroy();
121 128
             return -1;
122 129
         } else {
123 130
             mLoaded = true;
@@ -182,6 +189,12 @@ Entity& Game::getLara() {
182 189
     return getWorld().getEntity(mLara);
183 190
 }
184 191
 
192
+void Game::setLara(long lara) {
193
+    assert(lara >= 0);
194
+    assert(lara < getWorld().sizeEntity());
195
+    mLara = lara;
196
+}
197
+
185 198
 void Game::processSprites() {
186 199
     for (int i = 0; i < (mTombRaider.NumItems() - 1); i++) {
187 200
         if ((mTombRaider.Engine() == TR_VERSION_1) && (mTombRaider.Item()[i].intensity1 == -1))

+ 40
- 0
src/SkeletalModel.cpp View File

@@ -12,6 +12,15 @@
12 12
 #include "SkeletalModel.h"
13 13
 #include "World.h"
14 14
 
15
+BoneTag::BoneTag(int m, float o[3], float r[3], char f) {
16
+    mesh = m;
17
+    flag = f;
18
+    for (int i = 0; i < 3; i++) {
19
+        off[i] = o[i];
20
+        rot[i] = r[i];
21
+    }
22
+}
23
+
15 24
 BoneTag::BoneTag(TombRaider& tr, unsigned int index, unsigned int i, unsigned int* l,
16 25
                  unsigned int frame_offset) {
17 26
     tr2_moveable_t* moveable = tr.Moveable();
@@ -69,6 +78,13 @@ char BoneTag::getFlag() {
69 78
     return flag;
70 79
 }
71 80
 
81
+// ----------------------------------------------------------------------------
82
+
83
+BoneFrame::BoneFrame(float p[3]) {
84
+    for (int i = 0; i < 3; i++)
85
+        pos[i] = p[i];
86
+}
87
+
72 88
 BoneFrame::BoneFrame(TombRaider& tr, unsigned int index, unsigned int frame_offset) {
73 89
     tr2_moveable_t* moveable = tr.Moveable();
74 90
     unsigned short* frame = tr.Frame();
@@ -97,12 +113,22 @@ BoneTag& BoneFrame::get(unsigned long i) {
97 113
     return *tag.at(i);
98 114
 }
99 115
 
116
+void BoneFrame::add(BoneTag* t) {
117
+    tag.push_back(t);
118
+}
119
+
100 120
 void BoneFrame::getPosition(float p[3]) {
101 121
     p[0] = pos[0];
102 122
     p[1] = pos[1];
103 123
     p[2] = pos[2];
104 124
 }
105 125
 
126
+// ----------------------------------------------------------------------------
127
+
128
+AnimationFrame::AnimationFrame(char r) {
129
+    rate = r;
130
+}
131
+
106 132
 AnimationFrame::AnimationFrame(TombRaider& tr, unsigned int index, int a,
107 133
                                unsigned int* frame_offset, int frame_step) {
108 134
     tr2_moveable_t* moveable = tr.Moveable();
@@ -163,6 +189,16 @@ BoneFrame& AnimationFrame::get(unsigned long i) {
163 189
     return *frame.at(i);
164 190
 }
165 191
 
192
+void AnimationFrame::add(BoneFrame* f) {
193
+    frame.push_back(f);
194
+}
195
+
196
+// ----------------------------------------------------------------------------
197
+
198
+SkeletalModel::SkeletalModel(int i) {
199
+    id = i;
200
+}
201
+
166 202
 SkeletalModel::SkeletalModel(TombRaider& tr, unsigned int index, int objectId) {
167 203
     tr2_moveable_t* moveable = tr.Moveable();
168 204
     tr2_animation_t* anim = tr.Animation();
@@ -394,3 +430,7 @@ AnimationFrame& SkeletalModel::get(unsigned long i) {
394 430
     return *animation.at(i);
395 431
 }
396 432
 
433
+void SkeletalModel::add(AnimationFrame* f) {
434
+    animation.push_back(f);
435
+}
436
+

+ 3
- 3
src/TextureManager.cpp View File

@@ -47,9 +47,9 @@ bool TextureTile::isTriangle() {
47 47
         return true;
48 48
 
49 49
     return ((vertices.at(3)->xPixel == 0)
50
-            & (vertices.at(3)->xCoordinate == 0)
51
-            & (vertices.at(3)->yPixel == 0)
52
-            & (vertices.at(3)->yCoordinate == 0));
50
+            && (vertices.at(3)->xCoordinate == 0)
51
+            && (vertices.at(3)->yPixel == 0)
52
+            && (vertices.at(3)->yCoordinate == 0));
53 53
 }
54 54
 
55 55
 void TextureTile::display(float x, float y, float w, float h, float z) {

+ 4
- 4
src/commands/Command.cpp View File

@@ -138,10 +138,10 @@ std::string Command::autoComplete(std::string begin) {
138 138
 
139 139
     std::string help("help");
140 140
     if (begin.size() <= help.size()) {
141
-                if (begin.compare(0, begin.size(), help, 0, begin.size()) == 0) {
142
-                    candidates.push_back(help);
143
-                }
144
-            }
141
+        if (begin.compare(0, begin.size(), help, 0, begin.size()) == 0) {
142
+            candidates.push_back(help);
143
+        }
144
+    }
145 145
 
146 146
     for (auto& x : commands) {
147 147
         if (x) {

+ 217
- 19
src/loader/LoaderTR2.cpp View File

@@ -10,6 +10,7 @@
10 10
 #include <vector>
11 11
 
12 12
 #include "global.h"
13
+#include "Game.h"
13 14
 #include "Log.h"
14 15
 #include "Mesh.h"
15 16
 #include "Room.h"
@@ -75,7 +76,7 @@ void LoaderTR2::loadPaletteTextiles() {
75 76
     for (auto& x : palette)
76 77
         x = file.readU32();
77 78
 
78
-    // TODO store palette somewhere
79
+    // TODO store palette somewhere?
79 80
 
80 81
     uint32_t numTextiles = file.readU32();
81 82
 
@@ -95,6 +96,11 @@ void LoaderTR2::loadPaletteTextiles() {
95 96
         assert(r >= 0); //! \fixme properly handle error when texture could not be loaded!
96 97
         delete [] img;
97 98
     }
99
+
100
+    if (numTextiles > 0)
101
+        getLog() << "LoaderTR2: Found " << numTextiles << " Textures!" << Log::endl;
102
+    else
103
+        getLog() << "LoaderTR2: No Textures in this level?!" << Log::endl;
98 104
 }
99 105
 
100 106
 void LoaderTR2::loadTextures() {
@@ -124,14 +130,19 @@ void LoaderTR2::loadTextures() {
124 130
             uint8_t yCoordinate = file.readU8();
125 131
             uint8_t yPixel = file.readU8();
126 132
 
127
-            assert((xCoordinate != 1) || (xCoordinate != 255));
128
-            assert((yCoordinate != 1) || (yCoordinate != 255));
133
+            assert((xCoordinate == 1) || (xCoordinate == 255) || (xCoordinate == 0));
134
+            assert((yCoordinate == 1) || (yCoordinate == 255) || (yCoordinate == 0));
129 135
 
130 136
             t->add(new TextureTileVertex(xCoordinate, xPixel, yCoordinate, yPixel));
131 137
         }
132 138
 
133 139
         getTextureManager().addTile(t);
134 140
     }
141
+
142
+    if (numObjectTextures > 0)
143
+        getLog() << "LoaderTR2: Found " << numObjectTextures << " Textiles!" << Log::endl;
144
+    else
145
+        getLog() << "LoaderTR2: No Textiles in this level?!" << Log::endl;
135 146
 }
136 147
 
137 148
 void LoaderTR2::loadAnimatedTextures() {
@@ -158,8 +169,11 @@ void LoaderTR2::loadAnimatedTextures() {
158 169
         pos += count + 1;
159 170
     }
160 171
 
172
+    if ((numAnimatedTextures > 0) || (numWords > 0))
173
+        getLog() << "LoaderTR2: Found " << numAnimatedTextures << " Animated Textures!" << Log::endl;
174
+
161 175
     if (pos != numWords)
162
-        getLog() << "LoaderTR2: Extra bytes at end of AnimatedTextures?" << Log::endl;
176
+        getLog() << "LoaderTR2: Extra bytes at end of AnimatedTextures?!" << Log::endl;
163 177
 }
164 178
 
165 179
 // ---- Rooms ----
@@ -177,12 +191,11 @@ void LoaderTR2::loadRooms() {
177 191
         // Number of data words (2 bytes) to follow
178 192
         uint32_t dataToFollow = file.readU32();
179 193
 
180
-
181
-        std::vector<struct vertex_t> vertices;
194
+        std::vector<vertex_t> vertices;
182 195
 
183 196
         uint16_t numVertices = file.readU16();
184 197
         for (unsigned int v = 0; v < numVertices; v++) {
185
-            struct vertex_t vert;
198
+            vertex_t vert;
186 199
             // Vertex coordinates, relative to x/zOffset
187 200
             vert.x = file.read16();
188 201
             vert.y = file.read16();
@@ -340,6 +353,11 @@ void LoaderTR2::loadRooms() {
340 353
 
341 354
         getWorld().addRoom(room);
342 355
     }
356
+
357
+    if (numRooms > 0)
358
+        getLog() << "LoaderTR2: Found " << numRooms << " Rooms!" << Log::endl;
359
+    else
360
+        getLog() << "LoaderTR2: No Rooms in this Level?!" << Log::endl;
343 361
 }
344 362
 
345 363
 void LoaderTR2::loadFloorData() {
@@ -389,6 +407,12 @@ void LoaderTR2::loadSprites() {
389 407
         }
390 408
         getWorld().addSprite(ss);
391 409
     }
410
+
411
+    if ((numSpriteTextures > 0) || (numSpriteSequences > 0))
412
+        getLog() << "LoaderTR2: Found " << numSpriteTextures << " Sprites in " << numSpriteSequences <<
413
+                 " Sequences!" << Log::endl;
414
+    else
415
+        getLog() << "LoaderTR2: No Sprites in this level?!" << Log::endl;
392 416
 }
393 417
 
394 418
 // ---- Meshes ----
@@ -493,6 +517,9 @@ void LoaderTR2::loadMeshes() {
493 517
 
494 518
         // TODO store mesh data somewhere
495 519
     }
520
+
521
+    if (numMeshPointers > 0)
522
+        getLog() << "LoaderTR2: Found " << numMeshPointers << " Meshes, unimplemented!" << Log::endl;
496 523
 }
497 524
 
498 525
 void LoaderTR2::loadStaticMeshes() {
@@ -528,12 +555,45 @@ void LoaderTR2::loadStaticMeshes() {
528 555
 
529 556
     if (numStaticMeshes > 0)
530 557
         getLog() << "LoaderTR2: Found " << numStaticMeshes << " StaticMeshes, unimplemented!" << Log::endl;
558
+    else
559
+        getLog() << "LoaderTR2: No StaticMeshes in this level?!" << Log::endl;
531 560
 }
532 561
 
533 562
 // ---- Moveables ----
534 563
 
564
+struct Animation_t {
565
+    uint32_t frameOffset;
566
+    uint8_t frameRate, frameSize;
567
+    uint16_t stateID, frameStart, frameEnd, nextAnimation;
568
+    uint16_t nextFrame, numStateChanges, stateChangeOffset;
569
+    uint16_t numAnimCommands, animCommandOffset;
570
+
571
+    Animation_t(uint32_t fo, uint8_t fr, uint8_t fs, uint16_t si,
572
+                uint16_t fst, uint16_t fe, uint16_t na, uint16_t nf,
573
+                uint16_t ns, uint16_t so, uint16_t nac, uint16_t ao)
574
+        : frameOffset(fo), frameRate(fr), frameSize(fs),
575
+          stateID(si), frameStart(fst), frameEnd(fe), nextAnimation(na),
576
+          nextFrame(nf), numStateChanges(ns), stateChangeOffset(so),
577
+          numAnimCommands(nac), animCommandOffset(ao) { }
578
+};
579
+
580
+struct StateChange_t {
581
+    uint16_t stateID, numAnimDispatches, animDispatchOffset;
582
+
583
+    StateChange_t(uint16_t s, uint16_t n, uint16_t a)
584
+        : stateID(s), numAnimDispatches(n), animDispatchOffset(a) { }
585
+};
586
+
587
+struct AnimDispatch_t {
588
+    int16_t low, high, nextAnimation, nextFrame;
589
+
590
+    AnimDispatch_t(int16_t l, int16_t h, int16_t na, int16_t nf)
591
+        : low(l), high(h), nextAnimation(na), nextFrame(nf) { }
592
+};
593
+
535 594
 void LoaderTR2::loadMoveables() {
536 595
     uint32_t numAnimations = file.readU32();
596
+    std::vector<Animation_t> animations;
537 597
     for (unsigned int a = 0; a < numAnimations; a++) {
538 598
         // *Byte* Offset into Frames[] (so divide by 2!)
539 599
         uint32_t frameOffset = file.readU32();
@@ -559,59 +619,109 @@ void LoaderTR2::loadMoveables() {
559 619
         uint16_t numAnimCommands = file.readU16(); // How many animation commands to use
560 620
         uint16_t animCommandOffset = file.readU16(); // Index into AnimCommand[]
561 621
 
562
-        // TODO store animations somewhere
622
+        animations.emplace_back(frameOffset, frameRate, frameSize,
623
+                                stateID, frameStart, frameEnd, nextAnimation, nextFrame, numStateChanges,
624
+                                stateChangeOffset, numAnimCommands, animCommandOffset);
563 625
     }
564 626
 
627
+    if (numAnimations > 0)
628
+        getLog() << "LoaderTR2: Found " << numAnimations << " Animations!" << Log::endl;
629
+    else
630
+        getLog() << "LoaderTR2: No Animations in this level?!" << Log::endl;
631
+
565 632
     uint32_t numStateChanges = file.readU32();
633
+    std::vector<StateChange_t> stateChanges;
566 634
     for (unsigned int s = 0; s < numStateChanges; s++) {
567 635
         uint16_t stateID = file.readU16();
568
-        uint16_t numAnimDispatches = file.readU16();
636
+        uint16_t numAnimDispatches = file.readU16(); // Number of ranges (always 1..5?)
569 637
         uint16_t animDispatchOffset = file.readU16(); // Index into AnimDispatches[]
570 638
 
571
-        // TODO store state changes somewhere
639
+        stateChanges.emplace_back(stateID, numAnimDispatches, animDispatchOffset);
572 640
     }
573 641
 
642
+    if (numStateChanges > 0)
643
+        getLog() << "LoaderTR2: Found " << numStateChanges << " StateChanges!" << Log::endl;
644
+    else
645
+        getLog() << "LoaderTR2: No StateChanges in this level?!" << Log::endl;
646
+
574 647
     uint32_t numAnimDispatches = file.readU32();
648
+    std::vector<AnimDispatch_t> animDispatches;
575 649
     for (unsigned int a = 0; a < numAnimDispatches; a++) {
576 650
         int16_t low = file.read16(); // Lowest frame that uses this range
577 651
         int16_t high = file.read16(); // Highest frame (+1?) that uses this range
578 652
         int16_t nextAnimation = file.read16(); // Animation to go to
579 653
         int16_t nextFrame = file.read16(); // Frame offset to go to
580 654
 
581
-        // TODO store animation dispatches somewhere
655
+        animDispatches.emplace_back(low, high, nextAnimation, nextFrame);
582 656
     }
583 657
 
658
+    if (numAnimDispatches > 0)
659
+        getLog() << "LoaderTR2: Found " << numAnimDispatches << " AnimationDispatches!" << Log::endl;
660
+    else
661
+        getLog() << "LoaderTR2: No AnimationDispatches in this level?!" << Log::endl;
662
+
584 663
     uint32_t numAnimCommands = file.readU32();
585 664
     std::vector<int16_t> animCommands;
586 665
     for (unsigned int a = 0; a < numAnimCommands; a++) {
666
+        // A list of Opcodes with zero or more operands each,
667
+        // some referring to the whole animation (jump/grab points),
668
+        // some to specific frames (sound, bubbles, ...).
587 669
         animCommands.push_back(file.read16());
588 670
     }
589 671
 
672
+    if (numAnimCommands > 0)
673
+        getLog() << "LoaderTR2: Found " << numAnimCommands << " AnimationCommands!" << Log::endl;
674
+    else
675
+        getLog() << "LoaderTR2: No AnimationCommands in this level?!" << Log::endl;
676
+
677
+    // This is really one uint32_t flags, followed by
678
+    // three int32_t x, y, z. However, we're given the number
679
+    // of 32bits, as well as byte indices later, so we store
680
+    // it as a single list of int32_t.
590 681
     uint32_t numMeshTrees = file.readU32();
682
+    std::vector<int32_t> meshTrees;
591 683
     for (unsigned int m = 0; m < numMeshTrees; m++) {
592 684
         // 0x0002 - Put parent mesh on the mesh stack
593 685
         // 0x0001 - Pop mesh from stack, use as parent mesh
594 686
         // When both are not set, use previous mesh as parent mesh
595 687
         // When both are set, do 0x0001 first, then 0x0002, thereby
596 688
         // reading the stack but not changing it
597
-        uint32_t flags = file.readU32();
598
-
689
+        //uint32_t flags = file.readU32();
599 690
 
600 691
         // Offset of mesh origin from the parent mesh origin
601 692
         //int32_t x = file.read32();
602 693
         //int32_t y = file.read32();
603 694
         //int32_t z = file.read32();
604
-        // Does not appear to be true...?
605 695
 
606
-        // TODO store mesh trees somewhere
696
+        meshTrees.push_back(file.read32());
607 697
     }
608 698
 
699
+    if (numMeshTrees > 0)
700
+        getLog() << "LoaderTR2: Found " << numMeshTrees << " MeshTrees!" << Log::endl;
701
+    else
702
+        getLog() << "LoaderTR2: No MeshTrees in this level?!" << Log::endl;
703
+
609 704
     uint32_t numFrames = file.readU32();
610 705
     std::vector<uint16_t> frames;
611 706
     for (unsigned int f = 0; f < numFrames; f++) {
707
+        // int16 bb1x, bb1y, bb1z
708
+        // int16 bb2x, bb2y, bb2z
709
+        // int16 offsetX, offsetY, offsetZ
710
+        // What follows next is a list of angles with numMeshes (from Moveable) entries.
711
+        // If the top bit (0x8000) of the first uint16 is set, a single X angle follows,
712
+        // if the second bit (0x4000) is set, a Y angle follows, both are a Z angle.
713
+        // If none is set, it's a three-axis rotation. The next 10 bits (0x3FF0) are
714
+        // the X rotation, the next 10 (0x000F 0xFC00) are Y, the next (0x03FF) are
715
+        // the Z rotation. The scaling is always 0x100->90deg.
716
+        // Rotation order: Y, X, Z!
612 717
         frames.push_back(file.readU16());
613 718
     }
614 719
 
720
+    if (numFrames > 0)
721
+        getLog() << "LoaderTR2: Found " << numFrames << " Frames!" << Log::endl;
722
+    else
723
+        getLog() << "LoaderTR2: No Frames in this level?!" << Log::endl;
724
+
615 725
     uint32_t numMoveables = file.readU32();
616 726
     for (unsigned int m = 0; m < numMoveables; m++) {
617 727
         // Item identifier, matched in Items[]
@@ -620,16 +730,80 @@ void LoaderTR2::loadMoveables() {
620 730
         uint16_t startingMesh = file.readU16(); // Offset into MeshPointers[]
621 731
         uint32_t meshTree = file.readU32(); // Offset into MeshTree[]
622 732
         // *Byte* offset into Frames[] (divide by 2 for Frames[i])
623
-        uint32_t frameOffset = file.readU32();
733
+        uint32_t frameOffset = file.readU32(); // Only needed if no animation
624 734
 
625 735
         // If animation index is 0xFFFF, the object is stationary or
626 736
         // animated by the engine (ponytail)
627 737
         uint16_t animation = file.readU16();
628 738
 
629
-        // TODO store moveables somewhere
739
+        // TODO load all animations, not only the first frame!
740
+        //if (animation == 0xFFFF) {
741
+
742
+        // Just add the frame indicated in frameOffset, nothing else
743
+        char* tmp = reinterpret_cast<char*>(&frames[0]) + frameOffset;
744
+        BinaryMemory frame(tmp + 12, (numFrames * 2) - frameOffset - 12); // skip two BBs
745
+        float pos[3];
746
+        pos[0] = frame.read16();
747
+        pos[1] = frame.read16();
748
+        pos[2] = frame.read16();
749
+        BoneFrame* bf = new BoneFrame(pos);
750
+
751
+        for (int i = 0; i < numMeshes; i++) {
752
+            int mesh = startingMesh + i;
753
+            float offset[3] = { 0.0f, 0.0f, 0.0f };
754
+            float rotation[3] = { 0.0f, 0.0f, 0.0f };
755
+            char flag = (i == 0) ? 2 : 0;
756
+
757
+            // Nonprimary tag - positioned relative to first tag
758
+            if (i != 0) {
759
+                tmp = reinterpret_cast<char*>(&meshTrees[0]) + meshTree; // TODO (meshTree * 4)?
760
+                tmp += (i - 1) * 16; // TODO ?
761
+                BinaryMemory tree(tmp, (numMeshTrees * 4) - meshTree - ((i - 1) * 16));
762
+                flag = (char)tree.readU32();
763
+                offset[0] = tree.read32();
764
+                offset[1] = tree.read32();
765
+                offset[2] = tree.read32();
766
+
767
+                uint16_t a = frame.readU16();
768
+                if (a & 0xC000) {
769
+                    // Single angle
770
+                    int index = 0;
771
+                    if ((a & 0x8000) && (a & 0x4000))
772
+                        index = 2;
773
+                    else if (a & 0x4000)
774
+                        index = 1;
775
+                    rotation[index] = ((float)(a & 0x03FF)) * 360.0f / 1024.0f;
776
+                } else {
777
+                    // Three angles
778
+                    uint16_t b = frame.readU16();
779
+                    rotation[0] = (a & 0x3FF0) >> 4;
780
+                    rotation[1] = ((a & 0x000F) << 6) | ((b & 0xFC00) >> 10);
781
+                    rotation[2] = b & 0x03FF;
782
+                    for (int i = 0; i < 3; i++)
783
+                        rotation[i] = rotation[i] * 360.0f / 1024.0f;
784
+                }
785
+            }
786
+
787
+            BoneTag* bt = new BoneTag(mesh, offset, rotation, flag);
788
+            bf->add(bt);
789
+        }
790
+
791
+        AnimationFrame* af = new AnimationFrame(0);
792
+        af->add(bf);
793
+
794
+        SkeletalModel* sm = new SkeletalModel(objectID);
795
+        sm->add(af);
796
+        getWorld().addSkeletalModel(sm);
797
+
798
+        //} else {
799
+        // Add the whole animation hierarchy
800
+        //}
630 801
     }
631 802
 
632
-    // TODO combine all this into moveables with their animations
803
+    if (numMoveables > 0)
804
+        getLog() << "LoaderTR2: Found " << numMoveables << " Moveables!" << Log::endl;
805
+    else
806
+        getLog() << "LoaderTR2: No Moveables in this level?!" << Log::endl;
633 807
 }
634 808
 
635 809
 void LoaderTR2::loadItems() {
@@ -651,11 +825,35 @@ void LoaderTR2::loadItems() {
651 825
         // 0x3E00 - Activation mask, open, can be XORed with related FloorData list fields.
652 826
         uint16_t flags = file.readU16();
653 827
 
654
-        // TODO store items somewhere
828
+        // TODO for now we're only creating Entities for each Moveable Item
829
+        for (int m = 0; m < getWorld().sizeSkeletalModel(); m++) {
830
+            if (getWorld().getSkeletalModel(m).getId() == objectID) {
831
+                float pos[3] = {
832
+                    static_cast<float>(x),
833
+                    static_cast<float>(y),
834
+                    static_cast<float>(z)
835
+                };
836
+
837
+                float rot[3] = {
838
+                    0.0f,
839
+                    OR_DEG_TO_RAD(((angle >> 14) & 0x03) * 90.0f),
840
+                    0.0f
841
+                };
842
+
843
+                Entity* e = new Entity(pos, rot, objectID, room, m);
844
+                getWorld().addEntity(e);
845
+
846
+                if (objectID == 0) {
847
+                    getGame().setLara(getWorld().sizeEntity() - 1);
848
+                }
849
+            }
850
+        }
655 851
     }
656 852
 
657 853
     if (numItems > 0)
658 854
         getLog() << "LoaderTR2: Found " << numItems << " Items, unimplemented!" << Log::endl;
855
+    else
856
+        getLog() << "LoaderTR2: No Items in this level?!" << Log::endl;
659 857
 }
660 858
 
661 859
 void LoaderTR2::loadBoxesOverlapsZones() {

Loading…
Cancel
Save