fixes for API renaming
[k8vacspelynky.git] / packages / Sprites / BackTileStore.vc
bloba4fc8ed2946f10e5b9d7f3c975d0ea5a6f42bc1e
1 /**************************************************************************
2  *    This program is free software; you can redistribute it and/or
3  *  modify it under the terms of the GNU General Public License
4  *  as published by the Free Software Foundation; either version 3
5  *  of the License, or (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU General Public License for more details.
11  **************************************************************************/
12 class BackTileImage : Object transient;
14 name Name;
15 GLTexture tex;
16 int wdt, hgt;
17 int xofs, yofs;
18 int xsep, ysep;
19 int tileWidth, tileHeight;
20 bool goodSize;
23 override void Destroy () {
24   delete tex;
25   ::Destroy();
29 static final int roundToPOW (int n) {
30   --n;
31   n |= n>>1;
32   n |= n>>2;
33   n |= n>>4;
34   n |= n>>8;
35   n |= n>>16;
36   ++n;
37   return n;
41 final void blitAt (int x, int y, int scale, optional float angle) {
42   if (goodSize) {
43     tex.blitAt(x, y, scale, angle:angle!optional);
44   } else {
45     int w = wdt, h = hgt;
46     tex.blitExt(x, y, x+w*scale, y+h*scale, 0, 0, w, h, angle:angle!optional);
47   }
51 static final BackTileImage Load (string fname) {
52   bool allowNPot = GLVideo.glHasNPOT;
53   //if (allowNPot) writeln("*** NPOT textures allowed");
54   //allowNPot = false;
56   auto fl = TextReader.Open(fname);
57   if (!fl) return none;
58   // signature
59   string sign = fl.readBuf(4, true); // exact
60   if (sign != "TIL0" || fl.error) { delete fl; return none; }
61   // name
62   int nlen = fl.readU8();
63   if (fl.error) { delete fl; return none; }
64   string btName;
65   if (nlen) {
66     btName = fl.readBuf(nlen, true); // exact
67     if (fl.error) { delete fl; return none; }
68   }
69   // offset
70   int xofs = fl.readI16();
71   int yofs = fl.readI16();
72   // sep (???)
73   int xsep = fl.readI16();
74   int ysep = fl.readI16();
75   // tile dimensions
76   int tileW = fl.readU16();
77   int tileH = fl.readU16();
78   // image dimensions
79   int imageW = fl.readU16();
80   int imageH = fl.readU16();
81   if (fl.error) { delete fl; return none; }
82   if (imageW < 1 || imageH < 1 || imageW > 8192 || imageH > 8192) { delete fl; return none; }
83   if (tileW < 1 || tileH < 1 || tileW > imageW || tileH > imageH || imageW%tileW || imageH%tileH) { delete fl; return none; }
85   int txw = (allowNPot ? imageW : roundToPOW(imageW));
86   int txh = (allowNPot ? imageH : roundToPOW(imageH));
88   auto bgimg = SpawnObject(BackTileImage);
89   bgimg.Name = name(btName);
90   bgimg.wdt = imageW;
91   bgimg.hgt = imageH;
92   bgimg.goodSize = (txw == imageW && txh == imageH);
93   bgimg.xofs = xofs;
94   bgimg.yofs = yofs;
95   bgimg.xsep = xsep;
96   bgimg.ysep = ysep;
97   bgimg.tileWidth = tileW;
98   bgimg.tileHeight = tileH;
100   // load image
101   auto tex = GLTexture.CreateEmpty(txw, txh, name(btName));
102   if (!tex) { delete fl; delete bgimg; return none; }
103   bgimg.tex = tex;
104   foreach (int y; 0..imageH) {
105     foreach (int x; 0..imageW) {
106       ubyte r = fl.readU8();
107       ubyte g = fl.readU8();
108       ubyte b = fl.readU8();
109       ubyte a = 255-fl.readU8();
110       if (fl.error) { delete fl; delete bgimg; return none; }
111       //write("(", a, ",", r, ",", g, ",", b, ") ");
112       tex.setPixel(x, y, (a<<24)|(r<<16)|(g<<8)|b);
113     }
114     foreach (int x; imageW..txw) tex.setPixel(x, y, 0xff_00_00_00);
115     //writeln();
116   }
117   foreach (int y; imageH..txh) foreach (int x; imageW..txw) tex.setPixel(x, y, 0xff_00_00_00);
118   // update texture image
119   tex.upload();
121   delete fl;
122   return bgimg;
126 #define ALT_LIGHT_ATT_FORMULA
127 // color doesn't matter (and it is white for no reason); only alpha matters
128 static final BackTileImage buildLightTexture (name aname, int radius) {
129   auto tex = GLTexture.CreateEmpty(radius*2, radius*2, aname);
130   float sqrad = radius*radius;
131 #ifndef ALT_LIGHT_ATT_FORMULA
132   float minLight = 0.3;
133   float b = 1.0/(sqrad*minLight);
134 #endif
135   foreach (int y; 0..radius+1) {
136     foreach (int x; 0..radius+1) {
137       float dist = sqrt(x*x+y*y);
138 #ifdef ALT_LIGHT_ATT_FORMULA
139       float att = fclamp(1.0-dist*dist/sqrad, 0.0, 1.0);
140       att *= att;
141 #else
142       float att = 1.0/(1.0+b*dist*dist);
143       /*
144            if (att > 0.6) att += att/2.0;
145       else if (att < 0.6) att -= att/2.0;
146       */
147       //float att = 1.0-(dist/radius);
148 #endif
149       ubyte a = 255-int(fclamp(255.0*att, 0, 255));
150       int color = (a<<24)|0xff_ff_ff;
151       if (dist >= radius-8) color = 0xff_00_00_00;
152       tex.setPixel(radius-x, radius-y, color);
153       tex.setPixel(x+radius, radius-y, color);
154       tex.setPixel(radius-x, y+radius, color);
155       tex.setPixel(x+radius, y+radius, color);
156     }
157   }
158   tex.upload();
159   auto bgimg = SpawnObject(BackTileImage);
160   bgimg.Name = aname;
161   bgimg.xofs = 0;
162   bgimg.yofs = 0;
163   bgimg.xsep = 0;
164   bgimg.ysep = 0;
165   bgimg.tileWidth = radius*2;
166   bgimg.tileHeight = radius*2;
167   bgimg.tex = tex;
168   return bgimg;
172 static final BackTileImage buildCircleTexture (name aname, int radius) {
173   auto tex = GLTexture.CreateEmpty(radius*2, radius*2, aname);
174   float sqradius = radius*radius;
175   foreach (int y; 0..radius+1) {
176     foreach (int x; 0..radius+1) {
177       float dist = x*x+y*y;
178       int color = (dist < sqradius ? 0x00_ff_ff_ff : 0xff_00_00_00);
179       tex.setPixel(radius-x, radius-y, color);
180       tex.setPixel(x+radius, radius-y, color);
181       tex.setPixel(radius-x, y+radius, color);
182       tex.setPixel(x+radius, y+radius, color);
183     }
184   }
185   tex.upload();
186   auto bgimg = SpawnObject(BackTileImage);
187   bgimg.Name = aname;
188   bgimg.xofs = 0;
189   bgimg.yofs = 0;
190   bgimg.xsep = 0;
191   bgimg.ysep = 0;
192   bgimg.tileWidth = radius*2;
193   bgimg.tileHeight = radius*2;
194   bgimg.tex = tex;
195   return bgimg;
199 // ////////////////////////////////////////////////////////////////////////// //
200 class BackTileStore : Object transient;
202 array!BackTileImage bgbyid;
203 string tilePath;
204 bool bDumpLoaded;
207 private final void loadTile (name Name) {
208   if (!Name) FatalError("cannot load namelss sprite");
209   auto bgtile = BackTileImage.Load(va("%s/%n.tile", tilePath, Name));
210   if (!bgtile) FatalError("cannot load sprite '%n'", Name);
212   bgbyid[NameToInt(bgtile.Name)] = bgtile;
214   if (bDumpLoaded) {
215     writeln("bgtile: <", bgtile.Name, ">, id=", NameToInt(bgtile.Name), "; size=", bgtile.tex.width, "x", bgtile.tex.height);
216   }
220 final BackTileImage opIndex (name Name) {
221   int id = NameToInt(Name);
222   if (id <= 0) return none; // just in case
223   if (id >= bgbyid.length || !bgbyid[id]) loadTile(Name);
224   return (id >= 0 && id < bgbyid.length ? bgbyid[id] : none);
228 final BackTileImage lightTexture (name aname, int radius) {
229   if (!aname || radius < 8) return none;
230   int id = NameToInt(aname);
231   if (id <= 0) return none; // just in case
232   if (id >= bgbyid.length || !bgbyid[id]) {
233     writeln("creating light texture with raduis ", radius);
234     auto bi = BackTileImage.buildLightTexture(aname, radius);
235     bgbyid[id] = bi;
236   }
237   return (id >= 0 && id < bgbyid.length ? bgbyid[id] : none);
241 final BackTileImage circleTexture (name aname, int radius) {
242   if (!aname || radius < 8) return none;
243   int id = NameToInt(aname);
244   if (id <= 0) return none; // just in case
245   if (id >= bgbyid.length || !bgbyid[id]) {
246     auto bi = BackTileImage.buildCircleTexture(aname, radius);
247     bgbyid[id] = bi;
248   }
249   return (id >= 0 && id < bgbyid.length ? bgbyid[id] : none);
253 defaultproperties {
254   //tilePath = "data/gfx/tiles";
255   tilePath = "tiles";