1 /* 2 * Copyright (C) 2015-2017, by Laszlo Szeremi under the Boost license. 3 * 4 * Pixel Perfect Engine, graphics.bitmap module 5 */ 6 module PixelPerfectEngine.graphics.raster; 7 8 import PixelPerfectEngine.graphics.outputScreen; 9 import PixelPerfectEngine.graphics.layers; 10 import PixelPerfectEngine.graphics.bitmap; 11 import bindbc.sdl; 12 public import PixelPerfectEngine.graphics.common; 13 import std.conv; 14 import std.algorithm.sorting; 15 import std.algorithm.mutation; 16 import core.time; 17 18 ///The raster calls it every time it finishes the drawing to the framebuffers. 19 public interface RefreshListener{ 20 public void refreshFinished(); 21 } 22 23 ///Used to read the output from the raster and show it on the screen. 24 public interface IRaster{ 25 public SDL_Texture* getOutput(); 26 } 27 28 ///Handles multiple layers onto one framebuffer. 29 public class Raster : IRaster{ 30 private ushort rX, rY; ///Stores screen resolution. Set overscan resolutions at OutputWindow 31 //public SDL_Surface* workpad; 32 public SDL_Texture*[] frameBuffer; 33 public void*[] fbData; 34 public int[] fbPitch; 35 /** 36 * Color format is ARGB, with each index having their own transparency. 37 */ 38 public Color[] palette; 39 private Layer[int] layerList; ///Stores the layers by their priorities. 40 private int[] layerPriorityHandler, threads; 41 private bool r; 42 private int[2] doubleBufferRegisters; 43 private RefreshListener[] rL; 44 private MonoTime frameTime, frameTime_1; 45 private Duration delta_frameTime; 46 private real framesPerSecond, avgFPS; 47 //public Bitmap16Bit[2] frameBuffer; 48 49 ///Default constructor. x and y : represent the resolution of the raster. 50 public this(ushort x, ushort y, OutputScreen oW, size_t paletteLength = 65536){ 51 //workpad = SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 52 //this.threads = threads; 53 assert(paletteLength <= 65536); 54 SDL_Renderer* renderer = oW.renderer; 55 rX=x; 56 rY=y; 57 /*frameBuffer[0] = new Bitmap16Bit(x,y); 58 frameBuffer[1] = new Bitmap16Bit(x,y);*/ 59 /*frameBuffer ~= SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 60 frameBuffer ~= SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);*/ 61 frameBuffer ~= SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRX8888, SDL_TEXTUREACCESS_STREAMING, x, y); 62 frameBuffer ~= SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRX8888, SDL_TEXTUREACCESS_STREAMING, x, y); 63 fbData ~= null; 64 fbData ~= null; 65 fbPitch ~= 0; 66 fbPitch ~= 0; 67 doubleBufferRegisters[0] = 1; 68 doubleBufferRegisters[1] = 0; 69 oW.setMainRaster(this); 70 addRefreshListener(oW); 71 } 72 /** 73 * Returns the current FPS count. 74 */ 75 public @nogc @property real fps(){ 76 return framesPerSecond; 77 } 78 /** 79 * Returns the current average FPS count. 80 */ 81 public @nogc @property real avgfps(){ 82 return avgFPS; 83 } 84 /** 85 * Resets the avgFPS to zero. 86 */ 87 public @nogc void resetAvgfps(){ 88 avgFPS = 0; 89 } 90 ~this(){ 91 foreach(SDL_Texture* t ; frameBuffer){ 92 if(t) 93 SDL_DestroyTexture(t); 94 } 95 } 96 ///Adds a RefreshListener to its list. 97 public void addRefreshListener(RefreshListener r){ 98 rL ~= r; 99 } 100 ///Edits the given color index. 101 public void editColor(ushort c, Color val){ 102 palette[c] = val; 103 } 104 ///Sets the number of colors. 105 public void setupPalette(int i){ 106 palette.length = i; 107 } 108 ///Replaces the layer at the given number. 109 public void replaceLayer(Layer l, int i){ 110 l.setRasterizer(rX, rY); 111 layerList[i] = l; 112 } 113 ///Adds a layer at the given priority. 114 public void addLayer(Layer l, int i){ 115 l.setRasterizer(rX, rY); 116 layerList[i] = l; 117 layerPriorityHandler ~= i; 118 layerPriorityHandler.sort(); 119 } 120 ///Removes a layer at the given priority. 121 public void removeLayer(int n){ 122 layerList.remove(n); 123 int[] newlayerPriorityHandler; 124 for(int i; i < layerPriorityHandler.length; i++){ 125 //writeln(0); 126 if(layerPriorityHandler[i] != n){ 127 newlayerPriorityHandler ~= layerPriorityHandler[i]; 128 129 } 130 } 131 layerPriorityHandler = newlayerPriorityHandler; 132 } 133 /** 134 * Refreshes the whole framebuffer. 135 */ 136 public void refresh(){ 137 138 r = true; 139 //this.clearFramebuffer(); 140 if(doubleBufferRegisters[0] == 0){ 141 doubleBufferRegisters[0] = 1; 142 doubleBufferRegisters[1] = 0; 143 }else{ 144 doubleBufferRegisters[0] = 0; 145 doubleBufferRegisters[1] = 1; 146 } 147 148 SDL_LockTexture(frameBuffer[doubleBufferRegisters[0]], null, &fbData[doubleBufferRegisters[0]], &fbPitch[doubleBufferRegisters[0]]); 149 150 for(int i ; i < layerPriorityHandler.length ; i++){ 151 layerList[layerPriorityHandler[i]].updateRaster(fbData[doubleBufferRegisters[0]], fbPitch[doubleBufferRegisters[0]], palette.ptr); 152 } 153 154 SDL_UnlockTexture(frameBuffer[doubleBufferRegisters[0]]); 155 r = false; 156 157 foreach(r; rL){ 158 r.refreshFinished; 159 } 160 //get frame duration 161 frameTime_1 = frameTime; 162 frameTime = MonoTimeImpl!(ClockType.normal).currTime(); 163 delta_frameTime = frameTime_1 - frameTime; 164 real delta_frameTime0 = to!real(delta_frameTime.total!"hnsecs"()); 165 framesPerSecond = framesPerSecond + 1 / (delta_frameTime0 / 10000); 166 if(avgFPS) 167 avgFPS = (avgFPS + framesPerSecond) / 2; 168 else 169 avgFPS = framesPerSecond; 170 } 171 172 173 ///Returns the workpad. 174 public SDL_Texture* getOutput(){ 175 if(fbData[0] !is null) 176 return frameBuffer[0]; 177 return frameBuffer[1]; 178 } 179 180 181 ///Returns if the raster is refreshing. 182 public bool isRefreshing(){ 183 return r; 184 } 185 }