1 /*
2  *  BSD 3-Clause License
3  *  
4  *  Copyright (c) 2016, Mango-Engine Team
5  *  All rights reserved.
6  *  
7  *  Redistribution and use in source and binary forms, with or without
8  *  modification, are permitted provided that the following conditions are met:
9  *  
10  *  * Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *  
13  *  * Redistributions in binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *  
17  *  * Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from
19  *    this software without specific prior written permission.
20  *  
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 module mango_engine.graphics.opengl.gl_texture;
33 
34 version(mango_GLBackend) {
35     import mango_engine.game;
36     import mango_engine.graphics.texture;
37 
38     import blocksound.util : toCString;
39 
40     import derelict.opengl3.gl3;
41     import derelict.freeimage.freeimage;
42 
43     /// Uses FreeImage to load a BitMap.
44     FIBITMAP* loadImageBitMap(in string file) @system {
45         FIBITMAP* map;
46         FREE_IMAGE_FORMAT format;
47 
48         format = FreeImage_GetFileType(toCString(file), 0);
49 
50         if(format == FIF_UNKNOWN) {
51             throw new ImageLoadException(file ~ " has an unknown format!");
52         }
53         if(!FreeImage_FIFSupportsReading(format)) {
54             throw new ImageLoadException(file ~ " is not supported for reading!");
55         }
56 
57         map = FreeImage_Load(format, toCString(file));
58         return map;
59     }
60 
61     class GLTexture : Texture {
62         package shared GLuint textureId;
63 
64         this(GameManager game, in string name, in string filename, in bool useAlpha = true) @safe {
65             super(game, name, filename, useAlpha);
66 
67             this.game.renderer.submitOperation(&this.doLoad);
68         }
69 
70         void use() @system nothrow {
71             glBindTexture(GL_TEXTURE_2D, this.textureId);
72             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
73         }
74 
75         private void doLoad() @trusted {
76             FIBITMAP* map = loadImageBitMap(this.filename);
77             if(!map) {
78                 throw new ImageLoadException("Failed to load Texture: " ~ filename);
79             }
80 
81             _width = FreeImage_GetWidth(map);
82             _height = FreeImage_GetHeight(map);
83 
84             GLuint id;
85 
86             glGenTextures(1, &id);
87             this.textureId = id;
88             use();
89 
90             setOptions();
91 
92             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, useAlpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, FreeImage_GetBits(map));
93             glGenerateMipmap(GL_TEXTURE_2D);
94 
95             FreeImage_Unload(map);
96         }
97 
98         protected void setOptions() @system nothrow {
99             // TODO: adjustable
100             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
101             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
102 
103             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
104             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
105         }
106 
107         override void cleanup() @system {
108             this.game.renderer.submitOperation(() {
109                 GLuint id = this.textureId;
110                 
111                 glDeleteTextures(1, &id);
112             });
113         }
114     }
115 }
116 
117 /// Exception related to loading images.
118 class ImageLoadException : Exception {
119     /// Default constructor.
120     this(in string message) @safe nothrow {
121         super(message);
122     }
123 }