Merge branch 'transfilterfix' into 'master'
[xonotic/netradiant.git] / plugins / spritemodel / plugin.cpp
1 /*
2    Copyright (C) 2002 Dominic Clifton.
3
4    This file is part of GtkRadiant.
5
6    GtkRadiant is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    GtkRadiant is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with GtkRadiant; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 //
22 // Sprite Model Plugin
23 //
24 // Code by Hydra aka Dominic Clifton
25 //
26 // Based on MD3Model source code by SPoG
27 //
28
29 /*
30     Overview
31     ========
32
33
34     Why ?
35     -----
36
37     It allows the user to see a graphical representation of the entity in the 3D view (maybe 2D views later) where the entity would just otherwise be a non-descriptive coloured box.
38
39     It is designed to be used with the entity view set to WireFrame (as the sprite images are rendered in the middle of the entity's bbox.
40
41     How ?
42     -----
43
44     Implemented as a model module, without any ISelect stuff.
45
46     For an entity to use an image (instead of a model) you just update the entity defintion file so that the eclass_t's modelpath is filled in with a relative path and filename of an image file.
47
48     e.g:
49
50       baseq3/scripts/entities.def
51       ===========================
52
53    \/\*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) SUSPENDED
54       ...
55       -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
56       model="sprites/powerups/ammo/bfgam.bmp"\*\/
57
58
59       valve/scripts/halflife.fgd
60       ==========================
61
62       @PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light) = light : "Invisible   lightsource"
63       [
64               ...
65       ]
66
67     What image formats are supported ?
68     ----------------------------------
69
70     This module can load any image format that there is an active image module for.  For q3 this would be bmp, tga and jpg.  For Half-Life this would be hlw and spr.
71
72     Version History
73     ===============
74
75     v0.1 - 27/May/2002
76       - Created an inital implementation of a sprite model plugin.
77         According to the powers that be, it seems creating a model
78         plugin is hackish.
79         It works ok, but there is no way to attach models (sprites if you will)
80         to non-fixedsize entities (like func_bombtarget)
81         Also, I can't get the alpha map stuff right so I had to invert the alpha
82         mask in the spr loader so that 0xff = not drawn pixel.
83
84     ToDo
85     ====
86
87  * make sprites always face the camera (is this done in camwindow.cpp ?)
88
89  * maybe add an option to scale the sprites in the prefs ?
90
91  * un-hack the default fall-though to "sprite" model version (see m_version)
92
93  * maybe convert to a new kind of class not based on model.
94
95  * allow sprites on non-fixedsize ents
96
97  * fix reversed alpha map in spr loader
98
99  * allow an entity to have both an .md? and a sprite model.
100  */
101
102 #include "plugin.h"
103 #include "spritemodel.h"
104
105 // =============================================================================
106 // Globals
107
108 // function tables
109 _QERFuncTable_1 __QERTABLENAME;
110 OpenGLBinding g_QglTable;
111 _QERShadersTable g_ShadersTable;
112
113 // =============================================================================
114 // SYNAPSE
115
116 #include "synapse.h"
117
118
119 char *supportedmodelformats[] = {"spr", "bmp", "tga", "jpg", "hlw", NULL}; // NULL is list delimiter
120
121 static void add_model_apis(CSynapseClient &client)
122 {
123     char **ext;
124     for (ext = supportedmodelformats; *ext != NULL; ext++) {
125         client.AddAPI(MODEL_MAJOR, *ext, sizeof(_QERPlugModelTable));
126     }
127 }
128
129 static bool model_is_supported(const char *extension)
130 {
131     char **ext;
132     for (ext = supportedmodelformats; *ext != NULL; ext++) {
133         if (stricmp(extension, *ext) == 0) {
134             return true;
135         }
136     }
137     return false;
138 }
139
140 void init_filetypes()
141 {
142     char **ext;
143     for (ext = supportedmodelformats; *ext != NULL; ext++) {
144         GetFileTypeRegistry()->addType(MODEL_MAJOR, filetype_t("sprite", *ext));
145     }
146 }
147
148 extern CSynapseServer *g_pSynapseServer;
149
150 class CSynapseClientModel : public CSynapseClient {
151 public:
152 // CSynapseClient API
153     bool RequestAPI(APIDescriptor_t *pAPI);
154
155     const char *GetInfo();
156
157     const char *GetName();
158
159     CSynapseClientModel()
160     {}
161
162     virtual ~CSynapseClientModel()
163     {}
164
165     bool OnActivate()
166     {
167         init_filetypes(); // see todo list above.
168         return true;
169     }
170 };
171
172 CSynapseServer *g_pSynapseServer = NULL;
173 CSynapseClientModel g_SynapseClient;
174
175 extern "C" CSynapseClient *SYNAPSE_DLL_EXPORT
176
177 Synapse_EnumerateInterfaces(const char *version, CSynapseServer *pServer)
178 {
179     if (strcmp(version, SYNAPSE_VERSION)) {
180         Syn_Printf("ERROR: synapse API version mismatch: should be '"
181         SYNAPSE_VERSION
182         "', got '%s'\n", version );
183         return NULL;
184     }
185     g_pSynapseServer = pServer;
186     g_pSynapseServer->IncRef();
187     Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
188
189     add_model_apis(g_SynapseClient); // see todo list above.
190
191     g_SynapseClient.AddAPI(PLUGIN_MAJOR, "sprite", sizeof(_QERPluginTable));
192     g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
193     g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable);
194     g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(g_ShadersTable), SYN_REQUIRE, &g_ShadersTable);
195
196     return &g_SynapseClient;
197 }
198
199 bool CSynapseClientModel::RequestAPI(APIDescriptor_t *pAPI)
200 {
201     if (!strcmp(pAPI->major_name, MODEL_MAJOR)) {
202         _QERPlugModelTable *pTable = static_cast<_QERPlugModelTable *>( pAPI->mpTable );
203
204         if (!strcmp(pAPI->minor_name, "sprite")) {
205             pTable->m_pfnLoadModel = &LoadSpriteModel;
206             return true;
207         }
208     }
209
210     Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
211     return false;
212 }
213
214 #include "version.h"
215
216 const char *CSynapseClientModel::GetInfo()
217 {
218     return "Sprite Model module built " __DATE__ " "
219     RADIANT_VERSION;
220 }
221
222 const char *CSynapseClientModel::GetName()
223 {
224     return "sprite";
225 }