more hud api
[dd2d.git] / d2dsprite.d
blobc42fd8abe4e03fa356d3d55332743bf1ff791ad8
1 /* DooM2D: Midnight on the Firing Line
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module d2dsprite is aliced;
20 private:
21 import iv.glbinds;
22 import glutils;
23 import console;
24 import dacs;
25 import d2dgfx;
26 import tatlas;
28 //version = tatlas_dump;
31 // ////////////////////////////////////////////////////////////////////////// //
32 // sprite atlases
33 __gshared TexAtlas[] atlases;
34 __gshared ImgSprite[string] sprImages;
37 // ////////////////////////////////////////////////////////////////////////// //
38 public void realiseSpriteAtlases () {
39 foreach (immutable idx, TexAtlas a; atlases) {
40 import arsd.png;
41 import std.string : format;
42 a.updateTexture();
43 version(tatlas_dump) writePng("_za%02s.png".format(idx), a.img);
48 // ////////////////////////////////////////////////////////////////////////// //
49 public class ImgSprite {
50 D2DImage vga;
51 bool mirrored;
52 TexAtlas atlas;
53 TexAtlas.Rect arect;
54 TexAtlas.FRect frect;
55 GLuint listBase; // gl lists (4)
57 private this () {}
59 ~this () { if (/*!mirrored &&*/ listBase) glDeleteLists(listBase, 4); listBase = 0; }
61 final:
62 void putToAtlas () {
63 if (atlas !is null) return;
64 TexAtlas.Rect arc;
65 TexAtlas aa;
66 foreach (TexAtlas a; atlases) {
67 auto rc = a.insert(vga);
68 if (rc.valid) { arc = rc; aa = a; break; }
70 if (!arc.valid) {
71 int w = (vga.width < 1024 ? 1024 : vga.width);
72 int h = (vga.height < 1024 ? 1024 : vga.height);
73 aa = new TexAtlas(w, h);
74 arc = aa.insert(vga);
75 assert(arc.valid);
76 atlases ~= aa;
78 vga.releaseImage;
79 atlas = aa;
80 arect = arc;
81 frect = aa.texCoords(arc);
82 createLists();
85 private void createLists () {
86 listBase = glGenLists(4);
87 foreach (immutable my; 0..2) {
88 foreach (immutable mx; 0..2) {
89 GLuint ln = listBase+(my*2)+mx;
90 glNewList(ln, GL_COMPILE);
91 int x0 = -(mirrored ? vga.width-1-vga.sx : vga.sx);
92 int y0 = -vga.sy;
93 int x1 = x0+vga.width;
94 int y1 = y0+vga.height;
95 if (mx) { int tmp = x0; x0 = x1; x1 = tmp; }
96 if (my) { int tmp = y0; y0 = y1; y1 = tmp; }
97 glBegin(GL_QUADS);
98 glTexCoord2f(frect.x0, frect.y0); glVertex2i(x0, y0); // top-left
99 glTexCoord2f(frect.x1, frect.y0); glVertex2i(x1, y0); // top-right
100 glTexCoord2f(frect.x1, frect.y1); glVertex2i(x1, y1); // bottom-right
101 glTexCoord2f(frect.x0, frect.y1); glVertex2i(x0, y1); // bottom-left
102 glEnd();
103 glEndList();
108 void drawAtXY (int x, int y, bool mirrorX=false, bool mirrorY=false) {
109 if (atlas is null || !atlas.hasTexture) return;
110 //if (listBase == 0) createLists();
111 if (mirrored) mirrorX = !mirrorX;
112 ubyte lnum = (mirrorX ? 0x01 : 0x00)|(mirrorY ? 0x02 : 0x00);
113 bindTexture(atlas.tex.tid);
114 glPushMatrix();
115 scope(exit) glPopMatrix();
116 glTranslatef(x, y, 0);
117 glCallList(listBase+lnum);
122 public final class ImgSpriteMirrored : ImgSprite {
123 private this (ImgSprite aspr) {
124 vga = aspr.vga;
125 mirrored = true;
126 atlas = aspr.atlas;
127 arect = aspr.arect;
128 frect = aspr.frect;
129 assert(atlas !is null);
130 //listBase = aspr.listBase;
131 listBase = 0;
132 createLists();
137 // ////////////////////////////////////////////////////////////////////////// //
138 ImgSprite loadSpriteIntr (string spfilename, bool checkMirror, bool updateAtlas) {
139 if (spfilename.length == 0) return null;
140 ImgSprite im;
141 if (auto imm = spfilename in sprImages) {
142 // cached sprite
143 //conwriteln("cached sprite '", spfilename, "'");
144 im = *imm;
145 } else {
146 // new sprite
147 import std.algorithm : endsWith;
148 string spnameReal = spfilename;
149 if (checkMirror && spnameReal.endsWith("_mirrored.vga")) {
150 // for mirrored, load normal sprite and create mirrored one
151 spnameReal = spnameReal[0..$-13]~".vga";
152 if (auto imm = spnameReal in sprImages) {
153 im = *imm;
154 } else {
155 im = loadSpriteIntr(spnameReal, false, updateAtlas);
156 if (im !is null && updateAtlas) realiseSpriteAtlases();
158 if (im is null) return null;
159 im = new ImgSpriteMirrored(im);
160 assert(im.mirrored);
161 assert(im.listBase);
162 //conwriteln("mirroired sprite '", spfilename, "' [", spnameReal, "]");
163 } else {
164 im = new ImgSprite();
165 //conwriteln("loading sprite '", spfilename, "'");
166 im.vga = new D2DImage(spfilename);
167 im.putToAtlas();
168 if (updateAtlas) realiseSpriteAtlases();
170 sprImages[spfilename] = im;
172 return im;
176 public ImgSprite loadSprite (string spfilename, bool updateAtlas=false) { return loadSpriteIntr(spfilename, true, updateAtlas); }