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 }