diff options
31 files changed, 687 insertions, 294 deletions
diff --git a/projects/openttd.vcproj b/projects/openttd.vcproj index e395f4842..e7379545f 100644 --- a/projects/openttd.vcproj +++ b/projects/openttd.vcproj @@ -980,6 +980,12 @@ RelativePath=".\..\src\blitter\8bpp_simple.hpp"> </File> <File + RelativePath=".\..\src\blitter\null.cpp"> + </File> + <File + RelativePath=".\..\src\blitter\null.hpp"> + </File> + <File RelativePath=".\..\src\blitter\blitter.hpp"> </File> </Filter> @@ -997,6 +1003,25 @@ </File> </Filter> <Filter + Name="Renderer" + Filter=""> + <File + RelativePath=".\..\src\renderer\8bpp.cpp"> + </File> + <File + RelativePath=".\..\src\renderer\8bpp.hpp"> + </File> + <File + RelativePath=".\..\src\renderer\null.cpp"> + </File> + <File + RelativePath=".\..\src\renderer\null.hpp"> + </File> + <File + RelativePath=".\..\src\renderer\renderer.hpp"> + </File> + </Filter> + <Filter Name="NewGRF" Filter=""> <File diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index eee9ba6e4..613a61330 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -1528,6 +1528,14 @@ > </File> <File + RelativePath=".\..\src\blitter\null.cpp" + > + </File> + <File + RelativePath=".\..\src\blitter\null.hpp" + > + </File> + <File RelativePath=".\..\src\blitter\blitter.hpp" > </File> @@ -1549,6 +1557,30 @@ </File> </Filter> <Filter + Name="Renderer" + > + <File + RelativePath=".\..\src\renderer\8bpp.cpp" + > + </File> + <File + RelativePath=".\..\src\renderer\8bpp.hpp" + > + </File> + <File + RelativePath=".\..\src\renderer\null.cpp" + > + </File> + <File + RelativePath=".\..\src\renderer\null.hpp" + > + </File> + <File + RelativePath=".\..\src\renderer\renderer.hpp" + > + </File> + </Filter> + <Filter Name="NewGRF" > <File diff --git a/source.list b/source.list index 98e55bd00..4be5cf88c 100644 --- a/source.list +++ b/source.list @@ -297,6 +297,8 @@ blitter/8bpp_optimized.cpp blitter/8bpp_optimized.hpp blitter/8bpp_simple.cpp blitter/8bpp_simple.hpp +blitter/null.cpp +blitter/null.hpp blitter/blitter.hpp # Sprite loaders @@ -304,6 +306,13 @@ spriteloader/grf.cpp spriteloader/grf.hpp spriteloader/spriteloader.hpp +# Renderer +renderer/8bpp.cpp +renderer/8bpp.hpp +renderer/null.cpp +renderer/null.hpp +renderer/renderer.hpp + # NewGRF newgrf.cpp newgrf_canal.cpp diff --git a/src/blitter/8bpp_debug.cpp b/src/blitter/8bpp_debug.cpp index 3f4c0b046..3a9b52d2a 100644 --- a/src/blitter/8bpp_debug.cpp +++ b/src/blitter/8bpp_debug.cpp @@ -12,12 +12,12 @@ static FBlitter_8bppDebug iFBlitter_8bppDebug; void Blitter_8bppDebug::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { - const byte *src, *src_line; - Pixel8 *dst, *dst_line; + const uint8 *src, *src_line; + uint8 *dst, *dst_line; /* Find where to start reading in the source sprite */ - src_line = (const byte *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); - dst_line = (Pixel8 *)bp->dst + bp->top * bp->pitch + bp->left; + src_line = (const uint8 *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; for (int y = 0; y < bp->height; y++) { dst = dst_line; diff --git a/src/blitter/8bpp_debug.hpp b/src/blitter/8bpp_debug.hpp index 443fb20c4..7b8484f70 100644 --- a/src/blitter/8bpp_debug.hpp +++ b/src/blitter/8bpp_debug.hpp @@ -7,15 +7,15 @@ #include "blitter.hpp" -typedef Pixel Pixel8; - class Blitter_8bppDebug : public Blitter { public: - uint8 GetScreenDepth() { return 8; } + /* virtual */ uint8 GetScreenDepth() { return 8; } + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); - void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); - Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); + /* virtual */ const char *GetRenderer() { return "8bpp"; } }; class FBlitter_8bppDebug: public BlitterFactory<FBlitter_8bppDebug> { diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp index 7a105544c..9af922e30 100644 --- a/src/blitter/8bpp_optimized.cpp +++ b/src/blitter/8bpp_optimized.cpp @@ -12,16 +12,16 @@ static FBlitter_8bppOptimized iFBlitter_8bppOptimized; void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { - const byte *src, *src_next; - Pixel8 *dst, *dst_line; + const uint8 *src, *src_next; + uint8 *dst, *dst_line; uint offset = 0; /* Find the offset of this zoom-level */ - offset = ((const byte *)bp->sprite)[(int)zoom * 2] | ((const byte *)bp->sprite)[(int)zoom * 2 + 1] << 8; + offset = ((const uint8 *)bp->sprite)[(int)zoom * 2] | ((const byte *)bp->sprite)[(int)zoom * 2 + 1] << 8; /* Find where to start reading in the source sprite */ - src = (const byte *)bp->sprite + offset; - dst_line = (Pixel8 *)bp->dst + bp->top * bp->pitch + bp->left; + src = (const uint8 *)bp->sprite + offset; + dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; /* Skip over the top lines in the source image */ for (int y = 0; y < bp->skip_top; y++) { diff --git a/src/blitter/8bpp_optimized.hpp b/src/blitter/8bpp_optimized.hpp index b7f8b694f..540e9d1c6 100644 --- a/src/blitter/8bpp_optimized.hpp +++ b/src/blitter/8bpp_optimized.hpp @@ -7,15 +7,15 @@ #include "blitter.hpp" -typedef Pixel Pixel8; - class Blitter_8bppOptimized : public Blitter { public: - uint8 GetScreenDepth() { return 8; } + /* virtual */ uint8 GetScreenDepth() { return 8; } + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); - void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); - Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); + /* virtual */ const char *GetRenderer() { return "8bpp"; } }; class FBlitter_8bppOptimized: public BlitterFactory<FBlitter_8bppOptimized> { diff --git a/src/blitter/8bpp_simple.cpp b/src/blitter/8bpp_simple.cpp index 170afa460..010066f8a 100644 --- a/src/blitter/8bpp_simple.cpp +++ b/src/blitter/8bpp_simple.cpp @@ -11,12 +11,12 @@ static FBlitter_8bppSimple iFBlitter_8bppSimple; void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { - const byte *src, *src_line; - Pixel8 *dst, *dst_line; + const uint8 *src, *src_line; + uint8 *dst, *dst_line; /* Find where to start reading in the source sprite */ - src_line = (const byte *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); - dst_line = (Pixel8 *)bp->dst + bp->top * bp->pitch + bp->left; + src_line = (const uint8 *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; for (int y = 0; y < bp->height; y++) { dst = dst_line; diff --git a/src/blitter/8bpp_simple.hpp b/src/blitter/8bpp_simple.hpp index f47245729..1188e509d 100644 --- a/src/blitter/8bpp_simple.hpp +++ b/src/blitter/8bpp_simple.hpp @@ -7,15 +7,15 @@ #include "blitter.hpp" -typedef Pixel Pixel8; - class Blitter_8bppSimple : public Blitter { public: - uint8 GetScreenDepth() { return 8; } + /* virtual */ uint8 GetScreenDepth() { return 8; } + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); - void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); - Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); + /* virtual */ const char *GetRenderer() { return "8bpp"; } }; class FBlitter_8bppSimple: public BlitterFactory<FBlitter_8bppSimple> { diff --git a/src/blitter/blitter.hpp b/src/blitter/blitter.hpp index 1114dbf58..b2e0edfe3 100644 --- a/src/blitter/blitter.hpp +++ b/src/blitter/blitter.hpp @@ -53,6 +53,11 @@ public: */ virtual Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) = 0; + /** + * Get the renderer this class depends on. + */ + virtual const char *GetRenderer() = 0; + virtual ~Blitter() { } }; diff --git a/src/blitter/null.cpp b/src/blitter/null.cpp new file mode 100644 index 000000000..1aad792a1 --- /dev/null +++ b/src/blitter/null.cpp @@ -0,0 +1,24 @@ +#include "../stdafx.h" +#include "../zoom.hpp" +#include "../gfx.h" +#include "../functions.h" +#include "null.hpp" + +static FBlitter_Null iFBlitter_Null; + +void Blitter_Null::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ +} + +Sprite *Blitter_Null::Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator) +{ + Sprite *dest_sprite; + dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite)); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + return dest_sprite; +} diff --git a/src/blitter/null.hpp b/src/blitter/null.hpp new file mode 100644 index 000000000..5278bd474 --- /dev/null +++ b/src/blitter/null.hpp @@ -0,0 +1,30 @@ +/* $Id$ */ + +/** @file null.hpp */ + +#ifndef BLITTER_NULL_HPP +#define BLITTER_NULL_HPP + +#include "blitter.hpp" + +class Blitter_Null : public Blitter { +public: + /* virtual */ uint8 GetScreenDepth() { return 0; } + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + + /* virtual */ Sprite *Encode(SpriteLoader::Sprite *sprite, Blitter::AllocatorProc *allocator); + + /* virtual */ const char *GetRenderer() { return "null"; } +}; + +class FBlitter_Null: public BlitterFactory<FBlitter_Null> { +public: + /* virtual */ const char *GetName() { return "null"; } + + /* virtual */ const char *GetDescription() { return "Null Blitter (does nothing)"; } + + /* virtual */ Blitter *CreateInstance() { return new Blitter_Null(); } +}; + +#endif /* BLITTER_NULL_HPP */ diff --git a/src/gfx.cpp b/src/gfx.cpp index 3117d1782..332015ef3 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -50,7 +50,7 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode) FontSize _cur_fontsize; static FontSize _last_fontsize; -static Pixel _cursor_backup[64 * 64]; +static uint8 _cursor_backup[64 * 64 * 4]; static Rect _invalid_rect; static const byte *_color_remap_ptr; static byte _string_colorremap[3]; @@ -58,37 +58,20 @@ static byte _string_colorremap[3]; #define DIRTY_BYTES_PER_LINE (MAX_SCREEN_WIDTH / 64) static byte _dirty_blocks[DIRTY_BYTES_PER_LINE * MAX_SCREEN_HEIGHT / 8]; -void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch) -{ - Pixel *dstp = (Pixel *)dst; - Pixel *srcp = (Pixel *)src; - - assert(h >= 0); - for (; h != 0; --h) { - memcpy(dstp, srcp, w * sizeof(Pixel)); - dstp += dstpitch; - srcp += srcpitch; - } -} - void GfxScroll(int left, int top, int width, int height, int xo, int yo) { - const Pixel *src; - Pixel *dst; - int p; - int ht; + const void *src; + void *dst; if (xo == 0 && yo == 0) return; if (_cursor.visible) UndrawMouseCursor(); UndrawTextMessage(); - p = _screen.pitch; - if (yo > 0) { /*Calculate pointers */ - dst = _screen.dst_ptr + (top + height - 1) * p + left; - src = dst - yo * p; + dst = _screen.renderer->MoveTo(_screen.dst_ptr, left, top + height - 1); + src = _screen.renderer->MoveTo(dst, 0, -yo); /* Decrease height and increase top */ top += yo; @@ -97,23 +80,20 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo) /* Adjust left & width */ if (xo >= 0) { - dst += xo; + dst = _screen.renderer->MoveTo(dst, xo, 0); left += xo; width -= xo; } else { - src -= xo; + src = _screen.renderer->MoveTo(src, -xo, 0); width += xo; } - for (ht = height; ht > 0; --ht) { - memcpy(dst, src, width * sizeof(Pixel)); - src -= p; - dst -= p; - } + /* Negative height as we want to copy from bottom to top */ + _screen.renderer->CopyFromBuffer(dst, src, width, -height, _screen.pitch); } else { /* Calculate pointers */ - dst = _screen.dst_ptr + top * p + left; - src = dst - yo * p; + dst = _screen.renderer->MoveTo(_screen.dst_ptr, left, top); + src = _screen.renderer->MoveTo(dst, 0, -yo); /* Decrese height. (yo is <=0). */ height += yo; @@ -121,21 +101,17 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo) /* Adjust left & width */ if (xo >= 0) { - dst += xo; + dst = _screen.renderer->MoveTo(dst, xo, 0); left += xo; width -= xo; } else { - src -= xo; + src = _screen.renderer->MoveTo(src, -xo, 0); width += xo; } /* the y-displacement may be 0 therefore we have to use memmove, * because source and destination may overlap */ - for (ht = height; ht > 0; --ht) { - memmove(dst, src, width * sizeof(Pixel)); - src += p; - dst += p; - } + _screen.renderer->MoveBuffer(dst, src, width, height); } /* This part of the screen is now dirty. */ _video_driver->make_dirty(left, top, width, height); @@ -144,8 +120,8 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo) void GfxFillRect(int left, int top, int right, int bottom, int color) { - const DrawPixelInfo* dpi = _cur_dpi; - Pixel *dst; + const DrawPixelInfo *dpi = _cur_dpi; + void *dst; const int otop = top; const int oleft = left; @@ -166,40 +142,37 @@ void GfxFillRect(int left, int top, int right, int bottom, int color) bottom -= top; assert(bottom > 0); - dst = dpi->dst_ptr + top * dpi->pitch + left; + dst = _screen.renderer->MoveTo(dpi->dst_ptr, left, top); if (!HASBIT(color, PALETTE_MODIFIER_GREYOUT)) { if (!HASBIT(color, USE_COLORTABLE)) { do { - memset(dst, color, right * sizeof(Pixel)); - dst += dpi->pitch; + _screen.renderer->SetHorizontalLine(dst, right, (uint8)color); + dst = _screen.renderer->MoveTo(dst, 0, 1); } while (--bottom); } else { /* use colortable mode */ const byte* ctab = GetNonSprite(GB(color, 0, PALETTE_WIDTH)) + 1; do { - int i; - for (i = 0; i != right; i++) dst[i] = ctab[dst[i]]; - dst += dpi->pitch; + for (int i = 0; i != right; i++) _screen.renderer->SetPixel(dst, i, 0, ctab[((uint8 *)dst)[i]]); + dst = _screen.renderer->MoveTo(dst, 0, 1); } while (--bottom); } } else { byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; do { - int i; - for (i = (bo ^= 1); i < right; i += 2) dst[i] = (byte)color; - dst += dpi->pitch; + for (int i = (bo ^= 1); i < right; i += 2) _screen.renderer->SetPixel(dst, i, 0, (uint8)color); + dst = _screen.renderer->MoveTo(dst, 0, 1); } while (--bottom > 0); } } static void GfxSetPixel(int x, int y, int color) { - const DrawPixelInfo* dpi = _cur_dpi; - if ((x -= dpi->left) < 0 || x >= dpi->width || (y -= dpi->top)<0 || y >= dpi->height) - return; - dpi->dst_ptr[y * dpi->pitch + x] = color; + const DrawPixelInfo *dpi = _cur_dpi; + if ((x -= dpi->left) < 0 || x >= dpi->width || (y -= dpi->top) < 0 || y >= dpi->height) return; + _screen.renderer->SetPixel(dpi->dst_ptr, x, y, color); } void GfxDrawLine(int x, int y, int x2, int y2, int color) @@ -817,6 +790,13 @@ void DoPaletteAnimations() Colour old_val[38]; // max(38, 28) uint i; uint j; + int old_tc = _timer_counter; + + /* We can only update the palette in 8bpp for now */ + /* TODO -- We need support for other bpps too! */ + if (BlitterFactoryBase::GetCurrentBlitter() != NULL && BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 8) { + _timer_counter = 0; + } d = &_cur_palette[217]; memcpy(old_val, d, c * sizeof(*old_val)); @@ -913,6 +893,8 @@ void DoPaletteAnimations() if (_pal_first_dirty > 217) _pal_first_dirty = 217; if (_pal_last_dirty < 217 + c) _pal_last_dirty = 217 + c; } + + if (old_tc != _timer_counter) _timer_counter = old_tc; } @@ -959,11 +941,7 @@ void UndrawMouseCursor() { if (_cursor.visible) { _cursor.visible = false; - memcpy_pitch( - _screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch, - _cursor_backup, - _cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x, _screen.pitch); - + _screen.renderer->CopyFromBuffer(_screen.renderer->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup, _cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x); _video_driver->make_dirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); } } @@ -1006,13 +984,10 @@ void DrawMouseCursor() _cursor.draw_pos.y = y; _cursor.draw_size.y = h; - assert(w * h < (int)sizeof(_cursor_backup)); + assert(_screen.renderer->BufferSize(w, h) < (int)sizeof(_cursor_backup)); /* Make backup of stuff below cursor */ - memcpy_pitch( - _cursor_backup, - _screen.dst_ptr + _cursor.draw_pos.x + _cursor.draw_pos.y * _screen.pitch, - _cursor.draw_size.x, _cursor.draw_size.y, _screen.pitch, _cursor.draw_size.x); + _screen.renderer->CopyToBuffer(_screen.renderer->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup, _cursor.draw_size.x, _cursor.draw_size.y, _cursor.draw_size.x); /* Draw cursor on screen */ _cur_dpi = &_screen; @@ -1233,7 +1208,8 @@ bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int heigh n->top = 0; } - n->dst_ptr = o->dst_ptr + left + top * (n->pitch = o->pitch); + n->dst_ptr = _screen.renderer->MoveTo(o->dst_ptr, left, top); + n->pitch = o->pitch; if (height > o->height - top) { height = o->height - top; @@ -7,6 +7,7 @@ #include "openttd.h" #include "zoom.hpp" +#include "renderer/renderer.hpp" enum WindowKeyCodes { WKC_SHIFT = 0x8000, @@ -93,7 +94,6 @@ void GameLoop(); void CreateConsole(); typedef int32 CursorID; -typedef byte Pixel; struct Point { int x,y; @@ -134,10 +134,11 @@ struct CursorVars { }; struct DrawPixelInfo { - Pixel *dst_ptr; + void *dst_ptr; int left, top, width, height; int pitch; ZoomLevel zoom; + Renderer *renderer; }; struct Colour { diff --git a/src/openttd.cpp b/src/openttd.cpp index b6462bdb1..c3983aee1 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -402,6 +402,7 @@ int ttd_main(int argc, char *argv[]) strcpy(musicdriver, "null"); strcpy(sounddriver, "null"); strcpy(videodriver, "dedicated"); + strcpy(blitter, "null"); dedicated = true; if (mgo.opt != NULL) { /* Use the existing method for parsing (openttd -n). diff --git a/src/renderer/8bpp.cpp b/src/renderer/8bpp.cpp new file mode 100644 index 000000000..2f595c6c9 --- /dev/null +++ b/src/renderer/8bpp.cpp @@ -0,0 +1,71 @@ +#include "../stdafx.h" +#include "../gfx.h" +#include "8bpp.hpp" + +static FRenderer_8bpp iFRenderer_8bpp; + +void *Renderer_8bpp::MoveTo(const void *video, int x, int y) +{ + return (uint8 *)video + x + y * _screen.pitch; +} + +void Renderer_8bpp::SetPixel(void *video, int x, int y, uint8 color) +{ + *((uint8 *)video + x + y * _screen.pitch) = color; +} + +void Renderer_8bpp::SetPixelIfEmpty(void *video, int x, int y, uint8 color) +{ + uint8 *dst = (uint8 *)video + x + y * _screen.pitch; + if (*dst == 0) *dst = color; +} + +void Renderer_8bpp::SetHorizontalLine(void *video, int width, uint8 color) +{ + memset(video, color, width); +} + +void Renderer_8bpp::CopyFromBuffer(void *video, const void *src, int width, int height, int src_pitch) +{ + int direction = (height < 0) ? -1 : 1; + uint8 *dst = (uint8 *)video; + uint8 *usrc = (uint8 *)src; + + height = abs(height); + for (; height > 0; height--) { + memcpy(dst, usrc, width); + usrc += src_pitch * direction; + dst += _screen.pitch * direction; + } +} + +void Renderer_8bpp::CopyToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ + int direction = (height < 0) ? -1 : 1; + uint8 *udst = (uint8 *)dst; + uint8 *src = (uint8 *)video; + + height = abs(height); + for (; height > 0; height--) { + memcpy(udst, src, width); + src += _screen.pitch * direction; + udst += dst_pitch * direction; + } +} + +void Renderer_8bpp::MoveBuffer(void *video_dst, const void *video_src, int width, int height) +{ + uint8 *dst = (uint8 *)video_dst; + uint8 *src = (uint8 *)video_src; + + for (; height > 0; height--) { + memmove(dst, src, width); + src += _screen.pitch; + dst += _screen.pitch; + } +} + +int Renderer_8bpp::BufferSize(int width, int height) +{ + return width * height; +} diff --git a/src/renderer/8bpp.hpp b/src/renderer/8bpp.hpp new file mode 100644 index 000000000..a8bb27a48 --- /dev/null +++ b/src/renderer/8bpp.hpp @@ -0,0 +1,29 @@ +/* $Id$ */ + +/** @file 8bpp.hpp */ + +#ifndef RENDERER_8BPP_HPP +#define RENDERER_8BPP_HPP + +#include "renderer.hpp" + +class Renderer_8bpp : public Renderer { +public: + /* virtual */ void *MoveTo(const void *video, int x, int y); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 color); + /* virtual */ void SetPixelIfEmpty(void *video, int x, int y, uint8 color); + /* virtual */ void SetHorizontalLine(void *video, int width, uint8 color); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height, int src_pitch); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); + /* virtual */ void MoveBuffer(void *video_dst, const void *video_src, int width, int height); + /* virtual */ int BufferSize(int width, int height); +}; + +class FRenderer_8bpp: public RendererFactory<FRenderer_8bpp> { +public: + /* virtual */ const char *GetName() { return "8bpp"; } + + /* virtual */ Renderer *CreateInstance() { return new Renderer_8bpp(); } +}; + +#endif /* RENDERER_8BPP_HPP */ diff --git a/src/renderer/null.cpp b/src/renderer/null.cpp new file mode 100644 index 000000000..fc68feaf2 --- /dev/null +++ b/src/renderer/null.cpp @@ -0,0 +1,39 @@ +#include "../stdafx.h" +#include "../gfx.h" +#include "null.hpp" + +static FRenderer_Null iFRenderer_Null; + +void *Renderer_Null::MoveTo(const void *video, int x, int y) +{ + return NULL; +} + +void Renderer_Null::SetPixel(void *video, int x, int y, uint8 color) +{ +} + +void Renderer_Null::SetPixelIfEmpty(void *video, int x, int y, uint8 color) +{ +} + +void Renderer_Null::SetHorizontalLine(void *video, int width, uint8 color) +{ +} + +void Renderer_Null::CopyFromBuffer(void *video, const void *src, int width, int height, int src_pitch) +{ +} + +void Renderer_Null::CopyToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ +} + +void Renderer_Null::MoveBuffer(void *video_dst, const void *video_src, int width, int height) +{ +} + +int Renderer_Null::BufferSize(int width, int height) +{ + return 0; +} diff --git a/src/renderer/null.hpp b/src/renderer/null.hpp new file mode 100644 index 000000000..1eb95bbdd --- /dev/null +++ b/src/renderer/null.hpp @@ -0,0 +1,29 @@ +/* $Id$ */ + +/** @file null.hpp */ + +#ifndef RENDERER_NULL_HPP +#define RENDERER_NULL_HPP + +#include "renderer.hpp" + +class Renderer_Null : public Renderer { +public: + /* virtual */ void *MoveTo(const void *video, int x, int y); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 color); + /* virtual */ void SetPixelIfEmpty(void *video, int x, int y, uint8 color); + /* virtual */ void SetHorizontalLine(void *video, int width, uint8 color); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height, int src_pitch); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); + /* virtual */ void MoveBuffer(void *video_dst, const void *video_src, int width, int height); + /* virtual */ int BufferSize(int width, int height); +}; + +class FRenderer_Null: public RendererFactory<FRenderer_Null> { +public: + /* virtual */ const char *GetName() { return "null"; } + + /* virtual */ Renderer *CreateInstance() { return new Renderer_Null(); } +}; + +#endif /* RENDERER_NULL_HPP */ diff --git a/src/renderer/renderer.hpp b/src/renderer/renderer.hpp new file mode 100644 index 000000000..7b7ad0f4f --- /dev/null +++ b/src/renderer/renderer.hpp @@ -0,0 +1,165 @@ +/* $Id$ */ + +/** @file renderer.hpp */ + +#ifndef RENDERER_HPP +#define RENDERER_HPP + +#include <string> +#include <map> + +class Renderer { +public: + virtual ~Renderer() { } + + /** + * Move the destination pointer the requested amount x and y, keeping in mind + * any pitch and bpp of the renderer. + * @param video The destination pointer (video-buffer) to scroll. + * @param x How much you want to scroll to the right. + * @param y How much you want to scroll to the bottom. + * @return A new destination pointer moved the the requested place. + */ + virtual void *MoveTo(const void *video, int x, int y) = 0; + + /** + * Draw a pixel with a given color on the video-buffer. + * @param video The destination pointer (video-buffer). + * @param x The x position within video-buffer. + * @param y The y position within video-buffer. + * @param color A 8bpp mapping color. + */ + virtual void SetPixel(void *video, int x, int y, uint8 color) = 0; + + /** + * Draw a pixel with a given color on the video-buffer if there is currently a black pixel. + * @param video The destination pointer (video-buffer). + * @param x The x position within video-buffer. + * @param y The y position within video-buffer. + * @param color A 8bpp mapping color. + */ + virtual void SetPixelIfEmpty(void *video, int x, int y, uint8 color) = 0; + + /** + * Make a single horizontal line in a single color on the video-buffer. + * @param video The destination pointer (video-buffer). + * @param width The lenght of the line. + * @param color A 8bpp mapping color. + */ + virtual void SetHorizontalLine(void *video, int width, uint8 color) = 0; + + /** + * Copy from a buffer to the screen. + * @param video The destionation pointer (video-buffer). + * @param src The buffer from which the data will be read. + * @param width The width of the buffer. + * @param height The height of the buffer. + * @param src_pitch The pitch (byte per line) of the source buffer. + */ + virtual void CopyFromBuffer(void *video, const void *src, int width, int height, int src_pitch) = 0; + + /** + * Copy from the screen to a buffer. + * @param video The destination pointer (video-buffer). + * @param dst The buffer in which the data will be stored. + * @param width The width of the buffer. + * @param height The height of the buffer. + * @param dst_pitch The pitch (byte per line) of the destination buffer. + */ + virtual void CopyToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) = 0; + + /** + * Move the videobuffer some places (via memmove). + * @param video_dst The destination pointer (video-buffer). + * @param video_src The source pointer (video-buffer). + * @param width The width of the buffer to move. + * @param height The height of the buffer to move. + */ + virtual void MoveBuffer(void *video_dst, const void *video_src, int width, int height) = 0; + + /** + * Calculate how much memory there is needed for an image of this size in the video-buffer. + * @param width The width of the buffer-to-be. + * @param height The height of the buffer-to-be. + * @return The size needed for the buffer. + */ + virtual int BufferSize(int width, int height) = 0; +}; + +/** + * The factory, keeping track of all renderers. + */ +class RendererFactoryBase { +private: + char *name; + typedef std::map<std::string, RendererFactoryBase *> Renderers; + + static Renderers &GetRenderers() + { + static Renderers &s_renderers = *new Renderers(); + return s_renderers; + } + +protected: + /** + * Register a renderer internally, based on his bpp. + * @param name the name of the renderer. + * @note an assert() will be trigger if 2 renderers with the same bpp try to register. + */ + void RegisterRenderer(const char *name) + { + /* Don't register nameless Renderers */ + if (name == NULL) return; + + this->name = strdup(name); + std::pair<Renderers::iterator, bool> P = GetRenderers().insert(Renderers::value_type(name, this)); + assert(P.second); + } + +public: + RendererFactoryBase() : + name(NULL) + { } + + virtual ~RendererFactoryBase() { if (this->name != NULL) GetRenderers().erase(this->name); free(this->name); } + + /** + * Find the requested renderer and return his class-instance. + * @param name the renderer to select. + */ + static Renderer *SelectRenderer(const char *name) + { + if (GetRenderers().size() == 0) return NULL; + + Renderers::iterator it = GetRenderers().begin(); + for (; it != GetRenderers().end(); it++) { + RendererFactoryBase *r = (*it).second; + if (strcasecmp(name, r->name) == 0) { + return r->CreateInstance(); + } + } + return NULL; + } + + /** + * Create an instance of this Renderer-class. + */ + virtual Renderer *CreateInstance() = 0; +}; + +/** + * A template factory, so ->GetBpp() works correctly. This because else some compiler will complain. + */ +template <class T> +class RendererFactory: public RendererFactoryBase { +public: + RendererFactory() { this->RegisterRenderer(((T *)this)->GetName()); } + + /** + * Get the name for this renderer. + */ + const char *GetName(); +}; + + +#endif /* RENDERER_HPP */ diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 738f28a68..9beac53d5 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -14,6 +14,7 @@ #include "variables.h" #include "date.h" #include "helpers.hpp" +#include "blitter/blitter.hpp" #include "fileio.h" char _screenshot_format_name[8]; @@ -22,7 +23,7 @@ uint _cur_screenshot_format; ScreenshotType current_screenshot_type; /* called by the ScreenShot proc to generate screenshot lines. */ -typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n); +typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n); typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette); struct ScreenshotFormat { @@ -72,10 +73,11 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user FILE *f; uint i, padw; uint n, maxlines; + uint pal_size = 0; + uint bpp = pixelformat / 8; - /* only implemented for 8bit images so far. */ - if (pixelformat != 8) - return false; + /* only implemented for 8bit and 32bit images so far. */ + if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; @@ -83,18 +85,20 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user /* each scanline must be aligned on a 32bit boundary */ padw = ALIGN(w, 4); + if (pixelformat == 8) pal_size = sizeof(RgbQuad) * 256; + /* setup the file header */ bfh.type = TO_LE16('MB'); - bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h); + bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size + padw * h * bpp); bfh.reserved = 0; - bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256); + bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + pal_size); /* setup the info header */ bih.size = TO_LE32(sizeof(BitmapInfoHeader)); bih.width = TO_LE32(w); bih.height = TO_LE32(h); bih.planes = TO_LE16(1); - bih.bitcount = TO_LE16(8); + bih.bitcount = TO_LE16(pixelformat); bih.compression = 0; bih.sizeimage = 0; bih.xpels = 0; @@ -102,24 +106,26 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user bih.clrused = 0; bih.clrimp = 0; - /* convert the palette to the windows format */ - for (i = 0; i != 256; i++) { - rq[i].red = palette[i].r; - rq[i].green = palette[i].g; - rq[i].blue = palette[i].b; - rq[i].reserved = 0; + if (pixelformat == 8) { + /* convert the palette to the windows format */ + for (i = 0; i != 256; i++) { + rq[i].red = palette[i].r; + rq[i].green = palette[i].g; + rq[i].blue = palette[i].b; + rq[i].reserved = 0; + } } /* write file header and info header and palette */ if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false; if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false; - if (fwrite(rq, sizeof(rq), 1, f) != 1) return false; + if (pixelformat == 8) if (fwrite(rq, sizeof(rq), 1, f) != 1) return false; /* use by default 64k temp memory */ maxlines = clamp(65536 / padw, 16, 128); /* now generate the bitmap bits */ - Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time. + void *buff = MallocT<uint8>(padw * maxlines * bpp); // by default generate 128 lines at a time. if (buff == NULL) { fclose(f); return false; @@ -137,7 +143,7 @@ static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *user /* write each line */ while (n) - if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) { + if (fwrite((uint8 *)buff + (--n) * padw * bpp, padw * bpp, 1, f) != 1) { free(buff); fclose(f); return false; @@ -173,12 +179,12 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user FILE *f; uint i, y, n; uint maxlines; + uint bpp = pixelformat / 8; png_structp png_ptr; png_infop info_ptr; - /* only implemented for 8bit images so far. */ - if (pixelformat != 8) - return false; + /* only implemented for 8bit and 32bit images so far. */ + if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; @@ -207,31 +213,53 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user png_set_filter(png_ptr, 0, PNG_FILTER_NONE); - png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE, + png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - /* convert the palette to the .PNG format. */ - for (i = 0; i != 256; i++) { - rq[i].red = palette[i].r; - rq[i].green = palette[i].g; - rq[i].blue = palette[i].b; + if (pixelformat == 8) { + /* convert the palette to the .PNG format. */ + for (i = 0; i != 256; i++) { + rq[i].red = palette[i].r; + rq[i].green = palette[i].g; + rq[i].blue = palette[i].b; + } + + png_set_PLTE(png_ptr, info_ptr, rq, 256); } - png_set_PLTE(png_ptr, info_ptr, rq, 256); png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 512); + if (pixelformat == 32) { + png_color_8 sig_bit; + + /* Save exact color/alpha resolution */ + sig_bit.alpha = 0; + sig_bit.blue = 8; + sig_bit.green = 8; + sig_bit.red = 8; + sig_bit.gray = 8; + png_set_sBIT(png_ptr, info_ptr, &sig_bit); + +#ifdef TTD_LITTLE_ENDIAN + png_set_bgr(png_ptr); + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); +#else + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#endif + } + /* use by default 64k temp memory */ maxlines = clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ - Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. + void *buff = MallocT<uint8>(w * maxlines * bpp); // by default generate 128 lines at a time. if (buff == NULL) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return false; } - memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0 + memset(buff, 0, w * maxlines * bpp); y = 0; do { @@ -244,7 +272,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user /* write them to png */ for (i = 0; i != n; i++) - png_write_row(png_ptr, buff + i * w); + png_write_row(png_ptr, (png_bytep)buff + i * w * bpp); } while (y != h); png_write_end(png_ptr, info_ptr); @@ -288,6 +316,10 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user PcxHeader pcx; bool success; + if (pixelformat == 32) { + DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick an other format."); + return false; + } if (pixelformat != 8 || w == 0) return false; @@ -321,7 +353,7 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user maxlines = clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ - Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. + uint8 *buff = MallocT<uint8>(w * maxlines); // by default generate 128 lines at a time. if (buff == NULL) { fclose(f); return false; @@ -340,14 +372,14 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user /* write them to pcx */ for (i = 0; i != n; i++) { - const Pixel* bufp = buff + i * w; + const uint8 *bufp = buff + i * w; byte runchar = bufp[0]; uint runcount = 1; uint j; /* for each pixel... */ for (j = 1; j < w; j++) { - Pixel ch = bufp[j]; + uint8 ch = bufp[j]; if (ch != runchar || runcount >= 0x3f) { if (runcount > 1 || (runchar & 0xC0) == 0xC0) @@ -447,17 +479,14 @@ void SetScreenshotFormat(int i) } /* screenshot generator that dumps the current video buffer */ -static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) +static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n) { - for (; n > 0; --n) { - memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width * sizeof(Pixel)); - ++y; - buf += pitch; - } + void *src = _screen.renderer->MoveTo(_screen.dst_ptr, 0, y); + _screen.renderer->CopyToBuffer(src, buf, _screen.width, n, pitch); } /* generate a large piece of the world */ -static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) +static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n) { ViewPort *vp = (ViewPort *)userdata; DrawPixelInfo dpi, *old_dpi; @@ -534,7 +563,7 @@ bool IsScreenshotRequested() static bool MakeSmallScreenshot() { const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; - return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, 8, _cur_palette); + return sf->proc(MakeScreenshotName(sf->extension), CurrentScreenCallback, NULL, _screen.width, _screen.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette); } static bool MakeWorldScreenshot() @@ -553,7 +582,7 @@ static bool MakeWorldScreenshot() vp.height = vp.virtual_height; sf = _screenshot_formats + _cur_screenshot_format; - return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, 8, _cur_palette); + return sf->proc(MakeScreenshotName(sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(), _cur_palette); } bool MakeScreenshot() diff --git a/src/settings.cpp b/src/settings.cpp index aa1fbc6d1..4363eec52 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1225,14 +1225,13 @@ static const SettingDesc _music_settings[] = { /* win32_v.c only settings */ #ifdef WIN32 -extern bool _force_full_redraw, _double_size, _window_maximize; +extern bool _force_full_redraw, _window_maximize; extern uint _display_hz, _fullscreen_bpp; static const SettingDescGlobVarList _win32_settings[] = { SDTG_VAR("display_hz", SLE_UINT, S, 0, _display_hz, 0, 0, 120, 0, STR_NULL, NULL), SDTG_BOOL("force_full_redraw", S, 0, _force_full_redraw,false, STR_NULL, NULL), SDTG_VAR("fullscreen_bpp", SLE_UINT, S, 0, _fullscreen_bpp, 8, 8, 32, 0, STR_NULL, NULL), - SDTG_BOOL("double_size", S, 0, _double_size, false, STR_NULL, NULL), SDTG_BOOL("window_maximize", S, 0, _window_maximize, false, STR_NULL, NULL), SDTG_END() }; diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 0c10e7fc5..25b6e1468 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -167,41 +167,23 @@ static const LegendAndColour * const _legend_table[] = { _legend_land_owners, }; -#if defined(OTTD_ALIGNMENT) - static inline void WRITE_PIXELS(Pixel* d, uint32 val) - { -# if defined(TTD_BIG_ENDIAN) - d[0] = GB(val, 24, 8); - d[1] = GB(val, 16, 8); - d[2] = GB(val, 8, 8); - d[3] = GB(val, 0, 8); -# elif defined(TTD_LITTLE_ENDIAN) - d[0] = GB(val, 0, 8); - d[1] = GB(val, 8, 8); - d[2] = GB(val, 16, 8); - d[3] = GB(val, 24, 8); -# endif - } +static inline void WRITE_PIXELS(void *d, uint32 val) +{ + uint8 *val8 = (uint8 *)&val; + _screen.renderer->SetPixel(d, 0, 0, val8[0]); + _screen.renderer->SetPixel(d, 1, 0, val8[1]); + _screen.renderer->SetPixel(d, 2, 0, val8[2]); + _screen.renderer->SetPixel(d, 3, 0, val8[3]); +} -/* need to use OR, otherwise we will overwrite the wrong pixels at the edges :( */ - static inline void WRITE_PIXELS_OR(Pixel *d, uint32 val) - { -# if defined(TTD_BIG_ENDIAN) - d[0] |= GB(val, 24, 8); - d[1] |= GB(val, 16, 8); - d[2] |= GB(val, 8, 8); - d[3] |= GB(val, 0, 8); -# elif defined(TTD_LITTLE_ENDIAN) - d[0] |= GB(val, 0, 8); - d[1] |= GB(val, 8, 8); - d[2] |= GB(val, 16, 8); - d[3] |= GB(val, 24, 8); -# endif - } -#else -# define WRITE_PIXELS(dst, val) *(uint32*)(dst) = (val); -# define WRITE_PIXELS_OR(dst,val) *(uint32*)(dst) |= (val); -#endif +static inline void WRITE_PIXELS_OR(void *d, uint32 val) +{ + uint8 *val8 = (uint8 *)&val; + _screen.renderer->SetPixelIfEmpty(d, 0, 0, val8[0]); + _screen.renderer->SetPixelIfEmpty(d, 1, 0, val8[1]); + _screen.renderer->SetPixelIfEmpty(d, 2, 0, val8[2]); + _screen.renderer->SetPixelIfEmpty(d, 3, 0, val8[3]); +} #define MKCOLOR(x) TO_LE32X(x) @@ -296,9 +278,9 @@ typedef uint32 GetSmallMapPixels(TileIndex tile); // typedef callthrough functio * @param proc Pointer to the colour function * @see GetSmallMapPixels(TileIndex) */ -static void DrawSmallMapStuff(Pixel *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc) +static void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, GetSmallMapPixels *proc) { - Pixel *dst_ptr_end = _screen.dst_ptr + _screen.width * _screen.height - _screen.width; + void *dst_ptr_end = _screen.renderer->MoveTo(_screen.dst_ptr, _screen.width, _screen.height - 1); do { /* check if the tile (xc,yc) is within the map range */ @@ -308,7 +290,7 @@ static void DrawSmallMapStuff(Pixel *dst, uint xc, uint yc, int pitch, int reps, WRITE_PIXELS_OR(dst, proc(TileXY(xc, yc)) & mask); } /* switch to next tile in the column */ - } while (xc++, yc++, dst += pitch, --reps != 0); + } while (xc++, yc++, dst = _screen.renderer->MoveTo(dst, pitch, 0), --reps != 0); } @@ -530,7 +512,7 @@ static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_town { DrawPixelInfo *old_dpi; int dx,dy, x, y, x2, y2; - Pixel *ptr; + void *ptr; int tile_x; int tile_y; ViewPort *vp; @@ -582,7 +564,7 @@ static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_town } } - ptr = dpi->dst_ptr - dx - 4; + ptr = _screen.renderer->MoveTo(dpi->dst_ptr, -dx - 4, 0); x = - dx - 4; y = 0; @@ -609,7 +591,6 @@ static void DrawSmallMap(DrawPixelInfo *dpi, Window *w, int type, bool show_town /* number of lines */ reps = (dpi->height - y + 1) / 2; if (reps > 0) { -// assert(ptr >= dpi->dst_ptr); DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, _smallmap_draw_procs[type]); } @@ -617,13 +598,13 @@ skip_column: if (y == 0) { tile_y++; y++; - ptr += dpi->pitch; + ptr = _screen.renderer->MoveTo(ptr, 0, 1); } else { tile_x--; y--; - ptr -= dpi->pitch; + ptr = _screen.renderer->MoveTo(ptr, 0, -1); } - ptr += 2; + ptr = _screen.renderer->MoveTo(ptr, 2, 0); x += 2; } @@ -666,12 +647,11 @@ skip_column: } /* Calculate pointer to pixel and the color */ - ptr = dpi->dst_ptr + y * dpi->pitch + x; color = (type == 1) ? _vehicle_type_colors[v->type] : 0xF; /* And draw either one or two pixels depending on clipping */ - ptr[0] = color; - if (!skip) ptr[1] = color; + _screen.renderer->SetPixel(dpi->dst_ptr, x, y, color); + if (!skip) _screen.renderer->SetPixel(dpi->dst_ptr, x + 1, y, color);; } } } diff --git a/src/texteff.cpp b/src/texteff.cpp index ad94b1d6f..dd73f509d 100644 --- a/src/texteff.cpp +++ b/src/texteff.cpp @@ -54,9 +54,7 @@ static bool _textmessage_visible = false; /* The chatbox grows from the bottom so the coordinates are pixels from * the left and pixels from the bottom. The height is the maximum height */ static const Oblong _textmsg_box = {10, 30, 500, 150}; -static Pixel _textmessage_backup[150 * 500]; // (height * width) - -extern void memcpy_pitch(void *dst, void *src, int w, int h, int srcpitch, int dstpitch); +static uint8 _textmessage_backup[150 * 500 * 4]; // (height * width) static inline uint GetTextMessageCount() { @@ -163,11 +161,7 @@ void UndrawTextMessage() _textmessage_visible = false; /* Put our 'shot' back to the screen */ - memcpy_pitch( - _screen.dst_ptr + x + y * _screen.pitch, - _textmessage_backup, - width, height, _textmsg_box.width, _screen.pitch); - + _screen.renderer->CopyFromBuffer(_screen.renderer->MoveTo(_screen.dst_ptr, x, y), _textmessage_backup, width, height, _textmsg_box.width); /* And make sure it is updated next time */ _video_driver->make_dirty(x, y, width, height); @@ -227,10 +221,7 @@ void DrawTextMessage() if (width <= 0 || height <= 0) return; /* Make a copy of the screen as it is before painting (for undraw) */ - memcpy_pitch( - _textmessage_backup, - _screen.dst_ptr + x + y * _screen.pitch, - width, height, _screen.pitch, _textmsg_box.width); + _screen.renderer->CopyToBuffer(_screen.renderer->MoveTo(_screen.dst_ptr, x, y), _textmessage_backup, width, height, _textmsg_box.width); _cur_dpi = &_screen; // switch to _screen painting diff --git a/src/video/cocoa_v.mm b/src/video/cocoa_v.mm index b8193e902..7c563d281 100644 --- a/src/video/cocoa_v.mm +++ b/src/video/cocoa_v.mm @@ -69,6 +69,7 @@ extern "C" void HideMenuBar(); #include "../macros.h" #include "../os/macosx/splash.h" #include "../variables.h" +#include "../blitter/blitter.hpp" #include "cocoa_v.h" #include "cocoa_keys.h" @@ -950,6 +951,10 @@ static void QZ_SetPortAlphaOpaque() static void QZ_UpdateWindowPalette(uint start, uint count) { + /* We can only update the palette in 8bpp for now */ + /* TODO -- We need support for other bpps too! */ + if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 8) return; + uint i; switch (_cocoa_video_data.device_bpp) { diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index 046dc2ac8..4aa6b9f20 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -13,6 +13,7 @@ #include "../console.h" #include "../variables.h" #include "../genworld.h" +#include "../blitter/blitter.hpp" #include "dedicated_v.h" #ifdef BEOS_NET_SERVER @@ -112,7 +113,7 @@ static void CloseWindowsConsoleThread() #endif -static Pixel *_dedicated_video_mem; +static void *_dedicated_video_mem; extern bool SafeSaveOrLoad(const char *filename, int mode, int newgm); extern void SwitchMode(int new_mode); @@ -120,9 +121,14 @@ extern void SwitchMode(int new_mode); static const char *DedicatedVideoStart(const char * const *parm) { + int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); + if (bpp == 0) _dedicated_video_mem = NULL; + else _dedicated_video_mem = malloc(_cur_resolution[0] * _cur_resolution[1] * (bpp / 8)); + _screen.width = _screen.pitch = _cur_resolution[0]; _screen.height = _cur_resolution[1]; - _dedicated_video_mem = (Pixel *)malloc(_cur_resolution[0] * _cur_resolution[1] * sizeof(Pixel)); + _screen.renderer = RendererFactoryBase::SelectRenderer(BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); + if (_screen.renderer == NULL) error("Couldn't load the renderer '%s' the selected blitter depends on", BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); SetDebugString("net=6"); diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp index fd15954d9..0c1f4715e 100644 --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -5,19 +5,23 @@ #include "../gfx.h" #include "../variables.h" #include "../window.h" +#include "../debug.h" +#include "../blitter/blitter.hpp" #include "null_v.h" -static Pixel *_null_video_mem = NULL; - static const char* NullVideoStart(const char* const* parm) { _screen.width = _screen.pitch = _cur_resolution[0]; _screen.height = _cur_resolution[1]; - _null_video_mem = (Pixel *)malloc(_cur_resolution[0] * _cur_resolution[1] * sizeof(Pixel)); + /* Do not render, nor blit */ + DEBUG(misc, 1, "Forcing blitter 'null'..."); + BlitterFactoryBase::SelectBlitter("null"); + _screen.renderer = RendererFactoryBase::SelectRenderer(BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); + if (_screen.renderer == NULL) error("Couldn't load the renderer '%s' the selected blitter depends on", BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); return NULL; } -static void NullVideoStop() { free(_null_video_mem); } +static void NullVideoStop() { } static void NullVideoMakeDirty(int left, int top, int width, int height) {} @@ -27,7 +31,7 @@ static void NullVideoMainLoop() for (i = 0; i < 1000; i++) { GameLoop(); - _screen.dst_ptr = _null_video_mem; + _screen.dst_ptr = NULL; UpdateWindows(); } } diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 9a70b55a6..8b851e2d6 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -13,6 +13,8 @@ #include "../window.h" #include "../network/network.h" #include "../variables.h" +#include "../blitter/blitter.hpp" +#include "../renderer/renderer.hpp" #include "sdl_v.h" #include <SDL.h> @@ -36,6 +38,10 @@ static void SdlVideoMakeDirty(int left, int top, int width, int height) static void UpdatePalette(uint start, uint count) { + /* We can only update the palette in 8bpp for now */ + /* TODO -- We need support for other bpps too! */ + if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 8) return; + SDL_Color pal[256]; uint i; @@ -172,10 +178,13 @@ static bool CreateMainSurface(int w, int h) extern const char _openttd_revision[]; SDL_Surface *newscreen, *icon; char caption[50]; + int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); GetAvailableVideoMode(&w, &h); - DEBUG(driver, 1, "SDL: using mode %dx%d", w, h); + DEBUG(driver, 1, "SDL: using mode %dx%dx%d", w, h, bpp); + + if (bpp == 0) error("Can't use a blitter that blits 0 bpp for normal visuals"); /* Give the application an icon */ icon = SDL_CALL SDL_LoadBMP(ICON_DIR PATHSEP "openttd.32.bmp"); @@ -189,14 +198,15 @@ static bool CreateMainSurface(int w, int h) } // DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK - newscreen = SDL_CALL SDL_SetVideoMode(w, h, 8, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); + newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | SDL_HWPALETTE | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); if (newscreen == NULL) return false; _screen.width = newscreen->w; _screen.height = newscreen->h; - _screen.pitch = newscreen->pitch / sizeof(Pixel); - + _screen.pitch = newscreen->pitch / (bpp / 8); + _screen.renderer = RendererFactoryBase::SelectRenderer(BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); + if (_screen.renderer == NULL) error("Couldn't load the renderer '%s' the selected blitter depends on", BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); _sdl_screen = newscreen; InitPalette(); @@ -469,7 +479,7 @@ static void SdlVideoMainLoop() (keys[SDLK_DOWN] ? 8 : 0); GameLoop(); - _screen.dst_ptr = (Pixel*)_sdl_screen->pixels; + _screen.dst_ptr = _sdl_screen->pixels; UpdateWindows(); if (++pal_tick > 4) { CheckPaletteAnim(); @@ -478,7 +488,7 @@ static void SdlVideoMainLoop() DrawSurfaceToScreen(); } else { SDL_CALL SDL_Delay(1); - _screen.dst_ptr = (Pixel*)_sdl_screen->pixels; + _screen.dst_ptr = _sdl_screen->pixels; DrawTextMessage(); DrawMouseCursor(); DrawSurfaceToScreen(); diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index cee533c7c..9e14290d3 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -9,6 +9,7 @@ #include "../variables.h" #include "../win32.h" #include "../window.h" +#include "../blitter/blitter.hpp" #include "win32_v.h" #include <windows.h> #include <tchar.h> @@ -16,22 +17,18 @@ static struct { HWND main_wnd; HBITMAP dib_sect; - Pixel *bitmap_bits; - Pixel *buffer_bits; - Pixel *alloced_bits; + void *buffer_bits; HPALETTE gdi_palette; int width; int height; int width_org; int height_org; bool fullscreen; - bool double_size; bool has_focus; bool running; } _wnd; bool _force_full_redraw; -bool _double_size; bool _window_maximize; uint _display_hz; uint _fullscreen_bpp; @@ -63,6 +60,10 @@ static void MakePalette() static void UpdatePalette(HDC dc, uint start, uint count) { + /* We can only update the palette in 8bpp for now */ + /* TODO -- We need support for other bpps too! */ + if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() != 8) return; + RGBQUAD rgb[256]; uint i; @@ -136,11 +137,6 @@ static bool AllocateDibSection(int w, int h); static void ClientSizeChanged(int w, int h) { - if (_wnd.double_size) { - w /= 2; - h /= 2; - } - // allocate new dib section of the new size if (AllocateDibSection(w, h)) { // mark all palette colors dirty @@ -319,11 +315,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP DrawMouseCursor(); } - if (_wnd.double_size) { - x /= 2; - y /= 2; - } - if (_cursor.fix_at) { int dx = x - _cursor.pos.x; int dy = y - _cursor.pos.y; @@ -334,10 +325,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP pt.x = _cursor.pos.x; pt.y = _cursor.pos.y; - if (_wnd.double_size) { - pt.x *= 2; - pt.y *= 2; - } ClientToScreen(hwnd, &pt); SetCursorPos(pt.x, pt.y); } @@ -400,13 +387,6 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP * WM_KEYDOWN only handles CTRL+ commands and special keys like VK_LEFT, etc. */ if (keycode == 0 || (keycode > WKC_PAUSE && GB(keycode, 13, 4) == 0)) return 0; - if (keycode == ('D' | WKC_CTRL) && !_wnd.fullscreen) { - _double_size ^= 1; - _wnd.double_size = _double_size; - ClientSizeChanged(_wnd.width, _wnd.height); - MarkWholeScreenDirty(); - } - HandleKeypress(0 | (keycode << 16)); return 0; } @@ -455,16 +435,8 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP w = r->right - r->left - (r2.right - r2.left); h = r->bottom - r->top - (r2.bottom - r2.top); - if (_wnd.double_size) { - w /= 2; - h /= 2; - } w = clamp(w, 64, MAX_SCREEN_WIDTH); h = clamp(h, 64, MAX_SCREEN_HEIGHT); - if (_wnd.double_size) { - w *= 2; - h *= 2; - } SetRect(&r2, 0, 0, w, h); AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); @@ -567,8 +539,6 @@ static void MakeWindow(bool full_screen) { _fullscreen = full_screen; - _wnd.double_size = _double_size && !full_screen; - // recreate window? if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) { DestroyWindow(_wnd.main_wnd); @@ -581,6 +551,9 @@ static void MakeWindow(bool full_screen) if (full_screen) { DEVMODE settings; + /* Make sure we are always at least the screen-depth of the blitter */ + if (_fullscreen_bpp < BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth()) _fullscreen_bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); + memset(&settings, 0, sizeof(settings)); settings.dmSize = sizeof(settings); settings.dmFields = @@ -649,49 +622,39 @@ static bool AllocateDibSection(int w, int h) { BITMAPINFO *bi; HDC dc; + int bpp = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); w = clamp(w, 64, MAX_SCREEN_WIDTH); h = clamp(h, 64, MAX_SCREEN_HEIGHT); + if (bpp == 0) error("Can't use a blitter that blits 0 bpp for normal visuals"); + if (w == _screen.width && h == _screen.height) return false; _screen.width = w; _screen.pitch = ALIGN(w, 4); _screen.height = h; - - if (_wnd.alloced_bits) { - free(_wnd.alloced_bits); - _wnd.alloced_bits = NULL; - } - + _screen.renderer = RendererFactoryBase::SelectRenderer(BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); + if (_screen.renderer == NULL) error("Couldn't load the renderer '%s' the selected blitter depends on", BlitterFactoryBase::GetCurrentBlitter()->GetRenderer()); bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - if (_wnd.double_size) { - w = ALIGN(w, 4); - _wnd.alloced_bits = _wnd.buffer_bits = (Pixel *)malloc(w * h * sizeof(Pixel)); - w *= 2; - h *= 2; - } - bi->bmiHeader.biWidth = _wnd.width = w; bi->bmiHeader.biHeight = -(_wnd.height = h); bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = 8; + bi->bmiHeader.biBitCount = BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth(); bi->bmiHeader.biCompression = BI_RGB; if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect); dc = GetDC(0); - _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.bitmap_bits, NULL, 0); + _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, NULL, 0); if (_wnd.dib_sect == NULL) error("CreateDIBSection failed"); ReleaseDC(0, dc); - if (!_wnd.double_size) _wnd.buffer_bits = _wnd.bitmap_bits; - return true; } @@ -723,7 +686,7 @@ static void FindResolutions() * Doesn't really matter since we don't pass a string anyways, but still * a letdown */ for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) { - if (dm.dmBitsPerPel == 8 && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) && + if (dm.dmBitsPerPel == BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() && IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) && IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1)) { uint j; @@ -786,43 +749,13 @@ static void Win32GdiStop() #if !defined(WINCE) if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); #endif - if (_wnd.double_size) { - _cur_resolution[0] *= 2; - _cur_resolution[1] *= 2; - } - MyShowCursor(true); } -// simple upscaler by 2 -static void filter(int left, int top, int width, int height) -{ - uint p = _screen.pitch; - const Pixel *s = _wnd.buffer_bits + top * p + left; - Pixel *d = _wnd.bitmap_bits + top * p * 4 + left * 2; - - for (; height > 0; height--) { - int i; - - for (i = 0; i != width; i++) { - d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i]; - } - s += p; - d += p * 4; - } -} - static void Win32GdiMakeDirty(int left, int top, int width, int height) { RECT r = { left, top, left + width, top + height }; - if (_wnd.double_size) { - filter(left, top, width, height); - r.left *= 2; - r.top *= 2; - r.right *= 2; - r.bottom *= 2; - } InvalidateRect(_wnd.main_wnd, &r, FALSE); } diff --git a/src/viewport.cpp b/src/viewport.cpp index 085f74c97..e23c69622 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1269,7 +1269,7 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom x = UnScaleByZoom(vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left; y = UnScaleByZoom(vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top; - vd.dpi.dst_ptr = old_dpi->dst_ptr + x - old_dpi->left + (y - old_dpi->top) * old_dpi->pitch; + vd.dpi.dst_ptr = _screen.renderer->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top); vd.parent_list = parent_list; vd.eof_parent_list = endof(parent_list); diff --git a/src/window.cpp b/src/window.cpp index f4309971a..bdc8a75f5 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -270,7 +270,7 @@ static void DrawOverlappedWindow(Window* const *wz, int left, int top, int right dp->left = left - (*wz)->left; dp->top = top - (*wz)->top; dp->pitch = _screen.pitch; - dp->dst_ptr = _screen.dst_ptr + top * _screen.pitch + left; + dp->dst_ptr = _screen.renderer->MoveTo(_screen.dst_ptr, left, top); dp->zoom = ZOOM_LVL_NORMAL; CallWindowEventNP(*wz, WE_PAINT); } |