Kaynağa Gözat

Added PCX image reading support

Thomas Buck 10 yıl önce
ebeveyn
işleme
f9d10c89c4
9 değiştirilmiş dosya ile 239 ekleme ve 15 silme
  1. 2
    0
      ChangeLog.md
  2. 1
    5
      TODO.md
  3. 3
    9
      include/Camera.h
  4. 7
    1
      include/global.h
  5. 18
    0
      include/utils/pcx.h
  6. 7
    0
      src/Render.cpp
  7. 13
    0
      src/Texture.cpp
  8. 1
    0
      src/utils/CMakeLists.txt
  9. 187
    0
      src/utils/pcx.cpp

+ 2
- 0
ChangeLog.md Dosyayı Görüntüle

@@ -6,6 +6,8 @@
6 6
     * No longer crashes simply by walking in the wrong place
7 7
     * Added walk Action, supposed to switch to slow walking/sidesteps
8 8
     * Removed unused Camera functionality (side and up vector)
9
+    * Wrote simple PCX image reading library with proof-of-concept
10
+      code to load the TR2 menu background as splash screen
9 11
 
10 12
     [ 20140517 ]
11 13
     * Wrote new assert() implementation for Unix that prints a call stack

+ 1
- 5
TODO.md Dosyayı Görüntüle

@@ -17,10 +17,6 @@ There are these DebugModel, DebugMap flags...?
17 17
 ## Changes
18 18
 
19 19
 * Using std::vector with [] is not bound checked. Segfaults were caused because the upper bound of the argument was never checked and garbage was returned... Do consistent checks, or use .at() as it throws an exception
20
-* Creating the Room class has introduced a bug that crashes when walking the level:
21
-
22
-    Assertion failed: (sector < (int)mRooms.at(room)->sizeSectors()), function isWall, file /Users/thomas/Projekte/OpenRaider/src/World.cpp, line 180.
23
-
24 20
 * The wrong SkeletalModels are used by entities, except for Lara...?
25 21
 
26 22
 ## Cmake
@@ -32,7 +28,7 @@ There are these DebugModel, DebugMap flags...?
32 28
 ## Future Features
33 29
 
34 30
 * Use only assets from old TR games?
