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 }