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 derelict.sdl2.sdl; 12 //public import graphics.color; 13 import std.conv; 14 import std.stdio; 15 16 //Used to invoke the blitting when the raster finished its work. 17 public interface RefreshListener{ 18 public void refreshFinished(); 19 } 20 21 //Used to read the output from the raster and show it on the screen. 22 public interface IRaster{ 23 public SDL_Texture* getOutput(); 24 } 25 26 ///Handles multiple layers onto one framebuffer. 27 public class Raster : IRaster{ 28 private ushort rX, rY; 29 //public SDL_Surface* workpad; 30 public SDL_Texture*[] frameBuffer; 31 public void*[] fbData; 32 public int[] fbPitch; 33 //IMPORTANT: Color 0 is used as a default and writes it to the raster if it can't find a layer with non-transparent pixel at a given position 34 //public Color[ushort] palette; 35 //private ubyte[ushort] colorR; 36 //private ubyte[ushort] colorG; 37 //private ubyte[ushort] colorB; 38 public ubyte[] palette; //FORMAT ARGB 39 private Layer[] layerList; 40 private bool r; 41 private int[2] doubleBufferRegisters; 42 private RefreshListener[] rL; 43 //public Bitmap16Bit[2] frameBuffer; 44 45 //Default constructor. x and y : represent the resolution of the raster. 46 public this(ushort x, ushort y, OutputScreen oW){ 47 //workpad = SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 48 SDL_Renderer* renderer = oW.renderer; 49 rX=x; 50 rY=y; 51 /*frameBuffer[0] = new Bitmap16Bit(x,y); 52 frameBuffer[1] = new Bitmap16Bit(x,y);*/ 53 /*frameBuffer ~= SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); 54 frameBuffer ~= SDL_CreateRGBSurface(SDL_SWSURFACE, x, y, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);*/ 55 frameBuffer ~= SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRX8888, SDL_TEXTUREACCESS_STREAMING, x, y); 56 frameBuffer ~= SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRX8888, SDL_TEXTUREACCESS_STREAMING, x, y); 57 fbData ~= null; 58 fbData ~= null; 59 fbPitch ~= 0; 60 fbPitch ~= 0; 61 doubleBufferRegisters[0] = 1; 62 doubleBufferRegisters[1] = 0; 63 oW.setMainRaster(this); 64 addRefreshListener(oW); 65 } 66 67 ~this(){ 68 foreach(SDL_Texture* t ; frameBuffer){ 69 SDL_DestroyTexture(t); 70 } 71 } 72 //Adds a RefreshListener to its list. 73 public void addRefreshListener(RefreshListener r){ 74 rL ~= r; 75 } 76 //Writes a color at the last position 77 public void addColor(ubyte r, ubyte g, ubyte b, ubyte a = 255) { 78 /*colorR[c] = r; 79 colorG[c] = g; 80 colorB[c] = b;*/ 81 82 palette ~= a; 83 palette ~= r; 84 palette ~= g; 85 palette ~= b; 86 //palette[c][3] = [r,g,b]; 87 } 88 89 public void editColor(ushort c, ubyte r, ubyte g, ubyte b, ubyte a = 255){ 90 palette[c*3] = a; 91 palette[(c*3)+1] = r; 92 palette[(c*3)+2] = g; 93 palette[(c*3)+3] = b; 94 } 95 //Sets the number of colors. 96 public void setupPalette(int i){ 97 palette.length = i * 3; 98 } 99 100 /*public void clearFramebuffer(){ 101 frameBuffer.destroy(); 102 }*/ 103 //Replaces the layer at the given number. 104 public void replaceLayer(Layer l, int i){ 105 l.setRasterizer(rX, rY); 106 layerList[i] = l; 107 } 108 //Adds a layer at the highest available priority. 0 is highest. 109 public void addLayer(Layer l){ 110 l.setRasterizer(rX, rY); 111 layerList ~= l; 112 } 113 114 public void refresh(){ 115 116 r = true; 117 //this.clearFramebuffer(); 118 if(doubleBufferRegisters[0] == 0){ 119 doubleBufferRegisters[0] = 1; 120 doubleBufferRegisters[1] = 0; 121 }else{ 122 doubleBufferRegisters[0] = 0; 123 doubleBufferRegisters[1] = 1; 124 } 125 //SDL_LockSurface(frameBuffer[doubleBufferRegisters[0]]); 126 127 SDL_LockTexture(frameBuffer[doubleBufferRegisters[0]], null, &fbData[doubleBufferRegisters[0]], &fbPitch[doubleBufferRegisters[0]]); 128 //SDL_SetSurfaceRLE(frameBuffer[doubleBufferRegisters[0]], 1); 129 130 for(int i ; i < layerList.length ; i++){ 131 layerList[i].updateRaster(fbData[doubleBufferRegisters[0]], fbPitch[doubleBufferRegisters[0]], palette, null); 132 } 133 134 //writeToWorkpad(frameBuffer[doubleBufferRegisters[1]]); 135 136 137 //frameBuffer[doubleBufferRegisters[1]] = frameBuffer[doubleBufferRegisters[0]]; 138 139 //SDL_SetSurfaceRLE(frameBuffer[doubleBufferRegisters[0]], 0); 140 //SDL_UnlockSurface(frameBuffer[doubleBufferRegisters[0]]); 141 SDL_UnlockTexture(frameBuffer[doubleBufferRegisters[0]]); 142 r = false; 143 144 foreach(r; rL){ 145 r.refreshFinished; 146 } 147 //frameBuffer.clear(); 148 } 149 150 /*public void getPixel(ushort i, ushort j){ 151 int layerNum = 0; 152 bool next; 153 do{ 154 155 if(layerNum == layerList.length){ 156 writeToWorkpad(i,j,0); 157 next = true; 158 } 159 else{ 160 PixelData pd = layerList[layerNum].getPixelData(i,j); 161 162 if(!pd.alpha){ 163 //writeln(0); 164 writeToWorkpad(i,j,pd.color); 165 next = true; 166 } 167 else{ 168 layerNum++; 169 } 170 } 171 }while(!next); 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 //Writes a pixel to the given place. 180 181 //Returns if the raster is refreshing. 182 public bool isRefreshing(){ 183 return r; 184 } 185 }