Skip to content
This repository was archived by the owner on Jun 28, 2025. It is now read-only.

Commit 0c070cf

Browse files
committed
Use RGB555 for back buffers in graphics software mode
This simplifies a bit the conversions and provide an extra bit that can be used to prevent additive blending, fixing a few glitches found with the original 3DO version.
1 parent 8c3eb71 commit 0c070cf

File tree

11 files changed

+72
-65
lines changed

11 files changed

+72
-65
lines changed

graphics.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
enum {
88
FMT_CLUT,
9-
FMT_RGB565,
9+
FMT_RGB555,
1010
FMT_RGB,
1111
FMT_RGBA,
1212
};
@@ -29,6 +29,7 @@ enum {
2929
};
3030

3131
enum {
32+
ALPHA_COLOR_INDEX = 12,
3233
GFX_W = 320,
3334
GFX_H = 200
3435
};
@@ -39,7 +40,7 @@ struct Graphics {
3940

4041
static const uint8_t _font[];
4142
static bool _is1991; // draw graphics as in the original 1991 game release
42-
static bool _use565; // use 16bits graphics buffer (for 3DO)
43+
static bool _use555; // use 16bits graphics buffer (for 3DO)
4344

4445
int _fixUpPalette;
4546
bool _screenshot;

graphics_gl.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ struct Texture {
7272
void clear();
7373
void readRaw16(const uint8_t *src, const Color *pal, int w, int h);
7474
void readFont(const uint8_t *src);
75+
void readRGB555(const uint16_t *src, int w, int h);
7576
};
7677

7778
void Texture::init() {
@@ -226,6 +227,24 @@ void Texture::readFont(const uint8_t *src) {
226227
}
227228
}
228229

230+
static uint16_t rgb555_to_565(const uint16_t color) {
231+
const int r = (color >> 10) & 31;
232+
const int g = (color >> 5) & 31;
233+
const int b = color & 31;
234+
return (r << 11) | (g << 6) | b;
235+
}
236+
237+
void Texture::readRGB555(const uint16_t *src, int w, int h) {
238+
_rgbData = (uint8_t *)malloc(w * h * sizeof(uint16_t));
239+
if (!_rgbData) {
240+
return;
241+
}
242+
for (int i = 0; i < w * h; ++i) {
243+
((uint16_t *)_rgbData)[i] = rgb555_to_565(src[i]);
244+
}
245+
uploadDataRGB(_rgbData, w * sizeof(uint16_t), w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
246+
}
247+
229248
struct DrawListEntry {
230249
static const int NUM_VERTICES = 1024;
231250

@@ -312,7 +331,7 @@ struct GraphicsGL : Graphics {
312331
GraphicsGL::GraphicsGL() {
313332
_fixUpPalette = FIXUP_PALETTE_NONE;
314333
memset(_pal, 0, sizeof(_pal));
315-
_alphaColor = &_pal[12]; /* _pal[0x8 | color] */
334+
_alphaColor = &_pal[ALPHA_COLOR_INDEX];
316335
_spritesSizeX = _spritesSizeY = 0;
317336
_sprite.num = -1;
318337
}
@@ -494,9 +513,9 @@ void GraphicsGL::drawBitmap(int listNum, const uint8_t *data, int w, int h, int
494513
_backgroundTex.clear();
495514
_backgroundTex.uploadDataRGB(data, w * 3, w, h, GL_RGB, GL_UNSIGNED_BYTE);
496515
break;
497-
case FMT_RGB565:
516+
case FMT_RGB555:
498517
_backgroundTex.clear();
499-
_backgroundTex.uploadDataRGB(data, w * 2, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
518+
_backgroundTex.readRGB555((const uint16_t *)data, w, h);
500519
break;
501520
}
502521
_fptr.glBindFramebuffer(GL_FRAMEBUFFER, _fbPage0);

graphics_soft.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void GraphicsSoft::setSize(int w, int h) {
7878
_v = (h << 16) / GFX_H;
7979
_w = w;
8080
_h = h;
81-
_byteDepth = _use565 ? 2 : 1;
81+
_byteDepth = _use555 ? 2 : 1;
8282
assert(_byteDepth == 1 || _byteDepth == 2);
8383
_colorBuffer = (uint16_t *)realloc(_colorBuffer, _w * _h * sizeof(uint16_t));
8484
if (!_colorBuffer) {
@@ -189,7 +189,7 @@ void GraphicsSoft::drawChar(uint8_t c, uint16_t x, uint16_t y, uint8_t color) {
189189
}
190190
}
191191
} else if (_byteDepth == 2) {
192-
const uint16_t rgbColor = _pal[color].rgb565();
192+
const uint16_t rgbColor = _pal[color].rgb555();
193193
for (int j = 0; j < 8; ++j) {
194194
const uint8_t ch = ft[j];
195195
for (int i = 0; i < 8; ++i) {
@@ -202,19 +202,22 @@ void GraphicsSoft::drawChar(uint8_t c, uint16_t x, uint16_t y, uint8_t color) {
202202
}
203203
}
204204

205-
static void blend_rgb565(uint16_t *dst, const uint16_t b) {
206-
static const uint16_t RB_MASK = 0xf81f;
207-
static const uint16_t G_MASK = 0x07e0;
208-
uint16_t r, a = *dst;
209-
r = (((a & RB_MASK) + (b & RB_MASK)) >> 1) & RB_MASK;
210-
r |= (((a & G_MASK) + (b & G_MASK)) >> 1) & G_MASK;
211-
*dst = r;
205+
static void blend_rgb555(uint16_t *dst, const uint16_t b) {
206+
static const uint16_t RB_MASK = 0x7c1f;
207+
static const uint16_t G_MASK = 0x03e0;
208+
uint16_t a = *dst;
209+
if ((a & 0x8000) == 0) { // use bit 15 to prevent additive blending
210+
uint16_t r = 0x8000;
211+
r |= (((a & RB_MASK) + (b & RB_MASK)) >> 1) & RB_MASK;
212+
r |= (((a & G_MASK) + (b & G_MASK)) >> 1) & G_MASK;
213+
*dst = r;
214+
}
212215
}
213216

214217
void GraphicsSoft::drawPoint(int16_t x, int16_t y, uint8_t color) {
215218
x = xScale(x);
216219
y = yScale(y);
217-
const int offset = y * _w + x * _byteDepth;
220+
const int offset = (y * _w + x) * _byteDepth;
218221
if (_byteDepth == 1) {
219222
switch (color) {
220223
case COL_ALPHA:
@@ -230,13 +233,13 @@ void GraphicsSoft::drawPoint(int16_t x, int16_t y, uint8_t color) {
230233
} else if (_byteDepth == 2) {
231234
switch (color) {
232235
case COL_ALPHA:
233-
blend_rgb565((uint16_t *)(_drawPagePtr + offset), _pal[12].rgb565());
236+
blend_rgb555((uint16_t *)(_drawPagePtr + offset), _pal[ALPHA_COLOR_INDEX].rgb555());
234237
break;
235238
case COL_PAGE:
236239
*(uint16_t *)(_drawPagePtr + offset) = *(uint16_t *)(_pagePtrs[0] + offset);
237240
break;
238241
default:
239-
*(uint16_t *)(_drawPagePtr + offset) = _pal[color].rgb565();
242+
*(uint16_t *)(_drawPagePtr + offset) = _pal[color].rgb555();
240243
break;
241244
}
242245
}
@@ -252,10 +255,10 @@ void GraphicsSoft::drawLineT(int16_t x1, int16_t x2, int16_t y, uint8_t color) {
252255
_drawPagePtr[offset + i] |= 8;
253256
}
254257
} else if (_byteDepth == 2) {
255-
const uint16_t rgbColor = _pal[12].rgb565();
258+
const uint16_t rgbColor = _pal[ALPHA_COLOR_INDEX].rgb555();
256259
uint16_t *p = (uint16_t *)(_drawPagePtr + offset);
257260
for (int i = 0; i < w; ++i) {
258-
blend_rgb565(p + i, rgbColor);
261+
blend_rgb555(p + i, rgbColor);
259262
}
260263
}
261264
}
@@ -268,7 +271,7 @@ void GraphicsSoft::drawLineN(int16_t x1, int16_t x2, int16_t y, uint8_t color) {
268271
if (_byteDepth == 1) {
269272
memset(_drawPagePtr + offset, color, w);
270273
} else if (_byteDepth == 2) {
271-
const uint16_t rgbColor = _pal[color].rgb565();
274+
const uint16_t rgbColor = _pal[color].rgb555();
272275
uint16_t *p = (uint16_t *)(_drawPagePtr + offset);
273276
for (int i = 0; i < w; ++i) {
274277
p[i] = rgbColor;
@@ -331,7 +334,7 @@ void GraphicsSoft::drawBitmap(int buffer, const uint8_t *data, int w, int h, int
331334
}
332335
break;
333336
case 2:
334-
if (fmt == FMT_RGB565 && _w == w && _h == h) {
337+
if (fmt == FMT_RGB555 && _w == w && _h == h) {
335338
memcpy(getPagePtr(buffer), data, getPageSize());
336339
}
337340
break;
@@ -357,7 +360,7 @@ void GraphicsSoft::clearBuffer(int num, uint8_t color) {
357360
if (_byteDepth == 1) {
358361
memset(getPagePtr(num), color, getPageSize());
359362
} else if (_byteDepth == 2) {
360-
const uint16_t rgbColor = _pal[color].rgb565();
363+
const uint16_t rgbColor = _pal[color].rgb555();
361364
uint16_t *p = (uint16_t *)getPagePtr(num);
362365
for (int i = 0; i < _w * _h; ++i) {
363366
p[i] = rgbColor;
@@ -378,7 +381,7 @@ void GraphicsSoft::copyBuffer(int dst, int src, int vscroll) {
378381
}
379382
}
380383

381-
static void dumpBuffer565(const uint16_t *src, int w, int h, int num) {
384+
static void dumpBuffer555(const uint16_t *src, int w, int h, int num) {
382385
char name[32];
383386
snprintf(name, sizeof(name), "screenshot-%d.tga", num);
384387
saveTGA(name, src, w, h);
@@ -391,7 +394,7 @@ static void dumpPalette555(uint16_t *dst, int w, const Color *pal) {
391394
uint16_t *p = dst + (color & 7) * SZ;
392395
for (int y = 0; y < SZ; ++y) {
393396
for (int x = 0; x < SZ; ++x) {
394-
p[x] = pal[color].rgb565();
397+
p[x] = pal[color].rgb555();
395398
}
396399
p += w;
397400
}
@@ -408,22 +411,22 @@ void GraphicsSoft::drawBuffer(int num, SystemStub *stub) {
408411
if (_byteDepth == 1) {
409412
const uint8_t *src = getPagePtr(num);
410413
for (int i = 0; i < _w * _h; ++i) {
411-
_colorBuffer[i] = _pal[src[i]].rgb565();
414+
_colorBuffer[i] = _pal[src[i]].rgb555();
412415
}
413416
if (0) {
414417
dumpPalette555(_colorBuffer, _w, _pal);
415418
}
416-
stub->setScreenPixels565(_colorBuffer, _w, _h);
419+
stub->setScreenPixels555(_colorBuffer, _w, _h);
417420
if (_screenshot) {
418-
dumpBuffer565(_colorBuffer, _w, _h, _screenshotNum);
421+
dumpBuffer555(_colorBuffer, _w, _h, _screenshotNum);
419422
++_screenshotNum;
420423
_screenshot = false;
421424
}
422425
} else if (_byteDepth == 2) {
423426
const uint16_t *src = (uint16_t *)getPagePtr(num);
424-
stub->setScreenPixels565(src, _w, _h);
427+
stub->setScreenPixels555(src, _w, _h);
425428
if (_screenshot) {
426-
dumpBuffer565(src, _w, _h, _screenshotNum);
429+
dumpBuffer555(src, _w, _h, _screenshotNum);
427430
++_screenshotNum;
428431
_screenshot = false;
429432
}
@@ -434,7 +437,7 @@ void GraphicsSoft::drawBuffer(int num, SystemStub *stub) {
434437
void GraphicsSoft::drawRect(int num, uint8_t color, const Point *pt, int w, int h) {
435438
assert(_byteDepth == 2);
436439
setWorkPagePtr(num);
437-
const uint16_t rgbColor = _pal[color].rgb565();
440+
const uint16_t rgbColor = _pal[color].rgb555();
438441
const int x1 = xScale(pt->x);
439442
const int y1 = yScale(pt->y);
440443
const int x2 = xScale(pt->x + w - 1);

intern.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ struct Color {
132132
uint8_t g;
133133
uint8_t b;
134134

135-
uint16_t rgb565() const {
136-
return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
135+
uint16_t rgb555() const {
136+
return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
137137
}
138138
};
139139

main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static const struct {
5050
};
5151

5252
bool Graphics::_is1991 = false;
53-
bool Graphics::_use565 = false;
53+
bool Graphics::_use555 = false;
5454
bool Video::_useEGA = false;
5555

5656
static Graphics *createGraphics(int type) {
@@ -197,7 +197,7 @@ int main(int argc, char *argv[]) {
197197
}
198198
if (graphicsType != GRAPHICS_GL && e->_res.getDataType() == Resource::DT_3DO) {
199199
graphicsType = GRAPHICS_SOFTWARE;
200-
Graphics::_use565 = true;
200+
Graphics::_use555 = true;
201201
}
202202
Graphics *graphics = createGraphics(graphicsType);
203203
SystemStub *stub = SystemStub_SDL_create();

screenshot.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,7 @@ static void TO_LE16(uint8_t *dst, uint16_t value) {
1616

1717
static const int TGA_HEADER_SIZE = 18;
1818

19-
// 16 bits TGA expects 15 bits color depth
20-
static uint16_t rgb565_to_555(const uint16_t color) {
21-
const int r = (color >> 11) & 31;
22-
const int g = (color >> 6) & 31;
23-
const int b = (color >> 0) & 31;
24-
return (r << 10) | (g << 5) | b;
25-
}
26-
27-
void saveTGA(const char *filename, const uint16_t *rgb, int w, int h) {
19+
void saveTGA(const char *filename, const uint16_t *rgb555, int w, int h) {
2820

2921
static const uint8_t kImageType = kTgaImageTypeRunLengthEncodedTrueColor;
3022
uint8_t buffer[TGA_HEADER_SIZE];
@@ -46,16 +38,16 @@ void saveTGA(const char *filename, const uint16_t *rgb, int w, int h) {
4638
f.write(buffer, sizeof(buffer));
4739
if (kImageType == kTgaImageTypeUncompressedTrueColor) {
4840
for (int i = 0; i < w * h; ++i) {
49-
uint16_t color = rgb565_to_555(*rgb++);
41+
const uint16_t color = *rgb555++;
5042
f.writeByte(color & 255);
5143
f.writeByte(color >> 8);
5244
}
5345
} else {
5446
assert(kImageType == kTgaImageTypeRunLengthEncodedTrueColor);
55-
uint16_t prevColor = rgb565_to_555(*rgb++);
47+
uint16_t prevColor = *rgb555++;
5648
int count = 0;
5749
for (int i = 1; i < w * h; ++i) {
58-
uint16_t color = rgb565_to_555(*rgb++);
50+
const uint16_t color = *rgb555++;
5951
if (prevColor == color && count < 127) {
6052
++count;
6153
continue;

script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ void Script::init() {
3737
_scriptVars[0xF2] = (_res->getDataType() == Resource::DT_AMIGA || _res->getDataType() == Resource::DT_ATARI) ? 6000 : 4000;
3838
// these 2 variables are set by the engine executable
3939
_scriptVars[0xDC] = 33;
40+
#endif
4041
if (_res->getDataType() == Resource::DT_DOS || _res->getDataType() == Resource::DT_WIN31) {
4142
_scriptVars[0xE4] = 20;
4243
}
43-
#endif
4444
}
4545
}
4646

systemstub.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct SystemStub {
5555
virtual void prepareScreen(int &w, int &h, float ar[4]) = 0;
5656
virtual void updateScreen() = 0;
5757
// framebuffer rendering
58-
virtual void setScreenPixels565(const uint16_t *data, int w, int h) = 0;
58+
virtual void setScreenPixels555(const uint16_t *data, int w, int h) = 0;
5959

6060
virtual void processEvents() = 0;
6161
virtual void sleep(uint32_t duration) = 0;

systemstub_sdl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct SystemStub_SDL : SystemStub {
3434

3535
virtual void prepareScreen(int &w, int &h, float ar[4]);
3636
virtual void updateScreen();
37-
virtual void setScreenPixels565(const uint16_t *data, int w, int h);
37+
virtual void setScreenPixels555(const uint16_t *data, int w, int h);
3838

3939
virtual void processEvents();
4040
virtual void sleep(uint32_t duration);
@@ -146,7 +146,7 @@ void SystemStub_SDL::updateScreen() {
146146
}
147147
}
148148

149-
void SystemStub_SDL::setScreenPixels565(const uint16_t *data, int w, int h) {
149+
void SystemStub_SDL::setScreenPixels555(const uint16_t *data, int w, int h) {
150150
if (_renderer) {
151151
if (_texW != w || _texH != h) {
152152
if (_texture) {
@@ -155,7 +155,7 @@ void SystemStub_SDL::setScreenPixels565(const uint16_t *data, int w, int h) {
155155
}
156156
}
157157
if (!_texture) {
158-
_texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB565, SDL_TEXTUREACCESS_STREAMING, w, h);
158+
_texture = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB555, SDL_TEXTUREACCESS_STREAMING, w, h);
159159
if (!_texture) {
160160
return;
161161
}

video.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -433,19 +433,11 @@ static void decode_atari(const uint8_t *src, uint8_t *dst) {
433433
}
434434
}
435435

436-
static uint16_t rgb555_to_565(const uint16_t color) {
437-
const int r = (color >> 10) & 31;
438-
const int g = (color >> 5) & 31;
439-
const int b = (color >> 0) & 31;
440-
return (r << 11) | (g << 6) | b;
441-
}
442-
443436
static void deinterlace555(const uint8_t *src, int w, int h, uint16_t *dst) {
444437
for (int y = 0; y < h / 2; ++y) {
445438
for (int x = 0; x < w; ++x) {
446-
dst[x] = rgb555_to_565(READ_BE_UINT16(&src[0]));
447-
dst[w + x] = rgb555_to_565(READ_BE_UINT16(&src[2]));
448-
src += 4;
439+
dst[x] = READ_BE_UINT16(src) & 0x7FFF; src += 2;
440+
dst[w + x] = READ_BE_UINT16(src) & 0x7FFF; src += 2;
449441
}
450442
dst += w * 2;
451443
}
@@ -481,8 +473,8 @@ void Video::copyBitmapPtr(const uint8_t *src, uint32_t size) {
481473
yflip(src, BITMAP_W, BITMAP_H, _tempBitmap);
482474
scaleBitmap(_tempBitmap, FMT_CLUT);
483475
} else if (_res->getDataType() == Resource::DT_3DO) {
484-
deinterlace555(src, BITMAP_W, BITMAP_H, _bitmap565);
485-
scaleBitmap((const uint8_t *)_bitmap565, FMT_RGB565);
476+
deinterlace555(src, BITMAP_W, BITMAP_H, _bitmap555);
477+
scaleBitmap((const uint8_t *)_bitmap555, FMT_RGB555);
486478
} else { // .BMP
487479
if (Graphics::_is1991) {
488480
const int w = READ_LE_UINT32(src + 0x12);

0 commit comments

Comments
 (0)