diff --git a/src/PowderToyRenderer.cpp b/src/PowderToyRenderer.cpp index 5b9d0db30..a8c2b0227 100644 --- a/src/PowderToyRenderer.cpp +++ b/src/PowderToyRenderer.cpp @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) auto rng = std::make_unique(); Simulation * sim = new Simulation(); - Renderer * ren = new Renderer(new Graphics(), sim); + Renderer * ren = new Renderer(sim); if (gameSave) { @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) frame--; ren->render_parts(); ren->render_fire(); - ren->clearScreen(1.0f); + ren->clearScreen(); } } else diff --git a/src/common/Plane.h b/src/common/Plane.h index 8c8dcefa5..ca154a8c2 100644 --- a/src/common/Plane.h +++ b/src/common/Plane.h @@ -17,6 +17,9 @@ struct extentStorage { return Extent; } + + constexpr void setExtent(size_t) + {} }; template<> @@ -32,6 +35,11 @@ struct extentStorage { return extent; } + + constexpr void setExtent(size_t extent) + { + this->extent = extent; + } }; template @@ -51,6 +59,8 @@ struct yExtent: extentStorage template class PlaneAdapter: xExtent, yExtent { + friend class VideoBuffer; // TODO: remove + using value_type = std::remove_reference_t()[0])>; using iterator = decltype(std::begin(std::declval())); using const_iterator = decltype(std::begin(std::declval())); @@ -78,9 +88,11 @@ public: PlaneAdapter(PlaneAdapter &&) = default; - PlaneAdapter &operator=(PlaneAdapter const &) = default; - - PlaneAdapter &operator=(PlaneAdapter &&) = default; + PlaneAdapter(Vec2 size, T &&base): + xExtent(size.X), + yExtent(size.Y), + Base(std::move(base)) + {} template PlaneAdapter(Vec2 size, Args&&... args): @@ -89,11 +101,21 @@ public: Base(getWidth() * getHeight(), std::forward(args)...) {} + PlaneAdapter &operator=(PlaneAdapter const &) = default; + + PlaneAdapter &operator=(PlaneAdapter &&) = default; + Vec2 Size() const { return Vec2(getWidth(), getHeight()); } + void SetSize(Vec2 size) + { + xExtent::setExtent(size.X); + yExtent::setExtent(size.Y); + } + iterator RowIterator(Vec2 p) { return std::begin(Base) + (p.X + p.Y * getWidth()); diff --git a/src/graphics/Graphics.cpp b/src/graphics/Graphics.cpp index 0e88334b4..1145d2eef 100644 --- a/src/graphics/Graphics.cpp +++ b/src/graphics/Graphics.cpp @@ -1,60 +1,62 @@ -#include "Graphics.h" -#include "common/platform/Platform.h" -#include "FontReader.h" -#include "resampler/resampler.h" -#include "SimulationConfig.h" +#include +#include #include -#include #include #include -#include +#include #include +#include "common/platform/Platform.h" +#include "FontReader.h" +#include "Graphics.h" +#include "resampler/resampler.h" +#include "SimulationConfig.h" + +VideoBuffer::VideoBuffer(Vec2 size): + video(size) +{} + +VideoBuffer::VideoBuffer(pixel const *data, Vec2 size): + VideoBuffer(size) +{ + std::copy_n(data, size.X * size.Y, video.data()); +} + +VideoBuffer::VideoBuffer(pixel const *data, Vec2 size, size_t rowStride): + VideoBuffer(size) +{ + for(int y = 0; y < size.Y; y++) + std::copy_n(data + rowStride * y, size.X, video.RowIterator(Vec2(0, y))); +} VideoBuffer::VideoBuffer(int width, int height): - Width(width), - Height(height) -{ - Buffer = new pixel[width*height]; - std::fill(Buffer, Buffer+(width*height), 0); -}; - -VideoBuffer::VideoBuffer(const VideoBuffer & old): - Width(old.Width), - Height(old.Height) -{ - Buffer = new pixel[old.Width*old.Height]; - std::copy(old.Buffer, old.Buffer+(old.Width*old.Height), Buffer); -}; + VideoBuffer(Vec2(width, height)) +{} VideoBuffer::VideoBuffer(VideoBuffer * old): - Width(old->Width), - Height(old->Height) -{ - Buffer = new pixel[old->Width*old->Height]; - std::copy(old->Buffer, old->Buffer+(old->Width*old->Height), Buffer); -}; + VideoBuffer(*old) +{} -VideoBuffer::VideoBuffer(pixel * buffer, int width, int height, int pitch): - Width(width), - Height(height) -{ - Buffer = new pixel[width*height]; - CopyData(buffer, width, height, pitch ? pitch : width); -} +VideoBuffer::VideoBuffer(pixel const *buffer, int width, int height, int pitch): + VideoBuffer(buffer, Vec2(width, height), pitch == 0 ? width : pitch) +{} void VideoBuffer::CopyData(pixel * buffer, int width, int height, int pitch) { for (auto y = 0; y < height; ++y) { - std::copy(buffer + y * pitch, buffer + y * pitch + width, Buffer + y * width); + std::copy(buffer + y * pitch, buffer + y * pitch + width, Buffer.data() + y * width); } } +void VideoBuffer::Crop(Rect rect) +{ + Crop(rect.Size().X, rect.Size().Y, rect.TopLeft.X, rect.TopLeft.Y); +} + void VideoBuffer::Crop(int width, int height, int x, int y) { - CopyData(Buffer + y * Width + x, width, height, Width); - Width = width; - Height = height; + CopyData(Buffer.data() + y * Width + x, width, height, Width); + video.SetSize(Vec2(width, height)); } void VideoBuffer::Resize(float factor, bool resample) @@ -87,16 +89,15 @@ void VideoBuffer::Resize(int width, int height, bool resample, bool fixedRatio) newHeight = (int)(Height * (newWidth/(float)Width)); } if(resample) - newBuffer = Graphics::resample_img(Buffer, Width, Height, newWidth, newHeight); + newBuffer = Graphics::resample_img(Buffer.data(), Width, Height, newWidth, newHeight); else - newBuffer = Graphics::resample_img_nn(Buffer, Width, Height, newWidth, newHeight); + newBuffer = Graphics::resample_img_nn(Buffer.data(), Width, Height, newWidth, newHeight); if(newBuffer) { - delete[] Buffer; - Buffer = newBuffer; - Width = newWidth; - Height = newHeight; + Buffer.assign(newBuffer, newBuffer + newWidth * newHeight); + delete[] newBuffer; + video.SetSize(Vec2(newWidth, newHeight)); } } @@ -127,11 +128,6 @@ int VideoBuffer::AddCharacter(int x, int y, String::value_type c, int r, int g, return x + reader.GetWidth(); } -VideoBuffer::~VideoBuffer() -{ - delete[] Buffer; -} - pixel *Graphics::resample_img_nn(pixel * src, int sw, int sh, int rw, int rh) { int y, x; @@ -739,7 +735,7 @@ void Graphics::draw_rgba_image(const pixel *data, int w, int h, int x, int y, fl VideoBuffer Graphics::DumpFrame() { VideoBuffer newBuffer(WINDOWW, WINDOWH); - std::copy(vid, vid+(WINDOWW*WINDOWH), newBuffer.Buffer); + std::copy(vid, vid+(WINDOWW*WINDOWH), newBuffer.Buffer.data()); return newBuffer; } diff --git a/src/graphics/Graphics.h b/src/graphics/Graphics.h index d6db6380a..41de6ae15 100644 --- a/src/graphics/Graphics.h +++ b/src/graphics/Graphics.h @@ -1,23 +1,66 @@ #pragma once +#include +#include +#include "common/Plane.h" #include "common/String.h" #include "common/tpt-inline.h" -#include "Pixel.h" #include "Icons.h" +#include "Pixel.h" +#include "RasterDrawMethods.h" +#include "SimulationConfig.h" -//"Graphics lite" - slightly lower performance due to variable size, -class VideoBuffer +class VideoBuffer: public RasterDrawMethods { -public: - pixel * Buffer; - int Width, Height; + PlaneAdapter> video; + + Rect getClipRect() const + { + return video.Size().OriginRect(); + } + + friend struct RasterDrawMethods; + + void CopyData(pixel * buffer, int width, int height, int pitch); + +public: + [[deprecated("Use video")]] + std::vector &Buffer = video.Base; + [[deprecated("Use Size()")]] + size_t &Width = video.xExtent::extent; // See TODO in common/Plane.h + [[deprecated("Use Size()")]] + size_t &Height = video.yExtent::extent; + + VideoBuffer(VideoBuffer const &) = default; + VideoBuffer(pixel const *data, Vec2 size); + VideoBuffer(pixel const *data, Vec2 size, size_t rowStride); + VideoBuffer(Vec2 size); + + Vec2 Size() const + { + return video.Size(); + } + + pixel const *Data() const + { + return video.data(); + } + + void Crop(Rect); - VideoBuffer(const VideoBuffer & old); - VideoBuffer(VideoBuffer * old); - VideoBuffer(pixel * buffer, int width, int height, int pitch = 0); - VideoBuffer(int width, int height); void Resize(float factor, bool resample = false); + void Resize(Vec2 size, bool resamble = false, bool fixedRatio = true); + + [[deprecated("Use VideoBuffer(VideoBuffer const &)")]] + VideoBuffer(VideoBuffer * old); + [[deprecated("Use VideoBuffer(pixel const *, Vec2)")]] + VideoBuffer(pixel const *buffer, int width, int height, int pitch = 0); + [[deprecated("Use VideoBuffer(Vec2)")]] + VideoBuffer(int width, int height); + [[deprecated("Use Resize(Vec2, bool, bool)")]] void Resize(int width, int height, bool resample = false, bool fixedRatio = true); + [[deprecated("Use Crop(Rect)")]] void Crop(int width, int height, int x, int y); + TPT_INLINE void BlendPixel(int x, int y, int r, int g, int b, int a) { pixel t; @@ -60,22 +103,39 @@ public: int SetCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); int BlendCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); int AddCharacter(int x, int y, String::value_type c, int r, int g, int b, int a); - ~VideoBuffer(); - void CopyData(pixel * buffer, int width, int height, int pitch); bool WritePNG(const ByteString &path) const; }; -class Graphics +class Graphics: public RasterDrawMethods { - int clipx1; - int clipy1; - int clipx2; - int clipy2; + PlaneAdapter, WINDOW.X, WINDOW.Y> video; + Rect clipRect = video.Size().OriginRect(); + + Rect getClipRect() const + { + return clipRect; + } + + friend struct RasterDrawMethods; + + [[deprecated("Use clipRect")]] + int &clipx1 = clipRect.TopLeft.X; + [[deprecated("Use clipRect")]] + int &clipy1 = clipRect.TopLeft.Y; + [[deprecated("Use clipRect")]] + int &clipx2 = clipRect.BottomRight.X; + [[deprecated("Use clipRect")]] + int &clipy2 = clipRect.BottomRight.Y; public: - pixel *vid; - int sdl_scale; + pixel const *Data() const + { + return video.data(); + } + + [[deprecated("Use Data()")]] + pixel *vid = video.data(); struct GradientStop { @@ -98,38 +158,15 @@ public: VideoBuffer DumpFrame(); - void blendpixel(int x, int y, int r, int g, int b, int a); - void addpixel(int x, int y, int r, int g, int b, int a); - void draw_icon(int x, int y, Icon icon, unsigned char alpha = 255, bool invert = false); void Clear(); void Finalise(); - // - int drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a); - int drawtext(int x, int y, const String &s, int r, int g, int b, int a); - int drawchar(int x, int y, String::value_type c, int r, int g, int b, int a); - int addchar(int x, int y, String::value_type c, int r, int g, int b, int a); - void xor_pixel(int x, int y); - void xor_line(int x, int y, int x2, int y2); - void xor_rect(int x, int y, int width, int height); - void xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h); - - void draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a); - void drawrect(int x, int y, int width, int height, int r, int g, int b, int a); - void fillrect(int x, int y, int width, int height, int r, int g, int b, int a); - void drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); - void fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); - void clearrect(int x, int y, int width, int height); - void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); - - void draw_image(const pixel *img, int x, int y, int w, int h, int a); - void draw_image(const VideoBuffer * vidBuf, int x, int y, int a); void draw_rgba_image(const pixel *data, int w, int h, int x, int y, float alpha); - Graphics(); - ~Graphics(); + Graphics() + {} void SetClipRect(int &x, int &y, int &w, int &h); }; diff --git a/src/graphics/RasterDrawMethods.h b/src/graphics/RasterDrawMethods.h new file mode 100644 index 000000000..86cf66462 --- /dev/null +++ b/src/graphics/RasterDrawMethods.h @@ -0,0 +1,32 @@ +#pragma once +#include "common/String.h" +#include "common/Vec2.h" +#include "graphics/Pixel.h" + +class VideoBuffer; + +// This is a mixin that adds methods to the Derived class, using the "Curiously +// Recurring Template Pattern" trick. +template +struct RasterDrawMethods +{ + int drawtext_outline(int x, int y, const String &, int r, int g, int b, int a); + int drawtext(int x, int y, const String &, int r, int g, int b, int a); + int drawchar(int x, int y, String::value_type, int r, int g, int b, int a); + int addchar(int x, int y, String::value_type, int r, int g, int b, int a); + void xor_pixel(int x, int y); + void blendpixel(int x, int y, int r, int g, int b, int a); + void addpixel(int x, int y, int r, int g, int b, int a); + void xor_line(int x1, int y1, int x2, int y2); + void xor_rect(int x, int y, int w, int h); + void xor_bitmap(unsigned char *bitmap, int x, int y, int w, int h); + void draw_line(int x1, int y1, int x2, int y2, int r, int g, int b, int a); + void drawrect(int x, int y, int w, int h, int r, int g, int b, int a); + void fillrect(int x, int y, int w, int h, int r, int g, int b, int a); + void drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); + void fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); + void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); + void clearrect(int x, int y, int w, int h); + void draw_image(pixel const *, int x, int y, int w, int h, int a); + void draw_image(VideoBuffer const *, int x, int y, int a); +}; diff --git a/src/graphics/RasterDrawMethods.inl b/src/graphics/RasterDrawMethodsImpl.h similarity index 66% rename from src/graphics/RasterDrawMethods.inl rename to src/graphics/RasterDrawMethodsImpl.h index c4f35154b..6a655c41d 100644 --- a/src/graphics/RasterDrawMethods.inl +++ b/src/graphics/RasterDrawMethodsImpl.h @@ -1,7 +1,16 @@ #include +#include +#include "RasterDrawMethods.h" +#include "Graphics.h" #include "FontReader.h" -int PIXELMETHODS_CLASS::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a) +#define vid() (static_cast(*this).video.RowIterator(Vec2(0, 0))) +#define clipRect() (static_cast(*this).getClipRect()) +#define VIDXRES (static_cast(*this).video.Size().X) +#define VIDYRES (static_cast(*this).video.Size().Y) + +template +int RasterDrawMethods::drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a) { drawtext(x-1, y-1, s, 0, 0, 0, 120); drawtext(x+1, y+1, s, 0, 0, 0, 120); @@ -12,7 +21,8 @@ int PIXELMETHODS_CLASS::drawtext_outline(int x, int y, const String &s, int r, i return drawtext(x, y, s, r, g, b, a); } -int PIXELMETHODS_CLASS::drawtext(int x, int y, const String &str, int r, int g, int b, int a) +template +int RasterDrawMethods::drawtext(int x, int y, const String &str, int r, int g, int b, int a) { if(!str.size()) return 0; @@ -95,7 +105,8 @@ int PIXELMETHODS_CLASS::drawtext(int x, int y, const String &str, int r, int g, return x; } -int PIXELMETHODS_CLASS::drawchar(int x, int y, String::value_type c, int r, int g, int b, int a) +template +int RasterDrawMethods::drawchar(int x, int y, String::value_type c, int r, int g, int b, int a) { FontReader reader(c); for (int j = -2; j < FONT_H - 2; j++) @@ -104,7 +115,8 @@ int PIXELMETHODS_CLASS::drawchar(int x, int y, String::value_type c, int r, int return x + reader.GetWidth(); } -int PIXELMETHODS_CLASS::addchar(int x, int y, String::value_type c, int r, int g, int b, int a) +template +int RasterDrawMethods::addchar(int x, int y, String::value_type c, int r, int g, int b, int a) { FontReader reader(c); for (int j = -2; j < FONT_H - 2; j++) @@ -113,52 +125,43 @@ int PIXELMETHODS_CLASS::addchar(int x, int y, String::value_type c, int r, int g return x + reader.GetWidth(); } -TPT_INLINE void PIXELMETHODS_CLASS::xor_pixel(int x, int y) +template +void RasterDrawMethods::xor_pixel(int x, int y) { int c; -#ifdef DO_CLIPCHECK - if (x=clipx2 || y>=clipy2) -#else - if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) -#endif + if (!clipRect().Contains(Vec2(x, y))) return; - c = vid[y*(VIDXRES)+x]; + c = vid()[y*(VIDXRES)+x]; c = PIXB(c) + 3*PIXG(c) + 2*PIXR(c); if (c<512) - vid[y*(VIDXRES)+x] = PIXPACK(0xC0C0C0); + vid()[y*(VIDXRES)+x] = PIXPACK(0xC0C0C0); else - vid[y*(VIDXRES)+x] = PIXPACK(0x404040); + vid()[y*(VIDXRES)+x] = PIXPACK(0x404040); } -void PIXELMETHODS_CLASS::blendpixel(int x, int y, int r, int g, int b, int a) +template +void RasterDrawMethods::blendpixel(int x, int y, int r, int g, int b, int a) { pixel t; -#ifdef DO_CLIPCHECK - if (x=clipx2 || y>=clipy2) -#else - if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) -#endif + if (!clipRect().Contains(Vec2(x, y))) return; if (a!=255) { - t = vid[y*(VIDXRES)+x]; + t = vid()[y*(VIDXRES)+x]; r = (a*r + (255-a)*PIXR(t)) >> 8; g = (a*g + (255-a)*PIXG(t)) >> 8; b = (a*b + (255-a)*PIXB(t)) >> 8; } - vid[y*(VIDXRES)+x] = PIXRGB(r,g,b); + vid()[y*(VIDXRES)+x] = PIXRGB(r,g,b); } -void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a) +template +void RasterDrawMethods::addpixel(int x, int y, int r, int g, int b, int a) { pixel t; -#ifdef DO_CLIPCHECK - if (x=clipx2 || y>=clipy2) -#else - if (x<0 || y<0 || x>=VIDXRES || y>=VIDYRES) -#endif + if (!clipRect().Contains(Vec2(x, y))) return; - t = vid[y*(VIDXRES)+x]; + t = vid()[y*(VIDXRES)+x]; r = (a*r + 255*PIXR(t)) >> 8; g = (a*g + 255*PIXG(t)) >> 8; b = (a*b + 255*PIXB(t)) >> 8; @@ -168,10 +171,11 @@ void PIXELMETHODS_CLASS::addpixel(int x, int y, int r, int g, int b, int a) g = 255; if (b>255) b = 255; - vid[y*(VIDXRES)+x] = PIXRGB(r,g,b); + vid()[y*(VIDXRES)+x] = PIXRGB(r,g,b); } -void PIXELMETHODS_CLASS::xor_line(int x1, int y1, int x2, int y2) +template +void RasterDrawMethods::xor_line(int x1, int y1, int x2, int y2) { int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy; float e, de; @@ -217,7 +221,8 @@ void PIXELMETHODS_CLASS::xor_line(int x1, int y1, int x2, int y2) } } -void PIXELMETHODS_CLASS::xor_rect(int x, int y, int w, int h) +template +void RasterDrawMethods::xor_rect(int x, int y, int w, int h) { int i; for (i=0; i +void RasterDrawMethods::xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h) { for(int x1 = 0; x1 < w; x1++) { @@ -261,7 +267,8 @@ void PIXELMETHODS_CLASS::xor_bitmap(unsigned char * bitmap, int x, int y, int w, } } -void PIXELMETHODS_CLASS::draw_line(int x1, int y1, int x2, int y2, int r, int g, int b, int a) +template +void RasterDrawMethods::draw_line(int x1, int y1, int x2, int y2, int r, int g, int b, int a) { int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy; float e, de; @@ -307,7 +314,8 @@ void PIXELMETHODS_CLASS::draw_line(int x1, int y1, int x2, int y2, int r, int g, } } -void PIXELMETHODS_CLASS::drawrect(int x, int y, int w, int h, int r, int g, int b, int a) +template +void RasterDrawMethods::drawrect(int x, int y, int w, int h, int r, int g, int b, int a) { int i; w--; @@ -324,7 +332,8 @@ void PIXELMETHODS_CLASS::drawrect(int x, int y, int w, int h, int r, int g, int } } -void PIXELMETHODS_CLASS::fillrect(int x, int y, int w, int h, int r, int g, int b, int a) +template +void RasterDrawMethods::fillrect(int x, int y, int w, int h, int r, int g, int b, int a) { int i,j; for (j=0; j +void RasterDrawMethods::drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a) { int yTop = ry, yBottom, i, j; if (!rx) @@ -362,7 +372,8 @@ void PIXELMETHODS_CLASS::drawcircle(int x, int y, int rx, int ry, int r, int g, } } -void PIXELMETHODS_CLASS::fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a) +template +void RasterDrawMethods::fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a) { int yTop = ry+1, yBottom, i, j; if (!rx) @@ -385,12 +396,14 @@ void PIXELMETHODS_CLASS::fillcircle(int x, int y, int rx, int ry, int r, int g, } } -void PIXELMETHODS_CLASS::gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2) +template +void RasterDrawMethods::gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2) { } -void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h) +template +void RasterDrawMethods::clearrect(int x, int y, int w, int h) { int i; @@ -400,41 +413,21 @@ void PIXELMETHODS_CLASS::clearrect(int x, int y, int w, int h) w -= 1; h -= 1; -#ifdef DO_CLIPCHECK - if (x+w > clipx2) w = clipx2-x; - if (y+h > clipy2) h = clipy2-y; - if (x VIDXRES) w = VIDXRES-x; - if (y+h > VIDYRES) h = VIDYRES-y; - if (x<0) - { - w += x; - x = 0; - } - if (y<0) - { - h += y; - y = 0; - } -#endif + Rect rect = clipRect() & RectSized(Vec2(x, y), Vec2(w, h)); + x = rect.TopLeft.X; + y = rect.TopLeft.Y; + w = rect.Size().X; + h = rect.Size().Y; + if (w<0 || h<0) return; for (i=0; i +void RasterDrawMethods::draw_image(const pixel *img, int x, int y, int w, int h, int a) { int startX = 0; if (!img) @@ -467,10 +460,8 @@ void PIXELMETHODS_CLASS::draw_image(const pixel *img, int x, int y, int w, int h img += startX; for (int i = startX; i < w; i++) { -#ifdef DO_CLIPCHECK - if (!(x+i=clipx2 || y+j>=clipy2)) -#endif - vid[(y+j)*(VIDXRES)+(x+i)] = *img; + if (clipRect().Contains(Vec2(x + i, y + j))) + vid()[(y+j)*(VIDXRES)+(x+i)] = *img; img++; } } @@ -492,7 +483,8 @@ void PIXELMETHODS_CLASS::draw_image(const pixel *img, int x, int y, int w, int h } } -void PIXELMETHODS_CLASS::draw_image(const VideoBuffer * vidBuf, int x, int y, int a) +template +void RasterDrawMethods::draw_image(const VideoBuffer * vidBuf, int x, int y, int a) { - draw_image(vidBuf->Buffer, x, y, vidBuf->Width, vidBuf->Height, a); + draw_image(vidBuf->Buffer.data(), x, y, vidBuf->Width, vidBuf->Height, a); } diff --git a/src/graphics/RasterGraphics.cpp b/src/graphics/RasterGraphics.cpp index 6bd8e6cc7..b5f42f216 100644 --- a/src/graphics/RasterGraphics.cpp +++ b/src/graphics/RasterGraphics.cpp @@ -1,23 +1,8 @@ -#include "Graphics.h" -#include "SimulationConfig.h" #include #include - -Graphics::Graphics(): - clipx1(0), - clipy1(0), - clipx2(WINDOWW), - clipy2(WINDOWH), - sdl_scale(1) -{ - vid = (pixel *)malloc(PIXELSIZE * (WINDOWW * WINDOWH)); - -} - -Graphics::~Graphics() -{ - free(vid); -} +#include "Graphics.h" +#include "SimulationConfig.h" +#include "RasterDrawMethodsImpl.h" void Graphics::Clear() { @@ -29,9 +14,4 @@ void Graphics::Finalise() } -constexpr auto VIDXRES = WINDOWW; -constexpr auto VIDYRES = WINDOWH; -#define PIXELMETHODS_CLASS Graphics -#define DO_CLIPCHECK -#include "RasterDrawMethods.inl" -#undef PIXELMETHODS_CLASS +template class RasterDrawMethods; diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index ead15095a..c4a485524 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -1,9 +1,10 @@ #pragma once +#include +#include +#include #include "Graphics.h" #include "gui/interface/Point.h" #include "SimulationConfig.h" -#include -#include class RenderPreset; class Simulation; @@ -32,11 +33,26 @@ typedef struct gcache_item gcache_item; int HeatToColour(float temp); -class Renderer +class Renderer: public RasterDrawMethods { + PlaneAdapter, WINDOW.X, RES.Y> video; + std::array persistentVideo; + PlaneAdapter, WINDOW.X, RES.Y> warpVideo; + + Rect getClipRect() const + { + return video.Size().OriginRect(); + } + + friend struct RasterDrawMethods; + public: + pixel const *Data() const + { + return video.data(); + } + Simulation * sim; - Graphics * g; gcache_item *graphicscache; std::vector render_modes; @@ -89,38 +105,18 @@ public: void FinaliseParts(); void ClearAccumulation(); - void clearScreen(float alpha); + void clearScreen(); void SetSample(int x, int y); - pixel * vid; - pixel * persistentVid; - pixel * warpVid; - void blendpixel(int x, int y, int r, int g, int b, int a); - void addpixel(int x, int y, int r, int g, int b, int a); + [[deprecated("Use video")]] + pixel *const vid = video.Base.data(); + [[deprecated("Use persistentVideo")]] + pixel *const persistentVid = persistentVideo.data(); + [[deprecated("Use wrapVideo")]] + pixel *const warpVid = warpVideo.data(); void draw_icon(int x, int y, Icon icon); - int drawtext_outline(int x, int y, const String &s, int r, int g, int b, int a); - int drawtext(int x, int y, const String &s, int r, int g, int b, int a); - int drawchar(int x, int y, String::value_type c, int r, int g, int b, int a); - int addchar(int x, int y, String::value_type c, int r, int g, int b, int a); - - void xor_pixel(int x, int y); - void xor_line(int x, int y, int x2, int y2); - void xor_rect(int x, int y, int width, int height); - void xor_bitmap(unsigned char * bitmap, int x, int y, int w, int h); - - void draw_line(int x, int y, int x2, int y2, int r, int g, int b, int a); - void drawrect(int x, int y, int width, int height, int r, int g, int b, int a); - void fillrect(int x, int y, int width, int height, int r, int g, int b, int a); - void drawcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); - void fillcircle(int x, int y, int rx, int ry, int r, int g, int b, int a); - void clearrect(int x, int y, int width, int height); - void gradientrect(int x, int y, int width, int height, int r, int g, int b, int a, int r2, int g2, int b2, int a2); - - void draw_image(const pixel *img, int x, int y, int w, int h, int a); - void draw_image(const VideoBuffer * vidBuf, int w, int h, int a); - VideoBuffer DumpFrame(); void drawblob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb); @@ -148,7 +144,7 @@ public: static VideoBuffer * WallIcon(int wallID, int width, int height); - Renderer(Graphics * g, Simulation * sim); + Renderer(Simulation * sim); ~Renderer(); #define RENDERER_TABLE(name) \ diff --git a/src/graphics/RendererBasic.cpp b/src/graphics/RendererBasic.cpp index bd9b535a2..9d12f05f4 100644 --- a/src/graphics/RendererBasic.cpp +++ b/src/graphics/RendererBasic.cpp @@ -1,27 +1,19 @@ -#include "Renderer.h" -#include "gui/game/RenderPreset.h" -#include "simulation/Simulation.h" -#include "simulation/ElementGraphics.h" -#include "simulation/ElementClasses.h" #include +#include "gui/game/RenderPreset.h" +#include "RasterDrawMethodsImpl.h" +#include "Renderer.h" +#include "simulation/ElementClasses.h" +#include "simulation/ElementGraphics.h" +#include "simulation/Simulation.h" + +#undef VIDXRES +#undef VIDYRES constexpr auto VIDXRES = WINDOWW; constexpr auto VIDYRES = WINDOWH; void Renderer::RenderBegin() { - if(display_mode & DISPLAY_PERS) - { - std::copy(persistentVid, persistentVid+(VIDXRES*YRES), vid); - } - pixel * oldVid = NULL; - if(display_mode & DISPLAY_WARP) - { - oldVid = vid; - vid = warpVid; - std::fill(warpVid, warpVid+(VIDXRES*VIDYRES), 0); - } - draw_air(); draw_grav(); DrawWalls(); @@ -50,11 +42,6 @@ void Renderer::RenderBegin() draw_grav_zones(); DrawSigns(); - if(display_mode & DISPLAY_WARP) - { - vid = oldVid; - } - FinaliseParts(); } @@ -68,15 +55,24 @@ void Renderer::SetSample(int x, int y) sampleColor = GetPixel(x, y); } -void Renderer::clearScreen(float alpha) +void Renderer::clearScreen() { - g->Clear(); + if(display_mode & DISPLAY_PERS) + { + std::copy(persistentVid, persistentVid+(VIDXRES*YRES), vid); + } + else + { + std::fill_n(video.data(), VIDXRES * YRES, 0); + } } void Renderer::FinaliseParts() { if(display_mode & DISPLAY_WARP) { + warpVideo = video; + std::fill_n(video.data(), VIDXRES * YRES, 0); render_gravlensing(warpVid); } } @@ -269,9 +265,8 @@ void Renderer::PopulateTables() } } -Renderer::Renderer(Graphics * g, Simulation * sim): +Renderer::Renderer(Simulation * sim): sim(NULL), - g(NULL), render_mode(0), colour_mode(0), display_mode(0), @@ -293,11 +288,7 @@ Renderer::Renderer(Graphics * g, Simulation * sim): { PopulateTables(); - this->g = g; this->sim = sim; - vid = g->vid; - persistentVid = new pixel[VIDXRES*YRES]; - warpVid = new pixel[VIDXRES*VIDYRES]; memset(fire_r, 0, sizeof(fire_r)); memset(fire_g, 0, sizeof(fire_g)); @@ -515,18 +506,14 @@ VideoBuffer Renderer::DumpFrame() VideoBuffer newBuffer(XRES, YRES); for(int y = 0; y < YRES; y++) { - std::copy(vid+(y*WINDOWW), vid+(y*WINDOWW)+XRES, newBuffer.Buffer+(y*XRES)); + std::copy(vid+(y*WINDOWW), vid+(y*WINDOWW)+XRES, newBuffer.Buffer.data()+(y*XRES)); } return newBuffer; } Renderer::~Renderer() { - delete[] persistentVid; - delete[] warpVid; delete[] graphicscache; } -#define PIXELMETHODS_CLASS Renderer -#include "RasterDrawMethods.inl" -#undef PIXELMETHODS_CLASS +template class RasterDrawMethods; diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index d4bdebe45..4cb15b3b9 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -58,7 +58,7 @@ GameModel::GameModel(): decoSpace(0) { sim = new Simulation(); - ren = new Renderer(ui::Engine::Ref().g, sim); + ren = new Renderer(sim); activeTools = regularToolset; diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 35af0ee7e..ac84e6451 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -958,7 +958,7 @@ ByteString GameView::TakeScreenshot(int captureUI, int fileType) // We should be able to simply use SDL_PIXELFORMAT_XRGB8888 here with a bit depth of 32 to convert RGBA data to RGB data, // and save the resulting surface directly. However, ubuntu-18.04 ships SDL2 so old that it doesn't have // SDL_PIXELFORMAT_XRGB8888, so we first create an RGBA surface and then convert it. - auto *rgbaSurface = SDL_CreateRGBSurfaceWithFormatFrom(screenshot->Buffer, screenshot->Width, screenshot->Height, 32, screenshot->Width * sizeof(pixel), SDL_PIXELFORMAT_ARGB8888); + auto *rgbaSurface = SDL_CreateRGBSurfaceWithFormatFrom(screenshot->Buffer.data(), screenshot->Width, screenshot->Height, 32, screenshot->Width * sizeof(pixel), SDL_PIXELFORMAT_ARGB8888); auto *rgbSurface = SDL_ConvertSurfaceFormat(rgbaSurface, SDL_PIXELFORMAT_RGB888, 0); if (!rgbSurface || SDL_SaveBMP(rgbSurface, filename.c_str())) { @@ -2074,7 +2074,7 @@ void GameView::OnDraw() Graphics * g = GetGraphics(); if (ren) { - ren->clearScreen(1.0f); + ren->clearScreen(); ren->RenderBegin(); ren->SetSample(c->PointTranslate(currentMouse).X, c->PointTranslate(currentMouse).Y); if (showBrush && selectMode == SelectNone && (!zoomEnabled || zoomCursorFixed) && activeBrush && (isMouseDown || (currentMouse.X >= 0 && currentMouse.X < XRES && currentMouse.Y >= 0 && currentMouse.Y < YRES))) @@ -2196,6 +2196,9 @@ void GameView::OnDraw() ren->RenderEnd(); + std::copy_n(ren->Data(), WINDOWW * YRES, g->vid); + + if (doScreenshot) { doScreenshot = false; diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp index f9588d501..0dedf634e 100644 --- a/src/gui/preview/PreviewView.cpp +++ b/src/gui/preview/PreviewView.cpp @@ -285,7 +285,7 @@ void PreviewView::OnDraw() g->clearrect(Position.X-2, Position.Y-2, Size.X+4, Size.Y+4); //Save preview (top-left) - if(savePreview && savePreview->Buffer) + if(savePreview) { g->draw_image(savePreview, (Position.X+1)+(((XRES/2)-savePreview->Width)/2), (Position.Y+1)+(((YRES/2)-savePreview->Height)/2), 255); } @@ -465,16 +465,16 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) { savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true); - if(savePreview && savePreview->Buffer && !(savePreview->Width == XRES/2 && savePreview->Height == YRES/2)) + if(savePreview && !(savePreview->Width == XRES/2 && savePreview->Height == YRES/2)) { - pixel * oldData = savePreview->Buffer; float factorX = ((float)XRES/2)/((float)savePreview->Width); float factorY = ((float)YRES/2)/((float)savePreview->Height); float scaleFactor = factorY < factorX ? factorY : factorX; - savePreview->Buffer = Graphics::resample_img(oldData, savePreview->Width, savePreview->Height, int(savePreview->Width*scaleFactor), int(savePreview->Height*scaleFactor)); - delete[] oldData; + pixel *data = Graphics::resample_img(savePreview->Buffer.data(), savePreview->Width, savePreview->Height, int(savePreview->Width*scaleFactor), int(savePreview->Height*scaleFactor)); savePreview->Width = int(savePreview->Width * scaleFactor); savePreview->Height = int(savePreview->Height * scaleFactor); + savePreview->Buffer.assign(data, data + savePreview->Width * savePreview->Height); + delete[] data; } } else if (!sender->GetCanOpen()) diff --git a/src/gui/render/RenderView.cpp b/src/gui/render/RenderView.cpp index 93e68db88..bdc22928f 100644 --- a/src/gui/render/RenderView.cpp +++ b/src/gui/render/RenderView.cpp @@ -158,7 +158,7 @@ void RenderView::OnDraw() g->clearrect(-1, -1, WINDOWW+1, WINDOWH+1); if(ren) { - ren->clearScreen(1.0f); + ren->clearScreen(); ren->RenderBegin(); ren->RenderEnd(); } diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp index 4efd83fc2..f9084d287 100644 --- a/src/simulation/SaveRenderer.cpp +++ b/src/simulation/SaveRenderer.cpp @@ -8,9 +8,8 @@ #include "Simulation.h" SaveRenderer::SaveRenderer(){ - g = new Graphics(); sim = new Simulation(); - ren = new Renderer(g, sim); + ren = new Renderer(sim); ren->decorations_enable = true; ren->blackDecorations = true; } @@ -38,7 +37,6 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire, width = save->blockWidth; height = save->blockHeight; - g->Clear(); sim->clear_sim(); if(!sim->Load(save, true)) @@ -47,7 +45,7 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire, ren->blackDecorations = !decorations; pixel * pData = NULL; pixel * dst; - pixel * src = g->vid; + pixel * src = ren->vid; ren->ClearAccumulation(); @@ -59,7 +57,7 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire, frame--; ren->render_parts(); ren->render_fire(); - ren->clearScreen(1.0f); + ren->clearScreen(); } } @@ -86,5 +84,4 @@ SaveRenderer::~SaveRenderer() { delete ren; delete sim; - delete g; } diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h index f03b9e731..a65d24e08 100644 --- a/src/simulation/SaveRenderer.h +++ b/src/simulation/SaveRenderer.h @@ -9,7 +9,6 @@ class Simulation; class Renderer; class SaveRenderer: public ExplicitSingleton { - Graphics * g; Simulation * sim; Renderer * ren; std::mutex renderMutex;