FREESCAPE: first iteration of the CGA renderer for driller DOS (CGA)

This commit is contained in:
neuromancer 2022-12-19 23:06:43 -03:00
parent 43911004a4
commit 20529cbb30
8 changed files with 188 additions and 72 deletions

View File

@ -260,6 +260,7 @@ void DrillerEngine::loadAssetsDemo() {
loadSoundsFx(&file, 0, 25);
} else if (isDOS()) {
_renderMode = Common::kRenderCGA; // DOS demos is CGA only
_gfx->_renderMode = _renderMode;
loadBundledImages();
file.open("d2");
if (!file.isOpen())

View File

@ -41,11 +41,18 @@ byte dos_EGA_palette[16][3] = {
{0xff, 0xff, 0x55},
{0xff, 0xff, 0xff}};
byte dos_CGA_palette[4][3] = {
{0x00, 0x00, 0x00},
{0x00, 0xaa, 0x00},
{0xaa, 0x00, 0x00},
{0xaa, 0x55, 0x00},
};
void FreescapeEngine::loadColorPalette() {
if (_renderMode == Common::kRenderEGA) {
_gfx->_palette = (byte *)&dos_EGA_palette;
} else if (_renderMode == Common::kRenderCGA) {
_gfx->_palette = (byte *)&dos_EGA_palette;
_gfx->_palette = (byte *)&dos_CGA_palette;
} else if (_renderMode == Common::kRenderAmiga || _renderMode == Common::kRenderAtariST) {
_gfx->_palette = nullptr; // palette depends on the area
} else

View File

@ -68,38 +68,37 @@ void Renderer::setColorRemaps(ColorReMap *colorRemaps) {
_colorRemaps = colorRemaps;
}
bool Renderer::getRGBAt(uint8 index, uint8 &r, uint8 &g, uint8 &b) {
if (_colorRemaps && _colorRemaps->contains(index)) {
index = (*_colorRemaps)[index];
readFromPalette(index, r, g, b);
return true;
}
bool Renderer::getRGBAtCGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) {
if (index == _keyColor)
return false;
if (index == 0) {
readFromPalette(0, r, g, b);
assert (_renderMode == Common::kRenderCGA);
if (index <= 4) { // Solid colors
readFromPalette(index - 1, r1, g1, b1);
r2 = r1;
g2 = g1;
b2 = b1;
return true;
}
if (_renderMode == Common::kRenderAmiga || _renderMode == Common::kRenderAtariST) {
readFromPalette(index, r, g, b);
return true;
}
byte *entry = (*_colorMap)[index - 1];
byte be = *(entry);
readFromPalette((be >> 4) % 4, r1, g1, b1);
entry++;
be = *(entry);
readFromPalette((be >> 4) % 4, r2, g2, b2);
return true;
}
// assert(index-1 < _colorMap->size());
bool Renderer::getRGBAtEGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) {
// assert(index-1 < _colorMap->size());
byte *entry = (*_colorMap)[index - 1];
uint8 color = 0;
uint8 acc = 1;
for (int i = 0; i < 4; i++) {
byte be = *entry;
if (be != 0 && be != 0xff) {
readFromPalette(index, r, g, b);
return true;
}
assert (be == 0 || be == 0xff);
if (be == 0xff)
color = color + acc;
@ -107,10 +106,46 @@ bool Renderer::getRGBAt(uint8 index, uint8 &r, uint8 &g, uint8 &b) {
entry++;
}
assert(color < 16);
readFromPalette(color, r, g, b);
readFromPalette(color, r1, g1, b1);
r2 = r1;
g2 = g1;
b2 = b1;
return true;
}
bool Renderer::getRGBAt(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2) {
/*if (_colorRemaps && _colorRemaps->contains(index)) {
index = (*_colorRemaps)[index];
readFromPalette(index, r, g, b);
return true;
}*/
if (index == _keyColor)
return false;
if (index == 0) {
readFromPalette(0, r1, g1, b1);
r2 = r1;
g2 = g1;
b2 = b1;
return true;
}
if (_renderMode == Common::kRenderAmiga || _renderMode == Common::kRenderAtariST) {
readFromPalette(index, r1, g1, b1);
r2 = r1;
g2 = g1;
b2 = b1;
return true;
} else if (_renderMode == Common::kRenderEGA)
return getRGBAtEGA(index, r1, g1, b1, r2, g2, b2);
else if (_renderMode == Common::kRenderCGA)
return getRGBAtCGA(index, r1, g1, b1, r2, g2, b2);
error("Invalid or unsupported render mode");
}
void Renderer::flipVertical(Graphics::Surface *s) {
for (int y = 0; y < s->h / 2; ++y) {
// Flip the lines
@ -237,9 +272,9 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
}
Common::Array<Math::Vector3d> face;
uint8 r, g, b;
if (getRGBAt((*colours)[0], r, g, b)) {
useColor(r, g, b);
uint8 r1, g1, b1, r2, g2, b2;
if (getRGBAt((*colours)[0], r1, g1, b1, r1, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[4]);
face.push_back(vertices[5]);
@ -250,8 +285,8 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
face.clear();
}
if (getRGBAt((*colours)[1], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[5]);
face.push_back(vertices[6]);
@ -262,8 +297,8 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
face.clear();
}
if (getRGBAt((*colours)[2], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[2], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[6]);
face.push_back(vertices[7]);
@ -273,8 +308,8 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
face.clear();
}
if (getRGBAt((*colours)[3], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[3], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[7]);
face.push_back(vertices[4]);
@ -285,8 +320,8 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
face.clear();
}
if (getRGBAt((*colours)[4], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[4], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[0]);
face.push_back(vertices[1]);
@ -296,8 +331,8 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
face.clear();
}
if (getRGBAt((*colours)[5], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[5], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(vertices[7]);
face.push_back(vertices[6]);
@ -308,66 +343,102 @@ void Renderer::renderPyramid(const Math::Vector3d &origin, const Math::Vector3d
}
void Renderer::renderCube(const Math::Vector3d &origin, const Math::Vector3d &size, Common::Array<uint8> *colours) {
uint8 r, g, b;
uint8 r1, g1, b1, r2, g2, b2;
Common::Array<Math::Vector3d> face;
if (getRGBAt((*colours)[0], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.push_back(origin);
face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z()));
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
if (getRGBAt((*colours)[1], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.clear();
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z()));
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
if (getRGBAt((*colours)[2], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[2], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.clear();
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z()));
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
if (getRGBAt((*colours)[3], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[3], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.clear();
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z()));
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
if (getRGBAt((*colours)[4], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[4], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.clear();
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z()));
face.push_back(origin);
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
if (getRGBAt((*colours)[5], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[5], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
face.clear();
face.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x() + size.x(), origin.y() + size.y(), origin.z() + size.z()));
face.push_back(Math::Vector3d(origin.x(), origin.y() + size.y(), origin.z() + size.z()));
renderFace(face);
if (r1 != r2 || g1 != g2 || b1 != b2) {
useStipple(true);
useColor(r2, g2, b2);
renderFace(face);
useStipple(false);
}
}
}
@ -377,13 +448,13 @@ void Renderer::renderRectangle(const Math::Vector3d &origin, const Math::Vector3
polygonOffset(true);
float dx, dy, dz;
uint8 r, g, b;
uint8 r1, g1, b1, r2, g2, b2;
Common::Array<Math::Vector3d> vertices;
for (int i = 0; i < 2; i++) {
// debug("rec color: %d", (*colours)[i]);
if (getRGBAt((*colours)[i], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[i], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
vertices.clear();
vertices.push_back(Math::Vector3d(origin.x(), origin.y(), origin.z()));
@ -421,7 +492,7 @@ void Renderer::renderRectangle(const Math::Vector3d &origin, const Math::Vector3
}
void Renderer::renderPolygon(const Math::Vector3d &origin, const Math::Vector3d &size, const Common::Array<uint16> *ordinates, Common::Array<uint8> *colours) {
uint8 r, g, b;
uint8 r1, g1, b1, r2, g2, b2;
if (ordinates->size() % 3 > 0 && ordinates->size() > 0)
error("Invalid polygon with size %f %f %f and ordinates %d", size.x(), size.y(), size.z(), ordinates->size());
@ -429,30 +500,30 @@ void Renderer::renderPolygon(const Math::Vector3d &origin, const Math::Vector3d
polygonOffset(true);
if (ordinates->size() == 6) { // Line
assert(getRGBAt((*colours)[0], r, g, b)); // It will never return false?
useColor(r, g, b);
assert(getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2)); // It will never return false?
useColor(r1, g1, b1);
for (uint i = 0; i < ordinates->size(); i = i + 3)
vertices.push_back(Math::Vector3d((*ordinates)[i], (*ordinates)[i + 1], (*ordinates)[i + 2]));
renderFace(vertices);
vertices.clear();
assert(getRGBAt((*colours)[1], r, g, b)); // It will never return false?
useColor(r, g, b);
assert(getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2)); // It will never return false?
useColor(r1, g1, b1);
for (int i = ordinates->size(); i > 0; i = i - 3)
vertices.push_back(Math::Vector3d((*ordinates)[i - 3], (*ordinates)[i - 2], (*ordinates)[i - 1]));
renderFace(vertices);
} else {
if (getRGBAt((*colours)[0], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[0], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
for (uint i = 0; i < ordinates->size(); i = i + 3) {
vertices.push_back(Math::Vector3d((*ordinates)[i], (*ordinates)[i + 1], (*ordinates)[i + 2]));
}
renderFace(vertices);
}
vertices.clear();
if (getRGBAt((*colours)[1], r, g, b)) {
useColor(r, g, b);
if (getRGBAt((*colours)[1], r1, g1, b1, r2, g2, b2)) {
useColor(r1, g1, b1);
for (int i = ordinates->size(); i > 0; i = i - 3) {
vertices.push_back(Math::Vector3d((*ordinates)[i - 3], (*ordinates)[i - 2], (*ordinates)[i - 1]));
}

View File

@ -98,7 +98,11 @@ public:
// palette
void readFromPalette(uint8 index, uint8 &r, uint8 &g, uint8 &b);
uint8 indexFromColor(uint8 r, uint8 g, uint8 b);
bool getRGBAt(uint8 index, uint8 &r, uint8 &g, uint8 &b);
bool getRGBAt(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2);
bool getRGBAtCGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2);
bool getRGBAtEGA(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &r2, uint8 &g2, uint8 &b2);
virtual void useStipple(bool enabled) {};
byte *_palette;
ColorMap *_colorMap;
ColorReMap *_colorRemaps;

View File

@ -196,7 +196,7 @@ void OpenGLRenderer::renderPlayerShoot(byte color, const Common::Point position,
glReadPixels(g_system->getWidth() / 2, g_system->getHeight() / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
_texturePixelFormat.colorToARGB(pixel, a, r, g, b);
color = indexFromColor(r, g, b);
readFromPalette((color + 3) % 16, r, g, b);
readFromPalette((color + 3) % (_renderMode == Common::kRenderCGA ? 4 : 16), r, g, b);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
@ -268,6 +268,19 @@ void OpenGLRenderer::polygonOffset(bool enabled) {
}
}
void OpenGLRenderer::useStipple(bool enabled) {
if (enabled) {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-5.0f, 1.0f);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(_stippleArray);
} else {
glPolygonOffset(0, 0);
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_STIPPLE);
}
}
void OpenGLRenderer::useColor(uint8 r, uint8 g, uint8 b) {
glColor3ub(r, g, b);
}
@ -285,9 +298,9 @@ void OpenGLRenderer::clear(uint8 color) {
}
void OpenGLRenderer::drawFloor(uint8 color) {
uint8 r, g, b;
assert(getRGBAt(color, r, g, b)); // TODO: move check inside this function
glColor3ub(r, g, b);
uint8 r1, g1, b1, r2, g2, b2;
assert(getRGBAt(color, r1, g1, b1, r2, g2, b2)); // TODO: move check inside this function
glColor3ub(r1, g1, b1);
glEnableClientState(GL_VERTEX_ARRAY);
copyToVertexArray(0, Math::Vector3d(-100000.0, 0.0, -100000.0));

View File

@ -60,6 +60,25 @@ public:
_coords[idx].x = src.getValue(0); _coords[idx].y = src.getValue(1);
}
GLubyte _stippleArray[128] = {
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
};
virtual void init() override;
virtual void clear(uint8 color) override;
virtual void setViewport(const Common::Rect &rect) override;
@ -68,6 +87,7 @@ public:
virtual void useColor(uint8 r, uint8 g, uint8 b) override;
virtual void polygonOffset(bool enabled) override;
virtual void useStipple(bool enabled) override;
Texture *createTexture(const Graphics::Surface *surface) override;
void freeTexture(Texture *texture) override;

View File

@ -226,9 +226,9 @@ void TinyGLRenderer::clear(uint8 color) {
}
void TinyGLRenderer::drawFloor(uint8 color) {
uint8 r, g, b;
assert(getRGBAt(color, r, g, b)); // TODO: move check inside this function
tglColor3ub(r, g, b);
uint8 r1, g1, b1, r2, g2, b2;
assert(getRGBAt(color, r1, g1, b1, r2, g2, b2)); // TODO: move check inside this function
tglColor3ub(r1, g1, b1);
tglEnableClientState(TGL_VERTEX_ARRAY);
copyToVertexArray(0, Math::Vector3d(-100000.0, 0.0, -100000.0));

View File

@ -130,15 +130,15 @@ Object *FreescapeEngine::load8bitObject(Common::SeekableReadStream *file) {
for (uint8 colour = 0; colour < numberOfColours / 2; colour++) {
uint8 data = readField(file, 8);
entry = data & 0xf;
if (_renderMode == Common::kRenderCGA)
entry = entry % 4; // TODO: use dithering
//if (_renderMode == Common::kRenderCGA)
// entry = entry % 4; // TODO: use dithering
colours->push_back(entry);
debugC(1, kFreescapeDebugParser, "color[%d] = %x", 2 * colour, entry);
entry = data >> 4;
if (_renderMode == Common::kRenderCGA)
entry = entry % 4; // TODO: use dithering
//if (_renderMode == Common::kRenderCGA)
// entry = entry % 4; // TODO: use dithering
colours->push_back(entry);
debugC(1, kFreescapeDebugParser, "color[%d] = %x", 2 * colour + 1, entry);