35
-* PCX image reading for eg. TR2 built-in menu background
31
+* [PCX image reading](http://bespin.org/~qz/pc-gpe/pcx.txt) for eg. TR2 built-in menu background
36 32
     * Cut TGA image reader, currently only used for menu background?!
37 33
 * When cutscene rendering is working, use TR4/5 style menu?
38 34
 

+ 3
- 9
include/Camera.h Dosyayı Görüntüle

@@ -65,21 +65,15 @@ public:
65 65
     void update();
66 66
 
67 67
     /*!
68
-     * \brief Rotate the camera
69
-     * \param angle angle in radians
70
-     * \param x X coordinate of axis
71
-     * \param y Y coordinate of axis
72
-     * \param z Z coordinate of axis
73
-     */
74
-    void rotate(vec_t angle, vec_t x, vec_t y, vec_t z);
75
-
76
-    /*!
77 68
      * \brief Sends interactive command to camera
78 69
      * \param cmd valid camera command
79 70
      */
80 71
     void command(enum camera_command cmd);
81 72
 
82 73
 private:
74
+
75
+    void rotate(vec_t angle, vec_t x, vec_t y, vec_t z);
76
+
83 77
     Quaternion mQ;         //!< Quaternion for rotation
84 78
     vec4_t mPos;           //!< Location in 3 space (aka eye)
85 79
     vec4_t mTarget;        //!< Postition we're looking at

+ 7
- 1
include/global.h Dosyayı Görüntüle

@@ -24,6 +24,7 @@
24 24
 #include <GL/gl.h>
25 25
 #endif
26 26
 
27
+// If available, use our own assert that prints the call stack
27 28
 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
28 29
 #ifndef NDEBUG
29 30
 [[noreturn]] void assertImplementation(const char *exp, const char *file, int line);
@@ -32,9 +33,11 @@
32 33
 #define assert(x)
33 34
 #endif
34 35
 #else
36
+// Fall back to the default C assert
35 37
 #include <cassert>
36 38
 #endif
37 39
 
40
+// Colors used for Rendering
38 41
 const float BLACK[]       = {  0.0f,  0.0f,  0.0f, 1.0f };
39 42
 const float DIM_WHITE[]   = {  0.5f,  0.5f,  0.5f, 1.0f };
40 43
 const float WHITE[]       = {  1.0f,  1.0f,  1.0f, 1.0f };
@@ -46,6 +49,7 @@ const float PINK[]        = {  1.0f,  0.0f,  1.0f, 1.0f };
46 49
 const float YELLOW[]      = {  1.0f,  1.0f,  0.0f, 1.0f };
47 50
 const float CYAN[]        = {  0.0f,  1.0f,  1.0f, 1.0f };
48 51
 
52
+// Actions that can be bound to a key and sent to the game engine
49 53
 typedef enum {
50 54
     menuAction = 0,
51 55
     consoleAction, // menu and console should always be the first two items
@@ -62,6 +66,7 @@ typedef enum {
62 66
     ActionEventCount // Should always be at the end
63 67
 } ActionEvents;
64 68
 
69
+// Keys available for binding
65 70
 typedef enum {
66 71
     zeroKey = '0', oneKey = '1', twoKey = '2',
67 72
     threeKey = '3', fourKey = '4', fiveKey = '5',
@@ -83,7 +88,8 @@ typedef enum {
83 88
     rightguiKey, rightbracketKey, rightshiftKey, scrolllockKey,
84 89
     semicolonKey, slashKey, spaceKey, tabKey,
85 90
     leftmouseKey, middlemouseKey, rightmouseKey,
86
-    unknownKey
91
+
92
+    unknownKey // Should always be at the end
87 93
 } KeyboardButton;
88 94
 
89 95
 #endif

+ 18
- 0
include/utils/pcx.h Dosyayı Görüntüle

@@ -0,0 +1,18 @@
1
+/*!
2
+ * \file include/utils/pcx.h
3
+ * \brief PCX image reader
4
+ *
5
+ * Based on official technical documentation from ZSoft:
6
+ * http://bespin.org/~qz/pc-gpe/pcx.txt
7
+ *
8
+ * \author xythobuz
9
+ */
10
+
11
+#ifndef _UTILS_PCX_H_
12
+#define _UTILS_PCX_H_
13
+
14
+// Returns 0 on success
15
+int pcxLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height);
16
+
17
+#endif
18
+

+ 7
- 0
src/Render.cpp Dosyayı Görüntüle

@@ -101,11 +101,18 @@ int Render::initTextures(char *textureDir) {
101 101
     if (mTexture.loadColorTexture(color, 32, 32) > -1)
102 102
         numTextures++;
103 103
 
104
+#ifdef PCX_PROOF_OF_CONCEPT
105
+    filename = bufferString("/Users/thomas/.OpenRaider/paks/tr2/TITLE.PCX");
106
+    if (mTexture.loadTGA(filename) > -1)
107
+        numTextures++;
108
+    delete [] filename;
109
+#else
104 110
     //! \fixme Error Checking. Return negative error code, check in calling place too
105 111
     filename = bufferString("%s/%s", textureDir, "splash.tga");
106 112
     if (mTexture.loadTGA(filename) > -1)
107 113
         numTextures++;
108 114
     delete [] filename;
115
+#endif
109 116
 
110 117
     return numTextures;
111 118
 }

+ 13
- 0
src/Texture.cpp Dosyayı Görüntüle

@@ -12,6 +12,7 @@
12 12
 #include <stdarg.h>
13 13
 
14 14
 #include "global.h"
15
+#include "utils/pcx.h"
15 16
 #include "utils/strings.h"
16 17
 #include "utils/tga.h"
17 18
 #include "Texture.h"
@@ -279,6 +280,17 @@ void Texture::bindTextureId(unsigned int n) {
279 280
 }
280 281
 
281 282
 int Texture::loadTGA(const char *filename) {
283
+#ifdef PCX_PROOF_OF_CONCEPT
284
+    unsigned char *image;
285
+    unsigned int w, h;
286
+    int id = -1;
287
+    int error = pcxLoad(filename, &image, &w, &h);
288
+    if (error == 0) {
289
+        id = loadBuffer(image, w, h, RGBA, 32);
290
+        delete [] image;
291
+    }
292
+    return id;
293
+#else
282 294
     FILE *f;
283 295
     unsigned char *image = NULL;
284 296
     unsigned char *image2 = NULL;
@@ -321,6 +333,7 @@ int Texture::loadTGA(const char *filename) {
321 333
     }
322 334
 
323 335
     return id;
336
+#endif
324 337
 }
325 338
 
326 339
 int Texture::nextPower(int seed) {

+ 1
- 0
src/utils/CMakeLists.txt Dosyayı Görüntüle

@@ -1,4 +1,5 @@
1 1
 # Source files
2
+set (UTIL_SRCS ${UTIL_SRCS} "pcx.cpp")
2 3
 set (UTIL_SRCS ${UTIL_SRCS} "strings.cpp")
3 4
 set (UTIL_SRCS ${UTIL_SRCS} "tga.cpp")
4 5
 set (UTIL_SRCS ${UTIL_SRCS} "time.cpp")

+ 187
- 0
src/utils/pcx.cpp Dosyayı Görüntüle

@@ -0,0 +1,187 @@
1
+/*!
2
+ * \file src/utils/pcx.cpp
3
+ * \brief PCX image reader
4
+ *
5
+ * Based on official technical documentation from ZSoft:
6
+ * http://bespin.org/~qz/pc-gpe/pcx.txt
7
+ *
8
+ * \author xythobuz
9
+ */
10
+
11
+#include <fstream>
12
+
13
+#include "global.h"
14
+#include "utils/pcx.h"
15
+
16
+#include "Console.h"
17
+
18
+#ifdef DEBUG
19
+#define pcxPrint getConsole().print
20
+#else
21
+void pcxPrint(...) { }
22
+#endif
23
+
24
+int pcxLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height) {
25
+    std::ifstream file(filename, std::ios::in | std::ios::binary);
26
+
27
+    // Read raw PCX header, 128 bytes
28
+    unsigned char *header = new unsigned char[128];
29
+
30
+    // Basic validation
31
+    if (!file.read((char *)(&header[0]), 128)) {
32
+        pcxPrint("File not big enough for valid PCX header!");
33
+        delete [] header;
34
+        return -1;
35
+    }
36
+
37
+    if (header[0] != 0x0A) {
38
+        pcxPrint("Magic number at file start is wrong (0x%X != 0x0A)", header[0]);
39
+        delete [] header;
40
+        return -2;
41
+    }
42
+
43
+    if ((header[1] != 0) && ((header[1] < 2) || (header[1] > 5))) {
44
+        // Valid: 0, 2, 3, 4, 5
45
+        pcxPrint("Unknown PCX file format version (%d)", header[1]);
46
+        delete [] header;
47
+        return -3;
48
+    }
49
+
50
+    if ((header[2] != 0) && (header[2] != 1)) {
51
+        pcxPrint("Unknown PCX file encoding (%d)", header[2]);
52
+        delete [] header;
53
+        return -4;
54
+    }
55
+
56
+    if (header[3] != 8) {
57
+        pcxPrint("Only supporting 8bit (%dbit)", header[3]);
58
+        delete [] header;
59
+        return -5;
60
+    }
61
+
62
+    if (header[64] != 0) {
63
+        pcxPrint("Reserved field is  used (%d != 0)", header[64]);
64
+        delete [] header;
65
+        return -6;
66
+    }
67
+
68
+    // Read header informations
69
+    bool versionFive = (header[1] == 5);
70
+    bool compressed = (header[2] == 1);
71
+    //unsigned char bitsPerPixel = header[3];
72
+    unsigned int xMin = header[4] | (header[5] << 8);
73
+    unsigned int yMin = header[6] | (header[7] << 8);
74
+    unsigned int xMax = header[8] | (header[9] << 8);
75
+    unsigned int yMax = header[10] | (header[11] << 8);
76
+    //unsigned int hDPI = header[12] | (header[13] << 8);
77
+    //unsigned int vDPI = header[14] | (header[15] << 8);
78
+    //unsigned char *colormap = header + 16;
79
+    unsigned char nPlanes = header[65];
80
+    unsigned int bytesPerLine = header[66] | (header[67] << 8);
81
+    //unsigned int paletteInfo = header[68] | (header[69] << 8);
82
+    //unsigned int hScreenSize = header[70] | (header[71] << 8); // Only in some versionFive files
83
+    //unsigned int vScreenSize = header[72] | (header[73] << 8); // Only in some versionFive files
84
+
85
+    delete [] header;
86
+
87
+    // Calculations
88
+    *width = xMax - xMin + 1;
89
+    *height = yMax - yMin + 1;
90
+    unsigned long totalBytes = nPlanes * bytesPerLine; // total bytes per scan line
91
+    unsigned long imageSize = totalBytes * *height;
92
+    unsigned char *buffer = new unsigned char[imageSize];
93
+    unsigned long b = 0;
94
+
95
+    // Read encoded pixel data
96
+    for (unsigned long i = 0; i < imageSize;) {
97
+        unsigned int n = 1; // Run-length-encoding assumes 1
98
+        int c = file.get();
99
+        if (!file) {
100
+            pcxPrint("Could not read data (%lu%s)", i, (file.eof() ? " EOF" : ""));
101
+            delete buffer;
102
+            return -7;
103
+        }
104
+
105
+        // Run-Length-Encoding
106
+        if (compressed) {
107
+            if ((c & 0xC0) == 0xC0) {
108
+                n = c & 0x3F;
109
+                c = file.get();
110
+                if (!file) {
111
+                    pcxPrint("Could not read data rle (%lu%s)", i, (file.eof() ? " EOF" : ""));
112
+                    return -8;
113
+                }
114
+            }
115
+        }
116
+
117
+        for (unsigned int j = 0; j < n; j++)
118
+            buffer[b++] = (unsigned char)c;
119
+
120
+        i += n;
121
+    }
122
+
123
+    // Read color palette
124
+    unsigned char *palette = NULL;
125
+    if (versionFive) {
126
+        int c = file.get();
127
+        if ((c == 12) && file) {
128
+            palette = new unsigned char[768];
129
+            for (unsigned int i = 0; i < 768; i++) {
130
+                palette[i] = (unsigned char)file.get();
131
+                if (!file) {
132
+                    pcxPrint("Could not read 256 color palette (%d)", i);
133
+                    return -9;
134
+                }
135
+            }
136
+        }
137
+    }
138
+
139
+    // Bring buffer into preferred format
140
+    unsigned long size = *width * *height * 4;
141
+    *image = new unsigned char[size];
142
+    for (unsigned int y = 0; y < *height; y++) {
143
+        for (unsigned int x = 0; x < *width; x++) {
144
+            unsigned long baseIndex = (x + (y * *width)) * 4;
145
+            unsigned char alpha = 255, red = 0, green = 0, blue = 0;
146
+
147
+            if (palette != NULL) {
148
+                if (nPlanes == 1) {
149
+                    red = palette[buffer[(y * totalBytes) + x] * 3];
150
+                    green = palette[(buffer[(y * totalBytes) + x] * 3) + 1];
151
+                    blue = palette[(buffer[(y * totalBytes) + x] * 3) + 2];
152
+                } else {
153
+                    pcxPrint("Unsupported number of planes (%d)", nPlanes);
154
+                    delete [] buffer;
155
+                    delete [] *image;
156
+                    return -10;
157
+                }
158
+            } else {
159
+                if ((nPlanes == 3) || (nPlanes == 4)) {
160
+                    red = buffer[(y * totalBytes) + x];
161
+                    green = buffer[(y * totalBytes) + *width + x];
162
+                    blue = buffer[(y * totalBytes) + (2 * *width) + x];
163
+                    if (nPlanes == 4)
164
+                        alpha = buffer[(y * totalBytes) + (3 * *width) + x];
165
+                } else if (nPlanes == 1) {
166
+                    red = green = blue = buffer[(y * totalBytes) + x];
167
+                } else {
168
+                    pcxPrint("Unsupported number of planes (%d)", nPlanes);
169
+                    delete [] buffer;
170
+                    delete [] *image;
171
+                    return -11;
172
+                }
173
+            }
174
+
175
+            (*image)[baseIndex + 0] = red;
176
+            (*image)[baseIndex + 1] = green;
177
+            (*image)[baseIndex + 2] = blue;
178
+            (*image)[baseIndex + 3] = alpha;
179
+        }
180
+    }
181
+
182
+    if (palette != NULL)
183
+        delete [] palette;
184
+
185
+    return 0;
186
+}
187
+

Loading…
İptal
Kaydet