1 module caLib.renderers.TwoDimBasicRenderer; 2 3 import caLib_abstract.lattice : isBoundedLattice, isAnyBoundedLattice; 4 import caLib_abstract.palette : isColorPalette, isAnyColorPalette; 5 import std.exception : enforce; 6 import std.algorithm : canFind; 7 import std.algorithm.comparison : max; 8 import std.traits : CommonType; 9 import caLib_util.image : Image; 10 import caLib_util.video : Video; 11 import caLib_util.structs : Rect, Color; 12 import caLib_util.graphics; 13 14 public import caLib_util.graphics : Window; 15 16 17 18 template create_TwoDimBasicRenderer(Ct, Lt, Pt) 19 if(isBoundedLattice!(Lt, Ct, 2) && isColorPalette!(Pt, Ct)) 20 { 21 TwoDimBasicRenderer!(Ct, Lt, Pt)* 22 create_TwoDimBasicRenderer(Lt* lattice, Pt* palette, Window window) 23 { 24 return new TwoDimBasicRenderer!(Ct, Lt, Pt)(lattice, palette, window); 25 } 26 } 27 28 29 30 31 auto create_TwoDimBasicRenderer(Lt, Pt)(Lt* lattice, Pt* palette, Window window) 32 if(isAnyBoundedLattice!Lt && isAnyColorPalette!Pt && Lt.Dimension == 2) 33 { 34 alias Ct = CommonType!(Lt.CellStateType, Pt.CellStateType); 35 static assert(!is(Ct == void)); 36 37 return new TwoDimBasicRenderer!(Ct, Lt, Pt)(lattice, palette, window); 38 } 39 40 41 42 struct TwoDimBasicRenderer(Ct, Lt, Pt) 43 if(isColorPalette!(Pt, Ct) && isBoundedLattice!(Lt, Ct, 2)) 44 { 45 46 private: 47 48 Lt* lattice; 49 50 Pt* palette; 51 52 Window window; 53 Texture texture; 54 immutable SDL_Rect sRect; 55 immutable SDL_Rect dRect; 56 57 bool recording; 58 string videoPath; 59 Video video; 60 61 public: 62 63 this(Lt* lattice, Pt* palette, Window window) 64 { 65 this.lattice = lattice; 66 this.palette = palette; 67 68 this.window = window; 69 70 texture = new Texture(window, lattice.getLatticeBounds()[0], lattice.getLatticeBounds()[1]); 71 sRect = SDL_Rect(0, 0, texture.getWidth(), texture.getHeight()); 72 dRect = setupDRect(); 73 74 recording = false; 75 videoPath = null; 76 video = null; 77 } 78 79 void render() 80 { 81 { 82 uint* pixels = texture.lock(); 83 scope(exit) texture.unlock(); 84 85 for(int row=0; row<sRect.h; row++) 86 { 87 for(int col=0; col<sRect.w; col++) 88 { 89 pixels[row * texture.getWidth() + col] = 90 palette.getDisplayValue(lattice.get(sRect.x + col, sRect.y + row)); 91 } 92 } 93 94 if(recording) 95 video.addFrame(Image.fromColorValues(pixels, sRect.w, sRect.h)); 96 } 97 98 SDL_RenderCopy(window.getRenderer(), texture.getTexture(), &sRect, &dRect); 99 SDL_RenderPresent(window.getRenderer()); 100 } 101 102 void screenshot(string path) 103 in 104 { assert(path !is(null)); } 105 body 106 { 107 Image image = Image.fromColorValues(texture.lock(), sRect.w, sRect.h); 108 scope(exit) texture.unlock(); 109 110 image.saveToFile(path); 111 } 112 113 void startRecording(string path, uint framerate) 114 { 115 if(recording) 116 stopRecording(); 117 118 recording = true; 119 video = new Video(path, framerate); 120 videoPath = path; 121 } 122 123 void stopRecording() 124 { 125 video.saveToFile(); 126 recording = false; 127 video = null; 128 videoPath = null; 129 } 130 131 132 private: 133 134 SDL_Rect setupDRect() 135 { 136 SDL_Rect dRect; 137 138 float ratio = cast(float) (sRect.y + sRect.h) / (sRect.x + sRect.w); 139 float windowRatio = cast(float) (window.getHeight()) / window.getWidth(); 140 141 if(ratio <= windowRatio) 142 { 143 dRect.x = 0; 144 dRect.w = window.getWidth(); 145 dRect.y = cast(int) ((window.getHeight() - window.getWidth() * ratio) / 2); 146 dRect.h = cast(int) (window.getWidth() * ratio); 147 } 148 else 149 { 150 dRect.y = 0; 151 dRect.h = window.getHeight(); 152 dRect.x = cast(int) ((window.getWidth() - window.getHeight() * 1/ratio) / 2); 153 dRect.w = cast(int) (window.getHeight() * 1/ratio); 154 } 155 156 return dRect; 157 } 158 } 159 160 161 162 version(unittest) 163 { 164 import caLib_abstract.renderer : isRenderer; 165 import caLib_abstract.lattice : BoundedLattice; 166 import caLib_abstract.palette : Palette; 167 } 168 169 170 171 unittest 172 { 173 alias Ct = string; 174 assert(isRenderer!(TwoDimBasicRenderer!(Ct, BoundedLattice!(Ct, 2), Palette!(Ct, Color)))); 175 }