Initial commit
This commit is contained in:
537
engines/ultima/nuvie/screen/surface.cpp
Normal file
537
engines/ultima/nuvie/screen/surface.cpp
Normal file
@@ -0,0 +1,537 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/screen/surface.h"
|
||||
#include "common/algorithm.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
// Colour shifting values
|
||||
uint8 RenderSurface::Rloss;
|
||||
uint8 RenderSurface::Gloss;
|
||||
uint8 RenderSurface::Bloss;
|
||||
uint8 RenderSurface::Rloss16;
|
||||
uint8 RenderSurface::Gloss16;
|
||||
uint8 RenderSurface::Bloss16;
|
||||
uint8 RenderSurface::Rshift;
|
||||
uint8 RenderSurface::Gshift;
|
||||
uint8 RenderSurface::Bshift;
|
||||
uint32 RenderSurface::Rmask;
|
||||
uint32 RenderSurface::Gmask;
|
||||
uint32 RenderSurface::Bmask;
|
||||
|
||||
// Default constructor for no created surface
|
||||
RenderSurface::RenderSurface() : buffer(0), zbuffer_priv(0), _rawSurface(nullptr),
|
||||
_disposeSurface(DisposeAfterUse::YES), opengl(0), bytes_per_pixel(0),
|
||||
bits_per_pixel(0), format_type(0), pixels(0), zbuffer(0), w(0), h(0),
|
||||
pitch(0), gl(0), gr(0), gt(0), gb(0), lock_count(0) {
|
||||
}
|
||||
|
||||
// Constructor for custom buffer
|
||||
RenderSurface::RenderSurface(uint32 width, uint32 height, uint32 bpp, byte *p) :
|
||||
buffer(0), zbuffer_priv(0), _rawSurface(nullptr), _disposeSurface(DisposeAfterUse::YES),
|
||||
opengl(0), bytes_per_pixel(bpp / 8), bits_per_pixel(bpp), pixels(p), zbuffer(0),
|
||||
w(width), h(height), pitch(width), gl(0), gr(width), gt(0), gb(height), lock_count(0) {
|
||||
// Set default formats for the buffer
|
||||
if (bpp == 32) set_format888();
|
||||
else set_format565();
|
||||
}
|
||||
|
||||
// Constructor for generic surface (with optional guardband)
|
||||
RenderSurface::RenderSurface(uint32 width, uint32 height, uint32 bpp, sint32 guard) :
|
||||
buffer(0), zbuffer_priv(0), _rawSurface(nullptr), _disposeSurface(DisposeAfterUse::YES),
|
||||
opengl(0), bytes_per_pixel(bpp / 8), bits_per_pixel(bpp), pixels(0), zbuffer(0),
|
||||
w(width), h(height), pitch(width * (bpp / 8) + 2 * guard * (bpp / 8)),
|
||||
gl(-guard), gr(guard + width), gt(-guard), gb(guard + height), lock_count(0) {
|
||||
// Set default formats for the buffer
|
||||
if (bpp == 32) set_format888();
|
||||
else set_format565();
|
||||
|
||||
buffer = new uint8[pitch * (height + 2 * gb)];
|
||||
pixels = buffer + (pitch * gb) + gb;
|
||||
}
|
||||
|
||||
// Constructor for sdl surface
|
||||
RenderSurface::RenderSurface(Graphics::ManagedSurface *surf) :
|
||||
_rawSurface(surf), _disposeSurface(DisposeAfterUse::NO), w(surf->w), h(surf->h),
|
||||
pitch(surf->pitch), gr(surf->w), pixels((byte*)surf->getPixels()), buffer(0),
|
||||
zbuffer_priv(0), opengl(0), bytes_per_pixel(0), bits_per_pixel(0), zbuffer(0),
|
||||
gl(0), gt(0), gb(surf->h), lock_count(0) {
|
||||
set_format(&surf->format);
|
||||
}
|
||||
|
||||
// Constructor for opengl surface
|
||||
RenderSurface::RenderSurface(OpenGL *ogl) : buffer(0), zbuffer_priv(0), _rawSurface(nullptr),
|
||||
_disposeSurface(DisposeAfterUse::NO), opengl(ogl), bytes_per_pixel(0),
|
||||
bits_per_pixel(0), format_type(0), pixels(0), zbuffer(0), w(0), h(0), pitch(0),
|
||||
gl(0), gr(0), gt(0), gb(0), lock_count(0) {
|
||||
}
|
||||
|
||||
RenderSurface::~RenderSurface() {
|
||||
delete[] buffer;
|
||||
delete[] zbuffer_priv;
|
||||
if (_rawSurface && _disposeSurface == DisposeAfterUse::YES)
|
||||
delete _rawSurface;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the buffer format from Graphics::PixelFormat
|
||||
//
|
||||
void RenderSurface::set_format(const Graphics::PixelFormat *fmt) {
|
||||
bits_per_pixel = fmt->bytesPerPixel * 8;
|
||||
bytes_per_pixel = fmt->bytesPerPixel;
|
||||
|
||||
Rloss = fmt->rLoss;
|
||||
Gloss = fmt->gLoss;
|
||||
Bloss = fmt->bLoss;
|
||||
Rloss16 = Rloss + 8;
|
||||
Gloss16 = Gloss + 8;
|
||||
Bloss16 = Bloss + 8;
|
||||
Rshift = fmt->rShift;
|
||||
Gshift = fmt->gShift;
|
||||
Bshift = fmt->bShift;
|
||||
Rmask = fmt->rMax() << fmt->rShift;
|
||||
Gmask = fmt->gMax() << fmt->gShift;
|
||||
Bmask = fmt->bMax() << fmt->bShift;
|
||||
|
||||
// RGB 565
|
||||
if (Rmask == 0xf800 && Gmask == 0x7e0 && Bmask == 0x1f)
|
||||
format_type = 565;
|
||||
// RGB 555
|
||||
else if (Rmask == 0x7c00 && Gmask == 0x3e0 && Bmask == 0x1f)
|
||||
format_type = 555;
|
||||
// RGB 888
|
||||
else if (Rmask == 0xFF0000 && Gmask == 0x00FF00 && Bmask == 0x0000FF)
|
||||
format_type = 888;
|
||||
// RGB 16 Bit Generic
|
||||
else if (bits_per_pixel == 16)
|
||||
format_type = 16;
|
||||
// RGB 32 Bit Generic
|
||||
else
|
||||
format_type = 32;
|
||||
}
|
||||
|
||||
//
|
||||
// Set a custom 565 format
|
||||
//
|
||||
void RenderSurface::set_format565(int rsft, int gsft, int bsft) {
|
||||
bits_per_pixel = 16;
|
||||
bytes_per_pixel = 2;
|
||||
|
||||
// Static Colour shifting values
|
||||
Rloss = 3;
|
||||
Gloss = 2;
|
||||
Bloss = 3;
|
||||
Rloss16 = Rloss + 8;
|
||||
Gloss16 = Gloss + 8;
|
||||
Bloss16 = Bloss + 8;
|
||||
Rshift = rsft;
|
||||
Gshift = gsft;
|
||||
Bshift = bsft;
|
||||
Rmask = 0x1f << rsft;
|
||||
Gmask = 0x2f << rsft;
|
||||
Bmask = 0x1f << rsft;
|
||||
|
||||
// RGB 565
|
||||
if (Rmask == 0xf800 && Gmask == 0x7e0 && Bmask == 0x1f)
|
||||
format_type = 565;
|
||||
// RGB 16 Bit Generic
|
||||
else if (bits_per_pixel == 16)
|
||||
format_type = 16;
|
||||
}
|
||||
|
||||
//
|
||||
// Set a custom 555 format
|
||||
//
|
||||
void RenderSurface::set_format555(int rsft, int gsft, int bsft) {
|
||||
bits_per_pixel = 16;
|
||||
bytes_per_pixel = 2;
|
||||
|
||||
// Static Colour shifting values
|
||||
Rloss = 3;
|
||||
Gloss = 3;
|
||||
Bloss = 3;
|
||||
Rloss16 = Rloss + 8;
|
||||
Gloss16 = Gloss + 8;
|
||||
Bloss16 = Bloss + 8;
|
||||
Rshift = rsft;
|
||||
Gshift = gsft;
|
||||
Bshift = bsft;
|
||||
Rmask = 0x1f << rsft;
|
||||
Gmask = 0x1f << rsft;
|
||||
Bmask = 0x1f << rsft;
|
||||
|
||||
// RGB 555
|
||||
if (Rmask == 0x7c00 && Gmask == 0x3e0 && Bmask == 0x1f)
|
||||
format_type = 555;
|
||||
// RGB 16 Bit Generic
|
||||
else if (bits_per_pixel == 16)
|
||||
format_type = 16;
|
||||
}
|
||||
|
||||
//
|
||||
// Set a custom 888 format
|
||||
//
|
||||
void RenderSurface::set_format888(int rsft, int gsft, int bsft) {
|
||||
bits_per_pixel = 32;
|
||||
bytes_per_pixel = 4;
|
||||
|
||||
Rloss = 0;
|
||||
Gloss = 0;
|
||||
Bloss = 0;
|
||||
Rloss16 = Rloss + 8;
|
||||
Gloss16 = Gloss + 8;
|
||||
Bloss16 = Bloss + 8;
|
||||
Rshift = rsft;
|
||||
Gshift = gsft;
|
||||
Bshift = bsft;
|
||||
Rmask = 0xFF << rsft;
|
||||
Gmask = 0xFF << rsft;
|
||||
Bmask = 0xFF << rsft;
|
||||
|
||||
// RGB 888
|
||||
if (Rmask == 0xFF0000 && Gmask == 0x00FF00 && Bmask == 0x0000FF)
|
||||
format_type = 888;
|
||||
// RGB 32 Bit Generic
|
||||
else
|
||||
format_type = 32;
|
||||
}
|
||||
|
||||
void RenderSurface::draw_line(int sx, int sy, int ex, int ey, unsigned char col) {
|
||||
if (bytes_per_pixel == 4) draw_line32(sx, sy, ex, ey, col);
|
||||
else draw_line16(sx, sy, ex, ey, col);
|
||||
}
|
||||
|
||||
#define LINE_FRACTION 65536L
|
||||
|
||||
void RenderSurface::draw_line16(int sx, int sy, int ex, int ey, unsigned char col) {
|
||||
#ifdef WANT_OPENGL
|
||||
if (opengl) {
|
||||
opengl->draw_line(sx, sy + 1, 0, ex, ey + 1, 0, col);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int xinc = 1;
|
||||
int yinc = 1;
|
||||
|
||||
if (sx == ex) {
|
||||
sx --;
|
||||
if (sy > ey) {
|
||||
yinc = -1;
|
||||
sy--;
|
||||
}
|
||||
} else {
|
||||
if (sx > ex) {
|
||||
sx--;
|
||||
xinc = -1;
|
||||
} else {
|
||||
ex--;
|
||||
}
|
||||
|
||||
if (sy > ey) {
|
||||
yinc = -1;
|
||||
sy--;
|
||||
ey--;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 *pixptr = (uint16 *)(pixels + pitch * sy + sx * 2);
|
||||
uint16 *pixend = (uint16 *)(pixels + pitch * ey + ex * 2);
|
||||
int pitch_ = this->pitch * yinc / 2;
|
||||
|
||||
int cury = sy;
|
||||
int curx = sx;
|
||||
int width = w;
|
||||
int height = h;
|
||||
bool no_clip = true;
|
||||
|
||||
if (sx >= width && ex >= width) return;
|
||||
if (sy >= height && ey >= height) return;
|
||||
if (sx < 0 && ex < 0) return;
|
||||
if (sy < 0 && ey < 0) return;
|
||||
|
||||
if (sy < 0 || sy >= height || sx < 0 || sx >= width) no_clip = false;
|
||||
if (ey < 0 || ey >= height || ex < 0 || ex >= width) no_clip = false;
|
||||
|
||||
int col32 = colour32[col];
|
||||
|
||||
// vertical
|
||||
if (sx == ex) {
|
||||
//Std::cout << "Vertical" << Std::endl;
|
||||
// start is below end
|
||||
while (pixptr != pixend) {
|
||||
if (no_clip || (cury >= 0 && cury < height)) *pixptr = col32;
|
||||
pixptr += pitch_;
|
||||
cury += yinc;
|
||||
}
|
||||
}
|
||||
// Horizontal
|
||||
else if (sy == ey) {
|
||||
//Std::cout << "Horizontal" << Std::endl;
|
||||
while (pixptr != pixend) {
|
||||
if (no_clip || (curx >= 0 && curx < width)) *pixptr = col32;
|
||||
pixptr += xinc;
|
||||
curx += xinc;
|
||||
}
|
||||
}
|
||||
// Diagonal xdiff >= ydiff
|
||||
else if (ABS(sx - ex) >= ABS(sy - ey)) {
|
||||
//Std::cout << "Diagonal 1" << Std::endl;
|
||||
uint32 fraction = ABS((LINE_FRACTION * (sy - ey)) / (sx - ex));
|
||||
uint32 ycounter = 0;
|
||||
|
||||
for (; ;) {
|
||||
if ((no_clip || (cury >= 0 && cury < height && curx >= 0 && curx < width)))
|
||||
*pixptr = col32;
|
||||
pixptr += xinc;
|
||||
if (curx == ex) break;
|
||||
curx += xinc;
|
||||
ycounter += fraction;
|
||||
|
||||
// Need to work out if we need to change line
|
||||
if (ycounter > LINE_FRACTION) {
|
||||
ycounter -= LINE_FRACTION;
|
||||
pixptr += pitch_;
|
||||
cury += yinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Diagonal ydiff > xdiff
|
||||
else {
|
||||
//Std::cout << "Diagonal 2" << Std::endl;
|
||||
uint32 fraction = ABS((LINE_FRACTION * (sx - ex)) / (sy - ey));
|
||||
uint32 xcounter = 0;
|
||||
|
||||
for (; ;) {
|
||||
if ((no_clip || (cury >= 0 && cury < height && curx >= 0 && curx < width)))
|
||||
*pixptr = col32;
|
||||
pixptr += pitch_;
|
||||
if (cury == ey) break;
|
||||
cury += yinc;
|
||||
xcounter += fraction;
|
||||
|
||||
// Need to work out if we need to change line
|
||||
if (xcounter > LINE_FRACTION) {
|
||||
xcounter -= LINE_FRACTION;
|
||||
pixptr += xinc;
|
||||
curx += xinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderSurface::draw_line32(int sx, int sy, int ex, int ey, unsigned char col) {
|
||||
#ifdef WANT_OPENGL
|
||||
if (opengl) {
|
||||
opengl->draw_line(sx, sy + 1, 0, ex, ey + 1, 0, col);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int xinc = 1;
|
||||
int yinc = 1;
|
||||
|
||||
if (sx == ex) {
|
||||
sx --;
|
||||
if (sy > ey) {
|
||||
yinc = -1;
|
||||
sy--;
|
||||
}
|
||||
} else {
|
||||
if (sx > ex) {
|
||||
sx--;
|
||||
xinc = -1;
|
||||
} else {
|
||||
ex--;
|
||||
}
|
||||
|
||||
if (sy > ey) {
|
||||
yinc = -1;
|
||||
sy--;
|
||||
ey--;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 *pixptr = (uint32 *)(pixels + pitch * sy + sx * 4);
|
||||
uint32 *pixend = (uint32 *)(pixels + pitch * ey + ex * 4);
|
||||
int pitch_ = this->pitch * yinc / 4;
|
||||
|
||||
int cury = sy;
|
||||
int curx = sx;
|
||||
int width = w;
|
||||
int height = h;
|
||||
bool no_clip = true;
|
||||
|
||||
if (sx >= width && ex >= width) return;
|
||||
if (sy >= height && ey >= height) return;
|
||||
if (sx < 0 && ex < 0) return;
|
||||
if (sy < 0 && ey < 0) return;
|
||||
|
||||
if (sy < 0 || sy >= height || sx < 0 || sx >= width) no_clip = false;
|
||||
if (ey < 0 || ey >= height || ex < 0 || ex >= width) no_clip = false;
|
||||
|
||||
int col32 = colour32[col];
|
||||
|
||||
// vertical
|
||||
if (sx == ex) {
|
||||
//Std::cout << "Vertical" << Std::endl;
|
||||
// start is below end
|
||||
while (pixptr != pixend) {
|
||||
if (no_clip || (cury >= 0 && cury < height)) *pixptr = col32;
|
||||
pixptr += pitch_;
|
||||
cury += yinc;
|
||||
}
|
||||
}
|
||||
// Horizontal
|
||||
else if (sy == ey) {
|
||||
//Std::cout << "Horizontal" << Std::endl;
|
||||
while (pixptr != pixend) {
|
||||
if (no_clip || (curx >= 0 && curx < width)) *pixptr = col32;
|
||||
pixptr += xinc;
|
||||
curx += xinc;
|
||||
}
|
||||
}
|
||||
// Diagonal xdiff >= ydiff
|
||||
else if (ABS(sx - ex) >= ABS(sy - ey)) {
|
||||
//Std::cout << "Diagonal 1" << Std::endl;
|
||||
uint32 fraction = ABS((LINE_FRACTION * (sy - ey)) / (sx - ex));
|
||||
uint32 ycounter = 0;
|
||||
|
||||
for (; ;) {
|
||||
if ((no_clip || (cury >= 0 && cury < height && curx >= 0 && curx < width)))
|
||||
*pixptr = col32;
|
||||
pixptr += xinc;
|
||||
if (curx == ex) break;
|
||||
curx += xinc;
|
||||
ycounter += fraction;
|
||||
|
||||
// Need to work out if we need to change line
|
||||
if (ycounter > LINE_FRACTION) {
|
||||
ycounter -= LINE_FRACTION;
|
||||
pixptr += pitch_;
|
||||
cury += yinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Diagonal ydiff > xdiff
|
||||
else {
|
||||
//Std::cout << "Diagonal 2" << Std::endl;
|
||||
uint32 fraction = ABS((LINE_FRACTION * (sx - ex)) / (sy - ey));
|
||||
uint32 xcounter = 0;
|
||||
|
||||
for (; ;) {
|
||||
if ((no_clip || (cury >= 0 && cury < height && curx >= 0 && curx < width)))
|
||||
*pixptr = col32;
|
||||
pixptr += pitch_;
|
||||
if (cury == ey) break;
|
||||
cury += yinc;
|
||||
xcounter += fraction;
|
||||
|
||||
// Need to work out if we need to change line
|
||||
if (xcounter > LINE_FRACTION) {
|
||||
xcounter -= LINE_FRACTION;
|
||||
pixptr += xinc;
|
||||
curx += xinc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
void RenderSurface::draw_3d_line(int x, int y, int sx, int sy, int sz, int ex, int ey, int ez, unsigned char col) {
|
||||
int dispsx = x + (sx - sy) / 4;
|
||||
int dispsy = y + (sx + sy) / 8 - sz;
|
||||
int dispex = x + (ex - ey) / 4;
|
||||
int dispey = y + (ex + ey) / 8 - ez;
|
||||
|
||||
#ifdef WANT_OPENGL
|
||||
if (opengl) opengl->draw_line(dispsx, dispsy + 1, 0, dispex, dispey + 1, 0, col);
|
||||
else
|
||||
#endif
|
||||
draw_line(dispsx, dispsy + 1, dispex, dispey + 1, col);
|
||||
//draw_line (0, 0, 800, 600, col);
|
||||
}
|
||||
|
||||
void RenderSurface::create_zbuffer() {
|
||||
#ifdef ENABLE_SOFTREND_EMU
|
||||
SoftRend::SetupInitialState();
|
||||
#endif
|
||||
|
||||
// Not in opengl, or if we alraedy have one
|
||||
if (opengl || zbuffer_priv) return;
|
||||
|
||||
zbuffer = zbuffer_priv = new uint16[pitch * h];
|
||||
}
|
||||
|
||||
RenderSurface *CreateRenderSurface(uint32 width, uint32 height, uint32 bpp, byte *p) {
|
||||
return new RenderSurface(width, height, bpp, p);
|
||||
}
|
||||
|
||||
RenderSurface *CreateRenderSurface(uint32 width, uint32 height, uint32 bpp, sint32 gb) {
|
||||
return new RenderSurface(width, height, bpp, gb);
|
||||
}
|
||||
|
||||
RenderSurface *CreateRenderSurface(Graphics::ManagedSurface *surf) {
|
||||
return new RenderSurface(surf);
|
||||
}
|
||||
|
||||
RenderSurface *CreateRenderSurface(OpenGL *ogl) {
|
||||
return new RenderSurface(ogl);
|
||||
}
|
||||
|
||||
static int getBits(uint mask) {
|
||||
int count = 0;
|
||||
for (; mask; mask >>= 1)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface *RenderSurface::createSurface(int w, int h,
|
||||
const Graphics::PixelFormat &format) {
|
||||
return new Graphics::ManagedSurface(w, h, format);
|
||||
}
|
||||
|
||||
Graphics::ManagedSurface *RenderSurface::get_sdl_surface() {
|
||||
if (_rawSurface == nullptr) {
|
||||
_rawSurface = new Graphics::ManagedSurface(w, h,
|
||||
Graphics::PixelFormat(bytes_per_pixel, getBits(Rmask), getBits(Gmask),
|
||||
getBits(Bmask), 0, Rshift, Gshift, Bshift, 0));
|
||||
|
||||
byte *dest = (byte *)_rawSurface->getPixels();
|
||||
Common::copy(pixels, pixels + (_rawSurface->pitch * _rawSurface->h), dest);
|
||||
}
|
||||
|
||||
return _rawSurface;
|
||||
}
|
||||
|
||||
const unsigned char *RenderSurface::get_pixels() {
|
||||
return ((const unsigned char *)pixels);
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user